Writing Device Drivers

Device Access

If power management is supported, and detach(9E) and attach(9E) have code such as shown in the previous examples, the code fragment in Example 8-6 can be used where device access is about to be made to the device from user context (for example, in read(2), write(2), ioctl(2)).

In the following example, it is assumed that the operation about to be performed requires a component component that is operating at power level level.


Example 8-6 Device Access

/*
 * Because multiple threads may come through this code
 * simultaneously and ddi_dev_is_needed() does not
 * atomically set the power level and trigger the attach
 * call with DDI_PM_RESUME, a lot of checking is done here
 *
	* prevent us from being powered down again immediately
	* due to still being idle
 */
pm_busy_component(dip, component);
mutex_enter(&xsp->mu);
do {
		 /*
		  * Block commands if/while device suspended via DDI_SUSPEND
		  */
		 while(xsp->xx_suspended)
			  cv_wait(&xsp->cv, &xsp->mu);
		 /* system may have been power cycled here */
		 if (xsp->xx_power_level[component] < level) {
			  /*
			   * Drop mutex because ddi_dev_is_needed will result in
			   * a call back into our power and/or attach routine
			   */
			   mutex_exit(&xsp->mu);
			   ddi_dev_is_needed(dip, component, level);
			   mutex_enter(&xsp->mu);
		}
		/*
		 * Block commands if device still suspended with
		 * DDI_PM_SUSPEND; because we had to drop the mutex to
		 * call ddi_dev_is_needed we may be executing in a
		 * thread that came in after the power level was raised
		 * but before attach was called with DDI_PM_RESUME
		 */
		while(xsp->xx_pm_suspended)
			  cv_wait(&xsp->cv, &xsp->mu);
		/*
		 * Because we may have dropped the lock in the cv_wait,
		 * we could have gotten a DDI_SUSPEND request, or we could
		 * have found the power level high enough on the way in
		 * but got powered down after we checked it, so we have
		 * to check everything over again (except the
		 * xx_pm_suspended state that we checked in the last
		 * while loop) because any of the things we tested before
		 * may have changed when we dropped the mutex
	 	*/

} while(xsp->xx_suspended || xsp->xx_power_level[component]
				< level);
check for busy, initiate commands, and so on
when command completes and there are no more commands pending
pm_idle_component(dip, component);
....