1 #include <stdint.h> 2 #include <string.h> 3 #include <stdlib.h> 4 #include <stdio.h> 5 #include <errno.h> 6 #include <gpxe/io.h> 7 #include <gpxe/isa.h> 8 9 FILE_LICENCE ( GPL2_OR_LATER ); 10 11 /* 12 * isa.c implements a "classical" port-scanning method of ISA device 13 * detection. The driver must provide a list of probe addresses 14 * (probe_addrs), together with a function (probe_addr) that can be 15 * used to test for the physical presence of a device at any given 16 * address. 17 * 18 * Note that this should probably be considered the "last resort" for 19 * device probing. If the card supports ISAPnP or EISA, use that 20 * instead. Some cards (e.g. the 3c509) implement a proprietary 21 * ISAPnP-like mechanism. 22 * 23 * The ISA probe address list can be overridden by config.h; if the 24 * user specifies ISA_PROBE_ADDRS then that list will be used first. 25 * (If ISA_PROBE_ONLY is defined, the driver's own list will never be 26 * used). 27 */ 28 29 /* 30 * User-supplied probe address list 31 * 32 */ 33 static isa_probe_addr_t isa_extra_probe_addrs[] = { 34 #ifdef ISA_PROBE_ADDRS 35 ISA_PROBE_ADDRS 36 #endif 37 }; 38 #define ISA_EXTRA_PROBE_ADDR_COUNT \ 39 ( sizeof ( isa_extra_probe_addrs ) / sizeof ( isa_extra_probe_addrs[0] ) ) 40 41 #define ISA_IOIDX_MIN( driver ) ( -ISA_EXTRA_PROBE_ADDR_COUNT ) 42 #ifdef ISA_PROBE_ONLY 43 #define ISA_IOIDX_MAX( driver ) ( -1 ) 44 #else 45 #define ISA_IOIDX_MAX( driver ) ( (int) (driver)->addr_count - 1 ) 46 #endif 47 48 #define ISA_IOADDR( driver, ioidx ) \ 49 ( ( (ioidx) < 0 ) ? \ 50 isa_extra_probe_addrs[ (ioidx) + ISA_EXTRA_PROBE_ADDR_COUNT ] : \ 51 (driver)->probe_addrs[(ioidx)] ) 52 53 static void isabus_remove ( struct root_device *rootdev ); 54 55 /** 56 * Probe an ISA device 57 * 58 * @v isa ISA device 59 * @ret rc Return status code 60 */ 61 static int isa_probe ( struct isa_device *isa ) { 62 int rc; 63 64 DBG ( "Trying ISA driver %s at I/O %04x\n", 65 isa->driver->name, isa->ioaddr ); 66 67 if ( ( rc = isa->driver->probe ( isa ) ) != 0 ) { 68 DBG ( "...probe failed\n" ); 69 return rc; 70 } 71 72 DBG ( "...device found\n" ); 73 return 0; 74 } 75 76 /** 77 * Remove an ISA device 78 * 79 * @v isa ISA device 80 */ 81 static void isa_remove ( struct isa_device *isa ) { 82 isa->driver->remove ( isa ); 83 DBG ( "Removed ISA%04x\n", isa->ioaddr ); 84 } 85 86 /** 87 * Probe ISA root bus 88 * 89 * @v rootdev ISA bus root device 90 * 91 * Scans the ISA bus for devices and registers all devices it can 92 * find. 93 */ 94 static int isabus_probe ( struct root_device *rootdev ) { 95 struct isa_device *isa = NULL; 96 struct isa_driver *driver; 97 int ioidx; 98 int rc; 99 100 for_each_table_entry ( driver, ISA_DRIVERS ) { 101 for ( ioidx = ISA_IOIDX_MIN ( driver ) ; 102 ioidx <= ISA_IOIDX_MAX ( driver ) ; ioidx++ ) { 103 /* Allocate struct isa_device */ 104 if ( ! isa ) 105 isa = malloc ( sizeof ( *isa ) ); 106 if ( ! isa ) { 107 rc = -ENOMEM; 108 goto err; 109 } 110 memset ( isa, 0, sizeof ( *isa ) ); 111 isa->driver = driver; 112 isa->ioaddr = ISA_IOADDR ( driver, ioidx ); 113 114 /* Add to device hierarchy */ 115 snprintf ( isa->dev.name, sizeof ( isa->dev.name ), 116 "ISA%04x", isa->ioaddr ); 117 isa->dev.desc.bus_type = BUS_TYPE_ISA; 118 isa->dev.desc.vendor = driver->vendor_id; 119 isa->dev.desc.device = driver->prod_id; 120 isa->dev.parent = &rootdev->dev; 121 list_add ( &isa->dev.siblings, 122 &rootdev->dev.children ); 123 INIT_LIST_HEAD ( &isa->dev.children ); 124 125 /* Try probing at this I/O address */ 126 if ( isa_probe ( isa ) == 0 ) { 127 /* isadev registered, we can drop our ref */ 128 isa = NULL; 129 } else { 130 /* Not registered; re-use struct */ 131 list_del ( &isa->dev.siblings ); 132 } 133 } 134 } 135 136 free ( isa ); 137 return 0; 138 139 err: 140 free ( isa ); 141 isabus_remove ( rootdev ); 142 return rc; 143 } 144 145 /** 146 * Remove ISA root bus 147 * 148 * @v rootdev ISA bus root device 149 */ 150 static void isabus_remove ( struct root_device *rootdev ) { 151 struct isa_device *isa; 152 struct isa_device *tmp; 153 154 list_for_each_entry_safe ( isa, tmp, &rootdev->dev.children, 155 dev.siblings ) { 156 isa_remove ( isa ); 157 list_del ( &isa->dev.siblings ); 158 free ( isa ); 159 } 160 } 161 162 /** ISA bus root device driver */ 163 static struct root_driver isa_root_driver = { 164 .probe = isabus_probe, 165 .remove = isabus_remove, 166 }; 167 168 /** ISA bus root device */ 169 struct root_device isa_root_device __root_device = { 170 .dev = { .name = "ISA" }, 171 .driver = &isa_root_driver, 172 }; 173