|
@@ -0,0 +1,161 @@
|
|
1
|
+#ifndef BUS_H
|
|
2
|
+#define BUS_H
|
|
3
|
+
|
|
4
|
+#include "stdint.h"
|
|
5
|
+
|
|
6
|
+/*
|
|
7
|
+ * When looking at the following data structures, mentally substitute
|
|
8
|
+ * "<bus>_" in place of "bus_" and everything will become clear.
|
|
9
|
+ * "struct bus_location" becomes "struct <bus>_location", which means
|
|
10
|
+ * "the location of a device on a <bus> bus", where <bus> is a
|
|
11
|
+ * particular type of bus such as "pci" or "isapnp".
|
|
12
|
+ *
|
|
13
|
+ */
|
|
14
|
+
|
|
15
|
+/*
|
|
16
|
+ * A physical device location.
|
|
17
|
+ *
|
|
18
|
+ */
|
|
19
|
+#define BUS_LOCATION_SIZE 4
|
|
20
|
+struct bus_location {
|
|
21
|
+ char bytes[BUS_LOCATION_SIZE];
|
|
22
|
+};
|
|
23
|
+
|
|
24
|
+/*
|
|
25
|
+ * A structure fully describing a physical device.
|
|
26
|
+ *
|
|
27
|
+ */
|
|
28
|
+#define BUS_DEVICE_SIZE 32
|
|
29
|
+struct bus_device {
|
|
30
|
+ char bytes[BUS_DEVICE_SIZE];
|
|
31
|
+};
|
|
32
|
+
|
|
33
|
+/*
|
|
34
|
+ * Individual buses will have different sizes for their <bus>_location
|
|
35
|
+ * and <bus>_device structures. We need to be able to allocate static
|
|
36
|
+ * storage that's large enough to contain these structures for any
|
|
37
|
+ * bus type that's being used in the current binary.
|
|
38
|
+ *
|
|
39
|
+ * We can't just create a union of all the various types, because some
|
|
40
|
+ * may be architecture-dependent (and some are even embedded in
|
|
41
|
+ * specific drivers, e.g. 3c509), so this would quickly get messy.
|
|
42
|
+ *
|
|
43
|
+ * We could use the magic of common symbols. Each bus could declare a
|
|
44
|
+ * common symbol with the name "_bus_device" of the correct size; this
|
|
45
|
+ * is easily done using code like
|
|
46
|
+ * struct pci_device _bus_device;
|
|
47
|
+ * The linker would then use the largest size of the "_bus_device"
|
|
48
|
+ * symbol in any included object, thus giving us a single _bus_device
|
|
49
|
+ * symbol of *exactly* the required size. However, there's no way to
|
|
50
|
+ * extract the size of this symbol, either directly as a linker symbol
|
|
51
|
+ * ("_bus_device_size = SIZEOF(_bus_device)"; the linker language just
|
|
52
|
+ * doesn't provide this construct) or via any linker trickery I can
|
|
53
|
+ * think of (such as creating a special common symbol section just for
|
|
54
|
+ * this symbol then using SIZE(section) to read the size of the
|
|
55
|
+ * section; ld recognises only a single common symbol section called
|
|
56
|
+ * "COMMON").
|
|
57
|
+ *
|
|
58
|
+ * Since there's no way to get the size of the symbol, this
|
|
59
|
+ * effectively limits us to just one instance of the symbol. This is
|
|
60
|
+ * all very well for the simple case of "just boot from any single
|
|
61
|
+ * device you can", but becomes limiting when you want to do things
|
|
62
|
+ * like introducing PCMCIA buses (which must instantiate other devices
|
|
63
|
+ * such as PCMCIA controllers).
|
|
64
|
+ *
|
|
65
|
+ * So, we declare the maximum sizes of these constructions to be
|
|
66
|
+ * compile-time constants. Each individual bus driver should define
|
|
67
|
+ * its own struct <bus>_location and struct <bus>_device however it
|
|
68
|
+ * likes, and can freely cast pointers from struct bus_location to
|
|
69
|
+ * struct <bus>_location (and similarly for bus_device). To guard
|
|
70
|
+ * against bounding errors, each bus driver *MUST* use the macros
|
|
71
|
+ * BUS_LOCATION_CHECK() and BUS_DEVICE_CHECK(), as in:
|
|
72
|
+ *
|
|
73
|
+ * BUS_LOCATION_CHECK ( struct pci_location );
|
|
74
|
+ * BUS_DEVICE_CHECK ( struct pci_device );
|
|
75
|
+ *
|
|
76
|
+ * These macros will generate a link-time error if the size of the
|
|
77
|
+ * <bus> structure exceeds the declared maximum size.
|
|
78
|
+ *
|
|
79
|
+ * The macros will generate no binary object code, but must be placed
|
|
80
|
+ * inside a function (in order to generate syntactically valid C).
|
|
81
|
+ * The easiest wy to do this is to place them in the
|
|
82
|
+ * <bus>_next_location() function.
|
|
83
|
+ *
|
|
84
|
+ * If anyone can think of a better way of doing this that avoids *ALL*
|
|
85
|
+ * of the problems described above, please implement it!
|
|
86
|
+ *
|
|
87
|
+ */
|
|
88
|
+
|
|
89
|
+#define LINKER_ASSERT(test,error_symbol) \
|
|
90
|
+ if ( ! (test) ) { \
|
|
91
|
+ extern void error_symbol ( void ); \
|
|
92
|
+ error_symbol(); \
|
|
93
|
+ }
|
|
94
|
+
|
|
95
|
+#define BUS_LOCATION_CHECK(datatype) \
|
|
96
|
+ LINKER_ASSERT( ( sizeof (datatype) < sizeof (struct bus_location) ),
|
|
97
|
+ __BUS_LOCATION_SIZE_is_too_small__see_dev_h )
|
|
98
|
+#define BUS_DEVICE_CHECK(datatype) \
|
|
99
|
+ LINKER_ASSERT( ( sizeof (datatype) < sizeof (struct bus_device) ),
|
|
100
|
+ __BUS_DEVICE_SIZE_is_too_small__see_dev_h )
|
|
101
|
+
|
|
102
|
+/*
|
|
103
|
+ * A description of a device. This is used to send information about
|
|
104
|
+ * the device to a DHCP server, and to provide a text string to
|
|
105
|
+ * describe the device to the user.
|
|
106
|
+ *
|
|
107
|
+ * Note that "text" is allowed to be NULL, in which case the
|
|
108
|
+ * describe_device() method will print the information directly to the
|
|
109
|
+ * console rather than writing it into a buffer. (This happens
|
|
110
|
+ * transparently because sprintf(NULL,...) is exactly equivalent to
|
|
111
|
+ * printf(...) in our vsprintf.c).
|
|
112
|
+ *
|
|
113
|
+ */
|
|
114
|
+struct bus_description {
|
|
115
|
+ char *text;
|
|
116
|
+ uint16_t vendor_id;
|
|
117
|
+ uint16_t device_id;
|
|
118
|
+ uint8_t bus_type;
|
|
119
|
+};
|
|
120
|
+
|
|
121
|
+/*
|
|
122
|
+ * A driver definition
|
|
123
|
+ *
|
|
124
|
+ */
|
|
125
|
+struct bus_driver;
|
|
126
|
+
|
|
127
|
+/*
|
|
128
|
+ * Bus-level operations.
|
|
129
|
+ *
|
|
130
|
+ * int next_location ( struct bus_location * bus_location )
|
|
131
|
+ *
|
|
132
|
+ * Increment bus_location to point to the next possible device on
|
|
133
|
+ * the bus (e.g. the next PCI busdevfn, or the next ISAPnP CSN).
|
|
134
|
+ * If there are no more valid locations, return 0 and leave
|
|
135
|
+ * struct bus_location zeroed, otherwise return true.
|
|
136
|
+ *
|
|
137
|
+ * int fill_device ( struct bus_location *bus_location,
|
|
138
|
+ * struct bus_device *bus_device )
|
|
139
|
+ *
|
|
140
|
+ * Fill out a bus_device structure with the parameters for the
|
|
141
|
+ * device at bus_location. (For example, fill in the PCI vendor
|
|
142
|
+ * and device IDs). Return true if there is a device physically
|
|
143
|
+ * present at this location, otherwise 0.
|
|
144
|
+ *
|
|
145
|
+ * int check_driver ( )
|
|
146
|
+ *
|
|
147
|
+ */
|
|
148
|
+struct bus_operations {
|
|
149
|
+ int ( *next_location ) ( struct bus_location * bus_location );
|
|
150
|
+ int ( *fill_device ) ( struct bus_location * bus_location,
|
|
151
|
+ struct bus_device * bus_device );
|
|
152
|
+ int ( *check_driver ) ( struct bus_device * bus_device,
|
|
153
|
+ struct bus_driver * bus_driver );
|
|
154
|
+ void ( *describe_device ) ( struct bus_device * bus_device,
|
|
155
|
+ struct bus_driver * bus_driver,
|
|
156
|
+ struct bus_description * bus_description );
|
|
157
|
+};
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+#endif /* BUS_H */
|