Writing Device Drivers for Oracle® Solaris 11.2

Exit Print View

Updated: September 2014
 
 

probe() Entry Point

For non-self-identifying devices, the probe(9E) entry point should determine whether the hardware device is present on the system.

For probe() to determine whether the instance of the device is present, probe() needs to perform many tasks that are also commonly done by attach(9E). In particular, probe() might 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 present. The test criteria must be rigorous enough to avoid misidentifying devices. For example, a device might appear to be present when in fact that device is not available, because a different device seems to behave like the expected device.

The test returns the following flags:

  • 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) still needs to be called

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

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

probe(9E) must free all the resources that probe() has allocated, because probe() might be called multiple times. However, attach(9E) is not necessarily called even if probe(9E) has succeeded

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

The following example is a sample probe() routine.

Example 6-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 attributes 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, the driver does not know whether the device being probed exists on the bus. Therefore, the driver might attempt to access device registers for a nonexistent device. A bus fault might be generated on some buses as a result.

The following example shows a probe(9E) routine that uses ddi_poke8(9F) to check for the existence of the device. ddi_poke8() 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 6-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);

    /*
     * Initialize the device access attrributes and map in
     * the device's 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 that
     * do not exist.  Use ddi_poke8(9f) to handle any faults that
     * might 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);
}