summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorMichael Brown2005-04-15 15:07:25 +0200
committerMichael Brown2005-04-15 15:07:25 +0200
commit85dd4fd8d659c73f9b64b1dd677f4960a4eb4e86 (patch)
treec183ce0d9e5e241b20927887315874f21df17a48 /src
parentCleaned up isolation protocol. (diff)
downloadipxe-85dd4fd8d659c73f9b64b1dd677f4960a4eb4e86.tar.gz
ipxe-85dd4fd8d659c73f9b64b1dd677f4960a4eb4e86.tar.xz
ipxe-85dd4fd8d659c73f9b64b1dd677f4960a4eb4e86.zip
Activation code now generalised as well.
Diffstat (limited to 'src')
-rw-r--r--src/drivers/bus/isapnp.c294
-rw-r--r--src/include/isapnp.h6
2 files changed, 149 insertions, 151 deletions
diff --git a/src/drivers/bus/isapnp.c b/src/drivers/bus/isapnp.c
index b0e645682..626c05a8c 100644
--- a/src/drivers/bus/isapnp.c
+++ b/src/drivers/bus/isapnp.c
@@ -35,9 +35,18 @@
#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
* gained by re-scanning for cards.
@@ -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
@@ -154,6 +188,42 @@ static uint8_t isapnp_checksum ( union isapnp_identifier *identifier ) {
}
/*
+ * 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 ();
+}
diff --git a/src/include/isapnp.h b/src/include/isapnp.h
index c490e1ec3..d5d9ed005 100644
--- a/src/include/isapnp.h
+++ b/src/include/isapnp.h
@@ -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 */