Writing Device Drivers

detach()

detach(9E) handles the following commands:

This section discusses only the DDI_DETACH command. For information on DDI_PM_SUSPEND and DDI_SUSPEND, see Chapter 8, Power Management. Note that detach(9E) is single-threaded when processing the DDI_DETACH command, but is not single-threaded when processing the DDI_SUSPEND or DDI_PM_SUSPEND commands.

When processing the DDI_DETACH command, detach(9E) is the inverse operation of attach(9E). The main purpose of the DDI_DETACH case of detach(9E) is to free resources allocated by attach(9E) for the specified device. For example, detach(9E) should unmap any mapped device registers, remove any interrupts registered with the system, and free the soft state structure for this device instance.

The system calls the DDI_DETACH case of detach(9E) for a device instance only if the device instance is not open. No calls to other driver entry points for that device instance occur during detach(9E), although interrupts and time-outs may occur.

If the detach(9E) routine entry in the dev_ops(9S) structure is initialized to nodev, it implies that detach(9E) always fails, and the driver will not be unloaded. This is the simplest way to specify that a driver is not unloadable.


Example 5-5 detach(9E) Routine

static int
xxdetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
{
	struct xxstate *xsp;
	int		instance;

	switch (cmd) {
	case DDI_DETACH:
	   	instance = ddi_get_instance(dip);
	   	xsp = ddi_get_soft_state(statep, instance);
		    make device quiescent;							/* device-specific */
	    	ddi_remove_minor_node(dip, NULL);
	    	pm_destroy_components(dip);
	    	ddi_regs_map_free(&xsp->data_access_handle);
	    	ddi_remove_intr(dip, inumber, xsp->iblock_cookie);
	    	mutex_destroy(&xsp->mu);
	    	cv_destroy(&xsp->cv);
	    	ddi_soft_state_free(statep, instance);
	    	return (DDI_SUCCESS);
	case DDI_PM_SUSPEND:
	    	For information, see Chapter 8, Power Management	case DDI_SUSPEND:
	    	For information, see Chapter 8, Power Management	default:
	    	return (DDI_FAILURE);
	}
}

In the call to ddi_regs_map_free(9F), xsp->data_access_handle is the data access handle previously allocated by the call to ddi_regs_map_setup(9F) in attach(9E). Similarly, in the call to ddi_remove_intr(9F), inumber is the same value that was passed to ddi_add_intr(9F).

Callbacks

The detach(9E) routine must not return DDI_SUCCESS while it has callback functions pending. This is critical only for callbacks registered for device instances that are not currently open, since the DDI_DETACH case is not entered if the device is open.

There are two types of callback routines of interest: callbacks that can be canceled, and callbacks that must run to completion. Callbacks that can be canceled do not pose a problem; the driver should cancel the callback before detach(9E) returns DDI_SUCCESS. Each of the callback cancellation routines in Table 5-2 atomically cancels callbacks so that a callback routine does not run while it is being canceled.

Table 5-2 Example of Functions With Cancelable Callbacks

Function 

Canceling Function 

timeout(9F) 

untimeout(9F) 

bufcall(9F) 

unbufcall(9F) 

esbbcall(9F) 

unbufcall(9F) 

Some callbacks cannot be canceled--for these it is necessary to wait until the callback has been called. In some cases, such as ddi_dma_buf_bind_handle(9F), the callback must also be prevented from rescheduling itself. See "Canceling DMA Callbacks" for an example.

Following is a list of some functions that may establish callbacks that cannot be canceled: