ChorusOS 4.0 Device Driver Framework Guide

Write Unload Function

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 theyell0w 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 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 instance, 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. The NS16_DRV_UNLOAD compilation flag is used to allow downsizing of the driver component, at compile time, in case the driver unload mechanism is not needed.

    /*
     * 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 ()
{
        /*
         * The driver unloading is an optional feature.
         * In case when such a feature is not supported, ns16_unload()
         * just returns K_EBUSY preventing the driver component to be
         * unloaded.
         */
#if defined(NS16_DRV_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
         * shutdown it. 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;
    }
#endif

    return K_EBUSY;
}