Writing Device Drivers

Power Management Device Access Example

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 9–8 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)).

The following example assumes that the operation about to be performed requires a component component that is operating at power level level.


Example 9–8 Device Access

...
mutex_enter(&xsp->mu);
/*
 * Block command while device is suspeded via DDI_SUSPEND
 */
while (xsp->xx_suspended)
        cv_wait(&xsp->xx_suspend_cv, &xsp->mu);

/*
 * Mark component busy so power() will reject attempt to lower power
 */
xsp->xx_busy[component]++;
if (pm_busy_component(dip, component) != DDI_SUCCESS) {
        xsp->xx_busy[component]--;
        /*
         * Log error and abort
         */
        ....
}

if (xsp->xx_power_level[component] < level) {
        mutex_exit(&xsp->mu);
        if (pm_raise_power(dip, component, level) != DDI_SUCESS) {
                /*
                 * Log error and abort
                 */
                ...
        }
        mutex_enter(&xsp->mu);
}
...

The code fragment in Example 9–9 can be used when device operation completes (for example, in the device's interrupt handler).


Example 9–9 Device Operation Completion

...
/*
 * For each command completion, decrement the busy count and unstack
 * the pm_busy_component() call by calling pm_idle_component(). This
 * will allow device power to be lowered when all commands complete
 * (all pm_busy_component() counts are unstacked)
 */
xsp->xx_busy[component]--;
if (pm_idle_component(dip, component) != DDI_SUCCESS) {
        xsp->xx_busy[component]++;
        /*
         * Log error and abort
         */
        ....
}

/*
 * If no more outstanding commands, wake up anyone (like DDI_SUSPEND)
 * waiting for all commands to  be completed
 */
...