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 9FILE_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 */ 33static 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 53static 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 */ 61static 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 */ 81static 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 */ 94static 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 */ 150static 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 */ 163static struct root_driver isa_root_driver = { 164 .probe = isabus_probe, 165 .remove = isabus_remove, 166}; 167 168/** ISA bus root device */ 169struct root_device isa_root_device __root_device = { 170 .dev = { .name = "ISA" }, 171 .driver = &isa_root_driver, 172}; 173