123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182 |
- #include <stdint.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <errno.h>
- #include <ipxe/io.h>
- #include <unistd.h>
- #include <ipxe/eisa.h>
-
- FILE_LICENCE ( GPL2_OR_LATER );
-
- static void eisabus_remove ( struct root_device *rootdev );
-
- /**
- * Reset and enable/disable an EISA device
- *
- * @v eisa EISA device
- * @v enabled 1=enable, 0=disable
- */
- void eisa_device_enabled ( struct eisa_device *eisa, int enabled ) {
- /* 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 ( enabled ? EISA_CMD_ENABLE : 0,
- eisa->ioaddr + EISA_GLOBAL_CONFIG );
- udelay ( 1000 ); /* Must wait 800 */
-
- DBG ( "EISA %s device %02x\n", ( enabled ? "enabled" : "disabled" ),
- eisa->slot );
- }
-
- /**
- * Probe an EISA device
- *
- * @v eisa EISA device
- * @ret rc Return status code
- *
- * Searches for a driver for the EISA device. If a driver is found,
- * its probe() routine is called.
- */
- static int eisa_probe ( struct eisa_device *eisa ) {
- struct eisa_driver *driver;
- struct eisa_device_id *id;
- unsigned int i;
- int rc;
-
- DBG ( "Adding EISA device %02x (%04x:%04x (\"%s\") io %x)\n",
- eisa->slot, eisa->vendor_id, eisa->prod_id,
- isa_id_string ( eisa->vendor_id, eisa->prod_id ), eisa->ioaddr );
-
- for_each_table_entry ( driver, EISA_DRIVERS ) {
- for ( i = 0 ; i < driver->id_count ; i++ ) {
- id = &driver->ids[i];
- if ( id->vendor_id != eisa->vendor_id )
- continue;
- if ( ISA_PROD_ID ( id->prod_id ) !=
- ISA_PROD_ID ( eisa->prod_id ) )
- continue;
- eisa->driver = driver;
- eisa->driver_name = id->name;
- DBG ( "...using driver %s\n", eisa->driver_name );
- if ( ( rc = driver->probe ( eisa, id ) ) != 0 ) {
- DBG ( "......probe failed\n" );
- continue;
- }
- return 0;
- }
- }
-
- DBG ( "...no driver found\n" );
- return -ENOTTY;
- }
-
- /**
- * Remove an EISA device
- *
- * @v eisa EISA device
- */
- static void eisa_remove ( struct eisa_device *eisa ) {
- eisa->driver->remove ( eisa );
- DBG ( "Removed EISA device %02x\n", eisa->slot );
- }
-
- /**
- * Probe EISA root bus
- *
- * @v rootdev EISA bus root device
- *
- * Scans the EISA bus for devices and registers all devices it can
- * find.
- */
- static int eisabus_probe ( struct root_device *rootdev ) {
- struct eisa_device *eisa = NULL;
- unsigned int slot;
- int rc;
-
- for ( slot = EISA_MIN_SLOT ; slot <= EISA_MAX_SLOT ; slot++ ) {
- /* Allocate struct eisa_device */
- if ( ! eisa )
- eisa = malloc ( sizeof ( *eisa ) );
- if ( ! eisa ) {
- rc = -ENOMEM;
- goto err;
- }
- memset ( eisa, 0, sizeof ( *eisa ) );
- eisa->slot = slot;
- eisa->ioaddr = EISA_SLOT_BASE ( eisa->slot );
-
- /* Test for board present */
- outb ( 0xff, eisa->ioaddr + EISA_VENDOR_ID );
- eisa->vendor_id =
- le16_to_cpu ( inw ( eisa->ioaddr + EISA_VENDOR_ID ) );
- eisa->prod_id =
- le16_to_cpu ( inw ( eisa->ioaddr + EISA_PROD_ID ) );
- if ( eisa->vendor_id & 0x80 ) {
- /* No board present */
- continue;
- }
-
- /* Add to device hierarchy */
- snprintf ( eisa->dev.name, sizeof ( eisa->dev.name ),
- "EISA%02x", slot );
- eisa->dev.desc.bus_type = BUS_TYPE_EISA;
- eisa->dev.desc.vendor = eisa->vendor_id;
- eisa->dev.desc.device = eisa->prod_id;
- eisa->dev.parent = &rootdev->dev;
- list_add ( &eisa->dev.siblings, &rootdev->dev.children );
- INIT_LIST_HEAD ( &eisa->dev.children );
-
- /* Look for a driver */
- if ( eisa_probe ( eisa ) == 0 ) {
- /* eisadev registered, we can drop our ref */
- eisa = NULL;
- } else {
- /* Not registered; re-use struct */
- list_del ( &eisa->dev.siblings );
- }
- }
-
- free ( eisa );
- return 0;
-
- err:
- free ( eisa );
- eisabus_remove ( rootdev );
- return rc;
- }
-
- /**
- * Remove EISA root bus
- *
- * @v rootdev EISA bus root device
- */
- static void eisabus_remove ( struct root_device *rootdev ) {
- struct eisa_device *eisa;
- struct eisa_device *tmp;
-
- list_for_each_entry_safe ( eisa, tmp, &rootdev->dev.children,
- dev.siblings ) {
- eisa_remove ( eisa );
- list_del ( &eisa->dev.siblings );
- free ( eisa );
- }
- }
-
- /** EISA bus root device driver */
- static struct root_driver eisa_root_driver = {
- .probe = eisabus_probe,
- .remove = eisabus_remove,
- };
-
- /** EISA bus root device */
- struct root_device eisa_root_device __root_device = {
- .dev = { .name = "EISA" },
- .driver = &eisa_root_driver,
- };
|