1 This file contains the documentation written by Thomas Kurschel that was originally
2 found in the headers of his pnp_manager.
3 It's outdated but could be used as a basis for the real documentation.
5 // former pnp_manager.h
7 Copyright (c) 2003-04, Thomas Kurschel
9 PnP manager; Takes care of registration and loading of PnP drivers
11 Read pnp_driver.h first to understand the basic idea behind PnP drivers.
13 To register a driver node, use register_driver. If the device got lost,
14 use unregister_driver (note: if the parent node is removed, your node
15 get removed automatically as your driver has obviously nothing to work
16 with anymore). To get access to a (parent) device, use load_driver/
19 To let the manager find a consumer (see pnp_driver.h), you can either
20 specify its name directly during registration, using a
21 PNP_DRIVER_FIXED_CONSUMER attribute, or let the manager search the
22 appropriate consumer(s) via a PNP_DRIVER_DYNAMIC_CONSUMER attribute.
24 Searching of dynamic consumers is done as follows:
26 - First, the manager searches for a Specific driver in the base
28 - If no Specific driver is found, all Generic drivers stored under
29 "generic" sub-directory are informed in turn until one returns success
30 - Finally, _all_ Universal drivers, stored in the "universal" sub-
31 directory, are informed
33 Specification of the base directory and of the names of Specific
34 drivers is done via a file name pattern given by a
35 PNP_DRIVER_DYNAMIC_CONSUMER attribute.
37 First, all substrings of the form "%attribute_name%" are replaced by the
38 content of the attribute "attribute_name" as follows:
40 - if the attribute contains an integer value, its content is converted to hex
41 (lowercase) with a fixed length according to the attribute's value range
42 - the content of string attributes is quoted by " and invalid characters
43 (i.e. /%" and all characters outside 32..126) are replaced by their
44 unsigned decimal value, delimited by %
45 - other attribute types cannot be used
47 Second, the resulting name is split into chunks according to the presence
48 of | characters (you can escape % and | with a ^ character). These
49 characters are only delimiters and get removed before further processing.
50 The directory before the first | character is the base directory (see
51 above). It contains the "generic" and the "universal" subdirectories.
52 The names of the specific drivers are created by first taking the entire
53 file name, then by removing the last chunk, then by removing the last
54 two chunks and so on until only the first chunk is left.
56 As drivers can contain multiple modules, the module name is constructed
57 by appending the content of the PNP_DRIVER_TYPE attribute to the driver's file
58 name, seperated by a slash character (note: this only applies to dynamic
59 consumers; for fixed consumers, you specify the module name directly via
60 PNP_DRIVER_FIXED_CONSUMER).
62 E.g. given a dynamic consumer pattern of
63 "pci/vendor=%vendor_id%|, device=%device_id%" for a device with the
64 attributes vendor_id=0x123 and device_id=0xabcd (both being uint16), the
65 PnP manager tries the specific drivers "pci/vendor=0123, device=abcd" and
66 (if the first one fails/doesn't exist) "pci/vendor=0123". If they both
67 refuse to handle the device, all drivers under "pci/generic" are tried
68 until one accepts the device. Finally, all drivers under "pci/universal"
69 are loaded, whatever happened before.
71 In practise, you should try to use specific drivers as much as possible.
72 If detection based on device IDs is impossible (e.g. because the bus
73 doesn't support them at all), you can put the driver under "generic".
74 Generic drivers can also be used to specify wrappers that try to load old-
75 style drivers if no new driver can be found. Also, they can be used to
76 report an error or invoke an user program that tries downloading a
77 proper Specific driver. Universal drivers are mainly used for
78 informational purposes, e.g. to publish data about each found device,
79 or to provide raw access to all devices.
81 If the device uses physical address space or I/O space or ISA DMA
82 channels (called I/O resources), the driver has to acquire these
83 resources. During hardware detection (usually via probe()),
84 acquire_io_resources() must be called to get exclusive access.
85 If no hardware could be found, they must be released via
86 release_io_resources(). If detection was successful, the list of
87 the (acquired) resources must be passed to register_device().
88 Resources can either belong to one hardware detection or to a device.
89 If a hardware detection collides with another, it has to wait;
90 if it collides with a device whose driver is not loaded, the
91 driver loading is blocked. When detection fails, i.e. if
92 release_io_resources() is called, all blocked drivers can be loaded
93 again. If the detection fails, i.e. the resources are transferred
94 via register_device(), all blocked devices are unregistered and
95 pending load requests aborted. If a hardware detection collides
96 with a device whose driver is loaded, acquire_io_resources() fails
97 with B_BUSY. As this makes a hardware rescan impossible if the
98 driver is loaded, you should define PNP_DRIVER_NO_LIVE_RESCAN
99 for nodes that use I/O resources (see below).
101 To search for new drivers for a given device node, use rescan(). This
102 marks all consumer devices as being verified and calls probe()
103 of all consumers drivers (see above) to let them rescan the parent
104 for devices. The <depth> parameter determines the nesting level, e.g.
105 2 means that first the consumers are scanned and then the consumers
108 Normally, all devices can be rescanned. If a driver cannot handle
109 a rescan safely when it is loaded (i.e. used by a consumer), it
110 must set PNP_DRIVER_NO_LIVE_RESCAN, in which case the device is
111 ignored during rescan if the driver is loaded and attempts
112 to load the driver during a rescan are blocked until the rescan
113 is finished. If rescanning a device is not possible at all, it must
114 have set PNP_DRIVER_NEVER_RESCAN to always ignore it.
116 To distinguish between new devices, lost devices and redetected
117 devices, consumer devices should provide a connection code and a
118 device identifier. They are specified by PNP_DRIVER_CONNECTION and
119 PNP_DRIVER_CONNECTION respectively, and are expanded in the same way
120 as PNP_DRIVER_DYNAMIC_CONSUMER. It is assumed that there can be only
121 one device per connection and that a device can be uniquely identify
122 by a device identifier. If a consumer device is registered on the
123 same connection as an existing device but with a different device
124 identifier, the old device gets unregistered automatically. If both
125 connection and device identifier are the same, registration is
126 handled as a redetection and ignored (unless a different type or
127 driver module is specified - in this case, the device is replaced).
128 Devices that were not redetected during a rescan get unregistered
129 unless they were ignored (see above).
132 // interface of PnP manager
133 typedef struct device_manager_info {
137 // node - node whos driver is to be loaded
138 // user_cookie - cookie to be passed to init_device of driver
139 // interface - interface of loaded driver
140 // cookie - device cookie issued by loaded driver
141 status_t (*init_driver)(device_node_handle node, void *userCookie,
142 driver_module_info **interface, void **cookie);
144 status_t (*uninit_driver)(device_node_handle node);
146 // rescan node for new dynamic drivers
147 // node - node whose dynamic drivers are to be scanned
148 status_t (*rescan)(device_node_handle node);
151 // parent - parent node
152 // attributes - NULL-terminated array of node attributes
153 // io_resources - NULL-terminated array of I/O resources (can be NULL)
154 // node - new node handle
155 // on return, io_resources are invalid: on success I/O resources belong
156 // to node, on fail they are released;
157 // if device is already registered, B_OK is returned but *node is NULL
158 status_t (*register_device)(device_node_handle parent,
159 const device_attr *attrs,
160 const io_resource_handle *io_resources,
161 device_node_handle *node);
163 // all nodes having this node as their parent are unregistered too.
164 // if the node contains PNP_MANAGER_ID_GENERATOR/PNP_MANAGER_AUTO_ID
165 // pairs, the id specified this way is freed too
166 status_t (*unregister_device)(device_node_handle node);
168 // find device by node content
169 // the given attributes must _uniquely_ identify a device node;
170 // parent - parent node (-1 for don't-care)
171 // attrs - list of attributes (can be NULL)
172 // The node you got will be automatically put on the next call
174 status_t (*get_next_child_device)(device_node_handle parent,
175 device_node_handle *_node, const device_attr *attrs);
177 // get parent device node
178 device_node_handle (*get_parent)(device_node_handle node);
180 // Must be called after get_next_child_device() (if you don't iterate through)
181 // and get_parent() to make sure the node is freed when it's not used anymore
182 void (*put_device_node)(device_node_handle node);
184 // acquire I/O resources
185 // resources - NULL-terminated array of resources to acquire
186 // handles - NULL-terminated array of handles (one per resource);
187 // array must be provided by caller
188 // return B_BUSY if a resource is used by a loaded driver
189 status_t (*acquire_io_resources)(io_resource *resources,
190 io_resource_handle *handles);
191 // release I/O resources
192 // handles - NULL-terminated array of handles
193 status_t (*release_io_resources)(const io_resource_handle *handles);
196 // generator - name of id set
197 // if result >= 0 - unique id
198 // result < 0 - error code
199 int32 (*create_id)(const char *generator);
201 status_t (*free_id)(const char *generator, uint32 id);
203 // helpers to extract attribute by name.
204 // if <recursive> is true, parent nodes are scanned if
205 // attribute isn't found in current node; unless you declared
206 // the attribute yourself, use recursive search to handle
207 // intermittent nodes, e.g. defined by filter drivers, transparently.
208 // for raw and string attributes, you get a copy that must
209 // be freed by caller
210 status_t (*get_attr_uint8)(device_node_handle node,
211 const char *name, uint8 *value, bool recursive);
212 status_t (*get_attr_uint16)(device_node_handle node,
213 const char *name, uint16 *value, bool recursive);
214 status_t (*get_attr_uint32)(device_node_handle node,
215 const char *name, uint32 *value, bool recursive);
216 status_t (*get_attr_uint64)(device_node_handle node,
217 const char *name, uint64 *value, bool recursive);
218 status_t (*get_attr_string)(device_node_handle node,
219 const char *name, char **value, bool recursive);
220 status_t (*get_attr_raw)(device_node_handle node,
221 const char *name, void **data, size_t *_size,
224 // get next attribute of node;
225 // on call, *<attr_handle> must contain handle of an attribute;
226 // on return, *<attr_handle> is replaced by the next attribute or
227 // NULL if it was the last;
228 // to get the first attribute, <attr_handle> must point to NULL;
229 // the returned handle must be released by either passing it to
230 // another get_next_attr() call or by using release_attr()
232 status_t (*get_next_attr)(device_node_handle node,
233 device_attr_handle *attrHandle);
235 // release attribute handle <attr_handle> of <node>;
237 status_t (*release_attr)(device_node_handle node,
238 device_attr_handle attr_handle);
240 // retrieve attribute data with handle given;
241 // <attr> is only valid as long as you don't release <attr_handle>
242 // implicitely or explicitely
243 status_t (*retrieve_attr)(device_attr_handle attr_handle,
244 const device_attr **attr);
246 // change/add attribute <attr> of/to node
247 status_t (*write_attr)(device_node_handle node,
248 const device_attr *attr);
250 // remove attribute of node by name
251 // <name> is name of attribute
252 status_t (*remove_attr)(device_node_handle node, const char *name);
253 } device_manager_info;
255 // former pnp_driver.h
257 Copyright (c) 2003-04, Thomas Kurschel
259 Required interface of PnP drivers
261 In contrast to standard BeOS drivers, PnP drivers are normal modules
262 having the interface described below.
264 Every device is described by its driver via a PnP node with properties
265 described in PnP Node Attributes. Devices are organized in a hierarchy,
266 e.g. a devfs device is a hard disk device that is connected to a
267 controller, which is a PCI device, that is connected to a PCI bus.
268 Every device is connected to its lower-level device via a parent link
269 stored in its Node. The higher-level is called the consumer of the
270 lower-level device. If the lower-level device gets removed, all its
271 consumers are removed too.
273 In our example, the hierarchy is
275 devfs device -> hard disk -> controller -> PCI device -> PCI bus
277 If the PCI bus is removed, everything up to including the devfs device
280 The driver hierarchy is constructed bottom-up, i.e. the lower-level
281 driver searches for a corresponding consumer, which in turns searches
282 for its consumer and so on. The lowest driver is usually something like
283 a PCI bus, the highest driver is normally a devfs entry (see pnp_devfs.h).
284 Registration of devices and the search for appropriate consumers is
285 done via the pnp_manager (see pnp_manager.h).
287 When a potential consumer is found, it gets informed about the new
288 lower-level device and can either refuse its handling or accept it.
289 On accept, it has to create a new node with the lower-level device
292 Loading of drivers is done on demand, i.e. if the consumer wants to
293 access its lower-level device, it explicitely loads the corresponding
294 driver, and once it doesn't need it anymore, the lower-level driver
295 must be unloaded. Usually, this process happens recursively, i.e. in
296 our example, the hard disk driver loads the controller driver, which
297 loads the PCI device driver which loads the PCI bus driver. The same
298 process applies to unloading.
300 Because of this dynamic loading, drivers must store persistent data
301 in the node of their devices. Please be aware that you cannot modify
302 a node once published.
304 If a device gets removed, you must unregister its node. As said, the
305 PnP manager will automatically unregister all consumers too. The
306 corresponding drivers are notified to stop talking to their lower-level
307 devices and to terminate running requests. Normally, you want to use a
308 dedicated variable that is verified at each call to make sure that the
309 parent is still there. The notification is done independantly of the
310 driver being loaded by its consumer(s) or not. If it isn't loaded,
311 the notification callback gets NULL as the device cookie; normally, the
312 driver returns immediately in this case. As soon as both the device
313 is removed and the driver is unloaded, device_cleanup gets called to
314 free resources that couldn't be safely removed in device_removed when
315 the driver was still loaded.
317 If a device has exactly one consumer, they often interact in some way.
318 To simplify that, the consumer can pass a user-cookie to its parent
319 during load. In this case, it's up to the parent driver to get a
320 pointer to the interface of the consumer. Effectively, such consumers
321 have one interface for their consumers (base on pnp_driver_info), and
322 a another for their parents (with a completely driver-specific
325 In terms of synchronization, loading/unloading/remove-notifications
326 are executed synchronously, i.e. if e.g. a device is to be unloaded
327 but the drive currently handles a remove-notification, the unloading
328 is delayed until the nofication callback returns. If multiple consumers
329 load a driver, the driver gets initialized only once; subsequent load
330 requests increase an internal load count only and return immediately.
331 In turn, unloading only happens once the load count reaches zero.
334 struct driver_module_info {
337 float (*supports_device)(device_node_handle parent, bool *_noConnection);
338 // check whether this parent is supported
340 status_t (*register_device)(device_node_handle parent);
341 // Register your device node.
343 status_t (*init_driver)(device_node_handle node, void *user_cookie, void **_cookie);
345 // node - node of device
346 // user_cookie - cookie passed by loading driver
347 // cookie - cookie issued by this driver
349 status_t (*uninit_driver)(void *cookie);
350 // driver gets unloaded.
352 void (*device_removed)(device_node_handle node, void *cookie);
353 // a device node, registered by this driver, got removed.
354 // if the driver wasn't loaded when this happenes, no (un)init_device
355 // is called and thus <cookie> is NULL;
357 void (*device_cleanup)(device_node_handle node);
358 // a device node, registered by this driver, got removed and
359 // the driver got unloaded
361 void (*get_supported_paths)(const char ***_busses, const char ***_devices);
366 Copyright (c) 2003-04, Thomas Kurschel
368 Required interface of PnP bus drivers
370 Busses consist of two node layers: the lower layer defines the bus,
371 the upper layer defines the abstract devices connected to the bus.
372 Both layers are handled by a bus manager. Actual device nodes are
373 on top of abstract device nodes.
375 E.g. if we have a PCI bus with an IDE controller on it, we get
377 IDE controller -> PCI device -> PCI bus
380 IDE controller = actual device node
381 PCI device = abstract device node
384 The PCI bus manager establishes both the PCI devices and the PCI busses.
386 Abstract device nodes act as a gateway between actual device nodes
387 and the corresponding bus node. They are constructed by the bus
388 node driver via its rescan() hook. To identify a bus node, define
389 PNP_BUS_IS_BUS as an attribute of it. As a result, the PnP manager
390 will call the rescan() method of the bus driver whenever the
391 bus is to be rescanned. Afterwards, all possible dynamic consumers
392 are informed as done for normal nodes.
394 Normally, potential device drivers are notified immediately when
395 rescan() registers a new abstract device node. But sometimes, device
396 drivers need to know _all_ devices connected to the bus for correct
397 detection. To ensure this, the bus node must define
398 PNP_BUS_NOTIFY_CONSUMERS_AFTER_RESCAN. In this case, scanning for
399 consumers is postponed until rescan() has finished.
401 If hot-plugging of devices can be detected automatically (e.g. USB),
402 you should define PNP_DRIVER_ALWAYS_LOADED, so the bus driver is
403 always loaded and thus capable of handling hot-plug events generated
404 by the bus controller hardware.