Управление питанием

Функциональность управления питанием Набора I/O стремится минимизировать питание, использованное компьютерной системой, поведение, которое особенно важно для портативных компьютеров, где время работы от батареи является фундаментальным свойством. Управление питанием также налагает организованную последовательность действий, таких как сохранение и восстановление состояния, когда система (или часть его) сны или следы.

Эта глава фокусируется на управлении питанием для в драйверах ядра, управляющих аппаратными средствами. Считайте эту главу, чтобы узнать об управлении питанием в OS X и узнать, какой уровень управления питанием поддерживают Вас, должен обеспечить и как реализовать его. Несмотря на то, что управление питанием является сложной технологией, большинством потребности в драйверах ядра реализовать только самую основную функциональность для участия успешно в управлении питанием OS X.

Точный набор ответственности управления питанием, которую должен выполнить Ваш драйвер, зависит от факторов такой как, сколько поддержки Ваш водительский суперкласс предоставляет, получает ли Ваше устройство питание от системной шины (такой как PCI), и к тому, какие события питания Ваш драйвер должен ответить.

Если Вы незнакомы с управлением питанием в 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  плоскость питания, показанная в Проводнике Реестра I/O

На рисунке 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 обеспечивают некоторый тип функциональности управления питанием:

Даже если Ваш драйвер является подклассом семьи I/O Kit, не предоставляющей поддержки управления питанием, или если Ваш драйвер является прямым подклассом IOService, это может все еще быть пассивный участник управления питанием, пока это только реагирует на инициируемые в систему события питания. Если с другой стороны Ваш драйвер должен определить, когда Ваше устройство неактивно, или выполните задачи перед завершением работы, необходимо реализовать усовершенствованное управление питанием.

Если Вы решаете разработать пассивный драйвер, необходимо считать Реализующее Основное Управление питанием, чтобы изучить, как участвовать в управлении питанием и реагировать на сон и события следа. Вы не должны читать никакие другие разделы в этой главе.

Если Ваш драйвер должен быть активным диспетчером электропитания, необходимо также считать Реализующее Основное Управление питанием Тогда, необходимо считать Реализацию Усовершенствованное Управление питанием для руководства при реализации определенных задач.

Реализация основного управления питанием

Как определено в Решении, Как Реализовать Управление питанием в Вашем Драйвере, пассивный драйвер только реагирует на сон и события следа; это не инициирует изменяющего состояние электропитания действия. Ваш пассивный драйвер должен сделать следующие вещи обработать сон и след:

Для участия в управлении питанием так, чтобы Вы получили уведомления о событиях питания гарантируйте, что Ваш драйвер правильно присоединяется в плоскость питания и изменения состояния электропитания дескриптора, Вы выполняете несколько вызовов и реализуете один виртуальный метод. IOService класс обеспечивает все методы, описанные в этом разделе. Выполните шаги, упомянутые ниже для реализации основного управления питанием в драйвере.

  1. Инициализируйте использование управления питанием PMinit. () метод выделяет внутренние структуры данных управления питанием, позволяющие внутренним процессам отслеживать Ваш драйвер.

    В Вашем водительском start подпрограмма, после вызова к Вашему суперклассу start метод, выполните следующий вызов:

    PMinit();
  2. Будьте присоединены в использование плоскости питания joinPMtree. (IOService*) метод присоединяет переданный - в объекте драйвера в плоскость питания как дочерний элемент ее провайдера.

    В Вашем водительском start подпрограмма, после вызова к PMinit и перед вызовом к registerPowerDriver (показанный на шаге 3), вызвать joinPMtree как показано ниже:

    provider->joinPMtree(this);
  3. Предоставьте информацию о состояниях электропитания своего устройства и зарегистрируйте свой драйвер в управлении питанием.

    1. Во-первых, объявите, что массив двух структур содержит информацию о Вашем устройстве прочь и на состояниях. Первый элемент в массиве должен содержать структуру, описывающую от состояния, и второй элемент массива должен содержать структуру, описывающую на состоянии. Как правило, драйвер переключает свое устройство на от состояния в ответ на событие сна и к на состоянии в ответ на событие следа, как описано в Событиях Питания

      В Вашем водительском 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}
      };
    2. Затем все еще в Вашем водительском start подпрограмма, зарегистрируйте свой драйвер в использовании управления питанием (IOService*,IOPMPowerState*,unsignedlong). registerPowerDriver метод говорит управлению питанием, что переданный - в объекте драйвера может перейти устройство между состояниями электропитания, описанными в переданном - в массиве. После того, как Вы заполняете IOPMPowerState структуры, вызвать registerPowerDriver с Вашим состоянием электропитания выстраивают как показано ниже:

      registerPowerDriver (this, myPowerStates, kMyNumberOfStates);
  4. Обработайте использование изменений состояния электропитания 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 во-первых.

  5. Нерегистр от управления питанием, когда Ваш драйвер разгружает использование PMstop. PMstop метод обрабатывает всю необходимую очистку, включая демонтаж Вашего драйвера от плоскости питания. Поскольку PMstop может поместить Ваши аппаратные средства в от состояния, несомненно, сможет завершить все аппаратные доступы перед вызовом его.

    В Вашем водительском stop подпрограмма после окончания всех вызовов, которые могли бы получить доступ аппаратным средствам, вызывает PMstop как показано ниже:

    PMstop();

Реализация усовершенствованного управления питанием

Этот раздел копается глубже в функциональности управления питанием Набора I/O. Подавляющее большинство разработчиков драйвера не должно понимать информацию в этом разделе, потому что основное управление питанием (как описано в Решении, Как Реализовать Управление питанием в Вашем Драйвере) достаточно для большинства устройств. Если Ваше устройство может быть пассивно питанием, которым управляют, считайте Реализующее Основное Управление питанием вместо этого.

Необходимо считать этот раздел, если драйвер должен выполнить усовершенствованные задачи управления питанием, такие как определение безделья устройства, принятие мер, когда система собирается завершить работу или решает изменить состояние электропитания устройства. Конечно, активные драйверы совместно используют некоторые задачи с пассивными драйверами, а именно, инициализация и разрушение управления питанием. Перед чтением о задачах в этом разделе, поэтому, необходимо поглядеть на шаги в Реализации Основного Управления питанием, чтобы изучить, как инициализировать и завершить управление питанием в драйвере. Даже если Ваш драйвер должен выполнить усовершенствованные задачи управления питанием, он все еще должен вызвать PMinit, joinPMtree, registerPowerDriver, и PMstop и реализация setPowerState, как показано в Реализации Основного Управления питанием

Этот раздел покрывает несколько задач, которые активный драйвер, возможно, должен был бы выполнить. Несмотря на то, что немного активных драйверов выполнят все задачи, большинство выполнит по крайней мере один. Каждая задача сопровождается фрагментом кода, чтобы помочь Вам реализовать его в своем драйвере.

Определяя и Используя многократные состояния электропитания

Как описано в информации об Устройствах и Состояниях электропитания о состояниях электропитания и возможностях устройства должно быть доступно управлению питанием Набора I/O. Несмотря на то, что большинство устройств имеет только два требуемых состояния электропитания, прочь и на, некоторые устройства имеют дополнительные состояния. Как показано на шаге 3 Реализации Основного Управления питанием Вы создаете массив IOPMPowerState структуры, каждая из которых содержит информацию о возможностях устройства в каждом состоянии электропитания. Таблица 9-1 описывает поля в IOPMPowerState структура, определяющаяся в IOPM.h заголовочный файл.

Табличные 9-1  Поля и надлежащие значения в IOPMPowerState структура

Поле

Описание

Значение

version

Номер версии этой структуры.

1

capabilityFlags

Возможность устройства в этом состоянии.

IOPMPowerFlags флаг.

outputPowerCharacter

Питание подано в этом состоянии.

IOPMPowerFlags флаг.

inputPowerRequirement

Входная мощность требуется в этом состоянии.

IOPMPowerFlags флаг.

staticPower

Потребление средней мощности (в милливаттах) устройства в этом состоянии.

0

unbudgetedPower

Дополнительная потребляемая мощность (в милливаттах) от отдельного источника питания, таких как батарея.

0

powerToAttain

Питание, использованное устройством (в милливаттах) во вводе этого состояния от следующего самого низкого состояния.

0

timeToAttain

Время (в микросекундах) требуемый для устройства ввести это состояние от следующего ниже утверждает; другими словами, время, требуемое программировать аппаратные средства.

0

settleUpTime

Время (в микросекундах) требуемый позволить питанию рассчитаться после ввода этого состояния от следующего ниже утверждает.

0

timeToLower

Время (в микросекундах) требуемый для устройства ввести следующее ниже утверждает от этого состояния; другими словами, время, требуемое программировать аппаратные средства.

0

settleDownTime

Время (в микросекундах) требуемый позволить питанию рассчитаться после ввода следующего ниже утверждает от этого состояния.

0

powerDomainBudget

Питание (в милливаттах), который родитель питания в этом состоянии электронно в состоянии поставить его дочерним элементам.

0

Как показано в Таблице 9-1 значения некоторых полей могут быть предоставлены IOPMPowerFlags флаг. Таблица 9-2 показывает IOPMPowerFlags флаги Вы, вероятно, будете использовать.

Табличные 9-2  флаги Питания, описывающие функции устройств

Флаг

Описание

kIOPMPowerOn

Устройство находится в состоянии полномочий.

kIOPMDeviceUsable

Клиенты устройства могут использовать его в этом состоянии.

kIOPMMaxPerformance

Устройство способно к своей самой высокой производительности в этом состоянии.

kIOPMAuxPowerOn

Вспомогательное питание 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.

enum {
    kMyOffState = 0,
    kMyOnState = 1
};
/*
 * Make sure the hardware is in the ON state
 * before accessing it. If it's powered off, call changePowerStateToPriv
 * to put the device in the ON state.
 */
if (getPowerState() == kMyOnState)
{
    /* Device is ON. OK to access hardware. */
} else {
    changePowerStateToPriv( kMyOnState );
    /*
     * Note: If your device has been powered off for a system sleep, you cannot
     * try to adjust your power state upwards. You are locked in your OFF or
     * low-power state until system power is restored on wake.
     */
 
    /*
     * Although changePowerStateToPriv returns immediately,
     * it is _NOT_ safe to touch the hardware yet. You must wait until you
     * receive your setPowerState() call before you can safely modify
     * the hardware.
     */
}

Реализация определения безделья и неактивной экономии электроэнергии

Когда устройство неактивно, оно может быть выключено для сохранения питания системы, которое особенно важно для портативных компьютеров, работающих на заряде батареи. Необходимо реализовать неактивную экономию электроэнергии в устройстве если:

  • Доступ к Вашему устройству неустойчив, и устройство часто оставляют неиспользованным в течение многих минут, часов или дней за один раз.

  • Ваше устройство использует существенное количество питания и помещение его в состоянии низкой мощности когда возможные результаты в существенной экономии электроэнергии.

Для реализации неактивной экономии электроэнергии необходимо определить, когда устройство неактивно, и укажите, сколько времени период безделья должен продлиться перед питанием устройства прочь. Вы определяете безделье путем предоставления информации доступа к устройствам к IOService суперкласс, использующий эту информацию, в сочетании с периодом безделья, который Вы указываете, чтобы сказать Вашему устройству выключаться в подходящее время. IOService класс обеспечивает два метода, которые активный драйвер использует, чтобы сделать это:

  • activityTickle. На пути доступа Вашего устройства Вы вызываете activityTickle каждый раз Ваш драйвер или любой другой клиент (включая приложение) инициировали аппаратный доступ. Это позволяет управлению питанием подтверждать, что Ваше устройство находится в применимом состоянии и отслеживать новые времена доступа для Вашего устройства.

  • setIdleTimerPeriod. Вы вызываете setIdleTimerPeriod указать продолжительность сторожевого таймера, отслеживающего, сколько времени Ваше устройство может быть неактивным на полной мощности, прежде чем это должно будет быть выключено. Путем установки продолжительности периода неактивности Вы эффективно запускаете обратный отсчет, начинающийся после каждого доступа к устройствам.

Когда период неактивности истекает без любого действия устройства, управление питанием вызывает Вашу реализацию setPowerState метод для понижения состояния электропитания устройства. Посмотрите Изменение Состояния электропитания Устройства для получения дополнительной информации о том, как реализовать этот метод.

Конечно, необходимо реагировать на любой запрос доступа к устройствам, который Вы получаете, в то время как Ваше устройство выключается первой установкой Вашего устройства к его состоянию полномочий. Поскольку Вы вызываете activityTickle на пути доступа Вашего устройства управление питанием сразу предупреждено к факту, что некоторый объект запрашивает доступ к в настоящее время выключающемуся устройству. Когда это происходит, IOService суперкласс автоматически вызывает makeUsable на Вашем устройстве, в конечном счете приводящем к вызову к Вашей реализации setPowerState метод.

Следующие шаги обрисовывают в общих чертах процесс определения безделья:

  1. Укажите, сколько времени Ваше устройство должно остаться в мощном состоянии, в то время как неактивный. Как правило, одна минута является надлежащим интервалом.

    Вызвать setIdleTimerPeriod, передача в неактивном интервале в секундах, как показано ниже:

    setIdleTimerPeriod ( 60 );
  2. Сообщите управлению питанием каждый раз, когда объект (включая Ваш драйвер) инициирует доступ к устройствам.

    По Вашему водительскому пути доступа к устройствам вызвать activityTickle, как показано ниже:

    activityTickle ( kIOPMSuperclassPolicy1, myDevicePowerOn );

    Как показано выше, первый параметр к activityTickle kIOPMSuperclassPolicy1, который указывает что IOService когда период неактивности истечет, суперкласс отследит действие устройства и примет меры. Второй параметр указывает состояние электропитания, требуемое для этого действия, обычно на состоянии.

  3. Когда неактивный таймер истекает, IOService суперкласс проверяет, было ли какое-либо действие устройства начиная с последнего неактивного истечения срока таймера. Суперкласс определяет это путем проверки когда activityTickle ( kIOPMSuperclassPolicy1 ) был в последний раз вызван.

  4. Если было действие устройства начиная с последнего истечения срока таймера, IOService суперкласс перезапускает таймер. Если никакое действие устройства не произошло, IOService вызовы суперкласса setPowerState на Вашем драйвере для выключения устройства к следующему самому низкому состоянию.

После того, как Ваше устройство было выключено к более низкому состоянию посредством этого процесса, нового activityTickle вызов заставляет управление питанием повышать питание устройства до уровня, требуемого для действия. Если устройство уже находится в корректном состоянии, суперкласс просто возвращается true от вызова до activityTickle ( kIOPMSuperclassPolicy1 ); иначе, возвраты суперкласса false и доходы для создания устройства применимым.

Несмотря на то, что возвращаемое значение activityTickle указывает, является ли устройство в применимом состоянии электропитания, лучше отслеживать текущее состояние электропитания Вашего устройства в Вашем драйвере, чем полагаться activityTickle возвращаемое значение для этой информации. Это вызвано тем, что activityTickle не вызывается на цикле работы управления питанием, и состояние электропитания устройства могло бы измениться прежде activityTickle возвраты.

Получение уведомления об изменениях состояния электропитания в других устройствах

В некоторых случаях, когда другой драйвер изменяет состояние электропитания своего устройства, Ваш драйвер, возможно, должен был бы быть уведомлен. Скобки управления питанием Набора I/O каждое изменение в состоянии электропитания устройства с парой уведомлений. Эти уведомления поставлены через вызовы IOService виртуальные методы powerStateWillChangeTo и powerStateDidChangeTo. Можно реализовать эти методы, чтобы получить уведомления и подготовиться к изменениям.

Ваш драйвер может зарегистрировать свой интерес к другому драйверу, пока следующее является истиной:

  • Драйвер, которым интересуется Ваш драйвер, должен быть присоединен в плоскость питания.

  • Ваш драйвер должен быть подклассом C++ IOService, но это не должно быть присоединено в саму плоскость питания.

Для обнаружения, когда другой драйвер изменит состояние электропитания своего устройства выполните эти шаги в драйвере:

  1. Вызовите IOService метод registerInterestedDriver. Это гарантирует, что управление питанием уведомит Ваш драйвер, когда это отошлет уведомления изменения питания.

  2. Реализуйте виртуальное IOService метод powerStateWillChangeTo. Этот метод вызывает драйвер устройства, когда это собирается изменить состояние электропитания устройства.

    Если Ваш драйвер подготовлен к изменению, он должен возвратиться kIOPMAckImplied; если требуется больше времени для подготовки, это должно возвратить верхний предел требуемого времени (в микросекундах).

    Если Ваш драйвер возвращает число, представляющее максимальное необходимое время для подготовки, это должно вызвать acknowledgePowerChange метод, когда это подготовлено. Если это не делает этого, и время, которое требуют на подготовку, протекает, другой драйвер продолжается, как будто Ваш драйвер подтвердил изменение. Это поведение препятствует тому, чтобы изменения состояния электропитания остановились из-за сбоя драйверов.

  3. Реализуйте виртуальное 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 );