• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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  */
isa_probe(struct isa_device * isa)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  */
isa_remove(struct isa_device * isa)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  */
isabus_probe(struct root_device * rootdev)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  */
isabus_remove(struct root_device * rootdev)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