[sundance] Add reset completion check
[gpxe.git] / src / drivers / bus / eisa.c
blobd9e4235977ba906fa8fead0528e107f47d698dfb
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 <unistd.h>
8 #include <gpxe/eisa.h>
10 static struct eisa_driver eisa_drivers[0]
11 __table_start ( struct eisa_driver, eisa_drivers );
12 static struct eisa_driver eisa_drivers_end[0]
13 __table_end ( struct eisa_driver, eisa_drivers );
15 static void eisabus_remove ( struct root_device *rootdev );
17 /**
18 * Reset and enable/disable an EISA device
20 * @v eisa EISA device
21 * @v enabled 1=enable, 0=disable
23 void eisa_device_enabled ( struct eisa_device *eisa, int enabled ) {
24 /* Set reset line high for 1000 µs. Spec says 500 µs, but
25 * this doesn't work for all cards, so we are conservative.
27 outb ( EISA_CMD_RESET, eisa->ioaddr + EISA_GLOBAL_CONFIG );
28 udelay ( 1000 ); /* Must wait 800 */
30 /* Set reset low and write a 1 to ENABLE. Delay again, in
31 * case the card takes a while to wake up.
33 outb ( enabled ? EISA_CMD_ENABLE : 0,
34 eisa->ioaddr + EISA_GLOBAL_CONFIG );
35 udelay ( 1000 ); /* Must wait 800 */
37 DBG ( "EISA %s device %02x\n", ( enabled ? "enabled" : "disabled" ),
38 eisa->slot );
41 /**
42 * Probe an EISA device
44 * @v eisa EISA device
45 * @ret rc Return status code
47 * Searches for a driver for the EISA device. If a driver is found,
48 * its probe() routine is called.
50 static int eisa_probe ( struct eisa_device *eisa ) {
51 struct eisa_driver *driver;
52 struct eisa_device_id *id;
53 unsigned int i;
54 int rc;
56 DBG ( "Adding EISA device %02x (%04x:%04x (\"%s\") io %x)\n",
57 eisa->slot, eisa->vendor_id, eisa->prod_id,
58 isa_id_string ( eisa->vendor_id, eisa->prod_id ), eisa->ioaddr );
60 for ( driver = eisa_drivers; driver < eisa_drivers_end; driver++ ) {
61 for ( i = 0 ; i < driver->id_count ; i++ ) {
62 id = &driver->ids[i];
63 if ( id->vendor_id != eisa->vendor_id )
64 continue;
65 if ( ISA_PROD_ID ( id->prod_id ) !=
66 ISA_PROD_ID ( eisa->prod_id ) )
67 continue;
68 eisa->driver = driver;
69 eisa->driver_name = id->name;
70 DBG ( "...using driver %s\n", eisa->driver_name );
71 if ( ( rc = driver->probe ( eisa, id ) ) != 0 ) {
72 DBG ( "......probe failed\n" );
73 continue;
75 return 0;
79 DBG ( "...no driver found\n" );
80 return -ENOTTY;
83 /**
84 * Remove an EISA device
86 * @v eisa EISA device
88 static void eisa_remove ( struct eisa_device *eisa ) {
89 eisa->driver->remove ( eisa );
90 DBG ( "Removed EISA device %02x\n", eisa->slot );
93 /**
94 * Probe EISA root bus
96 * @v rootdev EISA bus root device
98 * Scans the EISA bus for devices and registers all devices it can
99 * find.
101 static int eisabus_probe ( struct root_device *rootdev ) {
102 struct eisa_device *eisa = NULL;
103 unsigned int slot;
104 int rc;
106 for ( slot = EISA_MIN_SLOT ; slot <= EISA_MAX_SLOT ; slot++ ) {
107 /* Allocate struct eisa_device */
108 if ( ! eisa )
109 eisa = malloc ( sizeof ( *eisa ) );
110 if ( ! eisa ) {
111 rc = -ENOMEM;
112 goto err;
114 memset ( eisa, 0, sizeof ( *eisa ) );
115 eisa->slot = slot;
116 eisa->ioaddr = EISA_SLOT_BASE ( eisa->slot );
118 /* Test for board present */
119 outb ( 0xff, eisa->ioaddr + EISA_VENDOR_ID );
120 eisa->vendor_id =
121 le16_to_cpu ( inw ( eisa->ioaddr + EISA_VENDOR_ID ) );
122 eisa->prod_id =
123 le16_to_cpu ( inw ( eisa->ioaddr + EISA_PROD_ID ) );
124 if ( eisa->vendor_id & 0x80 ) {
125 /* No board present */
126 continue;
129 /* Add to device hierarchy */
130 snprintf ( eisa->dev.name, sizeof ( eisa->dev.name ),
131 "EISA%02x", slot );
132 eisa->dev.desc.bus_type = BUS_TYPE_EISA;
133 eisa->dev.desc.vendor = eisa->vendor_id;
134 eisa->dev.desc.device = eisa->prod_id;
135 eisa->dev.parent = &rootdev->dev;
136 list_add ( &eisa->dev.siblings, &rootdev->dev.children );
137 INIT_LIST_HEAD ( &eisa->dev.children );
139 /* Look for a driver */
140 if ( eisa_probe ( eisa ) == 0 ) {
141 /* eisadev registered, we can drop our ref */
142 eisa = NULL;
143 } else {
144 /* Not registered; re-use struct */
145 list_del ( &eisa->dev.siblings );
149 free ( eisa );
150 return 0;
152 err:
153 free ( eisa );
154 eisabus_remove ( rootdev );
155 return rc;
159 * Remove EISA root bus
161 * @v rootdev EISA bus root device
163 static void eisabus_remove ( struct root_device *rootdev ) {
164 struct eisa_device *eisa;
165 struct eisa_device *tmp;
167 list_for_each_entry_safe ( eisa, tmp, &rootdev->dev.children,
168 dev.siblings ) {
169 eisa_remove ( eisa );
170 list_del ( &eisa->dev.siblings );
171 free ( eisa );
175 /** EISA bus root device driver */
176 static struct root_driver eisa_root_driver = {
177 .probe = eisabus_probe,
178 .remove = eisabus_remove,
181 /** EISA bus root device */
182 struct root_device eisa_root_device __root_device = {
183 .dev = { .name = "EISA" },
184 .driver = &eisa_root_driver,