diff --git a/src/drivers/bus/mca.c b/src/drivers/bus/mca.c new file mode 100644 index 00000000..101bd468 --- /dev/null +++ b/src/drivers/bus/mca.c @@ -0,0 +1,114 @@ +/* + * MCA bus driver code + * + * Abstracted from 3c509.c. + * + */ + +#include "etherboot.h" +#include "dev.h" +#include "io.h" +#include "mca.h" + +#define DEBUG_MCA + +#undef DBG +#ifdef DEBUG_MCA +#define DBG(...) printf ( __VA_ARGS__ ) +#else +#define DBG(...) +#endif + +/* + * Fill in parameters for an MCA device based on slot number + * + */ +static int fill_mca_device ( struct mca_device *mca ) { + unsigned int i; + + /* Make sure motherboard setup is off */ + outb_p ( 0xff, MCA_MOTHERBOARD_SETUP_REG ); + + /* Select the slot */ + outb_p ( 0x8 | ( mca->slot & 0xf ), MCA_ADAPTER_SETUP_REG ); + + /* Read the POS registers */ + for ( i = 0 ; i < ( sizeof ( mca->pos ) / sizeof ( mca->pos[0] ) ) ; + i++ ) { + mca->pos[i] = inb_p ( MCA_POS_REG ( i ) ); + } + + /* Kill all setup modes */ + outb_p ( 0, MCA_ADAPTER_SETUP_REG ); + + DBG ( "MCA slot %d id %hx (%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx)\n", + mca->slot, MCA_ID ( mca ), + mca->pos[0], mca->pos[1], mca->pos[2], mca->pos[3], + mca->pos[4], mca->pos[5], mca->pos[6], mca->pos[7] ); + + return 1; +} + +/* + * Obtain a struct mca * from a struct dev * + * + * If dev has not previously been used for an MCA device scan, blank + * out dev.mca + */ +struct mca_device * mca_device ( struct dev *dev ) { + struct mca_device *mca = &dev->mca; + + if ( dev->devid.bus_type != MCA_BUS_TYPE ) { + memset ( mca, 0, sizeof ( *mca ) ); + dev->devid.bus_type = MCA_BUS_TYPE; + } + mca->dev = dev; + return mca; +} + +/* + * Find an MCA device matching the specified driver + * + */ +int find_mca_device ( struct mca_device *mca, struct mca_driver *driver ) { + unsigned int i; + + /* Iterate through all possible MCA slots, starting where we + * left off/ + */ + for ( ; mca->slot < MCA_MAX_SLOT_NR ; mca->slot++ ) { + /* If we've already used this device, skip it */ + if ( mca->already_tried ) { + mca->already_tried = 0; + continue; + } + + /* Fill in device parameters */ + if ( ! fill_mca_device ( mca ) ) { + continue; + } + + /* Compare against driver's ID list */ + for ( i = 0 ; i < driver->id_count ; i++ ) { + struct mca_id *id = &driver->ids[i]; + + if ( MCA_ID ( mca ) == id->id ) { + DBG ( "Device %s (driver %s) matches ID %hx\n", + id->name, driver->name, id->id ); + if ( mca->dev ) { + mca->dev->name = driver->name; + mca->dev->devid.vendor_id = + htons ( GENERIC_MCA_VENDOR ); + mca->dev->devid.device_id = + htons ( id->id ); + } + mca->already_tried = 1; + return 1; + } + } + } + + /* No device found */ + mca->slot = 0; + return 0; +} diff --git a/src/include/mca.h b/src/include/mca.h new file mode 100644 index 00000000..f6d37ba7 --- /dev/null +++ b/src/include/mca.h @@ -0,0 +1,75 @@ +/* + * MCA bus driver code + * + * Abstracted from 3c509.c. + * + */ + +#ifndef MCA_H +#define MCA_H + +/* + * MCA constants + * + */ + +#define MCA_MOTHERBOARD_SETUP_REG 0x94 +#define MCA_ADAPTER_SETUP_REG 0x96 +#define MCA_MAX_SLOT_NR 8 +#define MCA_POS_REG(n) (0x100+(n)) + +/* Is there a standard that would define this? */ +#include "isa.h" +#define GENERIC_MCA_VENDOR ISAPNP_VENDOR ( 'M', 'C', 'A' ) + +/* + * A physical MCA device + * + */ +struct dev; +struct mca_device { + struct dev *dev; + unsigned int slot; + unsigned char pos[8]; + int already_tried; +}; +#define MCA_ID(mca) ( ( (mca)->pos[1] << 8 ) + (mca)->pos[0] ) + +/* + * An individual MCA device identified by ID + * + */ +struct mca_id { + const char *name; + int id; +}; + +/* + * An MCA driver, with a device ID (struct mca_id) table. + * + */ +struct mca_driver { + const char *name; + struct mca_id *ids; + unsigned int id_count; +}; + +/* + * Define an MCA driver + * + */ +#define MCA_DRIVER( driver_name, mca_ids ) { \ + .name = driver_name, \ + .ids = mca_ids, \ + .id_count = sizeof ( mca_ids ) / sizeof ( mca_ids[0] ), \ +} + +/* + * Functions in mca.c + * + */ +extern struct mca_device * mca_device ( struct dev *dev ); +extern int find_mca_device ( struct mca_device *mca, + struct mca_driver *driver ); + +#endif