Trying to create a bus API.
[people/lynusvaz/gpxe.git] / src / include / bus.h
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 */