Extraced from 3c509.c
authorMichael Brown <mcb30@etherboot.org>
Wed, 13 Apr 2005 12:45:38 +0000 (12:45 +0000)
committerMichael Brown <mcb30@etherboot.org>
Wed, 13 Apr 2005 12:45:38 +0000 (12:45 +0000)
src/drivers/bus/eisa.c [new file with mode: 0644]
src/include/eisa.h [new file with mode: 0644]

diff --git a/src/drivers/bus/eisa.c b/src/drivers/bus/eisa.c
new file mode 100644 (file)
index 0000000..a294895
--- /dev/null
@@ -0,0 +1,136 @@
+#include "etherboot.h"
+#include "dev.h"
+#include "io.h"
+#include "timer.h"
+#include "eisa.h"
+
+#define DEBUG_EISA
+
+#undef DBG
+#ifdef DEBUG_EISA
+#define DBG(...) printf ( __VA_ARGS__ )
+#else
+#define DBG(...)
+#endif
+
+/*
+ * Fill in parameters for an EISA device based on slot number
+ *
+ * Return 1 if device present, 0 otherwise
+ *
+ */
+static int fill_eisa_device ( struct eisa_device *eisa ) {
+       uint8_t present;
+
+       /* Set ioaddr */
+       eisa->ioaddr = EISA_SLOT_BASE ( eisa->slot );
+
+       /* Test for board present */
+       outb ( 0xff, eisa->ioaddr + EISA_MFG_ID_HI );
+       present = inb ( eisa->ioaddr + EISA_MFG_ID_HI );
+       if ( present & 0x80 ) {
+               /* No board present */
+               return 0;
+       }
+
+       /* Read mfg and product IDs.  Yes, the resulting uint16_ts
+        * will be upside-down.  This appears to be by design.
+        */
+       eisa->mfg_id = ( inb ( eisa->ioaddr + EISA_MFG_ID_LO ) << 8 )
+               + present;
+       eisa->prod_id = ( inb ( eisa->ioaddr + EISA_PROD_ID_LO ) << 8 )
+               + inb ( eisa->ioaddr + EISA_PROD_ID_HI );
+
+       DBG ( "EISA slot %d (base %#hx) ID %hx:%hx (\"%s\")\n",
+             eisa->slot, eisa->ioaddr, eisa->mfg_id, eisa->prod_id,
+             isa_id_string ( eisa->mfg_id, eisa->prod_id ) );
+
+       return 1;
+}
+
+/*
+ * Obtain a struct eisa * from a struct dev *
+ *
+ * If dev has not previously been used for an EISA device scan, blank
+ * out dev.eisa
+ */
+struct eisa_device * eisa_device ( struct dev *dev ) {
+       struct eisa_device *eisa = &dev->eisa;
+
+       if ( dev->devid.bus_type != EISA_BUS_TYPE ) {
+               memset ( eisa, 0, sizeof ( *eisa ) );
+               dev->devid.bus_type = EISA_BUS_TYPE;
+               eisa->slot = EISA_MIN_SLOT;
+       }
+       eisa->dev = dev;
+       return eisa;
+}
+
+/*
+ * Find an EISA device matching the specified driver
+ *
+ */
+int find_eisa_device ( struct eisa_device *eisa, struct eisa_driver *driver ) {
+       unsigned int i;
+
+       /* Iterate through all possible EISA slots, starting where we
+        * left off/
+        */
+       for ( ; eisa->slot <= EISA_MAX_SLOT ; eisa->slot++ ) {
+               /* If we've already used this device, skip it */
+               if ( eisa->already_tried ) {
+                       eisa->already_tried = 0;
+                       continue;
+               }
+
+               /* Fill in device parameters */
+               if ( ! fill_eisa_device ( eisa ) ) {
+                       continue;
+               }
+
+               /* Compare against driver's ID list */
+               for ( i = 0 ; i < driver->id_count ; i++ ) {
+                       struct eisa_id *id = &driver->ids[i];
+                       
+                       if ( ( eisa->mfg_id == id->mfg_id ) &&
+                            ( ISA_PROD_ID ( eisa->prod_id ) ==
+                              ISA_PROD_ID ( id->prod_id ) ) ) {
+                               DBG ( "Device %s (driver %s) matches ID %s\n",
+                                     id->name, driver->name,
+                                     isa_id_string ( eisa->mfg_id,
+                                                     eisa->prod_id ) );
+                               if ( eisa->dev ) {
+                                       eisa->dev->name = driver->name;
+                                       eisa->dev->devid.vendor_id
+                                               = eisa->mfg_id;
+                                       eisa->dev->devid.device_id
+                                               = eisa->prod_id;
+                               }
+                               eisa->already_tried = 1;
+                               return 1;
+                       }
+               }
+       }
+
+       /* No device found */
+       eisa->slot = EISA_MIN_SLOT;
+       return 0;
+}
+
+/*
+ * Reset and enable an EISA device
+ *
+ */
+void enable_eisa_device ( struct eisa_device *eisa ) {
+       /* Set reset line high for 1000 µs.  Spec says 500 µs, but
+        * this doesn't work for all cards, so we are conservative.
+        */
+       outb ( EISA_CMD_RESET, eisa->ioaddr + EISA_GLOBAL_CONFIG );
+       udelay ( 1000 ); /* Must wait 800 */
+
+       /* Set reset low and write a 1 to ENABLE.  Delay again, in
+        * case the card takes a while to wake up.
+        */
+       outb ( EISA_CMD_ENABLE, eisa->ioaddr + EISA_GLOBAL_CONFIG );
+       udelay ( 1000 ); /* Must wait 800 */
+}
diff --git a/src/include/eisa.h b/src/include/eisa.h
new file mode 100644 (file)
index 0000000..4fe14fc
--- /dev/null
@@ -0,0 +1,76 @@
+#ifndef EISA_H
+#define EISA_H
+
+#include "isa_ids.h"
+
+/*
+ * EISA constants
+ *
+ */
+
+#define EISA_MIN_SLOT (0x1)
+#define EISA_MAX_SLOT (0xf)
+#define EISA_SLOT_BASE( n ) ( 0x1000 * (n) )
+
+#define EISA_MFG_ID_HI ( 0xc80 )
+#define EISA_MFG_ID_LO ( 0xc81 )
+#define EISA_PROD_ID_HI ( 0xc82 )
+#define EISA_PROD_ID_LO ( 0xc83 )
+#define EISA_GLOBAL_CONFIG ( 0xc84 )
+
+#define EISA_CMD_RESET ( 1 << 2 )
+#define EISA_CMD_ENABLE ( 1 << 0 )
+
+/*
+ * A physical EISA device
+ *
+ */
+struct dev;
+struct eisa_device {
+       struct dev *dev;
+       unsigned int slot;
+       uint16_t ioaddr;
+       uint16_t mfg_id;
+       uint16_t prod_id;
+       int already_tried;
+};
+
+/*
+ * An individual EISA device identified by ID
+ *
+ */
+struct eisa_id {
+        const char *name;
+       uint16_t mfg_id, prod_id;
+};
+
+/*
+ * An EISA driver, with a device ID (struct eisa_id) table.
+ *
+ */
+struct eisa_driver {
+       const char *name;
+       struct eisa_id *ids;
+       unsigned int id_count;
+};
+
+/*
+ * Define an EISA driver
+ *
+ */
+#define EISA_DRIVER( driver_name, eisa_ids ) {                         \
+       .name = driver_name,                                            \
+       .ids = eisa_ids,                                                \
+       .id_count = sizeof ( eisa_ids ) / sizeof ( eisa_ids[0] ),       \
+}
+
+/*
+ * Functions in eisa.c
+ *
+ */
+extern struct eisa_device * eisa_device ( struct dev *dev );
+extern int find_eisa_device ( struct eisa_device *eisa,
+                             struct eisa_driver *driver );
+extern void enable_eisa_device ( struct eisa_device *eisa );
+
+#endif /* EISA_H */