mirror of
https://github.com/xcat2/xNBA.git
synced 2024-12-13 23:01:31 +00:00
Activation code now generalised as well.
This commit is contained in:
parent
1980018b8b
commit
85dd4fd8d6
@ -35,8 +35,17 @@
|
||||
|
||||
#include "etherboot.h"
|
||||
#include "timer.h"
|
||||
#include "io.h"
|
||||
#include "isapnp.h"
|
||||
|
||||
/*
|
||||
* Ensure that there is sufficient space in the shared dev_bus
|
||||
* structure for a struct isapnp_device.
|
||||
*
|
||||
*/
|
||||
DEV_BUS( struct isapnp_device, isapnp_dev );
|
||||
static char isapnp_magic[0]; /* guaranteed unique symbol */
|
||||
|
||||
/*
|
||||
* We can have only one ISAPnP bus in a system. Once the read port is
|
||||
* known and all cards have been allocated CSNs, there's nothing to be
|
||||
@ -51,8 +60,6 @@
|
||||
static uint16_t isapnp_read_port;
|
||||
static uint16_t isapnp_max_csn;
|
||||
|
||||
static const char initdata[] = INITDATA;
|
||||
|
||||
/*
|
||||
* ISAPnP utility functions
|
||||
*
|
||||
@ -66,13 +73,18 @@ static inline void isapnp_write_data ( uint8_t data ) {
|
||||
outb ( data, ISAPNP_WRITE_DATA );
|
||||
}
|
||||
|
||||
static inline uint8_t isapnp_read_data ( void ) {
|
||||
return inb ( isapnp_read_port );
|
||||
}
|
||||
|
||||
static inline void isapnp_write_byte ( uint8_t address, uint8_t value ) {
|
||||
isapnp_write_address ( address );
|
||||
isapnp_write_data ( value );
|
||||
}
|
||||
|
||||
static inline uint8_t isapnp_read_data ( void ) {
|
||||
return inb ( isapnp_read_port );
|
||||
static inline uint8_t isapnp_read_byte ( uint8_t address ) {
|
||||
isapnp_write_address ( address );
|
||||
return isapnp_read_data ();
|
||||
}
|
||||
|
||||
static inline void isapnp_set_read_port ( void ) {
|
||||
@ -95,10 +107,32 @@ static inline void isapnp_wake ( uint8_t csn ) {
|
||||
isapnp_write_byte ( ISAPNP_WAKE, csn );
|
||||
}
|
||||
|
||||
static inline uint8_t isapnp_read_resourcedata ( void ) {
|
||||
return isapnp_read_byte ( ISAPNP_RESOURCEDATA );
|
||||
}
|
||||
|
||||
static inline uint8_t isapnp_read_status ( void ) {
|
||||
return isapnp_read_byte ( ISAPNP_STATUS );
|
||||
}
|
||||
|
||||
static inline void isapnp_write_csn ( uint8_t csn ) {
|
||||
isapnp_write_byte ( ISAPNP_CARDSELECTNUMBER, csn );
|
||||
}
|
||||
|
||||
static inline void isapnp_logicaldevice ( uint8_t logdev ) {
|
||||
isapnp_write_byte ( ISAPNP_LOGICALDEVICENUMBER, logdev );
|
||||
}
|
||||
|
||||
static inline void isapnp_activate ( uint8_t logdev ) {
|
||||
isapnp_logicaldevice ( logdev );
|
||||
isapnp_write_byte ( ISAPNP_ACTIVATE, 1 );
|
||||
}
|
||||
|
||||
static inline void isapnp_deactivate ( uint8_t logdev ) {
|
||||
isapnp_logicaldevice ( logdev );
|
||||
isapnp_write_byte ( ISAPNP_ACTIVATE, 0 );
|
||||
}
|
||||
|
||||
/*
|
||||
* The linear feedback shift register as described in Appendix B of
|
||||
* the PnP ISA spec. The hardware implementation uses eight D-type
|
||||
@ -153,6 +187,42 @@ static uint8_t isapnp_checksum ( union isapnp_identifier *identifier ) {
|
||||
return lfsr;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read a byte of resource data from the current location
|
||||
*
|
||||
*/
|
||||
static inline uint8_t isapnp_peek_byte ( void ) {
|
||||
int i;
|
||||
|
||||
/* Wait for data to be ready */
|
||||
for ( i = 0 ; i < 20 ; i ++ ) {
|
||||
if ( isapnp_read_status() & 0x01 ) {
|
||||
/* Byte ready - read it */
|
||||
return isapnp_read_resourcedata();
|
||||
}
|
||||
udelay ( 100 );
|
||||
}
|
||||
/* Data never became ready - return 0xff */
|
||||
return 0xff;
|
||||
}
|
||||
|
||||
/*
|
||||
* Read n bytes of resource data from the current location. If buf is
|
||||
* NULL, discard data.
|
||||
*
|
||||
*/
|
||||
static void isapnp_peek ( uint8_t *buf, size_t bytes ) {
|
||||
unsigned int i;
|
||||
uint8_t byte;
|
||||
|
||||
for ( i = 0 ; i < bytes ; i++) {
|
||||
byte = isapnp_peek_byte();
|
||||
if ( buf ) {
|
||||
buf[i] = byte;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Try isolating ISAPnP cards at the current read port. Return the
|
||||
* number of ISAPnP cards found.
|
||||
@ -277,146 +347,6 @@ static void isapnp_isolate ( void ) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Build device list for all present ISA PnP devices.
|
||||
*/
|
||||
static int isapnp_build_device_list(void)
|
||||
{
|
||||
int csn, device, vendor, serial;
|
||||
unsigned char header[9], checksum;
|
||||
for (csn = 1; csn <= 10; csn++) {
|
||||
Wake(csn);
|
||||
isapnp_peek(header, 9);
|
||||
checksum = isapnp_checksum(header);
|
||||
#ifdef EDEBUG
|
||||
printf
|
||||
("vendor: 0x%hX:0x%hX:0x%hX:0x%hX:0x%hX:0x%hX:0x%hX:0x%hX:0x%hX\n",
|
||||
header[0], header[1], header[2], header[3], header[4],
|
||||
header[5], header[6], header[7], header[8]);
|
||||
printf("checksum = 0xhX\n", checksum);
|
||||
#endif
|
||||
/* Don't be strict on the checksum, here !
|
||||
e.g. 'SCM SwapBox Plug and Play' has header[8]==0 (should be: b7) */
|
||||
if (header[8] == 0);
|
||||
else if (checksum == 0x00 || checksum != header[8]) /* not valid CSN */
|
||||
continue;
|
||||
|
||||
vendor = (header[1] << 8) | header[0];
|
||||
device = (header[3] << 8) | header[2];
|
||||
serial =
|
||||
(header[7] << 24) | (header[6] << 16) | (header[5] <<
|
||||
8) |
|
||||
header[4];
|
||||
if (vendor == 0x6D50)
|
||||
if (device == 0x5150) {
|
||||
printf
|
||||
("\nFound 3Com 3c515 PNP Card!\n Vendor ID: 0x%hX, Device ID: 0x%hX, Serial Num: 0x%hX\n",
|
||||
vendor, device, serial);
|
||||
pnp_card_csn = csn;
|
||||
}
|
||||
isapnp_checksum_value = 0x00;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Config(int csn)
|
||||
{
|
||||
#define TIMEOUT_PNP 100
|
||||
unsigned char id[IDENT_LEN];
|
||||
int i, x;
|
||||
Wake(csn);
|
||||
udelay(1000);
|
||||
for (i = 0; i < IDENT_LEN; i++) {
|
||||
for (x = 1; x < TIMEOUT_PNP; x++) {
|
||||
if (STATUS & 1)
|
||||
break;
|
||||
udelay(1000);
|
||||
}
|
||||
id[i] = RESOURCEDATA;
|
||||
#ifdef EDEBUG
|
||||
printf(" 0x%hX ", id[i]);
|
||||
#endif
|
||||
}
|
||||
#ifdef EDEBUG
|
||||
printf("Got The status bit\n");
|
||||
#endif
|
||||
/*Set Logical Device Register active */
|
||||
LOGICALDEVICENUMBER;
|
||||
/* Specify the first logical device */
|
||||
WRITE_DATA(0);
|
||||
|
||||
|
||||
/* Apparently just activating the card is enough
|
||||
for Etherboot to detect it. Why bother with the
|
||||
following code. Left in place in case it is
|
||||
later required */
|
||||
/*==========================================*/
|
||||
/* set DMA */
|
||||
/* ADDRESS(0x74 + 0);
|
||||
WRITE_DATA(7); */
|
||||
|
||||
/*Set IRQ */
|
||||
/* udelay(1000);
|
||||
ADDRESS(0x70 + (0 << 1));
|
||||
WRITE_DATA(9);
|
||||
udelay(1000); */
|
||||
/*=============================================*/
|
||||
/*Activate */
|
||||
ACTIVATE;
|
||||
WRITE_DATA(1);
|
||||
udelay(250);
|
||||
/* Ask for access to the Wait for Key command - ConfigControl register */
|
||||
CONFIGCONTROL;
|
||||
/* Write the Wait for Key Command to the ConfigControl Register */
|
||||
WRITE_DATA(CONFIG_WAIT_FOR_KEY);
|
||||
/* As per doc. Two Write cycles of 0x00 required befor the Initialization key is sent */
|
||||
ADDRESS(0);
|
||||
ADDRESS(0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
static void isapnp_peek(unsigned char *data, int bytes)
|
||||
{
|
||||
int i, j;
|
||||
unsigned char d = 0;
|
||||
|
||||
for (i = 1; i <= bytes; i++) {
|
||||
for (j = 0; j < 20; j++) {
|
||||
d = STATUS;
|
||||
if (d & 1)
|
||||
break;
|
||||
udelay(100);
|
||||
}
|
||||
if (!(d & 1)) {
|
||||
if (data != NULL)
|
||||
*data++ = 0xff;
|
||||
continue;
|
||||
}
|
||||
d = RESOURCEDATA; /* PRESDI */
|
||||
isapnp_checksum_value += d;
|
||||
if (data != NULL)
|
||||
*data++ = d;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Ensure that there is sufficient space in the shared dev_bus
|
||||
* structure for a struct isapnp_device.
|
||||
*
|
||||
*/
|
||||
DEV_BUS( struct isapnp_device, isapnp_dev );
|
||||
static char isapnp_magic[0]; /* guaranteed unique symbol */
|
||||
|
||||
/*
|
||||
* Fill in parameters for an ISAPnP device based on CSN
|
||||
*
|
||||
@ -424,23 +354,45 @@ static char isapnp_magic[0]; /* guaranteed unique symbol */
|
||||
*
|
||||
*/
|
||||
static int fill_isapnp_device ( struct isapnp_device *isapnp ) {
|
||||
|
||||
/*
|
||||
* Ensure that all ISAPnP cards have CSNs allocated to them,
|
||||
union isapnp_identifier identifier;
|
||||
|
||||
/* Ensure that all ISAPnP cards have CSNs allocated to them,
|
||||
* if we haven't already done so.
|
||||
*
|
||||
*/
|
||||
if ( ! isapnp_read_port ) {
|
||||
isapnp_isolate();
|
||||
}
|
||||
|
||||
/* wake csn, read config, send card to sleep */
|
||||
/* Wake the specified CSN */
|
||||
isapnp_wait_for_key ();
|
||||
isapnp_send_key ();
|
||||
isapnp_wake ( isapnp->csn );
|
||||
|
||||
/* Read the identifier and verify the checksum. Allow
|
||||
* checksum = 0 to cope with cards that just generate the
|
||||
* checksum using the LFSR during serial isolation.
|
||||
*/
|
||||
isapnp_peek ( identifier.bytes, sizeof ( identifier ) );
|
||||
if ( ( identifier.checksum != 0 ) &&
|
||||
( identifier.checksum != isapnp_checksum ( &identifier ) ) ) {
|
||||
DBG ( "ISAPnP invalid checksum on CSN %hhx "
|
||||
"(is %hhx, should be %hhx)\n", isapnp->csn,
|
||||
identifier.checksum, isapnp_checksum ( &identifier ) );
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read information from identifier structure */
|
||||
isapnp->vendor_id = identifier.vendor_id;
|
||||
isapnp->prod_id = identifier.prod_id;
|
||||
|
||||
/* Return all cards to Wait for Key state */
|
||||
isapnp_wait_for_key ();
|
||||
|
||||
DBG ( "ISAPnP found CSN %hhx ID %hx:%hx (\"%s\")\n",
|
||||
isapnp->csn, isapnp->vendor_id, isapnp->prod_id,
|
||||
isa_id_string ( isapnp->vendor_id, isapnp->prod_id ) );
|
||||
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -514,3 +466,45 @@ int find_isapnp_boot_device ( struct dev *dev, struct isapnp_driver *driver ) {
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* Activate a logical function on an ISAPnP device
|
||||
*
|
||||
* This routine simply activates the device in its current
|
||||
* configuration. It does not attempt any kind of resource
|
||||
* arbitration.
|
||||
*
|
||||
*/
|
||||
void activate_isapnp_device ( struct isapnp_device *isapnp,
|
||||
uint8_t logdev ) {
|
||||
/* Wake the device */
|
||||
isapnp_wait_for_key ();
|
||||
isapnp_send_key ();
|
||||
isapnp_wake ( isapnp->csn );
|
||||
|
||||
/* Select the specified logical device */
|
||||
isapnp_activate ( logdev );
|
||||
udelay ( 1000 );
|
||||
|
||||
/* Return all cards to Wait for Key state */
|
||||
isapnp_wait_for_key ();
|
||||
}
|
||||
|
||||
/*
|
||||
* Deactivate a logical function on an ISAPnP device
|
||||
*
|
||||
*/
|
||||
void deactivate_isapnp_device ( struct isapnp_device *isapnp,
|
||||
uint8_t logdev ) {
|
||||
/* Wake the device */
|
||||
isapnp_wait_for_key ();
|
||||
isapnp_send_key ();
|
||||
isapnp_wake ( isapnp->csn );
|
||||
|
||||
/* Select the specified logical device */
|
||||
isapnp_deactivate ( logdev );
|
||||
udelay ( 1000 );
|
||||
|
||||
/* Return all cards to Wait for Key state */
|
||||
isapnp_wait_for_key ();
|
||||
}
|
||||
|
@ -127,7 +127,7 @@ union isapnp_identifier {
|
||||
char bytes[9];
|
||||
struct {
|
||||
uint16_t vendor_id;
|
||||
uint16_t product_id;
|
||||
uint16_t prod_id;
|
||||
uint32_t serial;
|
||||
uint8_t checksum;
|
||||
} __attribute__ (( packed ));
|
||||
@ -183,5 +183,9 @@ extern int find_isapnp_device ( struct isapnp_device *isapnp,
|
||||
struct isapnp_driver *driver );
|
||||
extern int find_isapnp_boot_device ( struct dev *dev,
|
||||
struct isapnp_driver *driver );
|
||||
extern void activate_isapnp_device ( struct isapnp_device *isapnp,
|
||||
uint8_t logdev );
|
||||
extern void deactivate_isapnp_device ( struct isapnp_device *isapnp,
|
||||
uint8_t logdev );
|
||||
|
||||
#endif /* ISAPNP_H */
|
||||
|
Loading…
Reference in New Issue
Block a user