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