Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
5.  Driver Autoconfiguration Loadable Driver Interfaces _fini() Example  Previous   Contents   Next 
   
 

_info() Example

The following example demonstrates the _info(9E) routine.

int
_info(struct modinfo *modinfop)
{
        return (mod_info(&xxmodlinkage, modinfop));
}

The driver is called to return module information. The entry point should be implemented as shown above.

Device Configuration Concepts

For each node in the kernel device tree, the system selects a driver for the node based on the node name and the compatible property (see "Binding a Driver to a Device"). The same driver may bind to multiple device nodes; the driver can differentiate different nodes by instance numbers assigned by the system.

Once a driver is selected for a device node, the driver's probe(9E) entry point is called to determine the presence of device on the system. If probe(9E) is successful, the driver's attach(9E) entry point is invoked to set up and manage the device. The device can be opened if and only if attach(9E) returns success (see "The attach() Entry Point").

A device may be unconfigured to conserve system memory resources or to allow device to be hot removed. To allow device to be unconfigured, the system first checks if the device instance is referenced. This check involves calling the driver's getinfo(9E) entry point to obtain information known only to the driver (see "The getinfo() Entry Point"). If the device instance is not referenced, the driver's detach(9E) routine is invoked to unconfigure the device (see "The detach() Entry Point").

In short, each driver must define the following entry points that are used by the kernel for device configuration:

  • probe(9E)

  • attach(9E)

  • detach(9E)

  • getinfo(9E)

Note that attach(), detach(), and getinfo() are required. probe() is only required for non self-identifying devices. For self-identifying devices, an explicit probe() routine may be provided, or nulldev(9E) may be specified in the dev_ops structure for the probe() entry point.

Device Instances and Instance Numbers

The system assigns an instance number to each device. The driver may not reliably predict the value of the instance number assigned to a particular device. The driver should retrieve the particular instance number that has been assigned by calling ddi_get_instance(9F).

Instance numbers represent the system's notion of devices. Each dev_info (that is, each node in the device tree) for a particular driver is assigned an instance number by the kernel. Furthermore, instance numbers provide a convenient mechanism for indexing data specific to a particular physical device. The most common usage for this is ddi_get_soft_state(9F), which uses an instance number to retrieve soft state data for a particular physical device.


Caution - For pseudo devices (children of the pseudo nexus), the instance numbers are defined in the driver.conf(4) file via the instance property. If the driver.conf(4) file does not contain the instance property, the behavior is undefined. For hardware device nodes, the system assigns instance numbers when the device is first seen by the OS. The instance numbers persist across system reboots and OS upgrades.


Minor Nodes and Minor Numbers

Drivers are responsible for managing their minor number name space. For example, the sd driver needs to export 16 minor nodes (8 character, 8 block) to the file system for each disk. Each represents a different piece of the same disk, or a different interface to the same data (character/block). However, the driver still needs to be able to retrieve the instance number of the device in order to get soft state, and so forth. The getinfo(9E) entry point informs the system about the mapping from minor number to device instance (see "The getinfo() Entry Point").

The probe() Entry Point

For non-self-identifying devices, this entry point should determine whether the hardware device is present on the system.

For probe(9E) to determine whether the instance of the device is present, probe(9E) may need to do many of the things also commonly done by attach(9E). In particular, it may need to map the device registers.

Probing the device registers is device-specific. The driver often has to perform a series of tests of the hardware to assure that the hardware is really there. The test criteria must be rigorous enough to avoid misidentifying devices. For example, a device may appear to be present when in fact it is not, because a different device seems to behave like the expected device.

The test returns:

DDI_PROBE_SUCCESS if the probe was successful

DDI_PROBE_FAILURE if the probe failed

DDI_PROBE_DONTCARE if the probe was unsuccessful yet attach(9E) should still be called

DDI_PROBE_PARTIAL if the instance is not present now, but may be present in the future

For a given device instance, attach(9E) will not be called before probe(9E) has succeeded at least once on that device.

probe(9E) must free all the resources that it allocates, because it may be called multiple times; however, attach(9E) will not necessarily be called even if probe(9E) succeeds.

ddi_dev_is_sid(9F) may be used in a driver's probe(9E) routine to determine if the device is self-identifying. This is useful in drivers written for self-identifying and non-self-identifying versions of the same device.

Example 5-3 is a sample probe(9E) routine.


Example 5-3 probe(9E) Routine

static int
xxprobe(dev_info_t *dip)
{

    ddi_acc_handle_t dev_hdl;
    ddi_device_acc_attr_t dev_attr;
    Pio_csr *csrp;
    uint8_t csrval;

    /*
     * if the device is self identifying, no need to probe
     */
    if (ddi_dev_is_sid(dip) == DDI_SUCCESS)
        return (DDI_PROBE_DONTCARE);

    /*
     * Initalize the device access attrributes and map in
     * the devices CSR register (register 0)
     */
    dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
    dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
    dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;

    if (ddi_regs_map_setup(dip, 0, (caddr_t *)&csrp, 0, sizeof (Pio_csr),
        &dev_attr, &dev_hdl) != DDI_SUCCESS)
        return (DDI_PROBE_FAILURE);

    /*
     * Reset the device
     * Once the reset completes the CSR should read back
     * (PIO_DEV_READY | PIO_IDLE_INTR)
     */
    ddi_put8(dev_hdl, csrp, PIO_RESET);
    csrval = ddi_get8(dev_hdl, csrp);


    /*
     * tear down the mappings and return probe success/failure
     */
    ddi_regs_map_free(&dev_hdl);
    if ((csrval & 0xff) == (PIO_DEV_READY | PIO_IDLE_INTR))
        return (DDI_PROBE_SUCCESS);
    else
        return (DDI_PROBE_FAILURE);
}

When the driver's probe(9E) routine is called, it does not know whether the device being probed exists on the bus. Therefore, it is possible that the driver may attempt to access device registers for a nonexistent device. A bus fault may be generated on some buses as a result.

Example 5-4 shows a probe(9E) routine that uses ddi_poke8(9F) to check for the existence of the device. ddi_poke8(9F) cautiously attempts to write a value to a specified virtual address, using the parent nexus driver to assist in the process where necessary. If the address is not valid, or the value cannot be written without an error occurring, an error code is returned. See also ddi_peek(9F).

In this example, ddi_regs_map_setup(9F) is used to map the device registers.


Example 5-4 probe(9E) Routine Using ddi_poke8(9F)

static int
xxprobe(dev_info_t *dip)
{

    ddi_acc_handle_t dev_hdl;
    ddi_device_acc_attr_t dev_attr;
    Pio_csr *csrp;
    uint8_t csrval;

    /*
     * if the device is self identifying, no need to probe
     */
    if (ddi_dev_is_sid(dip) == DDI_SUCCESS)
        return (DDI_PROBE_DONTCARE);

    /*
     * Initalize the device access attrributes and map in
     * the devices CSR register (register 0)
     */
    dev_attr.devacc_attr_version - DDI_DEVICE_ATTR_V0;
    dev_attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC;
    dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;

    if (ddi_regs_map_setup(dip, 0, (caddr_t *)&csrp, 0, sizeof (Pio_csr),
        &dev_attr, &dev_hdl) != DDI_SUCCESS)
        return (DDI_PROBE_FAILURE);

    /*
     * The bus can generate a fault when probing for devices which
     * do not exist.  Use ddi_poke8(9f) to handle any faults which
     * may occur.
     *
     * Reset the device.  Once the reset completes the CSR should read
     * back (PIO_DEV_READY | PIO_IDLE_INTR)
     */
    if (ddi_poke8(dip, csrp, PIO_RESET) != DDI_SUCCESS) {
        ddi_regs_map_free(&dev_hdl);
        return (DDI_FAILURE);


    csrval = ddi_get8(dev_hdl, csrp);
    /*
     * tear down the mappings and return probe success/failure
     */
    ddi_regs_map_free(&dev_hdl);
    if ((csrval & 0xff) == (PIO_DEV_READY | PIO_IDLE_INTR))
        return (DDI_PROBE_SUCCESS);
    else
        return (DDI_PROBE_FAILURE);
}

 
 
 
  Previous   Contents   Next