電源管理フレームワークは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);
}
次の例は、2 つの部品で構成されるデバイスに対する 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);
}