ChorusOS 5.0 Board Support Package Developer's Guide

Write Load Handler Function

The load handler function resides in the bus driver, and is invoked by the parent bus/nexus driver when a new driver appears in the system (as when a new driver is downloaded at run time). The load handler address is given to the bus/nexus driver when a connection is established between the child driver and its parent bus/nexus driver.


Note -

The load handler is optional. Load handler functions are usually used by a bus-to-bus bridge which needs to apply a newly downloaded driver to its child devices.


The actions taken by the load handler are essentially the same as those in the initialization process, even though the bus/nexus device is already initialized:

  1. child device node creation (enumeration/probing)

  2. resource allocation for the newly created child nodes

  3. driver-to-device binding

  4. driver instance creation for non-active child device nodes

  5. child load handler invocation

Firstly, the bus/nexus driver invokes the probe routines registered in the driver registry matching the bus/nexus class. The probing loop example given in "Write the Probe Function" may be used as-is within the load handler. Note that the probe routines already invoked at initalization time will probably be invoked again.

Note that (as described in the "Write the Probe Function" section) a probe routine must be aware of existing device nodes to avoid the creation of redundant nodes. In addition, a probe routine must explicitly ask for bus resources (being used for probing) to avoid conflicts with bus resources currently in use.

In this way, the active device nodes and associated running driver instances are protected against any disturbance caused by run-time probing. The probing process may create new child device nodes because a new probe routine (implemented by a newly downloaded driver) may be executed and, as a consequence, it may discover a device previously unknown in the system.

For this reason, the bus/nexus driver has to check/allocate the bus resources required for these device nodes. Note that to satisfy this run-time resource request, the bus/nexus driver may need to confiscate resources already assigned to existing device nodes.

The bus/nexus driver is not allowed to confiscate resources in use (resources assigned to active device nodes). Driver instances associated with an active node must be shutdown by the bus/nexus driver before they can be re-allocated. To shut down a driver instance, the bus/nexus driver sends a shutdown event to the child driver, requesting closure of the child-to-parent driver connection (by invoking close).

Once the connection is closed, the resources are freed (and may be re-allocated). The bus/nexus driver should start the driver instance again, invoking the driver drv_init() routine.

Once the bus resource allocation is done, the bus/nexus driver calls the drv_bind() routines registered in the driver registry for each inactive device node (as explained in the "Write the Bind Function" section).

Once the driver-to-device binding is done, the bus/nexus driver iterates through the child nodes and, for each inactive device node, determines the driver component to be applied to the given device. Once a driver component is found, the bus/nexus driver calls the driver drv_init() routine (see the "Write the Init Function" section).

Finally, the bus/nexus driver invokes the child load handlers (if any) to propagate the loading process downstream (from parent to child). In this way, the loading process is recursively continued by the child driver load handler. The load handler is called in the context of DKI thread. This means that it can call all services, without worrying about synchronization, even those DKI services which can only be called in the DKI thread.

The following example shows the load handler of the PCI-to-ISA bridge driver.

    /*
     * The load handler is invoked by the parent driver (i.e. PCI bus) 
     * when a new driver has been registered in the system (e.g. a
     * loadable driver has been downloaded).
     */ 
    static void
pciLoadHandler (void* cookie)
{
    W83c553Data* w83c553 = (W83c553Data*)cookie;
    IsaDev*      isaDev;
        /*
         * Perform inactive children probing / initialization to start
         * instances of the new loaded driver
         */
    childrenProbeInit(w83c553);
        /*
         * Propagate to all load handlers connected by the device drivers.
         */
    isaDev = w83c553->dev;
    while (isaDev) {
        if (isaDev->loadHandler) {
            isaDev->loadHandler(isaDev->cookie);
        }
        isaDev = isaDev->next;
    }
}