ChorusOS 5.0 Board Support Package Developer's Guide

Bus Driver General Functions

This section describes the additional functions that are required to provide the common bus API services. This section is specific to writing bus drivers.

Once the bus class services are implemented in a bus driver component, you can also write the additional functions needed to provide the Common bus API services (in addition to those provided by the bus class API). This allows child device drivers to be written to the common bus-driver interface (CBDI), making them bus class independent (bottom-interface transparent).

In most cases, these services have already been implemented in the previous step. There are normally only three functions that must be added to allow the subsequent device drivers to perform independently of their bus type. These functions essentially allow the bus driver's clients to retrieve property elements from arrays.

The following code example illustrates this for a PCI-to-ISA bridge bus driver. In this example, the ISA bus class is provided, and the additional functions are written to provide the CBDI.


Note -

For clarity, only the code pertinent to this explanation is shown. Please refer to a complete implementation file for more details.


    /*
     * ISA bus provided API
     */
    static KnError
open (IsaId isaId, ...) { ... }
    static void
close (IsaDevId devId) { ... }
    /*
     * Interrupt management
     */
    static void
mask (IsaIntrId intrId) { ... } 
    static void
unmask (IsaIntrId intrId) { ... }
    static IsaIntrStatus
enable (IsaIntrId intrId) { ... }

static IsaIntrOps w83c553IntrOps = {
    mask,
    unmask,
    enable,
    unmask
};
    static KnError
intr_attach (IsaDevId devId, ...) { ... }
    static void
intr_detach (IsaIntrId intrId) { ... }
    /*
     * I/O management
     */
    static KnError
io_map (IsaDevId devId, ...) { ... }
    /*
     * Note that there is no io_unmap() method implementation.
     * The PCI bridge io_unmap() method is directly used instead.
     * This PCI method is set in the IsaBusOps at drv_init() time.
     */
    /*
     * DMA management
     */
    static KnError
dma_attach (IsaDevId devId, ...) { ... }
    static void
dma_detach (IsaDmaId dmaId) { ... }
    /*
     * Memory management
     */
    static KnError
mem_map (IsaDevId devId, ...) { ... }
    /*
     * Note that there is no mem_unmap() method implementation.
     * The PCI bridge mem_unmap() method is directly used instead.
     * This PCI method is set in the IsaBusOps at drv_init() time.
     */
    /*
     * Dynamic resource allocation
     */
    static KnError
resource_alloc (PciDevId devId, DevProperty prop) { ... }
    static void
resource_free  (PciDevId devId, DevProperty prop) { ... }

    /*
     * Common bus interface miscellaneous routines
     */
    static void*
intr_find (void* prop, int index)
{
    return ((IsaPropIntr*)prop) + index;
}
    static void*
io_regs_find (void* prop, int index)
{
    return ((IsaPropIoRegs*)prop) + index;
}
    static void*
mem_rgn_find (void* prop, int index)
{
    return ((IsaPropMemRgn*)prop) + index;
}

    /*
     * W83C553 driver initialization method
     */
    static void
drv_init (DevNode myNode, void* busOps, void* busId)
{
    PciBusOps*           pciOps = (PciBusOps*)busOps;
    PciBusOps*           pciId  = (PciId)busId;
    DevRegEntry*         w83c553Entry;
    W83c553Data*         w83c553;
    ...
        /*
         * Allocate driver instance data
         */
    w83c553 = w83c553Alloc(path, pathSize);
    if (w83c553 == NULL) {
        DKI_ERR(("%s: error -- not enough memory\n", path));
        return;
    }
    ...
        /*
         * Initialize my base level ISA bus operations
         */
    w83c553->isaOps->version        = ISA_VERSION_INITIAL;
    w83c553->isaOps->open           = open;
    w83c553->isaOps->close          = close;
    w83c553->isaOps->intr_attach    = intr_attach;
    w83c553->isaOps->intr_detach    = intr_detach;
    w83c553->isaOps->io_map         = io_map;
    w83c553->isaOps->io_unmap       = pciOps->io_unmap; /* parent bus ops */
    w83c553->isaOps->dma_attach     = dma_attach;
    w83c553->isaOps->dma_detach     = dma_detach;
    w83c553->isaOps->mem_map        = mem_map;
    w83c553->isaOps->mem_unmap      = pciOps->mem_unmap;/* parent bus ops */
    w83c553->isaOps->resource_alloc = resource_alloc;
    w83c553->isaOps->resource_free  = resource_free;
        /*
         * Initialize my base level Common bus operations
         */
    w83c553->busOps->version        = BUS_VERSION_INITIAL;
    w83c553->busOps->open           = open;
    w83c553->busOps->close          = close;
    w83c553->busOps->intr_attach    = (KnError(*)()) intr_attach;
    w83c553->busOps->intr_detach    = intr_detach;
    w83c553->busOps->io_map         = (KnError(*)()) io_map;
    w83c553->busOps->io_unmap       = pciOps->io_unmap; /* parent bus ops */
    w83c553->busOps->mem_map        = (KnError(*)()) mem_map;
    w83c553->busOps->mem_unmap      = pciOps->mem_unmap;/* parent bus ops */
    w83c553->busOps->intr_find      = intr_find;
    w83c553->busOps->io_regs_find   = io_regs_find;
    w83c553->busOps->mem_rgn_find   = mem_rgn_find;
    ...
        /*
         * Call children drv_probe() / drv_init() methods, if any.
         */
    childrenProbeInit(w83c553);
}