summaryrefslogtreecommitdiffstats
path: root/src/core/dev.c
blob: e5f5640e77a5a9bb99e23a7e80d8c48ae9f60abb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
#include "etherboot.h"
#include "stddef.h"
#include "dev.h"

/*
 * Each driver specifies a name, the bus-scanning function
 * (find_bus_boot_device) that it wants to use, a driver information
 * structure (bus_driver) containing e.g. device IDs to be passed to
 * find_bus_boot_device, and a probe function (probe) to be called
 * whenever a suitable device is found.
 *
 * The generic device-probing code knows nothing about particular bus
 * types; it simply passes the driver information structure
 * (bus_driver) to the bus-scanning function (find_bus_boot_device),
 * then passes the result of that function (if not NULL) to the probe
 * function (probe).
 */

/* Current attempted boot device */
struct dev dev = {
	.bus_driver = bus_drivers,
	.device_driver = device_drivers,
};

/*
 * Print all drivers 
 *
 */
void print_drivers ( void ) {
	struct device_driver *driver;

	for ( driver = device_drivers ;
	      driver < device_drivers_end ;
	      driver++ ) {
		printf ( "%s ", driver->name );
	}
}

/*
 * Move to the next location on any bus
 *
 */
static inline int next_location ( struct bus_driver **bus_driver,
				  struct bus_loc *bus_loc ) {
	/* Move to next location on this bus, if any */
	if ( (*bus_driver)->next_location ( bus_loc ) )
		return 1;

	/* Move to first (zeroed) location on next bus, if any */
	if ( ++(*bus_driver) < bus_drivers_end )
		return 1;

	/* Reset to first bus, return "no more locations" */
	*bus_driver = bus_drivers;
	return 0;
}

/*
 * Find the next available device on any bus
 *
 * Set skip=1 to skip over the current device
 *
 */
int find_any ( struct bus_driver **bus_driver, struct bus_loc *bus_loc,
	       struct bus_dev *bus_dev, signed int skip ) {
	DBG ( "DEV searching for any device\n" );
	do {
		if ( --skip >= 0 )
			continue;
		if ( ! (*bus_driver)->fill_device ( bus_dev, bus_loc ) )
			continue;
		DBG ( "DEV found device %s\n",
		      (*bus_driver)->describe ( bus_dev ) );
		return 1;
	} while ( next_location ( bus_driver, bus_loc ) );

	DBG ( "DEV found no device\n" );
	return 0;
}

/*
 * Find a driver by specified device.
 *
 * Set skip=1 to skip over the current driver
 *
 */
int find_by_device ( struct device_driver **device_driver,
		     struct bus_driver *bus_driver, struct bus_dev *bus_dev,
		     signed int skip ) {
	DBG ( "DEV searching for a driver for device %s\n",
	      bus_driver->describe ( bus_dev ) );
	do {
		if ( --skip >= 0 )
			continue;
		if ( (*device_driver)->bus_driver != bus_driver )
			continue;
		if ( ! bus_driver->check_driver ( bus_dev, *device_driver ))
			continue;
		DBG ( "DEV found driver %s\n", (*device_driver)->name );
		return 1;
	} while ( ++(*device_driver) < device_drivers_end );
	
	/* Reset to first driver, return "not found" */
	DBG ( "DEV found no driver for device %s\n",
	      bus_driver->describe ( bus_dev ) );
	*device_driver = device_drivers;
	return 0;
}

/*
 * Find a device by specified driver.
 *
 * Set skip=1 to skip over the current device
 *
 */
int find_by_driver ( struct bus_loc *bus_loc, struct bus_dev *bus_dev,
		     struct device_driver *device_driver,
		     signed int skip ) {
	struct bus_driver *bus_driver = device_driver->bus_driver;
	
	DBG ( "DEV searching for a device for driver %s\n",
	      device_driver->name );
	do {
		if ( --skip >= 0 )
			continue;
		if ( ! bus_driver->fill_device ( bus_dev, bus_loc ) )
			continue;
		if ( ! bus_driver->check_driver ( bus_dev, device_driver ) )
			continue;
		DBG ( "DEV found device %s\n",
		      bus_driver->describe ( bus_dev ) );
		return 1;
	} while ( bus_driver->next_location ( bus_loc ) );

	DBG ( "DEV found no device for driver %s\n" );
	return 0;
}

/*
 * Find the next available (device,driver) combination
 *
 * Set skip=1 to skip over the current (device,driver)
 *
 * Note that the struct dev may not have been previously used, and so
 * may not contain a valid (device,driver) combination.
 *
 */
int find_any_with_driver ( struct dev *dev, signed int skip ) {
	signed int skip_device = 0;
	signed int skip_driver = skip;

	while ( find_any ( &dev->bus_driver, &dev->bus_loc, &dev->bus_dev,
			   skip_device ) ) {
		if ( find_by_device ( &dev->device_driver, dev->bus_driver,
				      &dev->bus_dev, skip_driver ) ) {
			/* Set type_driver to be that of the device
			 * driver
			 */
			dev->type_driver = dev->device_driver->type_driver;
			/* Set type device instance to be the single
			 * instance provided by the type driver
			 */
			dev->type_dev = dev->type_driver->type_dev;
			return 1;
		}
		skip_driver = 0;
		skip_device = 1;
	}

	return 0;
}