[tcpip] Allow supported address families to be detected at runtime
[ipxe.git] / src / drivers / bus / isa.c
1 #include <stdint.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <errno.h>
6 #include <ipxe/io.h>
7 #include <ipxe/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 (driver)->probe_addrs[(ioidx)] : \
51 *( isa_extra_probe_addrs + (ioidx) + ISA_EXTRA_PROBE_ADDR_COUNT ) )
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.driver_name = driver->name;
118 isa->dev.desc.bus_type = BUS_TYPE_ISA;
119 isa->dev.desc.vendor = driver->vendor_id;
120 isa->dev.desc.device = driver->prod_id;
121 isa->dev.parent = &rootdev->dev;
122 list_add ( &isa->dev.siblings,
123 &rootdev->dev.children );
124 INIT_LIST_HEAD ( &isa->dev.children );
125
126 /* Try probing at this I/O address */
127 if ( isa_probe ( isa ) == 0 ) {
128 /* isadev registered, we can drop our ref */
129 isa = NULL;
130 } else {
131 /* Not registered; re-use struct */
132 list_del ( &isa->dev.siblings );
133 }
134 }
135 }
136
137 free ( isa );
138 return 0;
139
140 err:
141 free ( isa );
142 isabus_remove ( rootdev );
143 return rc;
144 }
145
146 /**
147 * Remove ISA root bus
148 *
149 * @v rootdev ISA bus root device
150 */
151 static void isabus_remove ( struct root_device *rootdev ) {
152 struct isa_device *isa;
153 struct isa_device *tmp;
154
155 list_for_each_entry_safe ( isa, tmp, &rootdev->dev.children,
156 dev.siblings ) {
157 isa_remove ( isa );
158 list_del ( &isa->dev.siblings );
159 free ( isa );
160 }
161 }
162
163 /** ISA bus root device driver */
164 static struct root_driver isa_root_driver = {
165 .probe = isabus_probe,
166 .remove = isabus_remove,
167 };
168
169 /** ISA bus root device */
170 struct root_device isa_root_device __root_device = {
171 .dev = { .name = "ISA" },
172 .driver = &isa_root_driver,
173 };