Writing Device Drivers

Registering Interrupts

Before a device driver can receive and service interrupts, it must register them with the system by calling ddi_add_intr(9F). Registering interrupts provides the system with a way to associate an interrupt handler with an interrupt specification. This interrupt handler is called when the device might have been responsible for the interrupt. It is the handler's responsibility to determine if it should handle the interrupt and, if so, claim it.

To register a driver's interrupt handler, the driver usually performs the following steps in attach(9E).

  1. Test for high-level interrupts.

    Call ddi_intr_hilevel(9F) to find out if the interrupt specification maps to a high-level interrupt. If it does, one possibility is to post a message to that effect and return DDI_FAILURE. See Example 6-1.

  2. Get the iblock cookie by calling ddi_get_iblock_cookie(9F).

  3. Initialize any associated mutexes with the iblock cookie by calling mutex_init(9F).

  4. Register the interrupt handler by calling ddi_add_intr(9F).


    Note -

    There is a potential race condition between adding the interrupt handler and initializing mutexes. The interrupt routine is eligible to be called as soon as ddi_add_intr(9F) returns, as another device might interrupt and cause the handler to be invoked. This may result in the interrupt routine being called before any mutexes have been initialized with the returned interrupt block cookie. If the interrupt routine acquires the mutex before it has been initialized, undefined behavior may result. To ensure that this race condition does not occur, always initialize mutexes and any other data used in the interrupt handler before adding the interrupt.


    Example 6-1 shows how to install an interrupt handler.


    Example 6-1 attach(9E) Routine Installing an Interrupt Handler

    static int
    xxattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
    {
    	struct xxstate *xsp;
    	switch (cmd) {
    	case DDI_ATTACH:
    	  	...
    	  	if (ddi_intr_hilevel(dip, inumber) != 0){
    			cmn_err(CE_CONT,
    				"xx: high-level interrupts are not supported\n");
    			return (DDI_FAILURE);
    	  	}
    	  	ddi_get_iblock_cookie(dip, inumber, &xsp->iblock_cookie);
    		mutex_init(&xsp->mu, "xx mutex", MUTEX_DRIVER,
    			    (void *)xsp->iblock_cookie);
    	  	cv_init(&xsp->cv, "xx cv", CV_DRIVER, NULL);
    	  	if (ddi_add_intr(dip, inumber, &xsp->iblock_cookie,
    			      &xsp->idevice_cookie, xxintr,
    					(caddr_t)xsp) != DDI_SUCCESS){
    			 cmn_err(CE_WARN, "xx: cannot add interrupt handler.");
    			 goto failed;
    	  	}
    	  	return (DDI_SUCCESS);
    
    	case DDI_PM_RESUME:
    	    	For information, see Chapter 8, Power Management	case DDI_RESUME:
    			For information, see Chapter 8, Power Management	default:
    	    	return (DDI_FAILURE);
    	}
    failed:
    	remove interrupt handler if necessary, destroy mutex and condition variable
    	return (DDI_FAILURE);
    }