From 0d7f2390a4d13279ef8de31dd68405f8464e3b62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Mon, 3 May 2004 09:26:12 +0000 Subject: [PATCH] The main header for the device_manager - work in progress. git-svn-id: file:///srv/svn/repos/haiku/trunk/current@7362 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/drivers/device_manager.h | 360 ++++++++++++++++++++++++++++ 1 file changed, 360 insertions(+) create mode 100644 headers/os/drivers/device_manager.h diff --git a/headers/os/drivers/device_manager.h b/headers/os/drivers/device_manager.h new file mode 100644 index 0000000000..be24af7568 --- /dev/null +++ b/headers/os/drivers/device_manager.h @@ -0,0 +1,360 @@ +/* + Copyright (c) 2003-04, Thomas Kurschel + + PnP manager; Takes care of registration and loading of PnP drivers + + Read pnp_driver.h first to understand the basic idea behind PnP drivers. + + To register a driver node, use register_driver. If the device got lost, + use unregister_driver (note: if the parent node is removed, your node + get removed automatically as your driver has obviously nothing to work + with anymore). To get access to a (parent) device, use load_driver/ + unload_driver. + + To let the manager find a consumer (see pnp_driver.h), you can either + specify its name directly during registration, using a + PNP_DRIVER_FIXED_CONSUMER attribute, or let the manager search the + appropriate consumer(s) via a PNP_DRIVER_DYNAMIC_CONSUMER attribute. + + Searching of dynamic consumers is done as follows: + + - First, the manager searches for a Specific driver in the base + directory (see below) + - If no Specific driver is found, all Generic drivers stored under + "generic" sub-directory are informed in turn until one returns success + - Finally, _all_ Universal drivers, stored in the "universal" sub- + directory, are informed + + Specification of the base directory and of the names of Specific + drivers is done via a file name pattern given by a + PNP_DRIVER_DYNAMIC_CONSUMER attribute. + + First, all substrings of the form "%attribute_name%" are replaced by the + content of the attribute "attribute_name" as follows: + + - if the attribute contains an integer value, its content is converted to hex + (lowercase) with a fixed length according to the attribute's value range + - the content of string attributes is quoted by " and invalid characters + (i.e. /%" and all characters outside 32..126) are replaced by their + unsigned decimal value, delimited by % + - other attribute types cannot be used + + Second, the resulting name is split into chunks according to the presence + of | characters (you can escape % and | with a ^ character). These + characters are only delimiters and get removed before further processing. + The directory before the first | character is the base directory (see + above). It contains the "generic" and the "universal" subdirectories. + The names of the specific drivers are created by first taking the entire + file name, then by removing the last chunk, then by removing the last + two chunks and so on until only the first chunk is left. + + As drivers can contain multiple modules, the module name is constructed + by appending the content of the PNP_DRIVER_TYPE attribute to the driver's file + name, seperated by a slash character (note: this only applies to dynamic + consumers; for fixed consumers, you specify the module name directly via + PNP_DRIVER_FIXED_CONSUMER). + + E.g. given a dynamic consumer pattern of + "pci/vendor=%vendor_id%|, device=%device_id%" for a device with the + attributes vendor_id=0x123 and device_id=0xabcd (both being uint16), the + PnP manager tries the specific drivers "pci/vendor=0123, device=abcd" and + (if the first one fails/doesn't exist) "pci/vendor=0123". If they both + refuse to handle the device, all drivers under "pci/generic" are tried + until one accepts the device. Finally, all drivers under "pci/universal" + are loaded, whatever happened before. + + In practise, you should try to use specific drivers as much as possible. + If detection based on device IDs is impossible (e.g. because the bus + doesn't support them at all), you can put the driver under "generic". + Generic drivers can also be used to specify wrappers that try to load old- + style drivers if no new driver can be found. Also, they can be used to + report an error or invoke an user program that tries downloading a + proper Specific driver. Universal drivers are mainly used for + informational purposes, e.g. to publish data about each found device, + or to provide raw access to all devices. + + If the device uses physical address space or I/O space or ISA DMA + channels (called I/O resources), the driver has to acquire these + resources. During hardware detection (usually via probe()), + acquire_io_resources() must be called to get exclusive access. + If no hardware could be found, they must be released via + release_io_resources(). If detection was successful, the list of + the (acquired) resources must be passed to register_device(). + Resources can either belong to one hardware detection or to a device. + If a hardware detection collides with another, it has to wait; + if it collides with a device whose driver is not loaded, the + driver loading is blocked. When detection fails, i.e. if + release_io_resources() is called, all blocked drivers can be loaded + again. If the detection fails, i.e. the resources are transferred + via register_device(), all blocked devices are unregistered and + pending load requests aborted. If a hardware detection collides + with a device whose driver is loaded, acquire_io_resources() fails + with B_BUSY. As this makes a hardware rescan impossible if the + driver is loaded, you should define PNP_DRIVER_NO_LIVE_RESCAN + for nodes that use I/O resources (see below). + + To search for new drivers for a given device node, use rescan(). This + marks all consumer devices as being verified and calls probe() + of all consumers drivers (see above) to let them rescan the parent + for devices. The parameter determines the nesting level, e.g. + 2 means that first the consumers are scanned and then the consumers + of the consumers. + + Normally, all devices can be rescanned. If a driver cannot handle + a rescan safely when it is loaded (i.e. used by a consumer), it + must set PNP_DRIVER_NO_LIVE_RESCAN, in which case the device is + ignored during rescan if the driver is loaded and attempts + to load the driver during a rescan are blocked until the rescan + is finished. If rescanning a device is not possible at all, it must + have set PNP_DRIVER_NEVER_RESCAN to always ignore it. + + To distinguish between new devices, lost devices and redetected + devices, consumer devices should provide a connection code and a + device identifier. They are specified by PNP_DRIVER_CONNECTION and + PNP_DRIVER_CONNECTION respectively, and are expanded in the same way + as PNP_DRIVER_DYNAMIC_CONSUMER. It is assumed that there can be only + one device per connection and that a device can be uniquely identify + by a device identifier. If a consumer device is registered on the + same connection as an existing device but with a different device + identifier, the old device gets unregistered automatically. If both + connection and device identifier are the same, registration is + handled as a redetection and ignored (unless a different type or + driver module is specified - in this case, the device is replaced). + Devices that were not redetected during a rescan get unregistered + unless they were ignored (see above). +*/ + +#ifndef _DEVICE_MANAGER_H +#define _DEVICE_MANAGER_H + +#include +#include + + +// type of I/O resource +enum { + IO_MEM = 1, + IO_PORT = 2, + ISA_DMA_CHANNEL = 3 +}; + + +// I/O resource description +typedef struct { + uint32 type; + // type of I/O resource + + uint32 base; + // I/O memory: first physical address (32 bit) + // I/O port: first port address (16 bit) + // ISA DMA channel: channel number (0-7) + + uint32 len; + // I/O memory: size of address range (32 bit) + // I/O port: size of port range (16 bit) + // ISA DMA channel: must be 1 +} io_resource; + + +// handle of acquired I/O resource +typedef struct io_resource_info *io_resource_handle; + +// handle of node attribute +typedef struct pnp_node_attr_info *pnp_node_attr_handle; + + +// interface of PnP manager +typedef struct device_manager_info { + module_info minfo; + + // load driver + // node - node whos driver is to be loaded + // user_cookie - cookie to be passed to init_device of driver + // interface - interface of loaded driver + // cookie - device cookie issued by loaded driver + status_t (*load_driver) ( + pnp_node_handle node, + void *user_cookie, + pnp_driver_info **interface, + void **cookie + ); + // unload driver + status_t (*unload_driver) ( + pnp_node_handle node + ); + + // rescan node for new dynamic drivers + // node - node whose dynamic drivers are to be scanned + // depth - recursive depth (>= 1) + status_t (*rescan) ( + pnp_node_handle node, + uint depth + ); + + // register device + // parent - parent node + // attributes - NULL-terminated array of node attributes + // io_resources - NULL-terminated array of I/O resources (can be NULL) + // node - new node handle + // on return, io_resources are invalid: on success I/O resources belong + // to node, on fail they are released; + // if device is already registered, B_OK is returned but *node is NULL + status_t (*register_device) ( + pnp_node_handle parent, + const pnp_node_attr *attrs, + const io_resource_handle *io_resources, + pnp_node_handle *node + ); + // unregister device + // all nodes having this node as their parent are unregistered too. + // if the node contains PNP_MANAGER_ID_GENERATOR/PNP_MANAGER_AUTO_ID + // pairs, the id specified this way is freed too + status_t (*unregister_device) ( + pnp_node_handle node + ); + + // acquire I/O resources + // resources - NULL-terminated array of resources to acquire + // handles - NULL-terminated array of handles (one per resource); + // array must be provided by caller + // return B_BUSY if a resource is used by a loaded driver + status_t (*acquire_io_resources) ( + io_resource *resources, + io_resource_handle *handles + ); + // release I/O resources + // handles - NULL-terminated array of handles + status_t (*release_io_resources) ( + const io_resource_handle *handles + ); + + // find device by node content + // the given attributes must _uniquely_ identify a device node; + // parent - parent node (-1 for don't-care) + // attrs - list of attributes (can be NULL) + // return: NULL if no device or multiple(!) devices found + pnp_node_handle (*find_device) ( + pnp_node_handle parent, + const pnp_node_attr *attrs + ); + + // create unique id + // generator - name of id set + // if result >= 0 - unique id + // result < 0 - error code + int32 (*create_id)( + const char *generator + ); + // free unique id + status_t (*free_id)( + const char *generator, + uint32 id + ); + + // get parent device node + pnp_node_handle (*get_parent)( + pnp_node_handle node + ); + + // helpers to extract attribute by name. + // if is true, parent nodes are scanned if + // attribute isn't found in current node; unless you declared + // the attribute yourself, use recursive search to handle + // intermittent nodes, e.g. defined by filter drivers, transparently. + // for raw and string attributes, you get a copy that must + // be freed by caller + status_t (*get_attr_uint8)( + pnp_node_handle node, + const char *name, + uint8 *value, + bool recursive + ); + status_t (*get_attr_uint16)( + pnp_node_handle node, + const char *name, + uint16 *value, + bool recursive + ); + status_t (*get_attr_uint32)( + pnp_node_handle node, + const char *name, + uint32 *value, + bool recursive + ); + status_t (*get_attr_uint64)( + pnp_node_handle node, + const char *name, + uint64 *value, + bool recursive + ); + status_t (*get_attr_string)( + pnp_node_handle node, + const char *name, + char **value, + bool recursive + ); + status_t (*get_attr_raw)( + pnp_node_handle node, + const char *name, + void **data, + size_t *len, + bool recursive + ); + + // get next attribute of node; + // on call, * must contain handle of an attribute; + // on return, * is replaced by the next attribute or + // NULL if it was the last; + // to get the first attribute, must point to NULL; + // the returned handle must be released by either passing it to + // another get_next_attr() call or by using release_attr() + // directly + status_t (*get_next_attr)( + pnp_node_handle node, + pnp_node_attr_handle *attr_handle + ); + + // release attribute handle of ; + // see get_next_attr + status_t (*release_attr)( + pnp_node_handle node, + pnp_node_attr_handle attr_handle + ); + + // retrieve attribute data with handle given; + // is only valid as long as you don't release + // implicitely or explicitely + status_t (*retrieve_attr)( + pnp_node_attr_handle attr_handle, + const pnp_node_attr **attr + ); + + // change/add attribute of/to node + status_t (*write_attr)( + pnp_node_handle node, + const pnp_node_attr *attr + ); + + // remove attribute of node by name + // is name of attribute + status_t (*remove_attr)( + pnp_node_handle node, + const char *name + ); +} device_manager_info; + + +// standard attributes: + +// if you are using an id generator (see create_id), you can let the +// manager automatically free the id when the node is deleted by setting +// the following attributes: +// name of generator (string) +#define PNP_MANAGER_ID_GENERATOR "id_generator" +// generated id (uint32) +#define PNP_MANAGER_AUTO_ID "auto_id" + +// modulename of PnP manager +#define DEVICE_MANAGER_MODULE_NAME "sys/device_manager/v1" + +#endif /* _DEVICE_MANAGER_H */