编写设备驱动程序

power() 入口点

电源管理框架使用 power(9E) 入口点。

power() 使用以下语法:

int power(dev_info_t *dip, int component, int level);

需要更改组件的电源级别时,系统将调用 power(9E) 入口点。该入口点执行的操作特定于设备驱动程序。在上面提到的 SCSI 目标磁盘驱动程序示例中,如果将电源级别设置为 0,则会发送 SCSI 命令停止磁盘运转,而如果将电源级别设置为全电源级别,则会发送 SCSI 命令启动磁盘。

如果电源转换导致设备丢失状态,则驱动程序必须将任何必需的状态保存在内存中,以便将来恢复。如果电源转换要求先恢复保存的状态,然后才能再次使用设备,则驱动程序必须恢复该状态。该框架并未对哪些电源事务会导致丢失自动电源管理设备的状态作出假设,也未对哪些电源事务会要求恢复自动电源管理设备的状态作出假设。以下示例给出了一个 power() 例程样例。


示例 12–4 将 power() 例程用于单组件设备

int
xxpower(dev_info_t *dip, int component, int level)
{
    struct xxstate *xsp;
    int instance;

    instance = ddi_get_instance(dip);
    xsp = ddi_get_soft_state(statep, instance);
   /*
    * Make sure the request is valid
    */
    if (!xx_valid_power_level(component, level))
        return (DDI_FAILURE);
    mutex_enter(&xsp->mu);
   /*
    * If the device is busy, don't lower its power level
    */
    if (xsp->xx_busy[component] &&
        xsp->xx_power_level[component] > level) {
        mutex_exit(&xsp->mu);
        return (DDI_FAILURE);
    }

    if (xsp->xx_power_level[component] != level) {
       /*
        * device- and component-specific setting of power level
        * goes here
        */
        xsp->xx_power_level[component] = level;
    }
    mutex_exit(&xsp->mu);
    return (DDI_SUCCESS);
}

以下示例是包含两个组件的设备的 power() 例程,其中,组件 1 为打开状态时,组件 0 必须也为打开状态。


示例 12–5 多组件设备的 power (9E) 例程

int
xxpower(dev_info_t *dip, int component, int level)
{
    struct xxstate *xsp;
    int instance;

    instance = ddi_get_instance(dip);
    xsp = ddi_get_soft_state(statep, instance);
   /*
    * Make sure the request is valid
    */
    if (!xx_valid_power_level(component, level))
        return (DDI_FAILURE);
    mutex_enter(&xsp->mu);
   /*
    * If the device is busy, don't lower its power level
    */
    if (xsp->xx_busy[component] &&
        xsp->xx_power_level[component] > level) {
        mutex_exit(&xsp->mu);
        return (DDI_FAILURE);
    }
   /*
    * This code implements inter-component dependencies:
    * If we are bringing up component 1 and component 0 
    * is off, we must bring component 0 up first, and if
    * we are asked to shut down component 0 while component
    * 1 is up we must refuse
    */
    if (component == 1 && level > 0 && xsp->xx_power_level[0] == 0) {
        xsp->xx_busy[0]++;
        if (pm_busy_component(dip, 0) != DDI_SUCCESS) {
           /*
            * This can only happen if the args to 
            * pm_busy_component()
            * are wrong, or pm-components property was not
            * exported by the driver.
            */
            xsp->xx_busy[0]--;
            mutex_exit(&xsp->mu);
            cmn_err(CE_WARN, "xxpower pm_busy_component() 
                failed");
            return (DDI_FAILURE);
        }
        mutex_exit(&xsp->mu);
        if (pm_raise_power(dip, 0, XX_FULL_POWER_0) != DDI_SUCCESS)
            return (DDI_FAILURE);
        mutex_enter(&xsp->mu);
    }
    if (component == 0 && level == 0 && xsp->xx_power_level[1] != 0) {
        mutex_exit(&xsp->mu);
        return (DDI_FAILURE);
    }
    if (xsp->xx_power_level[component] != level) {
       /*
        * device- and component-specific setting of power level
        * goes here
        */
        xsp->xx_power_level[component] = level;
    }
    mutex_exit(&xsp->mu);
    return (DDI_SUCCESS);
}