Writing Device Drivers

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 12, 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 be detached and with DDI_DETACH, which is 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 callbacks that can be canceled and those that cannot be canceled. 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. The driver must either block in detach() until the callback completes or else fail the request to detach.


Example 6–6 Typical detach() Entry Point

/*
 * 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);
    }
}