[e16e8f2] | 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 | }; |
---|