iPXE
isa.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 <ipxe/isa.h>
00008 
00009 FILE_LICENCE ( GPL2_OR_LATER );
00010 
00011 /*
00012  * isa.c implements a "classical" port-scanning method of ISA device
00013  * detection.  The driver must provide a list of probe addresses
00014  * (probe_addrs), together with a function (probe_addr) that can be
00015  * used to test for the physical presence of a device at any given
00016  * address.
00017  *
00018  * Note that this should probably be considered the "last resort" for
00019  * device probing.  If the card supports ISAPnP or EISA, use that
00020  * instead.  Some cards (e.g. the 3c509) implement a proprietary
00021  * ISAPnP-like mechanism.
00022  *
00023  * The ISA probe address list can be overridden by config.h; if the
00024  * user specifies ISA_PROBE_ADDRS then that list will be used first.
00025  * (If ISA_PROBE_ONLY is defined, the driver's own list will never be
00026  * used).
00027  */
00028 
00029 /*
00030  * User-supplied probe address list
00031  *
00032  */
00033 static isa_probe_addr_t isa_extra_probe_addrs[] = {
00034 #ifdef ISA_PROBE_ADDRS
00035         ISA_PROBE_ADDRS
00036 #endif
00037 };
00038 #define ISA_EXTRA_PROBE_ADDR_COUNT \
00039      ( sizeof ( isa_extra_probe_addrs ) / sizeof ( isa_extra_probe_addrs[0] ) )
00040 
00041 #define ISA_IOIDX_MIN( driver ) ( -ISA_EXTRA_PROBE_ADDR_COUNT )
00042 #ifdef ISA_PROBE_ONLY
00043 #define ISA_IOIDX_MAX( driver ) ( -1 )
00044 #else
00045 #define ISA_IOIDX_MAX( driver ) ( (int) (driver)->addr_count - 1 )
00046 #endif
00047 
00048 #define ISA_IOADDR( driver, ioidx )                                       \
00049         ( ( (ioidx) >= 0 ) ?                                              \
00050           (driver)->probe_addrs[(ioidx)] :                                \
00051           *( isa_extra_probe_addrs + (ioidx) + ISA_EXTRA_PROBE_ADDR_COUNT ) )
00052 
00053 static void isabus_remove ( struct root_device *rootdev );
00054 
00055 /**
00056  * Probe an ISA device
00057  *
00058  * @v isa               ISA device
00059  * @ret rc              Return status code
00060  */
00061 static int isa_probe ( struct isa_device *isa ) {
00062         int rc;
00063 
00064         DBG ( "Trying ISA driver %s at I/O %04x\n",
00065               isa->driver->name, isa->ioaddr );
00066 
00067         if ( ( rc = isa->driver->probe ( isa ) ) != 0 ) {
00068                 DBG ( "...probe failed\n" );
00069                 return rc;
00070         }
00071 
00072         DBG ( "...device found\n" );
00073         return 0;
00074 }
00075 
00076 /**
00077  * Remove an ISA device
00078  *
00079  * @v isa               ISA device
00080  */
00081 static void isa_remove ( struct isa_device *isa ) {
00082         isa->driver->remove ( isa );
00083         DBG ( "Removed ISA%04x\n", isa->ioaddr );
00084 }
00085 
00086 /**
00087  * Probe ISA root bus
00088  *
00089  * @v rootdev           ISA bus root device
00090  *
00091  * Scans the ISA bus for devices and registers all devices it can
00092  * find.
00093  */
00094 static int isabus_probe ( struct root_device *rootdev ) {
00095         struct isa_device *isa = NULL;
00096         struct isa_driver *driver;
00097         int ioidx;
00098         int rc;
00099 
00100         for_each_table_entry ( driver, ISA_DRIVERS ) {
00101                 for ( ioidx = ISA_IOIDX_MIN ( driver ) ;
00102                       ioidx <= ISA_IOIDX_MAX ( driver ) ; ioidx++ ) {
00103                         /* Allocate struct isa_device */
00104                         if ( ! isa )
00105                                 isa = malloc ( sizeof ( *isa ) );
00106                         if ( ! isa ) {
00107                                 rc = -ENOMEM;
00108                                 goto err;
00109                         }
00110                         memset ( isa, 0, sizeof ( *isa ) );
00111                         isa->driver = driver;
00112                         isa->ioaddr = ISA_IOADDR ( driver, ioidx );
00113 
00114                         /* Add to device hierarchy */
00115                         snprintf ( isa->dev.name, sizeof ( isa->dev.name ),
00116                                    "ISA%04x", isa->ioaddr );
00117                         isa->dev.driver_name = driver->name;
00118                         isa->dev.desc.bus_type = BUS_TYPE_ISA;
00119                         isa->dev.desc.vendor = driver->vendor_id;
00120                         isa->dev.desc.device = driver->prod_id;
00121                         isa->dev.parent = &rootdev->dev;
00122                         list_add ( &isa->dev.siblings,
00123                                    &rootdev->dev.children );
00124                         INIT_LIST_HEAD ( &isa->dev.children );
00125 
00126                         /* Try probing at this I/O address */
00127                         if ( isa_probe ( isa ) == 0 ) {
00128                                 /* isadev registered, we can drop our ref */
00129                                 isa = NULL;
00130                         } else {
00131                                 /* Not registered; re-use struct */
00132                                 list_del ( &isa->dev.siblings );
00133                         }
00134                 }
00135         }
00136 
00137         free ( isa );
00138         return 0;
00139 
00140  err:
00141         free ( isa );
00142         isabus_remove ( rootdev );
00143         return rc;
00144 }
00145 
00146 /**
00147  * Remove ISA root bus
00148  *
00149  * @v rootdev           ISA bus root device
00150  */
00151 static void isabus_remove ( struct root_device *rootdev ) {
00152         struct isa_device *isa;
00153         struct isa_device *tmp;
00154 
00155         list_for_each_entry_safe ( isa, tmp, &rootdev->dev.children,
00156                                    dev.siblings ) {
00157                 isa_remove ( isa );
00158                 list_del ( &isa->dev.siblings );
00159                 free ( isa );
00160         }
00161 }
00162 
00163 /** ISA bus root device driver */
00164 static struct root_driver isa_root_driver = {
00165         .probe = isabus_probe,
00166         .remove = isabus_remove,
00167 };
00168 
00169 /** ISA bus root device */
00170 struct root_device isa_root_device __root_device = {
00171         .dev = { .name = "ISA" },
00172         .driver = &isa_root_driver,
00173 };