To register a driver's interrupt handler, the driver typically performs the following steps in its attach(9E) entry point:
Use ddi_intr_get_supported_types(9F) to determine which types of interrupts are supported.
Use ddi_intr_get_nintrs(9F) to determine the number of supported interrupt types.
Use kmem_zalloc(9F) to allocate memory for DDI interrupt handles.
For each interrupt type that you allocate, take the following steps:
Use ddi_intr_get_pri(9F) to get the priority for the interrupt.
If you need to set a new priority for the interrupt, use ddi_intr_set_pri(9F).
Use mutex_init(9F) to initialize the lock.
Use ddi_intr_add_handler(9F) to register the handler for the interrupt.
Use ddi_intr_enable(9F) to enable the interrupt.
Take the following steps to free each interrupt:
Disable each interrupt using ddi_intr_disable(9F).
Remove the interrupt handler using ddi_intr_remove_handler(9F).
Remove the lock using mutex_destroy(9F).
Free the interrupt using ddi_intr_free(9F) and kmem_free(9F) to free memory that was allocated for DDI interrupt handles.
The following example shows how to install an interrupt handler for a device called mydev. This example assumes that mydev supports one interrupt only.
/* Determine which types of interrupts supported */ ret = ddi_intr_get_supported_types(mydevp->mydev_dip, &type); if ((ret != DDI_SUCCESS) || (!(type & DDI_INTR_TYPE_FIXED))) { cmn_err(CE_WARN, "Fixed type interrupt is not supported"); return (DDI_FAILURE); } /* Determine number of supported interrupts */ ret = ddi_intr_get_nintrs(mydevp->mydev_dip, DDI_INTR_TYPE_FIXED, &count); /* * Fixed interrupts can only have one interrupt. Check to make * sure that number of supported interrupts and number of * available interrupts are both equal to 1. */ if ((ret != DDI_SUCCESS) || (count != 1)) { cmn_err(CE_WARN, "No fixed interrupts"); return (DDI_FAILURE); } /* Allocate memory for DDI interrupt handles */ mydevp->mydev_htable = kmem_zalloc(sizeof (ddi_intr_handle_t), KM_SLEEP); ret = ddi_intr_alloc(mydevp->mydev_dip, mydevp->mydev_htable, DDI_INTR_TYPE_FIXED, 0, count, &actual, 0); if ((ret != DDI_SUCCESS) || (actual != 1)) { cmn_err(CE_WARN, "ddi_intr_alloc() failed 0x%x", ret); kmem_free(mydevp->mydev_htable, sizeof (ddi_intr_handle_t)); return (DDI_FAILURE); } /* Sanity check that count and available are the same. */ ASSERT(count == actual); /* Get the priority of the interrupt */ if (ddi_intr_get_pri(mydevp->mydev_htable[0], &mydevp->mydev_intr_pri)) { cmn_err(CE_WARN, "ddi_intr_alloc() failed 0x%x", ret); (void) ddi_intr_free(mydevp->mydev_htable[0]); kmem_free(mydevp->mydev_htable, sizeof (ddi_intr_handle_t)); return (DDI_FAILURE); } cmn_err(CE_NOTE, "Supported Interrupt pri = 0x%x", mydevp->mydev_intr_pri); /* Test for high level mutex */ if (mydevp->mydev_intr_pri >= ddi_intr_get_hilevel_pri()) { cmn_err(CE_WARN, "Hi level interrupt not supported"); (void) ddi_intr_free(mydevp->mydev_htable[0]); kmem_free(mydevp->mydev_htable, sizeof (ddi_intr_handle_t)); return (DDI_FAILURE); } /* Initialize the mutex */ mutex_init(&mydevp->mydev_int_mutex, NULL, MUTEX_DRIVER, DDI_INTR_PRI(mydevp->mydev_intr_pri)); /* Register the interrupt handler */ if (ddi_intr_add_handler(mydevp->mydev_htable[0], mydev_intr, (caddr_t)mydevp, NULL) !=DDI_SUCCESS) { cmn_err(CE_WARN, "ddi_intr_add_handler() failed"); mutex_destroy(&mydevp->mydev_int_mutex); (void) ddi_intr_free(mydevp->mydev_htable[0]); kmem_free(mydevp->mydev_htable, sizeof (ddi_intr_handle_t)); return (DDI_FAILURE); } /* Enable the interrupt */ if (ddi_intr_enable(mydevp->mydev_htable[0]) != DDI_SUCCESS) { cmn_err(CE_WARN, "ddi_intr_enable() failed"); (void) ddi_intr_remove_handler(mydevp->mydev_htable[0]); mutex_destroy(&mydevp->mydev_int_mutex); (void) ddi_intr_free(mydevp->mydev_htable[0]); kmem_free(mydevp->mydev_htable, sizeof (ddi_intr_handle_t)); return (DDI_FAILURE); } return (DDI_SUCCESS); }
The following example shows how legacy interrupts are removed.
/* disable interrupt */ (void) ddi_intr_disable(mydevp->mydev_htable[0]); /* Remove interrupt handler */ (void) ddi_intr_remove_handler(mydevp->mydev_htable[0]); /* free interrupt handle */ (void) ddi_intr_free(mydevp->mydev_htable[0]); /* free memory */ kmem_free(mydevp->mydev_htable, sizeof (ddi_intr_handle_t));