drv_unload is called by the driver registry module (more precisely, by the svDriverUnregister routine) when an application wishes to unload the driver component from the system. The drv_unload routine is called in the context of the DKI thread.
This makes it possible to invoke directly the bus/nexus and DKI services allowed in the DKI thread context only. The purpose of drv_unload is to check that the driver component is not currently in use. On success, drv_unload returns K_OK , otherwise K_EBUSY is returned.
The drv_unload routine is optional. If drv_unload is not provided, the driver code cannot be unloaded. drv_unload is a global, per driver component routine. Therefore, to implement unloading, the driver should handle a list of driver instances. When drv_unload is called, the driver should go through the list, and for each driver instance, check whether the driver instance is currently in use.
Once the check is positive (a given instance is not used), the driver instance must become invisible for potential clients. In other words, if drv_unload returns K_OK , all previously created driver instances (if any) must be deleted and all previously allocated system resources (if any) must be released.
If drv_unload returns K_EBUSY, the driver component will not be unloaded. In this case, the driver component state must not be changed by drv_unload.
The drv_unload routine of a bus/nexus driver typically takes the following actions:
Checks that the driver component is not in use.drv_unload iterates through the driver instances list and, for each driver instance, checks whether a connection is opened to the driver instance.
Once a driver instance with an open connection is found, the iteration is aborted and K_EBUSY is returned. Otherwise, drv_unload proceeds to step 2.
Releases resources associated to the driver component.drv_unload iterates through the driver instances list and, for each driver instance, releases all system resources associated to the instance ( io_unmap , mem_unmap , ...) and, finally, closes the connection to the parent bus. Once the iteration is finished, drv_unload returns K_OK.
Note that drv_unload runs in the DKI thread context.
This guarantees stability of the driver instances and open connections during the drv_unload execution. Indeed, a new driver instance may be created only by the drv_init routine and a new parent-to-child connection may be opened only by the drv_init or drv_probe routines.
Both drv_init and drv_probe are invoked in the DKI thread context. Thus, drv_init and drv_probe are serialized with drv_unload by the DKI thread.
On the other hand, if a bus/nexus driver supports hot-pluggable devices, it is up to the bus/nexus driver to implement a synchronization mechanism with a hot-plug insertion interrupt which may occur during the driver unloading.
In the following example, the W83C553_DRV_UNLOAD compilation flag is used to allow downsizing of the driver component, at compile time, if the unload mechanism is not needed.
/* * Unload the W83C553 driver. * This routine is called by the driver registry when an application * wishes to unload the driver component. */ static KnError drv_unload () { /* * The driver unloading is an optional feature. * In case when such a feature is not supported, drv_unload() * just returns K_EBUSY preventing the driver component to be * unloaded. */ #if defined(W83C553_DRV_UNLOAD) W83c553Data* udev; /* * Go through the driver instances list and check if it is unused * i.e. if the list of connected devices is empty. */ udev = w83c553Devs; while (udev && (udev->dev == NULL)) { udev = udev->next; } /* * If all driver instances are unused, we invoke shutdown() * to shutdown each instance. */ if (!udev) { while (w83c553Devs) { shutdown(w83c553Devs); } return K_OK; } /* * If there is a driver instance in use, we cannot unload the * driver, and return K_EBUSY. */ #endif return K_EBUSY; }