diff options
author | Michael Brown <mcb30@etherboot.org> | 2007-03-10 18:08:33 +0000 |
---|---|---|
committer | Michael Brown <mcb30@etherboot.org> | 2007-03-10 18:08:33 +0000 |
commit | 520d9c36af2f9e4f207dd7275a47ea97c668f749 (patch) | |
tree | fc665c3d4c250d3c9411219f580f5affbbf03873 /src/drivers/bus/mca.c | |
parent | f079865606ba846d53b99e60a63d1ebeb22ea08a (diff) | |
download | ipxe-520d9c36af2f9e4f207dd7275a47ea97c668f749.tar.gz |
Updated ISAPnP, EISA, MCA and ISA buses to current device model.
ISA 3c509 is currently non-functional, although the EISA (3c509-eisa) and
MCA (3c529) variants should build OK.
None of this code is yet tested.
Diffstat (limited to 'src/drivers/bus/mca.c')
-rw-r--r-- | src/drivers/bus/mca.c | 276 |
1 files changed, 148 insertions, 128 deletions
diff --git a/src/drivers/bus/mca.c b/src/drivers/bus/mca.c index 630442951..375a68344 100644 --- a/src/drivers/bus/mca.c +++ b/src/drivers/bus/mca.c @@ -5,157 +5,177 @@ * */ -#include "string.h" -#include "io.h" -#include "console.h" -#include "dev.h" -#include "mca.h" - -/* - * Increment a bus_loc structure to the next possible MCA location. - * Leave the structure zeroed and return 0 if there are no more valid - * locations. +#include <stdint.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <io.h> +#include <timer.h> +#include <gpxe/mca.h> + +static struct mca_driver mca_drivers[0] + __table_start ( struct mca_driver, mca_drivers ); +static struct mca_driver mca_drivers_end[0] + __table_end ( struct mca_driver, mca_drivers ); + +static void mcabus_remove ( struct root_device *rootdev ); + +/** + * Probe an MCA device * - */ -static int mca_next_location ( struct bus_loc *bus_loc ) { - struct mca_loc *mca_loc = ( struct mca_loc * ) bus_loc; - - /* - * Ensure that there is sufficient space in the shared bus - * structures for a struct mca_loc and a struct - * mca_dev, as mandated by bus.h. - * - */ - BUS_LOC_CHECK ( struct mca_loc ); - BUS_DEV_CHECK ( struct mca_device ); - - return ( mca_loc->slot = ( ++mca_loc->slot & MCA_MAX_SLOT_NR ) ); -} - -/* - * Fill in parameters for an MCA device based on slot number + * @v mca MCA device + * @ret rc Return status code * + * Searches for a driver for the MCA device. If a driver is found, + * its probe() routine is called. */ -static int mca_fill_device ( struct bus_dev *bus_dev, - struct bus_loc *bus_loc ) { - struct mca_loc *mca_loc = ( struct mca_loc * ) bus_loc; - struct mca_device *mca = ( struct mca_device * ) bus_dev; - unsigned int i, seen_non_ff; - - /* Store slot in struct mca, set default values */ - mca->slot = mca_loc->slot; - mca->name = "?"; - - /* 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 */ - seen_non_ff = 0; - for ( i = 0 ; i < ( sizeof ( mca->pos ) / sizeof ( mca->pos[0] ) ) ; - i++ ) { - mca->pos[i] = inb_p ( MCA_POS_REG ( i ) ); - if ( mca->pos[i] != 0xff ) - seen_non_ff = 1; - } - - /* If all POS registers are 0xff, this means there's no device - * present - */ - if ( ! seen_non_ff ) - return 0; - - /* Kill all setup modes */ - outb_p ( 0, MCA_ADAPTER_SETUP_REG ); +static int mca_probe ( struct mca_device *mca ) { + struct mca_driver *driver; + struct mca_device_id *id; + unsigned int i; + int rc; - DBG ( "MCA found slot %d id %hx " - "(POS %hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx:%hhx)\n", + DBG ( "Adding MCA slot %02x (ID %04x POS " + "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x)\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; -} - -/* - * Test whether or not a driver is capable of driving the device. - * - */ -static int mca_check_driver ( struct bus_dev *bus_dev, - struct device_driver *device_driver ) { - struct mca_device *mca = ( struct mca_device * ) bus_dev; - struct mca_driver *driver - = ( struct mca_driver * ) device_driver->bus_driver_info; - unsigned int i; - - /* 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 ( "MCA found ID %hx (device %s) " - "matching driver %s\n", - id->name, id->id, device_driver->name ); - mca->name = id->name; - return 1; + for ( driver = mca_drivers; driver < mca_drivers_end; driver++ ){ + for ( i = 0 ; i < driver->id_count ; i++ ) { + id = &driver->ids[i]; + if ( id->id != MCA_ID ( mca ) ) + continue; + mca->driver = driver; + mca->driver_name = id->name; + DBG ( "...using driver %s\n", mca->driver_name ); + if ( ( rc = driver->probe ( mca, id ) ) != 0 ) { + DBG ( "......probe failed\n" ); + continue; + } + return 0; } } - /* No device found */ - return 0; + DBG ( "...no driver found\n" ); + return -ENOTTY; } -/* - * Describe an MCA device +/** + * Remove an MCA device * + * @v mca MCA device */ -static char * mca_describe_device ( struct bus_dev *bus_dev ) { - struct mca_device *mca = ( struct mca_device * ) bus_dev; - static char mca_description[] = "MCA 00"; - - sprintf ( mca_description + 4, "%hhx", mca->slot ); - return mca_description; +static void mca_remove ( struct mca_device *mca ) { + mca->driver->remove ( mca ); + DBG ( "Removed MCA device %02x\n", mca->slot ); } -/* - * Name an MCA device +/** + * Probe MCA root bus + * + * @v rootdev MCA bus root device * + * Scans the MCA bus for devices and registers all devices it can + * find. */ -static const char * mca_name_device ( struct bus_dev *bus_dev ) { - struct mca_device *mca = ( struct mca_device * ) bus_dev; +static int mcabus_probe ( struct root_device *rootdev ) { + struct mca_device *mca = NULL; + unsigned int slot; + int seen_non_ff; + unsigned int i; + int rc; + + for ( slot = 0 ; slot <= MCA_MAX_SLOT_NR ; slot++ ) { + /* Allocate struct mca_device */ + if ( ! mca ) + mca = malloc ( sizeof ( *mca ) ); + if ( ! mca ) { + rc = -ENOMEM; + goto err; + } + memset ( mca, 0, sizeof ( *mca ) ); + mca->slot = slot; + + /* 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 */ + seen_non_ff = 0; + for ( i = 0 ; i < ( sizeof ( mca->pos ) / + sizeof ( mca->pos[0] ) ) ; i++ ) { + mca->pos[i] = inb_p ( MCA_POS_REG ( i ) ); + if ( mca->pos[i] != 0xff ) + seen_non_ff = 1; + } - return mca->name; + /* Kill all setup modes */ + outb_p ( 0, MCA_ADAPTER_SETUP_REG ); + + /* If all POS registers are 0xff, this means there's no device + * present + */ + if ( ! seen_non_ff ) + continue; + + /* Add to device hierarchy */ + snprintf ( mca->dev.name, sizeof ( mca->dev.name ), + "MCA%02x", slot ); + mca->dev.desc.bus_type = BUS_TYPE_MCA; + mca->dev.desc.vendor = GENERIC_MCA_VENDOR; + mca->dev.desc.device = MCA_ID ( mca ); + mca->dev.parent = &rootdev->dev; + list_add ( &mca->dev.siblings, &rootdev->dev.children ); + INIT_LIST_HEAD ( &mca->dev.children ); + + /* Look for a driver */ + if ( mca_probe ( mca ) == 0 ) { + /* mcadev registered, we can drop our ref */ + mca = NULL; + } else { + /* Not registered; re-use struct */ + list_del ( &mca->dev.siblings ); + } + } + + free ( mca ); + return 0; + + err: + free ( mca ); + mcabus_remove ( rootdev ); + return rc; } -/* - * MCA bus operations table +/** + * Remove MCA root bus * + * @v rootdev MCA bus root device */ -struct bus_driver mca_driver __bus_driver = { - .name = "MCA", - .next_location = mca_next_location, - .fill_device = mca_fill_device, - .check_driver = mca_check_driver, - .describe_device = mca_describe_device, - .name_device = mca_name_device, +static void mcabus_remove ( struct root_device *rootdev ) { + struct mca_device *mca; + struct mca_device *tmp; + + list_for_each_entry_safe ( mca, tmp, &rootdev->dev.children, + dev.siblings ) { + mca_remove ( mca ); + list_del ( &mca->dev.siblings ); + free ( mca ); + } +} + +/** MCA bus root device driver */ +static struct root_driver mca_root_driver = { + .probe = mcabus_probe, + .remove = mcabus_remove, }; -/* - * Fill in a nic structure - * - */ -void mca_fill_nic ( struct nic *nic, struct mca_device *mca ) { - - /* ioaddr and irqno must be read in a device-dependent way - * from the POS registers - */ - nic->ioaddr = 0; - nic->irqno = 0; - - /* Fill in DHCP device ID structure */ - nic->dhcp_dev_id.bus_type = MCA_BUS_TYPE; - nic->dhcp_dev_id.vendor_id = htons ( GENERIC_MCA_VENDOR ); - nic->dhcp_dev_id.device_id = htons ( MCA_ID ( mca ) ); -} +/** MCA bus root device */ +struct root_device mca_root_device __root_device = { + .dev = { .name = "MCA" }, + .driver = &mca_root_driver, +}; |