Управление питанием
Функциональность управления питанием Набора I/O стремится минимизировать питание, использованное компьютерной системой, поведение, которое особенно важно для портативных компьютеров, где время работы от батареи является фундаментальным свойством. Управление питанием также налагает организованную последовательность действий, таких как сохранение и восстановление состояния, когда система (или часть его) сны или следы.
Эта глава фокусируется на управлении питанием для в драйверах ядра, управляющих аппаратными средствами. Считайте эту главу, чтобы узнать об управлении питанием в OS X и узнать, какой уровень управления питанием поддерживают Вас, должен обеспечить и как реализовать его. Несмотря на то, что управление питанием является сложной технологией, большинством потребности в драйверах ядра реализовать только самую основную функциональность для участия успешно в управлении питанием OS X.
Точный набор ответственности управления питанием, которую должен выполнить Ваш драйвер, зависит от факторов такой как, сколько поддержки Ваш водительский суперкласс предоставляет, получает ли Ваше устройство питание от системной шины (такой как PCI), и к тому, какие события питания Ваш драйвер должен ответить.
Если Вы незнакомы с управлением питанием в OS X, необходимо начать путем чтения следующих трех разделов:
События питания, который объясняет, что события питания и как они влияют на Ваше устройство
Плоскость Питания: Иерархия Зависимостей от Питания, описывающая, как OS X контролирует отношения между начальником и подчиненным среди устройств, драйверов и других объектов
Устройства и Состояния электропитания, который определяет устройства и состояния электропитания в условиях управления питанием
Затем все разработчики драйвера должны считать Решение, Как Реализовать Управление питанием в Вашем Драйвере для обнаружения, что сделать затем. После решения, какое управление питанием необходимо реализовать, считайте Реализующее Основное Управление питанием и, при необходимости Реализовав Усовершенствованное Управление питанием
События питания
Перед рассмотрением, как реализовать управление питанием в драйвере, необходимо понять то, что события питания и как они могут влиять устройство. В OS X события питания являются переходами к и от следующих состояний:
Сон
След
Завершение работы или перезапуск
Все драйверы должны реагировать на события сна. OS X определяет различные типы сна, который может произойти по разным причинам. Например, когда пользователь выбирает Sleep из Меню Apple или закрывает крышку ноутбука, системный сон происходит; неактивный сон происходит, когда не было никакого действия устройства или системы во время интервала, пользователь выбирает в энергетических предпочтениях Средства сохранения. К Вашему драйверу, однако, все события сна кажутся идентичными. Важная вещь понять о событии сна состоит в том, что Ваше устройство может быть выключено, когда система спит, таким образом, Ваш драйвер должен быть подготовлен инициализировать устройство, когда это пробуждено.
Все драйверы должны реагировать на системное событие следа путем включения. След может произойти, когда пользователь нажимает клавишу на клавиатуре, нажимает кнопку питания, или когда компьютер получает пакет пробуждения администратора сети. На следе драйверы должны выполнить надлежащее восстановление состояния устройства.
Драйверы устройств не должны реагировать на завершение работы и события перезапуска. Драйвер может принять решение получить уведомление о нависшем завершении работы или перезапуске с помощью метода, описанного в Получении Завершения работы и Уведомлений Перезапуска, но важно понять, что никакой драйвер не может предотвратить событие завершения работы.
Другой тип события является запросом включения питания устройства, происходящим, когда некоторый объект в системе требует, чтобы неактивное или приводимый в действие - от устройства были в применимом состоянии. Уведомление запроса включения питания устройства использует большинство тех же механизмов в качестве уведомлений следа и сна. Несмотря на то, что большинство драйверов не должно знать о запросах включения питания устройства, некоторые драйверы, возможно, должны были бы реализовать их и даже выполнить такие запросы сами. Для получения дополнительной информации об этом, посмотрите Инициирование Изменения Состояния электропитания
Плоскость питания: иерархия зависимостей от питания
OS X отслеживает все управляемые устройства питания в древовидной структуре, названной плоскостью питания, получающей зависимости от питания среди устройств. Устройство, обычно листовой объект в плоскости питания, обычно получает питание от своих наследователей и может предоставить питание его дочерним элементам. Например, потому что плата PCI зависит для, включают шину PCI, к которой она присоединяется, плата PCI считается дочерним элементом питания шины PCI. Аналогично, шина PCI считается родителем питания устройств, присоединенных к нему.
Плоскость питания является одной из плоскостей Реестра I/O. Как описано в Реестре I/O Реестр I/O является базой динамических данных устройства, и драйвер возражает что экспрессы различные связи с потребителями провайдера среди них. Для просмотра плоскости питания в рабочей системе откройте приложение Проводника Реестра I/O (расположенный в /Developer/Applications/Utilities
) и выберите IOPower из всплывающего меню. Можно также войти ioreg -p IOPower
в командной строке для наблюдения представления текущей плоскости питания. Рисунок 9-1 показывает плоскость питания в Power Mac G5 рабочий OS X v10.5.
На рисунке 9-1 Вы видите корень плоскости питания, вызванный объект IOPMrootDomain
, и объекты, представляющие устройства и драйверы. Можно проигнорировать многих IOPowerConnection
объекты, представляющие подключения питания, потому что эти объекты представляют интерес только для внутренних объектов управления питанием и процессов.
Устройства и состояния электропитания
Фундаментальный объект в управлении питанием является устройством. С точки зрения управления питанием устройство является модулем аппаратных средств, потребляемую мощность которых можно измерить и управлять независимо от питания системы. Устройство может также иметь некоторое состояние, которое должно быть сохранено и восстановлено через изменения в питании. В условиях управления питанием «устройство» синонимично с объектом драйвера устройства, управляющим им.
Устройство должно иметь по крайней мере два состояния электропитания, связанные с ним — прочь и на. Устройство может также иметь промежуточные состояния, представляющие некоторый уровень питания между полномочиями и никакого питания. Эти состояния описаны в массиве состояния электропитания, который Вы создаете в своем драйвере. (Вы изучаете, как создать этот массив и предоставить информацию состояния электропитания на шаге 3 в Реализации Основного Управления питанием), функциональность управления питанием Набора I/O использует эти состояния, чтобы гарантировать, чтобы все драйверы в плоскости питания получили питание, которого они требуют. Каждое состояние электропитания определяется возможностями устройства когда в том состоянии:
Устройство, которое находится на максимальной мощности использования и имеет полную функциональность.
Устройство, которое не является от использования никаким питанием и не имеет никакой функциональности.
Устройство может быть в сокращенном состоянии электропитания, в котором это все еще применимо, но на более низком уровне производительности или функциональности.
Устройство может быть в промежуточном состоянии, в котором это не применимо, но сохраняет некоторую конфигурацию или состояние.
Функциональность управления питанием Набора I/O связывает несколько атрибутов с каждым состоянием электропитания устройства. Драйвер устройства должен установить эти атрибуты, чтобы гарантировать, что точная информация о возможностях и требованиях устройства доступна.
Атрибуты состояния электропитания предоставляют следующую информацию:
Возможность устройства, в то время как в данном состоянии
Требования питания устройства его родителя питания
Характеристики электропитания устройство могут обеспечить для его дочерних элементов питания
Версия состояния электропитания структурирует использование устройства, чтобы хранить его информацию состояния электропитания
Решение, как реализовать управление питанием в драйвере
Для участия в управлении питанием OS X потребность наиболее в драйверах ядра только гарантирует, чтобы их устройства соответственно реагировали на системный сон и события следа. Некоторые в драйверах ядра, возможно, должны были бы выполнить другие задачи, такие как реализация состояния ожидания или принятие мер при завершении работы системы, но эти драйверы не типичны. Отражая это различие, управление питанием OS X определяет два типа драйверов:
Пассивный драйвер реализует основное управление питанием для ответа на события питания системы; это не инициирует связанных с питанием действий для своего устройства.
Активный драйвер реализует основное управление питанием для ответа на события питания системы, но это также реализует усовершенствованное управление питанием для выполнения задач, таких как решение, когда устройство должно стать неактивным, изменив состояние электропитания устройства, или обработав до завершения работы системы.
Примером пассивного драйвера является настоящее драйвера AppleSmartBatteryManager в большинстве портативных компьютеров Macintosh. Драйвер AppleSmartBatteryManager предоставляет информацию состояния батареи пункту строки меню состояния батареи; когда система собирается спать, драйвер просто прекращает опрашивать батарею относительно информации о статусе. Хорошим примером активного драйвера является встроенный аудио драйвер микросхемы, потому что это выполняет свое собственное определение безделья, чтобы позволить аудио аппаратным средствам выключаться, когда это не используется. Если не будет никакого звука, выходящего из внутренних динамиков ноутбука или рабочего стола, то аудио аппаратные средства заскочат в режим низкой мощности, пока они не будут необходимы.
Как можно предположить, пассивный драйвер намного проще, чем активный драйвер к разработке и реализации. По существу пассивный драйвер реализует один виртуальный метод и делает между тремя и пятью вызовами для участия в управлении питанием. Ответственность активного драйвера, с другой стороны, начинается с тех из пассивного драйвера, но увеличение с каждой дополнительной задачей драйвер должно выполнить.
Некоторые семьи I/O Kit обеспечивают различные уровни встроенной поддержки управления питанием подклассам драйвера. Например, семья Network (IONetworkingFamily
) выполняет некоторые задачи инициализации управления питанием для драйвера подкласса, оставляя драйвер для выполнения других специфичных для устройства задач управления питанием.
Прежде чем Вы начнете разрабатывать свою водительскую реализацию управления питанием, необходимо искать семью I/O Kit в Ссылке семьи Набора I/O, чтобы узнать, предоставляет ли семья поддержку управления питанием или требует, чтобы подклассы выполнили различные или дополнительные задачи. Знайте, однако, что любая семья I/O Kit, обеспечивающая функциональность управления питанием, может все еще потребовать, чтобы Вы реализовали некоторые части ее. Следующие семьи I/O Kit обеспечивают некоторый тип функциональности управления питанием:
Аудио семья (описанный в Аудио)
Семья FireWire (описанный в FireWire)
Сетевая семья (описанный в Сети)
Семья стандарта PC Card, включающая Явно выраженные устройства Карты (описанный в плате ПК)
Семья PCI (описанный в PCI и AGP)
Семья Model архитектуры SCSI (описанный в Модели архитектуры SCSI)
Семья USB (описанный в USB)
Даже если Ваш драйвер является подклассом семьи I/O Kit, не предоставляющей поддержки управления питанием, или если Ваш драйвер является прямым подклассом IOService
, это может все еще быть пассивный участник управления питанием, пока это только реагирует на инициируемые в систему события питания. Если с другой стороны Ваш драйвер должен определить, когда Ваше устройство неактивно, или выполните задачи перед завершением работы, необходимо реализовать усовершенствованное управление питанием.
Если Вы решаете разработать пассивный драйвер, необходимо считать Реализующее Основное Управление питанием, чтобы изучить, как участвовать в управлении питанием и реагировать на сон и события следа. Вы не должны читать никакие другие разделы в этой главе.
Если Ваш драйвер должен быть активным диспетчером электропитания, необходимо также считать Реализующее Основное Управление питанием Тогда, необходимо считать Реализацию Усовершенствованное Управление питанием для руководства при реализации определенных задач.
Реализация основного управления питанием
Как определено в Решении, Как Реализовать Управление питанием в Вашем Драйвере, пассивный драйвер только реагирует на сон и события следа; это не инициирует изменяющего состояние электропитания действия. Ваш пассивный драйвер должен сделать следующие вещи обработать сон и след:
Будьте присоединены в плоскость питания, таким образом, Вы получаете уведомления изменения питания и гарантировать, что зависимости от питания Вашего устройства рассматривают, когда ей говорят спать и проснуться.
Зависимости от питания влияют на упорядочивание уведомлений следа и сна. В частности Вашему драйверу говорят спать, прежде чем его родителю питания скажут спать, и Вашему драйверу говорят проснуться после того, как его родителю питания говорят проснуться.
Сохраните аппаратное состояние к памяти перед системным сном и восстановите состояние во время следа.
Вы ответственны за запись кода, чтобы сделать это.
Предотвратите все аппаратные доступы, в то время как Ваше устройство подготавливается ко сну.
Можно возвратить ошибку любому запросу I/O, который Вы получаете, в то время как Ваше устройство засыпает, или можно блокировать все входящие потоки с помощью механизма пропускания, такой как
IOCommandGate
, на Вашем цикле работы (см. Циклы Работы для узнавания больше о циклах работы).
Для участия в управлении питанием так, чтобы Вы получили уведомления о событиях питания гарантируйте, что Ваш драйвер правильно присоединяется в плоскость питания и изменения состояния электропитания дескриптора, Вы выполняете несколько вызовов и реализуете один виртуальный метод. IOService
класс обеспечивает все методы, описанные в этом разделе. Выполните шаги, упомянутые ниже для реализации основного управления питанием в драйвере.
Инициализируйте использование управления питанием
PMinit
.()
метод выделяет внутренние структуры данных управления питанием, позволяющие внутренним процессам отслеживать Ваш драйвер.В Вашем водительском
start
подпрограмма, после вызова к Вашему суперклассуstart
метод, выполните следующий вызов:PMinit();
Будьте присоединены в использование плоскости питания
joinPMtree
.(IOService*)
метод присоединяет переданный - в объекте драйвера в плоскость питания как дочерний элемент ее провайдера.В Вашем водительском
start
подпрограмма, после вызова кPMinit
и перед вызовом кregisterPowerDriver
(показанный на шаге 3), вызватьjoinPMtree
как показано ниже:provider->joinPMtree(this);
Предоставьте информацию о состояниях электропитания своего устройства и зарегистрируйте свой драйвер в управлении питанием.
Во-первых, объявите, что массив двух структур содержит информацию о Вашем устройстве прочь и на состояниях. Первый элемент в массиве должен содержать структуру, описывающую от состояния, и второй элемент массива должен содержать структуру, описывающую на состоянии. Как правило, драйвер переключает свое устройство на от состояния в ответ на событие сна и к на состоянии в ответ на событие следа, как описано в Событиях Питания
В Вашем водительском
start
подпрограмма, после вызова кjoinPMtree
, заполните дваIOPMPowerState
структуры, как показано ниже:// Declare an array of two IOPMPowerState structures (kMyNumberOfStates = 2).
static IOPMPowerState myPowerStates[kMyNumberOfStates];
// Zero-fill the structures.
bzero (myPowerStates, sizeof(myPowerStates));
// Fill in the information about your device's off state:
myPowerStates[0].version = 1;
myPowerStates[0].capabilityFlags = kIOPMPowerOff;
myPowerStates[0].outputPowerCharacter = kIOPMPowerOff;
myPowerStates[0].inputPowerRequirement = kIOPMPowerOff;
// Fill in the information about your device's on state:
myPowerStates[1].version = 1;
myPowerStates[1].capabilityFlags = kIOPMPowerOn;
myPowerStates[1].outputPowerCharacter = kIOPMPowerOn;
myPowerStates[1].inputPowerRequirement = kIOPMPowerOn;
В некоторых драйверах Вы могли бы видеть этот шаг, реализованный в коде, подобном следующему:
static IOPMPowerState myPowerStates[kMyNumberOfStates] = {
{1, kIOPMPowerOff, kIOPMPowerOff, kIOPMPowerOff, 0, 0, 0, 0, 0, 0, 0, 0},
{1, kIOPMPowerOn, kIOPMPowerOn, kIOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0}
};
Затем все еще в Вашем водительском
start
подпрограмма, зарегистрируйте свой драйвер в использовании управления питанием(IOService*,IOPMPowerState*,unsignedlong)
.registerPowerDriver
метод говорит управлению питанием, что переданный - в объекте драйвера может перейти устройство между состояниями электропитания, описанными в переданном - в массиве. После того, как Вы заполняетеIOPMPowerState
структуры, вызватьregisterPowerDriver
с Вашим состоянием электропитания выстраивают как показано ниже:registerPowerDriver (this, myPowerStates, kMyNumberOfStates);
Обработайте использование изменений состояния электропитания
setPowerState
. В то время как Ваш драйвер работает, Вы выполняете задачи, обрабатывающие сон и будящие уведомления о событии в Вашей реализации виртуальногоIOService
методsetPowerState
. Пример того, как сделать это, показан ниже:IOReturn MyIOServiceDriver::setPowerState ( unsigned long whichState, IOService * whatDevice )
// Note that it is safe to ignore the whatDevice parameter.
{
if ( 0 == whichState ) {
// Going to sleep. Perform state-saving tasks here.
} else {
// Waking up. Perform device initialization here.
}
if ( done )
return kIOPMAckImplied;
else
return (/* a number of microseconds that represents the maximum time required to prepare for the state change */);
}
Если Вы возвращаетесь
kIOPMAckImplied
, Вы сигнализируете завершение перехода к новому состоянию электропитания. Если Вы не возвращаетесьkIOPMAckImplied
и вместо этого возвратите максимальную сумму времени, которое требуется для подготовки устройства к изменению состояния электропитания, несомненно, необходимо будет вызватьacknowledgeSetPowerState
когда Вы закончили переход состояния электропитания. Если Вы не вызываетеacknowledgeSetPowerState
прежде чем отрезок времени, который Вы указываете, протек, система продолжает свое изменение состояния электропитания, как будто Вы возвратилисьkIOPMAckImplied
во-первых.Нерегистр от управления питанием, когда Ваш драйвер разгружает использование
PMstop
.PMstop
метод обрабатывает всю необходимую очистку, включая демонтаж Вашего драйвера от плоскости питания. ПосколькуPMstop
может поместить Ваши аппаратные средства в от состояния, несомненно, сможет завершить все аппаратные доступы перед вызовом его.В Вашем водительском
stop
подпрограмма после окончания всех вызовов, которые могли бы получить доступ аппаратным средствам, вызываетPMstop
как показано ниже:PMstop();
Реализация усовершенствованного управления питанием
Этот раздел копается глубже в функциональности управления питанием Набора I/O. Подавляющее большинство разработчиков драйвера не должно понимать информацию в этом разделе, потому что основное управление питанием (как описано в Решении, Как Реализовать Управление питанием в Вашем Драйвере) достаточно для большинства устройств. Если Ваше устройство может быть пассивно питанием, которым управляют, считайте Реализующее Основное Управление питанием вместо этого.
Необходимо считать этот раздел, если драйвер должен выполнить усовершенствованные задачи управления питанием, такие как определение безделья устройства, принятие мер, когда система собирается завершить работу или решает изменить состояние электропитания устройства. Конечно, активные драйверы совместно используют некоторые задачи с пассивными драйверами, а именно, инициализация и разрушение управления питанием. Перед чтением о задачах в этом разделе, поэтому, необходимо поглядеть на шаги в Реализации Основного Управления питанием, чтобы изучить, как инициализировать и завершить управление питанием в драйвере. Даже если Ваш драйвер должен выполнить усовершенствованные задачи управления питанием, он все еще должен вызвать PMinit
, joinPMtree
, registerPowerDriver
, и PMstop
и реализация setPowerState
, как показано в Реализации Основного Управления питанием
Этот раздел покрывает несколько задач, которые активный драйвер, возможно, должен был бы выполнить. Несмотря на то, что немного активных драйверов выполнят все задачи, большинство выполнит по крайней мере один. Каждая задача сопровождается фрагментом кода, чтобы помочь Вам реализовать его в своем драйвере.
Определяя и Используя многократные состояния электропитания
Как описано в информации об Устройствах и Состояниях электропитания о состояниях электропитания и возможностях устройства должно быть доступно управлению питанием Набора I/O. Несмотря на то, что большинство устройств имеет только два требуемых состояния электропитания, прочь и на, некоторые устройства имеют дополнительные состояния. Как показано на шаге 3 Реализации Основного Управления питанием Вы создаете массив IOPMPowerState
структуры, каждая из которых содержит информацию о возможностях устройства в каждом состоянии электропитания. Таблица 9-1 описывает поля в IOPMPowerState
структура, определяющаяся в IOPM.h
заголовочный файл.
Поле | Описание | Значение |
---|---|---|
| Номер версии этой структуры. | 1 |
| Возможность устройства в этом состоянии. | |
| Питание подано в этом состоянии. | |
| Входная мощность требуется в этом состоянии. | |
| Потребление средней мощности (в милливаттах) устройства в этом состоянии. | 0 |
| Дополнительная потребляемая мощность (в милливаттах) от отдельного источника питания, таких как батарея. | 0 |
| Питание, использованное устройством (в милливаттах) во вводе этого состояния от следующего самого низкого состояния. | 0 |
| Время (в микросекундах) требуемый для устройства ввести это состояние от следующего ниже утверждает; другими словами, время, требуемое программировать аппаратные средства. | 0 |
| Время (в микросекундах) требуемый позволить питанию рассчитаться после ввода этого состояния от следующего ниже утверждает. | 0 |
| Время (в микросекундах) требуемый для устройства ввести следующее ниже утверждает от этого состояния; другими словами, время, требуемое программировать аппаратные средства. | 0 |
| Время (в микросекундах) требуемый позволить питанию рассчитаться после ввода следующего ниже утверждает от этого состояния. | 0 |
| Питание (в милливаттах), который родитель питания в этом состоянии электронно в состоянии поставить его дочерним элементам. | 0 |
Как показано в Таблице 9-1 значения некоторых полей могут быть предоставлены IOPMPowerFlags
флаг. Таблица 9-2 показывает IOPMPowerFlags
флаги Вы, вероятно, будете использовать.
Флаг | Описание |
---|---|
| Устройство находится в состоянии полномочий. |
| Клиенты устройства могут использовать его в этом состоянии. |
| Устройство способно к своей самой высокой производительности в этом состоянии. |
| Вспомогательное питание PCI идет (используемый только устройствами в семье PCI). |
Управление питанием имеет следующие требования для массива IOPMPowerState
структуры Вы создаете в своем водительском start
метод:
IOPMPowerState
структура, описывающая Ваше устройство от состояния, должна быть первым элементом в массиве.IOPMPowerState
структура, описывающая Ваше устройство на (т.е. полномочия) состояние, должна быть последним элементом в массиве.Можно определить любое число промежуточных состояний электропитания, но
IOPMPowerState
структуры, описывающие их, не должны быть первыми или последними элементами массива.
После построения массива состояния электропитания к этим спецификациям вызвать registerPowerDriver
, передача в указателе на массив и число состояний электропитания. Перечисление 9-1 показывает один способ сделать это. Это также показывает драйвер, создающий цикл работы и настраивающий логический элемент команды для синхронизации кода изменения состояния питания, описанного в Изменении Состояния электропитания Устройства
Перечисление 9-1 , Создающее массив состояния электропитания и регистрирующее драйвер
enum { |
kMyOffPowerState = 0, |
kMyIdlePowerState = 1, |
kMyOnPowerState = 2 |
}; |
static IOPMPowerState myPowerStates[3] = { |
{1, kMyOffPowerState, kMyOffPowerState, kMyOffPowerState, 0, 0, 0, 0, 0, 0, 0, 0}, |
{1,kIOPMPowerOn, kIOPMPowerOn, kIOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0}, |
{1,kIOPMPowerOn, kIOPMPowerOn, kIOPMPowerOn, 0, 0, 0, 0, 0, 0, 0, 0} |
}; |
bool PMExampleDriver::start(IOService * provider) |
{ |
/* |
* Create a work loop and set up synchronization |
* using a command gate. |
*/ |
fWorkloop = IOWorkLoop::workLoop(); |
fGate = IOCommandGate::commandGate(this); |
if (fGate && fWorkloop) { |
fWorkloop->addEventSource(fGate); |
} |
* Initialize power management, join the power plane, |
* and register with power management. |
*/ |
PMinit(); |
provider->joinPMtree(this); |
registerPowerDriver(this, myPowerStates, 3); |
} |
Изменение состояния электропитания устройства
Драйвер ответственен за изменение состояния электропитания его устройства. Когда система собирается спать или след, большинство запросов на изменение состояния электропитания прибывает из управления питанием. Для активного драйвера также возможно узнать потребность изменить состояние электропитания ее устройства и подать заявку. Следующие разделы описывают обе задачи.
Ответ на запрос изменения состояния питания
Как с пассивным драйвером, активный драйвер должен переопределить setPowerState
метод и изменение состояние электропитания его устройства, когда это проинструктировано, чтобы сделать так. Порядковый номер передал в setPowerState
индекс к массиву состояния электропитания для устройства.
При разработке драйвера для выполнения в версиях OS X до v10.5, необходимо выполнить только минимальную обработку, требуемую изменить состояние электропитания устройства в Вашем setPowerState
метод. Любая дополнительная обработка должна быть выполнена за пределами setPowerState
метод и сопровождаемый вызовом к acknowledgeSetPowerState
когда это закончено. Это описано на шаге 4 Реализации Основного Управления питанием
Если с другой стороны Ваш драйвер будет работать в OS X v10.5 и позже, можно выполнить всю необходимую обработку в Вашем setPowerState
метод перед возвратом kIOPMAckImplied
. Важно понять, однако, что управление питанием вызывает setPowerState
метод от контекста вызова потока. Другими словами, управление питанием не выполняет автоматической синхронизации с помощью водительского цикла работы. Поэтому важно, что Вы продолжаете использовать логический элемент команды или другую блокировку, примитивную, чтобы гарантировать, что сериализируется доступ к состоянию Вашего устройства.
Как только возвращается Ваш драйвер kIOPMAckImplied
или вызовы acknowledgeSetPowerState
после дополнительной обработки управление питанием отмечает изменение питания, как завершено. Таким образом это важно для всех драйверов, независимо от версии OS X, для которого они предназначаются, чтобы избежать сообщать об изменении питания как завершенном, пока фактически не изменилось состояние электропитания устройства. Возможно, что другие изменения питания зависят от Ваших аппаратных средств, завершавших его изменение питания перед вызовом acknowledgeSetPowerState
.
Инициирование изменения состояния электропитания
Активный драйвер мог бы узнать потребность изменить состояние электропитания ее устройства, или через собственные механизмы или через некоторый другой объект. IOService
класс обеспечивает три метода, помогающие в этой задаче:
makeUsable
changePowerStateTo
changePowerStateToPriv
Любой объект в штабеле драйвера, включая пользовательский клиент (описанный в Интерфейсном устройством Механизме), может запросить, чтобы бездействующее устройство было сделано активным путем вызова makeUsable
метод на драйвере устройства. makeUsable
метод интерпретируется как запрос для помещения устройства в его самое высокое состояние электропитания.
Активный драйвер обычно вызывает changePowerStateTo
метод один раз в start
метод, для установки начального состояния электропитания. Позже, когда это хочет изменить состояние электропитания своего устройства, активный драйвер вызывает changePowerStateToPriv
метод, передающий в желаемом состоянии электропитания. Активный драйвер мог бы сделать это для закрытия в настоящее время не использующихся частей аппаратных средств.
Управление питанием использует состояния, переданные в к changePowerStateTo
и changePowerStateToPriv
определить новое состояние электропитания устройства. В частности управление питанием выбирает как новое состояние электропитания самое высокое значение следующих трех значений:
Состояние электропитания, установленное
changePowerStateToPriv
Состояние электропитания, установленное
changePowerStateTo
Самое высокое из всех состояний электропитания требуется водительскими дочерними элементами питания
Следующий фрагмент кода показывает, как драйвер может получить текущее состояние электропитания устройства (использующий getPowerState
метод представил в OS X v10.5), и затем запросите изменение состояния электропитания с changePowerStateToPriv
.
Реализация определения безделья и неактивной экономии электроэнергии
Когда устройство неактивно, оно может быть выключено для сохранения питания системы, которое особенно важно для портативных компьютеров, работающих на заряде батареи. Необходимо реализовать неактивную экономию электроэнергии в устройстве если:
Доступ к Вашему устройству неустойчив, и устройство часто оставляют неиспользованным в течение многих минут, часов или дней за один раз.
Ваше устройство использует существенное количество питания и помещение его в состоянии низкой мощности когда возможные результаты в существенной экономии электроэнергии.
Для реализации неактивной экономии электроэнергии необходимо определить, когда устройство неактивно, и укажите, сколько времени период безделья должен продлиться перед питанием устройства прочь. Вы определяете безделье путем предоставления информации доступа к устройствам к IOService
суперкласс, использующий эту информацию, в сочетании с периодом безделья, который Вы указываете, чтобы сказать Вашему устройству выключаться в подходящее время. IOService
класс обеспечивает два метода, которые активный драйвер использует, чтобы сделать это:
activityTickle
. На пути доступа Вашего устройства Вы вызываетеactivityTickle
каждый раз Ваш драйвер или любой другой клиент (включая приложение) инициировали аппаратный доступ. Это позволяет управлению питанием подтверждать, что Ваше устройство находится в применимом состоянии и отслеживать новые времена доступа для Вашего устройства.setIdleTimerPeriod
. Вы вызываетеsetIdleTimerPeriod
указать продолжительность сторожевого таймера, отслеживающего, сколько времени Ваше устройство может быть неактивным на полной мощности, прежде чем это должно будет быть выключено. Путем установки продолжительности периода неактивности Вы эффективно запускаете обратный отсчет, начинающийся после каждого доступа к устройствам.
Когда период неактивности истекает без любого действия устройства, управление питанием вызывает Вашу реализацию setPowerState
метод для понижения состояния электропитания устройства. Посмотрите Изменение Состояния электропитания Устройства для получения дополнительной информации о том, как реализовать этот метод.
Конечно, необходимо реагировать на любой запрос доступа к устройствам, который Вы получаете, в то время как Ваше устройство выключается первой установкой Вашего устройства к его состоянию полномочий. Поскольку Вы вызываете activityTickle
на пути доступа Вашего устройства управление питанием сразу предупреждено к факту, что некоторый объект запрашивает доступ к в настоящее время выключающемуся устройству. Когда это происходит, IOService
суперкласс автоматически вызывает makeUsable
на Вашем устройстве, в конечном счете приводящем к вызову к Вашей реализации setPowerState
метод.
Следующие шаги обрисовывают в общих чертах процесс определения безделья:
Укажите, сколько времени Ваше устройство должно остаться в мощном состоянии, в то время как неактивный. Как правило, одна минута является надлежащим интервалом.
Вызвать
setIdleTimerPeriod
, передача в неактивном интервале в секундах, как показано ниже:setIdleTimerPeriod ( 60 );
Сообщите управлению питанием каждый раз, когда объект (включая Ваш драйвер) инициирует доступ к устройствам.
По Вашему водительскому пути доступа к устройствам вызвать
activityTickle
, как показано ниже:activityTickle ( kIOPMSuperclassPolicy1, myDevicePowerOn );
Как показано выше, первый параметр к
activityTickle
kIOPMSuperclassPolicy1
, который указывает чтоIOService
когда период неактивности истечет, суперкласс отследит действие устройства и примет меры. Второй параметр указывает состояние электропитания, требуемое для этого действия, обычно на состоянии.Когда неактивный таймер истекает,
IOService
суперкласс проверяет, было ли какое-либо действие устройства начиная с последнего неактивного истечения срока таймера. Суперкласс определяет это путем проверки когдаactivityTickle
(kIOPMSuperclassPolicy1
) был в последний раз вызван.Если было действие устройства начиная с последнего истечения срока таймера,
IOService
суперкласс перезапускает таймер. Если никакое действие устройства не произошло,IOService
вызовы суперклассаsetPowerState
на Вашем драйвере для выключения устройства к следующему самому низкому состоянию.
После того, как Ваше устройство было выключено к более низкому состоянию посредством этого процесса, нового activityTickle
вызов заставляет управление питанием повышать питание устройства до уровня, требуемого для действия. Если устройство уже находится в корректном состоянии, суперкласс просто возвращается true
от вызова до activityTickle
( kIOPMSuperclassPolicy1
); иначе, возвраты суперкласса false
и доходы для создания устройства применимым.
Несмотря на то, что возвращаемое значение activityTickle
указывает, является ли устройство в применимом состоянии электропитания, лучше отслеживать текущее состояние электропитания Вашего устройства в Вашем драйвере, чем полагаться activityTickle
возвращаемое значение для этой информации. Это вызвано тем, что activityTickle
не вызывается на цикле работы управления питанием, и состояние электропитания устройства могло бы измениться прежде activityTickle
возвраты.
Получение уведомления об изменениях состояния электропитания в других устройствах
В некоторых случаях, когда другой драйвер изменяет состояние электропитания своего устройства, Ваш драйвер, возможно, должен был бы быть уведомлен. Скобки управления питанием Набора I/O каждое изменение в состоянии электропитания устройства с парой уведомлений. Эти уведомления поставлены через вызовы IOService
виртуальные методы powerStateWillChangeTo
и powerStateDidChangeTo
. Можно реализовать эти методы, чтобы получить уведомления и подготовиться к изменениям.
Ваш драйвер может зарегистрировать свой интерес к другому драйверу, пока следующее является истиной:
Драйвер, которым интересуется Ваш драйвер, должен быть присоединен в плоскость питания.
Ваш драйвер должен быть подклассом C++
IOService
, но это не должно быть присоединено в саму плоскость питания.
Для обнаружения, когда другой драйвер изменит состояние электропитания своего устройства выполните эти шаги в драйвере:
Вызовите
IOService
методregisterInterestedDriver
. Это гарантирует, что управление питанием уведомит Ваш драйвер, когда это отошлет уведомления изменения питания.Реализуйте виртуальное
IOService
методpowerStateWillChangeTo
. Этот метод вызывает драйвер устройства, когда это собирается изменить состояние электропитания устройства.Если Ваш драйвер подготовлен к изменению, он должен возвратиться
kIOPMAckImplied
; если требуется больше времени для подготовки, это должно возвратить верхний предел требуемого времени (в микросекундах).Если Ваш драйвер возвращает число, представляющее максимальное необходимое время для подготовки, это должно вызвать
acknowledgePowerChange
метод, когда это подготовлено. Если это не делает этого, и время, которое требуют на подготовку, протекает, другой драйвер продолжается, как будто Ваш драйвер подтвердил изменение. Это поведение препятствует тому, чтобы изменения состояния электропитания остановились из-за сбоя драйверов.Реализуйте виртуальное
IOService
методpowerStateDidChangeTo
. Этот метод вызывает драйвер устройства после того, как измененное состояние электропитания будет завершено.После того, как изменение в питании происходит, и питание рассчиталось к его новому уровню, управление питанием широковещательно передает этот факт ко всем заинтересованным объектам через
powerStateDidChangeTo
метод. Если устройство идет в сокращенное состояние электропитания, заинтересованные драйверы обычно не должны делать многого с этим уведомлением. Однако, если бы устройство идет в более высокое состояние электропитания, заинтересованные драйверы использовали бы это уведомление для подготовки к изменению, например, восстанавливая состояние или программируя устройство.В Вашей реализации
powerStateDidChangeTo
, Ваш драйвер может исследоватьIOPMPowerFlags
битовое поле (описанный в Таблице 9-2) передало в сделать ее определение; это битовое поле получено изcapabilityFlags
поле массива состояния электропитания, описанного в Таблице 9-1 Как сpowerStateWillChangeTo
, Ваш драйвер должен возвратитьсяkIOPMAckImplied
если это подготовилось к изменению. Если требуется время для подготовки, это должно возвратить максимальное требуемое время (в микросекундах); когда Ваш драйвер наконец готов к изменению, он должен вызватьacknowledgePowerChange
метод.
Когда Ваш драйвер больше не интересуется изменениями питания других драйверов, он должен вычеркнуть из списка себя, чтобы прекратить получать уведомления. Чтобы сделать это, вызовите IOService
метод deRegisterInterestedDriver
, обычно в Вашем водительском stop
метод.
Получение уведомлений завершения работы и перезапуска
В OS X предназначения драйвера v10.5 и позже, можно реализовать systemWillShutdown
метод для получения уведомления о нависшем завершении работы или перезапуске. Важно понять, однако, что нет ничего, что Ваш драйвер может сделать для предотвращения завершения работы, независимо от уведомления, которое это получает. Ваш драйвер способен к задерживающемуся завершению работы, но этому строго обескураживают, потому что это может сильно ухудшить опыт пользователя.
Не предполагайте, что Ваш драйвер должен реализовать systemWillShutdown
так, чтобы это могло реагировать на завершение работы и перезапустить уведомления путем закрытия аппаратных средств. Во время завершения работы питание собирается быть удаленным из Вашего устройства независимо от его текущего состояния. Точно так же, если система перезапустит, то Ваше устройство будет повторно инициализировано вскоре и, снова, его текущее состояние не важно. Большинство драйверов встроенного устройства в OS X не закрывает свои устройства, когда система собирается завершить работу или перезапустить, и большинство сторонних драйверов устройств должно сделать то же.
Несмотря на то, что большинство драйверов устройств не должно обрабатывать завершение работы или перезапуск всегда вообще, существует две допустимых причины драйвера для выполнения во времени перезапуска или завершении работы:
Архитектура требует, чтобы драйвер выполнил код во время завершения работы. Например, все драйверы, выполняющие DMA в основанном на Intel Macintosh, должны остановить активный DMA, прежде чем сможет завершиться завершение работы.
Драйвер должен работать на завершении работы или время перезапуска для предотвращения отрицательного пользовательского опыта. Например, когда питание удалено, драйвер аудио, возможно, должен был бы выключить усилители своего устройства для предотвращения слышимой «популярности».
systemWillShutdown
метод вызывают на всех элементах плоскости питания в порядке листа к корню. Водительское systemWillShutdown
метод вызывается только после того, как все его дочерние элементы питания выполнили свои задачи завершения работы. Это гарантирует, что дочерний объект может обработать свое завершение работы или перезапустить задачи, прежде чем выключится его родитель. Обратите внимание на то, что не необходимо вызвать Ваше водительское free
метод, когда система собирается перезапустить или завершить работу, потому что все драйверы разгружены и уничтожены в это время.
Когда драйвер получает systemWillShutdown
вызовите, это выполняет необходимые задачи подготовиться к завершению работы или перезапустить и затем вызывает реализацию его суперкласса метода. Это важно, потому что завершение работы системы остановится, пока все драйверы не закончили обрабатывать их systemWillShutdown
уведомления. Кроме отсрочки вызова к super::systemWillShutdown
пока запрос I/O в полете не завершается, необходимо сделать все возможное, чтобы избежать задерживать завершение работы. Перечисление 9-2 показывает, как переопределить systemWillShutdown
и получите уведомление о завершении работы или перезапуске.
Перечисление 9-2 , Получающее уведомление о завершении работы системы или перезапуске
void MyExampleDriver::systemWillShutdown( IOOptionBits specifier ) |
{ |
if ( kIOMessageSystemWillPowerOff == specifier ) { |
// System is shutting down; perform appropriate processing. |
} else if ( kIOMessageSystemWillRestart == specifier ) { |
// System is restarting; perform appropriate processing. |
} |
/* |
* You must call your superclass's implementation of systemWillShutdown as |
* soon as you're finished processing your shutdown or restart |
* because the shutdown will not proceed until you do. |
*/ |
super::systemWillShutdown( specifier ); |
} |
Хранение включается для будущего присоединения устройства
Для сохранения питания устройство, дочерние элементы которого все исчезли, обычно считается неактивным и сказано выключиться. Однако Ваше устройство, возможно, должно было бы остаться включенным, чтобы позволить новым дочерним элементам присоединять в любое время. Например, шина, возможно, должна была бы остаться включенной, даже когда нет никаких устройств, присоединенных к ней, потому что новое устройство, пытающееся присоединить, может вызвать катастрофический отказ путем попытки получить доступ к аппаратным средствам, это выключено.
IOService
класс обеспечивает метод, позволяющий Вам сохранять питание своего устройства на, даже если исчезли все его дочерние элементы питания. clampPowerOn
метод позволяет Вам указывать отрезок времени для хранения устройства в его самом высоком состоянии электропитания. Если необходимо сделать это в драйвере, вызовите clampPowerOn
метод перед последним дочерним элементом питания исчезает, как показано ниже:
// timeToStayOn is a length of time in milliseconds. |
clampPowerOn ( timeToStayOn ); |