NAME | SYNOPSIS | FEATURES | DESCRIPTION | EXTENDED DESCRIPTION | Allowed Calling Contexts | ATTRIBUTES | SEE ALSO
#include <dki/dki.h>KnError svDriverRegister(DrvRegEntry * drv_entry);
typedef struct { char* drv_name; char* drv_info; char* bus_class; int bus_version; void (*drv_probe) (DevNode bus_node, void* bus_ops, void* bus_id); void (*drv_bind) (DevNode bus_node); void (*drv_init) (DevNode dev_node, void* bus_ops, void* bus_id); KnError (*drv_unload) (); } DrvRegEntry;
DKI
The driver registry module implements a data base of drivers which have registered within the system. The driver registry data base is populated by drivers which perform self-registration (using svDriverRegister ) at driver initialization time.
svDriverRegister adds the driver entry to the driver registry. It returns K_OK in case of success, otherwise K_ENOMEM is returned to indicate that the system is out of memory. The drv_entry argument points to the DrvRegEntry structure specifying driver properties and static driver routines. The DrvRegEntry structure is described below.
Points to a string specifying the driver name. For example, the driver file name.
Points to a string specifying extra information about the driver component, such as version or author.
Points to a string specifying the class of the parent driver API required for the driver, such as "pci".
Specifies the minimum version of the parent driver API required for the driver. Note that if a bus/nexus driver provides an API version which is less than bus_version , the corresponding driver component will never be called by this type of bus/nexus driver. In other words, the drv_probe and drv_init routines will never be invoked by this type of bus/nexus driver.
Points to a static driver routine which performs the device enumeration/probing on the bus.
Points to a static driver routine which performs the driver-to-device binding.
Points to a static driver routine which clones an instance of the driver for the given device.
Points to a static driver routine which is invoked by the driver registry module when somebody wishes to unload the driver code from the system.
The bus_class and bus_version fields specify a parent bus/nexus API required for the driver. This type of API is provided to the driver as a structure of indirect functions implementing the API service routines. For instance, the "pci" bus API is specified by the PciBusOps structure, the "isa" bus API is specified by IsaBusOps . When a bus driver invokes the drv_probe or drv_init driver's routine, it provides a pointer to the structure of the bus service routines. The structure type corresponds to the bus_class field value.
Note that a bus driver may provide multiple API's. A typical example is a PCI bus driver providing the common and PCI bus APIs. The common bus driver API is named by "bus" and specified by the BusOps structure. The PCI bus driver API is named by "pci" and specified by the PciBusOps structure. BusOps actually, provides a subset of services provided by PciBusOps . This type of bus driver is able to support drivers which use either common ( "bus" ) or PCI ( "pci" ) parent bus interfaces. When the bus driver invokes a child driver, it gives a pointer to either the BusOps or PciBusOps structure depending on the bus_class specified in the child driver registry entry.
Note also that a PROP_DRIVER may be adaptive to the parent bus API. In other words, such a driver is able to run on top of a number of different buses (for example, "pci" and "isa" ). Typically, this type of driver is composed of two parts: bus class specific and bus class independent.
The bus class specific part of the driver code mainly deals with the device probing and initialization. In addition, it provides an abstraction layer in order to hide the bus class dependencies from the bus class independent part of the driver code. This kind of multi-bus driver should be registered multiple times in the driver registry. Each entry specifies a given bus class API (via the bus_class field) on top of which the driver may run. In order to determine to which bus class the driver is applied, the drv_probe , drv_bind and drv_init routines have to be entry specific (that is, bus class API specific). Under these conditions, when a given driver's routine is invoked by a bus driver, the driver detects the bus class to which it is applied and casts the bus_ops argument to the appropriate structure (for example, PciBusOps ).
The drv_probe routine is invoked by a bus/nexus driver when the bus_class specified in the registry entry matches the bus/nexus driver class. drv_probe is called with three arguments.
The dev_node argument specifies the parent device node.
The bus_ops / bus_id pair specifies the parent device driver.
bus_ops points to a structure of service routines implementing a bus driver API. This structure is bus class specific and corresponds to the bus_class specified by the driver registry entry.
bus_id is opaque to the driver. It must be passed back to the bus driver when the open bus service routine is invoked. The drv_probe routine is optional. In cases where the drv_probe routine is not provided by the driver, the drv_probe field must be set to NULL .
The drv_bind routine is invoked by a bus/nexus driver when the bus_class specified in the registry entry matches the bus/nexus driver class.
drv_bind is called with one argument, dev_node , which specifies a given device node. The drv_bind routine enables the driver to perform a driver-to-device binding. Typically, the driver examines properties attached to the device node in order to determine the type of device at the node and to check whether the device may be serviced by the driver. If the check is positive, the driver binds the driver to the device node by attaching a PROP_DRIVER property to the device node. The property value specifies the driver name. The parent bus driver uses such a property to determine the name of the driver servicing the device. In other words, via the PROP_DRIVER property, the child driver gives its name to the parent bus driver, asking it to invoke the drv_init routine on that device. Note that, if a "driver" property is already present in the device node, then the drv_bind routine can not continue; drv_bind should not override existing driver-to-device binding.
The drv_bind routine is optional. If the drv_bind routine is not provided by the driver, the drv_bind field must be set to NULL.
The drv_init routine is invoked by a bus/nexus driver when the bus_class specified in the registry entry matches the bus/nexus driver class and a given driver is bound to a given device node.
drv_init is called with three arguments. The dev_node argument specifies the device node for which a device driver instance should be created. The bus_ops / bus_id pair specifies the parent device driver. bus_ops points to a structure of service routines implementing a bus driver API.
This structure is bus class specific and corresponds to the bus_class specified by the driver registry entry. bus_id is opaque to the driver. It must be passed back to the bus driver when the open bus service routine is invoked. The purpose of drv_init is to create an instance of the driver servicing the given device, to perform a device hardware initialization and to register the driver instance in the device registry .
Typically, drv_init would read the device and bus node properties in order to obtain the assigned bus resources and tunable parameters related to the bus/device. The drv_init routine is optional. In a case when the drv_init routine is not provided by the driver, the drv_init field must be set to NULL. A typical example of a probe-only driver is a self-identifying bus enumerator (for example, a PCI enumerator) which is implemented as driver. This type of driver has the drv_probe routine which enumerates devices residing on the bus and creates device nodes. This type of driver obviously does not have the drv_init routine.
drv_unload is called by the driver registry module (more exactly by the svDriverUnregister routine) when somebody wishes to unload the driver code from the system. The purpose of drv_unload is to check that the device driver code is not currently being used. The driver must check, for each driver instance, whether it is locked in the device registry.
In case of success, all device instances are removed from the device registry and K_OK is returned. Otherwise, the device entries are unchanged in the device registry and K_EBUSY is returned.
The drv_unload routine is optional. In cases when drv_unload is not provided by the driver, the drv_unload field must be set to NULL . Note that, in this case, the driver code cannot be unloaded.
svDriverLookupFirst returns the first driver entry in the registry. When the registry is not empty a non zero DrvRegId (designating the entry) is returned, otherwise NULL is returned. In case of success, the driver entry is locked in the registry. It should be unlocked by a subsequent invocation of svDriverRelease or svDriverUnregister .
The driver entry lock is not exclusive. It is simply a counter which prevents the driver component from being unloaded when it is still being used by a bus/nexus driver for probing or initialization.
svDriverLookupNext returns the next driver entry in the registry. The current entry is specified by the drv_id argument. The current entry must be locked by a previously called svDriverLookupFirst or svDriverLookupNext . If the current entry is not the last one in the registry a non zero DrvRegId (designating the entry) is returned, otherwise NULL is returned. In case of success, the next driver entry is locked in the registry. It should be unlocked by a subsequent invocation of svDriverRelease or svDriverUnregister .
svDriverRelease releases the lock of the driver entry specified by the drv_id argument.
svDriverEntry returns a pointer to the driver entry structure specified by the drv_id argument. The device entry being accessed must have been previously locked using svDriverLookupFirst or svDriverLookupNext . Note that the device entry structure is read-only.
svDriverCap returns a pointer to the driver actor capability. The driver entry is specified by the drv_id argument. The driver entry being accessed must have been previously locked using svDriverLookupFirst or svDriverLookupNext . Note that if a given driver entry is registered by a built-in driver, a NULL pointer is returned. In other words, the driver actor capability makes sense only for dynamically loaded drivers. The actor capability may be used by an application in order to delete the driver actor once the driver entry is unregistered. Note that the driver capability structure is read-only.
svDriverUnregister tries to remove the driver entry specified by the dev_id argument from the driver registry. The device entry being removed must have been previously locked using svDriverLookupFirst or svDriverLookupNext .
In case of success, K_OK is returned, otherwise K_EBUSY is returned. The K_EBUSY result means that either the driver entry is locked in the driver registry (that is, a static driver routine is currently being used by a bus/nexus driver) or an instance of the device driver is locked in the device registry (that is, there is a driver instance which is currently being used by a driver client). Note that when K_EBUSY is returned, the driver entry remains locked in the registry and should be unlocked explicitly by svDriverRelease .
The following table specifies the contexts in which a caller is allowed to invoke each service.
Services | Base level | DKI thread | Interrupt | Blocking |
svDriverRegister | + | + | - | + |
svDriverLookupFirst | + | + | - | + |
svDriverLookupNext | + | + | - | + |
svDriverRelease | + | + | - | + |
svDriverEntry | + | + | - | - |
svDriverCap | + | + | - | - |
svDriverUnregister | + | + | - | + |
See attributes(5) for descriptions of the following attributes:
ATTRIBUTE TYPE | ATTRIBUTE VALUE |
---|---|
Interface Stability | Evolving |
NAME | SYNOPSIS | FEATURES | DESCRIPTION | EXTENDED DESCRIPTION | Allowed Calling Contexts | ATTRIBUTES | SEE ALSO