NAME | SYNOPSIS | API RESTRICTIONS | FEATURES | DESCRIPTION | EXTENDED DESCRIPTION | Allowed Calling Contexts | ATTRIBUTES | SEE ALSO
#include <dki/dki.h>KnError svDriverRegister(DrvRegEntry * drv_entry);
The function or functions documented here may not be used safely in all application contexts with all APIs provided in the ChorusOS 5.0 product.
See API(5FEA) for details.
DKI
The driver registry module implements a database of drivers which have registered within the system. The driver registry database is populated by drivers that 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.
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;
Points to a string specifying the driver name. For example, the driver file name.
Points to a string specifying additional 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.
If a bus/nexus driver provides an API version that is less than bus_version , the corresponding driver component will not be called by this type of bus/nexus driver. Thus, the drv_probe and drv_init routines will not 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 asked 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.
A bus driver may provide multiple API's. An 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 provides a subset of the services provided by PciBusOps . This type of bus driver is able to support drivers that use either common ( bus() ) or PCI ( pci() ) parent bus interfaces. When the bus driver invokes a child driver, it points to either the BusOps or PciBusOps structure, depending on the bus_class specified in the child driver registry entry.
A PROP_DRIVER may be adaptive to the parent bus API , that is, able to run on top of a number of different buses (for example, pci() and isa() ). 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 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 (using the bus_class field) on top of which the driver may run. To determine the bus class to which 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: dev_node , bus_ops , and bus_id .
The dev_node argument specifies the parent device node.
The bus_ops and bus_id arguments together specify 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 parent bus driver to perform a driver-to-device binding. The driver examines properties attached to the device node to determine the type of device at the node and to check if the device can be serviced by the driver. If the check is positive, the parent bus 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. Using the PROP_DRIVER property, the child driver is identified to the parent bus driver, asking it to invoke the drv_init routine on that device.
If a driver property is already present in the device node, then the drv_bind routine cannot continue. This is to avoid overriding an 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. The 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_init routine creates an instance of the driver servicing the given device, performs a device hardware initialization, and registers the driver instance in the device registry.
The drv_init routine 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 and bus_id arguments together specify 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.
The drv_init structure reads 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 . An example of a probe-only driver is a self-identifying bus enumerator (for example, a PCI enumerator) that 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 does not have the drv_init routine.
The drv_unload routine is called by the svDriverUnregister() routine to unload the driver code from the system. The drv_unload routine checks that the d evice driver code is not in use. Thus, 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. When drv_unload is not provided by the driver, the drv_unload field must be set to NULL . In such a 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 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() .
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() .
If a given driver entry is registered by a built-in driver, a NULL pointer is returned. The driver actor capability works only for dynamically loaded drivers. The actor capability may be used by an application to delete the driver actor after the driver entry is unregistered.
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 result K_EBUSY means that either the driver entry is locked in the driver registry (that is, a static driver routine is 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 being used by a driver client).
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 | API RESTRICTIONS | FEATURES | DESCRIPTION | EXTENDED DESCRIPTION | Allowed Calling Contexts | ATTRIBUTES | SEE ALSO