Merge branch 'master' of /pub/scm/gpxe
[gpxe.git] / src / core / dev.c
blob582edf87acda71e69f4a0993097200645ecf1cc5
1 #include <stdio.h>
2 #include <etherboot.h>
3 #include <stddef.h>
4 #include <dev.h>
6 /*
7 * Each bus driver defines several methods, which are described in
8 * dev.h. This file provides a centralised, bus-independent mechanism
9 * for locating devices and drivers.
13 /* Linker symbols for the various tables */
14 static struct bus_driver bus_drivers[0]
15 __table_start ( struct bus_driver, bus_driver );
16 static struct bus_driver bus_drivers_end[0]
17 __table_end ( struct bus_driver, bus_driver );
18 static struct device_driver device_drivers[0]
19 __table_start ( struct device_driver, device_driver );
20 static struct device_driver device_drivers_end[0]
21 __table_end ( struct device_driver, device_driver );
23 /* Current attempted boot device */
24 struct dev dev = {
25 .bus_driver = bus_drivers,
26 .device_driver = device_drivers,
30 * Print all drivers
33 void print_drivers ( void ) {
34 struct device_driver *driver;
36 for ( driver = device_drivers ;
37 driver < device_drivers_end ;
38 driver++ ) {
39 printf ( "%s ", driver->name );
44 * Move to the next location on any bus
47 static inline int next_location ( struct bus_driver **bus_driver,
48 struct bus_loc *bus_loc ) {
49 /* Move to next location on this bus, if any */
50 if ( (*bus_driver)->next_location ( bus_loc ) )
51 return 1;
53 /* Move to first (zeroed) location on next bus, if any */
54 if ( ++(*bus_driver) < bus_drivers_end ) {
55 DBG ( "DEV scanning %s bus\n", (*bus_driver)->name );
56 return 1;
59 /* Reset to first bus, return "no more locations" */
60 *bus_driver = bus_drivers;
61 return 0;
65 * Find the next available device on any bus
67 * Set skip=1 to skip over the current device
70 int find_any ( struct bus_driver **bus_driver, struct bus_loc *bus_loc,
71 struct bus_dev *bus_dev, signed int skip ) {
72 DBG ( "DEV scanning %s bus\n", (*bus_driver)->name );
73 do {
74 if ( --skip >= 0 )
75 continue;
76 if ( ! (*bus_driver)->fill_device ( bus_dev, bus_loc ) )
77 continue;
78 DBG ( "DEV found device %s\n",
79 (*bus_driver)->describe_device ( bus_dev ) );
80 return 1;
81 } while ( next_location ( bus_driver, bus_loc ) );
83 DBG ( "DEV found no more devices\n" );
84 return 0;
88 * Find a driver by specified device.
90 * Set skip=1 to skip over the current driver
93 int find_by_device ( struct device_driver **device_driver,
94 struct bus_driver *bus_driver, struct bus_dev *bus_dev,
95 signed int skip ) {
96 do {
97 if ( --skip >= 0 )
98 continue;
99 if ( (*device_driver)->bus_driver != bus_driver )
100 continue;
101 if ( ! bus_driver->check_driver ( bus_dev, *device_driver ))
102 continue;
103 DBG ( "DEV found driver %s for device %s\n",
104 (*device_driver)->name,
105 bus_driver->describe_device ( bus_dev ) );
106 return 1;
107 } while ( ++(*device_driver) < device_drivers_end );
109 /* Reset to first driver, return "not found" */
110 DBG ( "DEV found no driver for device %s\n",
111 bus_driver->describe_device ( bus_dev ) );
112 *device_driver = device_drivers;
113 return 0;
117 * Find a device by specified driver.
119 * Set skip=1 to skip over the current device
122 int find_by_driver ( struct bus_loc *bus_loc, struct bus_dev *bus_dev,
123 struct device_driver *device_driver,
124 signed int skip ) {
125 struct bus_driver *bus_driver = device_driver->bus_driver;
127 do {
128 if ( --skip >= 0 )
129 continue;
130 if ( ! bus_driver->fill_device ( bus_dev, bus_loc ) )
131 continue;
132 if ( ! bus_driver->check_driver ( bus_dev, device_driver ) )
133 continue;
134 DBG ( "DEV found device %s for driver %s\n",
135 bus_driver->describe_device ( bus_dev ),
136 device_driver->name );
137 return 1;
138 } while ( bus_driver->next_location ( bus_loc ) );
140 DBG ( "DEV found no device for driver %s\n", device_driver->name );
141 return 0;
145 * Find the next available (device,driver) combination
147 * Set skip=1 to skip over the current (device,driver)
149 * Note that the struct dev may not have been previously used, and so
150 * may not contain a valid (device,driver) combination.
153 int find_any_with_driver ( struct dev *dev, signed int skip ) {
154 signed int skip_device = 0;
155 signed int skip_driver = skip;
157 while ( find_any ( &dev->bus_driver, &dev->bus_loc, &dev->bus_dev,
158 skip_device ) ) {
159 if ( find_by_device ( &dev->device_driver, dev->bus_driver,
160 &dev->bus_dev, skip_driver ) ) {
161 /* Set type_driver to be that of the device
162 * driver
164 dev->type_driver = dev->device_driver->type_driver;
165 /* Set type device instance to be the single
166 * instance provided by the type driver
168 dev->type_dev = dev->type_driver->type_dev;
169 return 1;
171 skip_driver = 0;
172 skip_device = 1;
175 return 0;