ChorusOS 5.0 Board Support Package Developer's Guide

Write the Unload Routine

The drv_unload() routine 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 yellow DKI thread. This makes it possible to directly invoke the bus/nexus and DKI services allowed in the DKI thread context.

The purpose of drv_unload() is to check that the driver component is not currently in use. For drv_unload() to succeed, the driver clients must have closed their connections with the driver and released the device registry lock (svDeviceRelease). On success, drv_unload() returns K_OK, otherwise K_EBUSY is returned.

The drv_unload() routine is optional. In cases when drv_unload() is not provided, the driver code cannot be unloaded.

The drv_unload() routine 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, should check whether the driver instance is currently in use.


Note -

Once the check is positive, (a given instance is not used), the driver instance must become invisible to 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(). For example, all registered driver instances must be in place.

Consider the driver unloading implementation for a driver using the standard client-to-driver binding mechanism based on the device registry. In cases where another client-to-driver binding mechanism is used, the driver unloading implementation is binding mechanism dependent.

The drv_unload() routine of a (leaf) device driver typically takes the following actions:

  1. Checks that the driver component is not in use.drv_unload() iterates through the driver instances list and, for each driver instance, invokes svDeviceUnregister to remove the driver instance entry from the registry.

    Once svDeviceUnregister fails (returns K_EBUSY ), the iteration is aborted and drv_unload() proceeds to step 3. Otherwise (if all device instances are successfully unregistered), drv_unload() proceeds to step 2.

  2. Releases resources associated to the driver component.drv_unload() iterates through the driver instances list and, for each driver instance, releases 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.

  3. Restores the initial state of the driver component.drv_unload() iterates through the driver instances list and, for each driver instance which has been unregistered at step 1, invokes svDeviceRegister to register the driver instance again. Once the iteration is finished, drv_unload() returns K_EBUSY.

Note that drv_unload() runs in the DKI thread context. This guarantees the stability of driver instances during the drv_unload() execution. In fact, a new driver instance may be created only by the drv_init() routine, which is also invoked in the DKI thread context. In this way, drv_init() is serialized with drv_unload() by the DKI thread.

The following example shows the unload function of the NS16x50 compatible UART device driver.

    /*
     * Unload the NS16x50 uart driver.
     * This routine is called by the driver registry when an application
     * wishes to unload the NS16550 driver component.
     */
    static KnError
ns16_unload ()
{
    Ns16_Device*  dev;
    Ns16_Device*  udev;
        /*
         * Go through the driver instances list and try to unregister
         * all instances. Note that the device registry entry becomes
         * invalid if svDeviceUnregister() returns K_OK. The iteration
         * is aborted if svDeviceUnregister() fails.
         */
    udev = ns16_devs;
    while (udev && (svDeviceUnregister(udev->regId) == K_OK)) {
        udev = udev->next;      
    }
        /*
         * If all driver instances are unregistered successfully,
         * we invoke ns16_shutdown() for each instance in order to
         * shut it down. Note that some shutdown events may be signaled
         * by the parent bus driver after the device entry has been 
         * unregistered. In such a case, these events will be ignored. 
         * Indeed, once unregistered, the device registry entry becomes
         * invalid.For invalid device entries, the device registry defers 
         * the events processing until svDeviceRegister(). But, the entries 
         * will be released (svDeviceFree) by ns16_shutdown() rather than 
         * registered again.       
         */
    if (!udev) {
        while (ns16_devs) {
            ns16_shutdown(ns16_devs);       
        }
        return K_OK;
    }
        /*
         * If there is a driver instance in use (i.e. svDeviceUnregister()
         * failed) , the driver component cannot be unloaded. 
         * We must register again the driver instances unregistered above.
         * Note that shutdown events may be signaled by the parent 
         * bus driver after the device entry has been unregistered.
         * In such a case, these events will be processed at this moment.
         * Indeed, once unregistered, the device registry entry becomes
         * invalid. For invalid device entries, the device registry defers
         * the events processing until svDeviceRegister().
         */
    dev = ns16_devs;
    while (dev != udev) {
        svDeviceRegister(dev->regId);
        dev = dev->next;
    }

    return K_EBUSY;
}