Sun Microsystems, Inc.
spacerspacer
spacer www.sun.com docs.sun.com |
spacer
black dot
 
 
5.  Driver Autoconfiguration Device Configuration Concepts The attach() Entry Point Deferred Attach  Previous   Contents   Next 
   
 

The detach() Entry Point

The kernel calls a driver's detach(9E) entry point to detach an instance of a device or to suspend operation for an instance of a device by power management. This section discusses the operation of detaching device instances. Refer to Chapter 9, Power Management for a discussion of power management issues.

A driver's detach() entry point is called to detach an instance of a device that is bound to the driver. The entry point is called with the instance of the device node to detach and DDI_DETACH specified as the cmd argument to the entry point.

A driver is required to cancel or wait for any time-outs or callbacks to complete, then release any resources that are allocated to the device instance before returning. If for some reason a driver cannot cancel outstanding callbacks for free resources, the driver is required to return the device to its original state and return DDI_FAILURE from the entry point, leaving the device instance in the attached state.

There are two types of callback routines: those that can be canceled and those that cannot. timeout(9F) and bufcall(9F) callbacks can be atomically cancelled by the driver during detach(9E). Other types of callbacks such as scsi_init_pkt(9F) and ddi_dma_buf_bind_handle(9F) cannot be canceled, requiring the driver to either block in detach() until the callback completes or to fail the request to detach.


Example 5-6 detach(9E) Routine

/*
 * detach(9e)
 * free the resources that were allocated in attach(9e)
 */
static int
xxdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
    Pio     *pio_p;
    int     instance;

    switch (cmd) {
    case DDI_DETACH:

        instance = ddi_get_instance(dip);
        pio_p = ddi_get_soft_state(pio_softstate, instance);

        /*
         * turn off the device
         * free any resources allocated in attach
         */
        ddi_put8(pio_p->csr_handle, pio_p->csr, PIO_RESET);

        ddi_remove_minor_node(dip, NULL);
        ddi_regs_map_free(&pio_p->csr_handle);
        ddi_regs_map_free(&pio_p->data_handle);
        ddi_remove_intr(pio_p->dip, 0, pio_p->iblock_cookie);
        mutex_destroy(&pio_p->mutex);
        ddi_soft_state_free(pio_softstate, instance);
        return (DDI_SUCCESS);

    case DDI_SUSPEND:
    default:
        return (DDI_FAILURE);
    }
}

The getinfo() Entry Point

The system calls getinfo(9E) to obtain configuration information that only the driver knows. The mapping of minor numbers to device instances is entirely under the control of the driver. The system sometimes needs to ask the driver which device a particular dev_t represents.

getinfo() can take one of two commands as its infocmd argument: DDI_INFO_DEVT2INSTANCE, which asks for a device's instance number, and DDI_INFO_DEVT2DEVINFO, which asks for pointer to the device's dev_info structure.

In the DDI_INFO_DEVT2INSTANCE case, arg is a dev_t, and getinfo() must translate the minor number in dev_t to an instance number. In the following example, the minor number is the instance number, so getinfo() simply passes back the minor number. In this case, the driver must not assume that a state structure is available, since getinfo() may be called before attach(9E). The mapping that the driver defines between the minor device number and the instance number does not necessarily follow the mapping shown in the example. In all cases, however, the mapping must be static.

In the DDI_INFO_DEVT2DEVINFO case, arg is again a dev_t, so getinfo() first decodes the instance number for the device. It then passes back the dev_info pointer saved in the driver's soft state structure for the appropriate device. This is shown in Example 5-7.


Example 5-7 getinfo(9E) Routine

/*
 * getinfo(9e)
 * Return the instance number or device node given a dev_t
 */
static int
xxgetinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
{
    int error;
    Pio *pio_p;
    int instance = getminor((dev_t)arg);

    switch (infocmd) {

    /*
     * return the device node if the driver has attached the
     * device instace identified by the dev_t value which was passed
     */
    case DDI_INFO_DEVT2DEVINFO:
        pio_p = ddi_get_soft_state(pio_softstate, instance);
        if (pio_p == NULL) {
            *result = NULL;
            error = DDI_FAILURE;
        } else {
            mutex_enter(&pio_p->mutex);
            *result = pio_p->dip;
            mutex_exit(&pio_p->mutex);
            error = DDI_SUCCESS;
        }
        break;

    /*
     * the driver can always return the instance number given a dev_t
     * value, even if the instance is not attached.
     */
    case DDI_INFO_DEVT2INSTANCE:
        *result = (void *)instance;
        error = DDI_SUCCESS;
        break;
    default:
        *result = NULL;
        error = DDI_FAILURE;
    }

    return (error);
}


Note - The getinfo() routine must be kept in sync with minor nodes that the driver creates. Failure to do so may cause failure of hotplug operations and result in system panics.


Using Device IDs

The Solaris DDI interfaces allow drivers to provide a persistent unique identifier for a device, a device ID, which can be used to identify or locate a device and which is independent of the /devices name or device number (dev_t). Applications can use the functions defined in libdevid(3LIB) to read and manipulate the device IDs registered by the drivers.

Before a driver can export a device ID, it needs to verify that the device is capable of either providing a unique ID, such as a WWN (world-wide number), or is capable of storing a host-generated unique ID in an area not accessible through normal operations, such as device NVRAM, reserved sectors, etc.

 
 
 
  Previous   Contents   Next