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