Выборочная приостановка в драйверах USB UMDF

В этом разделе описывается, как драйверы функций UMDF поддерживают выборочную приостановку USB.

Важные API

Драйверы функций UMDF могут поддерживать выборочную приостановку USB двумя способами:

  • Затребовав владение политикой управления питанием и обрабатывая выключение и возобновление работы бездействующего устройства.
  • Опираясь на драйвер WinUSB.sys, предоставляемый корпорацией Майкрософт, для обработки выборочной приостановки. WinUSB.sys устанавливается как часть стека устройств в режиме ядра во время установки USB-драйвера UMDF. WinUSB.sys реализует базовые механизмы приостановки и возобновления работы USB-устройства.

Для обоих подходов требуется лишь небольшой объем кода. В примере IdleWake, который предоставляется в WDK, показано, как поддерживать выборочную приостановку в USB-драйвере UMDF. Этот пример можно найти в папке %WinDDK%\BuildNumber\Src\Usb\OsrUsbFx2\ UMDF\Fx2_Driver\IdleWake. Папка содержит как версии PPO, так и версии, отличные от PPO примера.

Драйверы UMDF, поддерживающие выборочную приостановку, должны соответствовать следующим рекомендациям:

  • Драйвер UMDF может претендовать на владение политикой управления питанием для своего стека устройств, но это не требуется. По умолчанию базовый драйвер WinUSB.sys владеет политикой управления питанием.
  • Драйвер UMDF, который поддерживает выборочную приостановку и является PPO, может использовать управляемые питанием очереди или очереди, которые не управляются питанием. Драйвер UMDF, который поддерживает выборочную приостановку, но не является PPO, не должен использовать очереди, управляемые питанием.

Владение политикой питания в USB-драйверах UMDF

По умолчанию WinUSB.sys является PPO для стека устройств, содержащего USB-драйвер UMDF. Начиная с WDF 1.9, USB-драйверы на основе UMDF могут претендовать на владение политикой питания. Так как PPO может быть только один драйвер в каждом стеке устройств, USB-драйвер UMDF, который является PPO, должен явно отключить владение политикой питания в WinUSB.sys.

Получение права владения политикой питания в USB-драйвере UMDF

  1. Вызовите IWDFDeviceInitialize::SetPowerPolicyOwnership и передайте значение TRUE, как правило, из метода IDriverEntry::OnDeviceAdd в объекте обратного вызова драйвера. Пример:

    FxDeviceInit->SetPowerPolicyOwnership(TRUE);
    
  2. Отключите владение политикой управления питанием в WinUSB. Добавьте в INF-файл драйвера директиву AddReg , которая устанавливает ненулевое значение WinUsbPowerPolicyOwnershipDisabled в реестре. Директива AddReg должна отображаться в разделе DDInstall.HW. Пример:

    [MyDriver_Install.NT.hw]
    AddReg=MyDriver_AddReg
    
    [MyDriver_AddReg]
    HKR,,"WinUsbPowerPolicyOwnershipDisabled",0x00010001,1
    

Usb-драйверы UMDF, поддерживающие выборочную приостановку и созданные с использованием версий WDF до 1.9, не должны претендовать на владение политикой питания. В этих более ранних версиях WDF выборочная приостановка USB работает правильно, только если WinUSB.sys является PPO.

Очереди ввода-вывода в USB-драйверах UMDF

Для драйвера UMDF, который поддерживает выборочную приостановку, то, является ли драйвер UMDF владельцем политики питания для своего устройства, определяет тип очередей ввода-вывода, которые он может использовать. Драйверы UMDF, которые поддерживают выборочную приостановку и являются ППО, могут использовать очереди, управляемые питанием или не управляемые питанием. USB-драйверы UMDF, которые поддерживают выборочную приостановку, но не являются PPO, не должны использовать очереди ввода-вывода, управляемые питанием.

Если запрос ввода-вывода поступает для очереди, управляемой питанием, пока устройство приостановлено, платформа не представляет запрос, если драйвер не является PPO, как показано на рисунке в разделе Выборочная приостановка в USB-драйверах. Если драйвер UMDF не является PPO для устройства, платформа не может включить устройство от его имени. В результате запрос остается застрявшим в очереди, управляемой питанием. Запрос никогда не достигает WinUSB, поэтому WinUSB не может подключить устройство. Следовательно, стек устройств может зависнуть.

Если очередь не управляется питанием, платформа отправляет запросы ввода-вывода драйверу UMDF, даже если устройство выключено. Драйвер UMDF форматирует запрос и пересылает его вниз по стеку устройства в целевой объект ввода-вывода по умолчанию обычным способом. Специальный код не требуется. Когда запрос достигает PPO (WinUSB.sys), WinUSB.sys включает устройство и выполняет необходимую операцию ввода-вывода.

Пример драйвера в %WinDDK%\BuildNumber\Src\Usb\OsrUsbFx2\umdf\Fx2_Driver\IdleWake определяет константу _NOT_POWER_POLICY_OWNER_ при сборке версии драйвера, отличной от PPO. Когда драйвер создает очередь для запросов на чтение и запись, он определяет, следует ли создавать управляемую питанием очередь, проверив наличие константы.

Чтобы создать очередь, драйвер вызывает определяемый драйвером метод CMyQueue::Initialize , который принимает следующие три параметра:

  • DispatchType— значение перечисления WDF_IO_QUEUE_DISPATCH_TYPE, указывающее, как очередь отправляет запросы.
  • Значение по умолчанию — логическое значение, указывающее, является ли очередь очередью по умолчанию.
  • PowerManaged — логическое значение, указывающее, управляется ли очередь питанием.

В следующем фрагменте кода показан вызов драйвера к методу CMyQueue::Initialize в рамках создания очереди чтения и записи:

#if defined(_NOT_POWER_POLICY_OWNER_)
    powerManaged = false;
#else
    powerManaged = true;
#endif  
hr = __super::Initialize(WdfIoQueueDispatchParallel,
                         true,
                         powerManaged,
                         );

Затем CMyQueue::Initialize вызывает IWDFDevice::CreateIoQueue для создания очереди следующим образом:

hr = m_FxDevice->CreateIoQueue(
                               callback,
                               Default,
                               DispatchType,
                               PowerManaged,
                               FALSE,
                               &fxQueue
                               );

Эта последовательность кода приводит к по умолчанию к очереди, которая отправляет запросы параллельно. Если драйвер является PPO, очередь управляется питанием, а если драйвер не является PPO, очередь не управляется питанием.

Поддержка выборочной приостановки USB в PPO UMDF

Для поддержки выборочной приостановки USB-драйвер UMDF, который является PPO для стека устройств, должен выполнять следующие действия:

  1. Запросить право владения политикой управления питанием для стека устройств, как правило, в методе IDriverEntry::OnDeviceAdd в объекте обратного вызова драйвера, как описано выше.
  2. Включите выборочную приостановку, вызвав метод IWDFDevice2::AssignS0IdleSettings в объекте устройства платформы.

Включение выборочной приостановки USB в PPO

  • Вызовите IWDFDevice2::AssignS0IdleSettings, как правило, из метода OnPrepareHardware объекта обратного вызова устройства. Задайте для параметров значение AssignS0IdleSettings следующим образом:
    • IdleCaps в IdleUsbSelectiveSuspend.
    • DxState — состояние спящего режима устройства, в которое платформа переводит неактивное устройство. Для выборочной приостановки по USB укажите PowerDeviceMaximum, который указывает, что платформа должна использовать значение, указанное драйвером шины.
    • IdleTimeout — количество миллисекундах, в которых устройство должно быть бездействующим, прежде чем платформа переведет его в DxState.
    • UserControlOfIdleSettingsIdleAllowUserControl , если драйвер позволяет пользователям управлять параметрами простоя, или idleDoNotAllowUserControl.
    • Включено для WdfUseDefault , чтобы включить выборочную приостановку по умолчанию, но разрешить параметру пользователя переопределить значение по умолчанию.

В следующем примере показано, как драйвер IdleWake_PPO вызывает этот метод во внутреннем методе CMyDevice::SetPowerManagement:

hr = m_FxDevice->AssignS0IdleSettings( IdleUsbSelectiveSuspend,
                                PowerDeviceMaximum,
                                IDLE_TIMEOUT_IN_MSEC,
                                IdleAllowUserControl,
                                WdfUseDefault);                                                                                                   

Если оборудование устройства может генерировать сигнал пробуждения, драйвер UMDF также может поддерживать пробуждение системы из S1, S2 или S3. Дополнительные сведения см. в разделе Пробуждение системы в драйвере UMDF.

Поддержка выборочной приостановки USB в драйвере UMDF, отличном от PPO

Драйвер функции UMDF, который не является PPO, может поддерживать выборочную приостановку с помощью функций базового драйвера WinUSB.sys. Драйвер UMDF должен уведомить WinUSB о том, что устройство и драйвер поддерживают выборочную приостановку, и должен включить выборочную приостановку в INF-файле или путем установки политики питания для объекта целевого устройства USB.

Если драйвер функции UMDF включает выборочную приостановку, базовый драйвер WinUSB.sys определяет, когда устройство неактивно. WinUSB запускает счетчик времени ожидания простоя, если передача не ожидается или если единственными ожидающих передачи являются передачи в прерванной или массовой конечной точке. По умолчанию время ожидания простоя составляет 5 секунд, но драйвер UMDF может изменить это значение по умолчанию.

Когда WinUSB.sys определяет, что устройство неактивно, он отправляет запрос на приостановку устройства в стеке устройств в режиме ядра. Драйвер шины соответствующим образом изменяет состояние оборудования. Если все функции устройства на порту приостановлены, порт переходит в состояние выборочной приостановки USB.

Если запрос ввода-вывода поступает на WinUSB.sys во время приостановки устройства, WinUSB.sys возобновляет работу устройства, если устройство должно быть подключено для обслуживания запроса. Драйвер UMDF не требует никакого кода для возобновления работы устройства, пока система остается в S0. Если оборудование устройства может генерировать сигнал пробуждения, драйвер UMDF также может поддерживать пробуждение системы из S1, S2 или S3. Дополнительные сведения см. в разделе Пробуждение системы в драйвере UMDF.

Драйвер UMDF, который не является PPO, может поддерживать выборочную приостановку, выполнив следующие два действия:

  1. Уведомление WinUSB.sys, что устройство и драйвер поддерживают выборочную приостановку.
  2. Включение выборочной приостановки USB.

Кроме того, драйвер может при необходимости:

  • Задайте значение времени ожидания для устройства.
  • Разрешить пользователю включать или отключать выборочную приостановку.

Пример реализации выборочной приостановки USB в драйвере функции USB UMDF, который не является PPO, см. в примере Fx2_Driver в WDK. Этот пример находится в папке %WinDDK%\BuildNumber\Src\Usb\OsrUsbFx2\Umdf\Fx2_Driver\ IdleWake_Non-PPO.

Уведомление WinUSB о выборочной приостановке поддержки

Чтобы уведомить WinUSB.sys о том, что устройство может поддерживать выборочную приостановку USB, inf-файл устройства должен добавить значение DeviceIdleEnabled в аппаратный ключ устройства и установить значение 1. В следующем примере показано, как пример Fx2_Driver добавляет и задает это значение в файл WUDFOsrUsbFx2_IdleWakeNon-PPO.Inx:

[OsrUsb_Device_AddReg]
...
HKR,,"DeviceIdleEnabled",0x00010001,1

Включение выборочной приостановки USB

Usb-драйвер UMDF может включить выборочную приостановку USB во время выполнения или во время установки в INF.

  • Чтобы включить поддержку во время выполнения, драйвер функции вызывает IWDFUsbTargetDevice::SetPowerPolicy и задает параметру PolicyType значение AUTO_SUSPEND, а параметру Value значение TRUE или 1. В следующем примере показано, как пример Fx2_Driver включает выборочную приостановку в файле DeviceNonPpo.cpp:

    BOOL AutoSuspend = TRUE;
    hr = m_pIUsbTargetDevice->SetPowerPolicy( AUTO_SUSPEND,
                                              sizeof(BOOL),
                                             (PVOID) &AutoSuspend );
    
  • Чтобы включить поддержку во время установки, INF включает директиву AddReg, которая добавляет значение DefaultIdleState в аппаратный ключ устройства и устанавливает значение 1. Пример:

    HKR,,"DefaultIdleState",0x00010001,1
    

Установка значения времени ожидания простоя

По умолчанию WinUSB приостанавливает работу устройства через 5 секунд, если нет ожидающих передачи или если только ожидающие передачи являются передачами IN в прерывании или массовой конечной точке. Драйвер UMDF может изменить это значение времени ожидания простоя при установке в INF-файле или во время выполнения.

  • Чтобы задать время ожидания простоя при установке, INF включает директиву AddReg, которая добавляет значение DefaultIdleTimeout в аппаратный ключ устройства и задает значение интервала ожидания в миллисекундах. В следующем примере устанавливается время ожидания в 7 секунд:

    HKR,,"DefaultIdleTimeout",0x00010001,7000
    
  • Чтобы задать время ожидания простоя во время выполнения, драйвер вызывает IWDFUsbTargetDevice::SetPowerPolicy с параметром PolicyType, равным SUSPEND_DELAY, а Значение — значением времени ожидания простоя в миллисекундах. В следующем примере из файла Device.cpp в примере Fx2_Driver устанавливается время ожидания в 10 секунд:

    HRESULT hr;
    ULONG value;
    value = 10 * 1000;
    hr = m_pIUsbTargetDevice->SetPowerPolicy( SUSPEND_DELAY,
                                              sizeof(ULONG),
                                             (PVOID) &value );
    

Предоставление пользовательского контроля выборочной приостановки USB**

Usb-драйверы UMDF, использующие поддержку выборочной приостановки WinUSB, могут при необходимости разрешить пользователю включать или отключать выборочную приостановку. Для этого включите в INF директиву AddReg, которая добавляет значение UserSetDeviceIdleEnabled в аппаратный ключ устройства и задает значение 1. Ниже показана строка, используемая для директивы AddReg:

HKR,,"UserSetDeviceIdleEnabled",0x00010001,1

Если задан параметр UserSetDeviceIdleEnabled, в диалоговом окне Свойства устройства есть вкладка Управление питанием, которая позволяет пользователю включать или отключать выборочную приостановку USB.

Пробуждение системы в драйвере UMDF

В драйвере UMDF поддержка пробуждения системы не зависит от поддержки выборочной приостановки. Usb-драйвер UMDF может поддерживать как системный пробуждение, так и выборочную приостановку, ни системный или выборочный приостановка, либо системный пробуждение или выборочную приостановку. Устройство, поддерживающее пробуждение системы, может выбудить систему из спящего режима (S1, S2 или S3).

Драйвер PPO UMDF USB может поддерживать пробуждение системы, предоставляя сведения о пробуждении для объекта драйвера платформы. Когда внешнее событие запускает пробуждение системы, платформа возвращает устройство в рабочее состояние.

Драйвер USB без PPO может использовать поддержку пробуждения системы, реализованную драйвером WinUSB.sys.

Поддержка пробуждения системы в usb-драйвере UMDF, который является PPO**

Вызовите метод IWDFDevice2::AssignSxWakeSettings в объекте устройства платформы со следующими параметрами:

  • DxState переходит в состояние питания, в которое устройство переходит, когда система переходит в состояние SX с возможностью пробуждения. Для USB-устройств укажите PowerDeviceMaximum , чтобы использовать значение, указанное драйвером шины.
  • UserControlOfWakeSettings в WakeAllowUserControl , если ваш драйвер позволяет пользователям управлять параметрами пробуждения или иным образом использовать WakeDoNotAllowUserControl.
  • Включено для WdfUseDefault , чтобы включить пробуждение по умолчанию, но разрешить пользователю переопределить значение по умолчанию.

В следующем примере показано, как драйвер IdleWake_PPO вызывает этот метод во внутреннем методе CMyDevice::SetPowerManagement :

hr = m_FxDevice->AssignSxWakeSettings( PowerDeviceMaximum,
                                       WakeAllowUserControl,
                                       WdfUseDefault);

Включение пробуждения системы через WinUSB в драйвере, отличном от PPO**

Чтобы включить пробуждение системы через WinUSB, inf-файл драйвера добавляет значение реестра SystemWakeEnabled в аппаратный ключ устройства и устанавливает для него значение 1. Пример IdleWake_Non-PPO включает пробуждение системы следующим образом:

[OsrUsb_Device_AddReg]
...
HKR,,"SystemWakeEnabled",0x00010001,1

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