include stdio.h to suppress printf warning, general warnings fixups
[people/xl0/gpxe.git] / src / core / dev.c
1 #include "etherboot.h"
2 #include "stddef.h"
3 #include "dev.h"
4
5 /*
6  * Each bus driver defines several methods, which are described in
7  * dev.h.  This file provides a centralised, bus-independent mechanism
8  * for locating devices and drivers.
9  *
10  */
11
12 /* Linker symbols for the various tables */
13 static struct bus_driver bus_drivers[0] __table_start ( bus_driver );
14 static struct bus_driver bus_drivers_end[0] __table_end ( bus_driver );
15 static struct device_driver device_drivers[0] __table_start ( device_driver );
16 static struct device_driver device_drivers_end[0] __table_end (device_driver );
17
18 /* Current attempted boot device */
19 struct dev dev = {
20         .bus_driver = bus_drivers,
21         .device_driver = device_drivers,
22 };
23
24 /*
25  * Print all drivers 
26  *
27  */
28 void print_drivers ( void ) {
29         struct device_driver *driver;
30
31         for ( driver = device_drivers ;
32               driver < device_drivers_end ;
33               driver++ ) {
34                 printf ( "%s ", driver->name );
35         }
36 }
37
38 /*
39  * Move to the next location on any bus
40  *
41  */
42 static inline int next_location ( struct bus_driver **bus_driver,
43                                   struct bus_loc *bus_loc ) {
44         /* Move to next location on this bus, if any */
45         if ( (*bus_driver)->next_location ( bus_loc ) )
46                 return 1;
47
48         /* Move to first (zeroed) location on next bus, if any */
49         if ( ++(*bus_driver) < bus_drivers_end ) {
50                 DBG ( "DEV scanning %s bus\n", (*bus_driver)->name );
51                 return 1;
52         }
53
54         /* Reset to first bus, return "no more locations" */
55         *bus_driver = bus_drivers;
56         return 0;
57 }
58
59 /*
60  * Find the next available device on any bus
61  *
62  * Set skip=1 to skip over the current device
63  *
64  */
65 int find_any ( struct bus_driver **bus_driver, struct bus_loc *bus_loc,
66                struct bus_dev *bus_dev, signed int skip ) {
67         DBG ( "DEV scanning %s bus\n", (*bus_driver)->name );
68         do {
69                 if ( --skip >= 0 )
70                         continue;
71                 if ( ! (*bus_driver)->fill_device ( bus_dev, bus_loc ) )
72                         continue;
73                 DBG ( "DEV found device %s\n",
74                       (*bus_driver)->describe_device ( bus_dev ) );
75                 return 1;
76         } while ( next_location ( bus_driver, bus_loc ) );
77
78         DBG ( "DEV found no more devices\n" );
79         return 0;
80 }
81
82 /*
83  * Find a driver by specified device.
84  *
85  * Set skip=1 to skip over the current driver
86  *
87  */
88 int find_by_device ( struct device_driver **device_driver,
89                      struct bus_driver *bus_driver, struct bus_dev *bus_dev,
90                      signed int skip ) {
91         do {
92                 if ( --skip >= 0 )
93                         continue;
94                 if ( (*device_driver)->bus_driver != bus_driver )
95                         continue;
96                 if ( ! bus_driver->check_driver ( bus_dev, *device_driver ))
97                         continue;
98                 DBG ( "DEV found driver %s for device %s\n",
99                       (*device_driver)->name,
100                       bus_driver->describe_device ( bus_dev ) );
101                 return 1;
102         } while ( ++(*device_driver) < device_drivers_end );
103         
104         /* Reset to first driver, return "not found" */
105         DBG ( "DEV found no driver for device %s\n",
106               bus_driver->describe_device ( bus_dev ) );
107         *device_driver = device_drivers;
108         return 0;
109 }
110
111 /*
112  * Find a device by specified driver.
113  *
114  * Set skip=1 to skip over the current device
115  *
116  */
117 int find_by_driver ( struct bus_loc *bus_loc, struct bus_dev *bus_dev,
118                      struct device_driver *device_driver,
119                      signed int skip ) {
120         struct bus_driver *bus_driver = device_driver->bus_driver;
121         
122         do {
123                 if ( --skip >= 0 )
124                         continue;
125                 if ( ! bus_driver->fill_device ( bus_dev, bus_loc ) )
126                         continue;
127                 if ( ! bus_driver->check_driver ( bus_dev, device_driver ) )
128                         continue;
129                 DBG ( "DEV found device %s for driver %s\n",
130                       bus_driver->describe_device ( bus_dev ),
131                       device_driver->name );
132                 return 1;
133         } while ( bus_driver->next_location ( bus_loc ) );
134
135         DBG ( "DEV found no device for driver %s\n", device_driver->name );
136         return 0;
137 }
138
139 /*
140  * Find the next available (device,driver) combination
141  *
142  * Set skip=1 to skip over the current (device,driver)
143  *
144  * Note that the struct dev may not have been previously used, and so
145  * may not contain a valid (device,driver) combination.
146  *
147  */
148 int find_any_with_driver ( struct dev *dev, signed int skip ) {
149         signed int skip_device = 0;
150         signed int skip_driver = skip;
151
152         while ( find_any ( &dev->bus_driver, &dev->bus_loc, &dev->bus_dev,
153                            skip_device ) ) {
154                 if ( find_by_device ( &dev->device_driver, dev->bus_driver,
155                                       &dev->bus_dev, skip_driver ) ) {
156                         /* Set type_driver to be that of the device
157                          * driver
158                          */
159                         dev->type_driver = dev->device_driver->type_driver;
160                         /* Set type device instance to be the single
161                          * instance provided by the type driver
162                          */
163                         dev->type_dev = dev->type_driver->type_dev;
164                         return 1;
165                 }
166                 skip_driver = 0;
167                 skip_device = 1;
168         }
169
170         return 0;
171 }