[sis900] Enable interrupts to allow UNDI to work
[people/pcmattman/gpxe.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 <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 };