iPXE
eisa.c
Go to the documentation of this file.
00001 #include <stdint.h>
00002 #include <string.h>
00003 #include <stdlib.h>
00004 #include <stdio.h>
00005 #include <errno.h>
00006 #include <ipxe/io.h>
00007 #include <unistd.h>
00008 #include <ipxe/eisa.h>
00009 
00010 FILE_LICENCE ( GPL2_OR_LATER );
00011 
00012 static void eisabus_remove ( struct root_device *rootdev );
00013 
00014 /**
00015  * Reset and enable/disable an EISA device
00016  *
00017  * @v eisa              EISA device
00018  * @v enabled           1=enable, 0=disable
00019  */
00020 void eisa_device_enabled ( struct eisa_device *eisa, int enabled ) {
00021         /* Set reset line high for 1000 Ás.  Spec says 500 Ás, but
00022          * this doesn't work for all cards, so we are conservative.
00023          */
00024         outb ( EISA_CMD_RESET, eisa->ioaddr + EISA_GLOBAL_CONFIG );
00025         udelay ( 1000 ); /* Must wait 800 */
00026 
00027         /* Set reset low and write a 1 to ENABLE.  Delay again, in
00028          * case the card takes a while to wake up.
00029          */
00030         outb ( enabled ? EISA_CMD_ENABLE : 0,
00031                eisa->ioaddr + EISA_GLOBAL_CONFIG );
00032         udelay ( 1000 ); /* Must wait 800 */
00033 
00034         DBG ( "EISA %s device %02x\n", ( enabled ? "enabled" : "disabled" ),
00035               eisa->slot );
00036 }
00037 
00038 /**
00039  * Probe an EISA device
00040  *
00041  * @v eisa              EISA device
00042  * @ret rc              Return status code
00043  *
00044  * Searches for a driver for the EISA device.  If a driver is found,
00045  * its probe() routine is called.
00046  */
00047 static int eisa_probe ( struct eisa_device *eisa ) {
00048         struct eisa_driver *driver;
00049         struct eisa_device_id *id;
00050         unsigned int i;
00051         int rc;
00052 
00053         DBG ( "Adding EISA device %02x (%04x:%04x (\"%s\") io %x)\n",
00054               eisa->slot, eisa->vendor_id, eisa->prod_id,
00055               isa_id_string ( eisa->vendor_id, eisa->prod_id ), eisa->ioaddr );
00056 
00057         for_each_table_entry ( driver, EISA_DRIVERS ) {
00058                 for ( i = 0 ; i < driver->id_count ; i++ ) {
00059                         id = &driver->ids[i];
00060                         if ( id->vendor_id != eisa->vendor_id )
00061                                 continue;
00062                         if ( ISA_PROD_ID ( id->prod_id ) !=
00063                              ISA_PROD_ID ( eisa->prod_id ) )
00064                                 continue;
00065                         eisa->driver = driver;
00066                         eisa->dev.driver_name = id->name;
00067                         DBG ( "...using driver %s\n", eisa->dev.driver_name );
00068                         if ( ( rc = driver->probe ( eisa, id ) ) != 0 ) {
00069                                 DBG ( "......probe failed\n" );
00070                                 continue;
00071                         }
00072                         return 0;
00073                 }
00074         }
00075 
00076         DBG ( "...no driver found\n" );
00077         return -ENOTTY;
00078 }
00079 
00080 /**
00081  * Remove an EISA device
00082  *
00083  * @v eisa              EISA device
00084  */
00085 static void eisa_remove ( struct eisa_device *eisa ) {
00086         eisa->driver->remove ( eisa );
00087         DBG ( "Removed EISA device %02x\n", eisa->slot );
00088 }
00089 
00090 /**
00091  * Probe EISA root bus
00092  *
00093  * @v rootdev           EISA bus root device
00094  *
00095  * Scans the EISA bus for devices and registers all devices it can
00096  * find.
00097  */
00098 static int eisabus_probe ( struct root_device *rootdev ) {
00099         struct eisa_device *eisa = NULL;
00100         unsigned int slot;
00101         int rc;
00102 
00103         for ( slot = EISA_MIN_SLOT ; slot <= EISA_MAX_SLOT ; slot++ ) {
00104                 /* Allocate struct eisa_device */
00105                 if ( ! eisa )
00106                         eisa = malloc ( sizeof ( *eisa ) );
00107                 if ( ! eisa ) {
00108                         rc = -ENOMEM;
00109                         goto err;
00110                 }
00111                 memset ( eisa, 0, sizeof ( *eisa ) );
00112                 eisa->slot = slot;
00113                 eisa->ioaddr = EISA_SLOT_BASE ( eisa->slot );
00114 
00115                 /* Test for board present */
00116                 outb ( 0xff, eisa->ioaddr + EISA_VENDOR_ID );
00117                 eisa->vendor_id =
00118                         le16_to_cpu ( inw ( eisa->ioaddr + EISA_VENDOR_ID ) );
00119                 eisa->prod_id =
00120                         le16_to_cpu ( inw ( eisa->ioaddr + EISA_PROD_ID ) );
00121                 if ( eisa->vendor_id & 0x80 ) {
00122                         /* No board present */
00123                         continue;
00124                 }
00125 
00126                 /* Add to device hierarchy */
00127                 snprintf ( eisa->dev.name, sizeof ( eisa->dev.name ),
00128                            "EISA%02x", slot );
00129                 eisa->dev.desc.bus_type = BUS_TYPE_EISA;
00130                 eisa->dev.desc.vendor = eisa->vendor_id;
00131                 eisa->dev.desc.device = eisa->prod_id;
00132                 eisa->dev.parent = &rootdev->dev;
00133                 list_add ( &eisa->dev.siblings, &rootdev->dev.children );
00134                 INIT_LIST_HEAD ( &eisa->dev.children );
00135 
00136                 /* Look for a driver */
00137                 if ( eisa_probe ( eisa ) == 0 ) {
00138                         /* eisadev registered, we can drop our ref */
00139                         eisa = NULL;
00140                 } else {
00141                         /* Not registered; re-use struct */
00142                         list_del ( &eisa->dev.siblings );
00143                 }
00144         }
00145 
00146         free ( eisa );
00147         return 0;
00148 
00149  err:
00150         free ( eisa );
00151         eisabus_remove ( rootdev );
00152         return rc;
00153 }
00154 
00155 /**
00156  * Remove EISA root bus
00157  *
00158  * @v rootdev           EISA bus root device
00159  */
00160 static void eisabus_remove ( struct root_device *rootdev ) {
00161         struct eisa_device *eisa;
00162         struct eisa_device *tmp;
00163 
00164         list_for_each_entry_safe ( eisa, tmp, &rootdev->dev.children,
00165                                    dev.siblings ) {
00166                 eisa_remove ( eisa );
00167                 list_del ( &eisa->dev.siblings );
00168                 free ( eisa );
00169         }
00170 }
00171 
00172 /** EISA bus root device driver */
00173 static struct root_driver eisa_root_driver = {
00174         .probe = eisabus_probe,
00175         .remove = eisabus_remove,
00176 };
00177 
00178 /** EISA bus root device */
00179 struct root_device eisa_root_device __root_device = {
00180         .dev = { .name = "EISA" },
00181         .driver = &eisa_root_driver,
00182 };