Activation code now generalised as well.
authorMichael Brown <mcb30@etherboot.org>
Fri, 15 Apr 2005 13:07:25 +0000 (13:07 +0000)
committerMichael Brown <mcb30@etherboot.org>
Fri, 15 Apr 2005 13:07:25 +0000 (13:07 +0000)
src/drivers/bus/isapnp.c
src/include/isapnp.h

index b0e6456..626c05a 100644 (file)
 
 #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 ();
+}
index c490e1e..d5d9ed0 100644 (file)
@@ -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 */