Udostępnij przez


Selektywne wstrzymanie w sterownikach USB UMDF

W tym temacie opisano, jak sterowniki funkcji UMDF obsługują selektywne wstrzymywanie USB.

Ważne interfejsy API

Sterowniki funkcji UMDF mogą obsługiwać selektywne zawieszenie USB na jeden z dwóch sposobów:

  • Poprzez przejmowanie własności zasad zasilania i zarządzanie wyłączaniem urządzenia podczas bezczynności oraz wznawianiem.
  • Polegając na sterowniku WinUSB.sys, który firma Microsoft dostarcza, do zarządzania selektywnym zawieszaniem. WinUSB.sys jest instalowany jako część stosu urządzeń w trybie jądrowym podczas instalacji sterownika USB UMDF. WinUSB.sys implementuje podstawowe mechanizmy zawieszania i wznawiania operacji urządzenia USB.

Oba podejścia wymagają tylko niewielkiej ilości kodu. Przykład aplikacji IdleWake dostarczony w zestawie WDK pokazuje, jak obsługiwać selektywne wstrzymanie w sterowniku USB UMDF. Ten przykład można znaleźć w %WinDDK%\BuildNumber\Src\Usb\OsrUsbFx2\ UMDF\Fx2_Driver\IdleWake. Folder zawiera zarówno wersje PPO, jak i nie-PPO próbki.

Sterowniki UMDF obsługujące selektywne wstrzymanie muszą być zgodne z następującymi wytycznymi:

  • Sterownik UMDF może przejąć własność zasad zasilania dla swojego stosu urządzeń, ale nie jest to wymagane. Domyślnie podstawowy sterownik WinUSB.sys zarządza polityką zarządzania energią.
  • Sterownik UMDF, który obsługuje selektywne wstrzymanie i jest PPO może używać kolejek zarządzanych przez energię lub kolejek, które nie są zarządzane przez zasilanie. Sterownik UMDF, który obsługuje selektywne wstrzymanie, ale nie jest PPO, nie może używać kolejek z zarządzaniem energią.

Własność zasad zasilania w sterownikach USB UMDF

Domyślnie WinUSB.sys jest ppO dla stosu urządzenia, który zawiera sterownik USB UMDF. Począwszy od WDF 1.9, sterowniki USB oparte na UMDF mogą przejmować kontrolę nad zasadami zasilania. Ponieważ tylko jeden sterownik w każdym stosie urządzenia może być PPO, sterownik USB UMDF, który jest PPO, musi jawnie wyłączyć własność polityki zasilania w WinUSB.sys.

Aby uzyskać własność polityki zasilania w sterowniku USB UMDF

  1. Wywołaj metodę IWDFDeviceInitialize::SetPowerPolicyOwnership i przekaż wartość TRUE, zazwyczaj z metody IDriverEntry::OnDeviceAdd na obiekcie zwrotnym sterownika. Przykład:

    FxDeviceInit->SetPowerPolicyOwnership(TRUE);
    
  2. Wyłącz własność polityki zasilania w WinUSB. W pliku INF sterownika dołącz dyrektywę AddReg , która ustawia wartość WinUsbPowerPolicyOwnershipDisabled w rejestrze na wartość niezerową. Dyrektywa AddReg musi pojawić się w sekcji DDInstall.HW. Przykład:

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

Sterowniki USB UMDF, które obsługują selektywne wstrzymanie i są tworzone z wersjami WDF starszymi niż 1.9, nie mogą przejmować własności zasad zasilania. W przypadku tych wcześniejszych wersji WDF selektywne wstrzymanie USB działa prawidłowo tylko wtedy, gdy WinUSB.sys jest PPO.

Kolejki we/wy w sterownikach USB UMDF

W przypadku sterownika UMDF obsługującego selektywne wstrzymanie, to, czy sterownik UMDF zarządza polityką zasilania dla swojego urządzenia, determinuję typ kolejek wejścia/wyjścia, których może używać. Sterowniki UMDF, które obsługują selektywne wstrzymanie i są PPO, mogą używać kolejek zarządzanych energią lub niezarządzanych energią. Sterowniki USB UMDF obsługujące selektywne wstrzymanie, ale nie będące PPO nie powinny używać żadnych kolejek WE/WY zarządzanych zasilaniem.

Jeśli żądanie we/wy zostanie dostarczone dla kolejki zarządzanej przez energię, gdy urządzenie jest zawieszone, framework nie przekazuje żądania, chyba że sterownik jest PPO, jak pokazano na ilustracji w selektywnym zawieszaniu sterowników USB. Jeśli sterownik UMDF nie jest elementem PPO dla urządzenia, platforma nie może włączyć urządzenia w jego imieniu. W związku z tym żądanie pozostaje zablokowane w kolejce zarządzanej energią. Żądanie nigdy nie dociera do winUSB, więc usługa WinUSB nie może zasilać urządzenia. W związku z tym stos urządzeń może zatrzymać się.

Jeśli kolejka nie jest objęta zarządzaniem energią, framework przekazuje żądania we/wy do sterownika UMDF nawet gdy urządzenie jest wyłączone. Sterownik UMDF formatuje żądanie i przekazuje je w dół stosu urządzeń do domyślnego celu I/O jak zwykle. Kod specjalny nie jest wymagany. Gdy żądanie osiągnie wartość PPO (WinUSB.sys), WinUSB.sys uruchamia urządzenie i wykonuje wymaganą operację we/wy.

Przykładowy sterownik w %WinDDK%\BuildNumber\Src\Usb\OsrUsbFx2\umdf\Fx2_Driver\IdleWake definiuje stałą _NOT_POWER_POLICY_OWNER_ podczas kompilowania wersji sterownika innej niż PPO. Gdy sterownik tworzy kolejkę dla żądań odczytu i zapisu, określa, czy utworzyć kolejkę zarządzaną energetycznie, sprawdzając wartość stałej.

Aby utworzyć kolejkę, sterownik wywołuje zdefiniowaną przez sterownik metodę CMyQueue::Initialize , która przyjmuje następujące trzy parametry:

  • DispatchType, wartość wyliczenia WDF_IO_QUEUE_DISPATCH_TYPE wskazująca sposób, w jaki kolejka przetwarza żądania.
  • Domyślna, wartość logiczna wskazująca, czy kolejka jest kolejką domyślną.
  • PowerManaged, wartość logiczna wskazująca, czy kolejka jest objęta zarządzaniem energią.

Poniższy fragment kodu przedstawia wywołanie sterownika do metody CMyQueue::Initialize w ramach tworzenia kolejki odczytu i zapisu:

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

CMyQueue::Initialize następnie wywołuje metodę IWDFDevice::CreateIoQueue , aby utworzyć kolejkę w następujący sposób:

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

Ta sekwencja kodu powoduje, że kolejka domyślna wysyła żądania równolegle. Jeśli sterownik jest PPO, kolejka jest zarządzana pod względem energii, a jeśli sterownik nie jest PPO, kolejka nie jest zarządzana pod względem energii.

Obsługa selektywnego wstrzymania USB w UMDF PPO

Aby obsługiwać selektywne wstrzymanie, sterownik USB UMDF, który jest PPO dla stosu urządzenia, musi wykonać następujące czynności:

  1. Przejmij kontrolę nad zasadami zasilania dla stosu urządzeń, zazwyczaj w metodzie IDriverEntry::OnDeviceAdd w obiekcie wywołania zwrotnego sterownika, jak opisano wcześniej.
  2. Włącz selektywne zawieszenie, wywołując metodę IWDFDevice2::AssignS0IdleSettings na obiekcie urządzenia platformy.

Aby włączyć selektywne zawieszenie USB z PPO

  • Wywołaj metodę IWDFDevice2::AssignS0IdleSettings, zazwyczaj z metody OnPrepareHardware w obiekcie wywołania zwrotnego urządzenia. Ustaw parametry na AssignS0IdleSettings w następujący sposób:
    • IdleCaps do idleUsbSelectiveSuspend.
    • DxState do stanu uśpienia urządzenia, do którego platforma przenosi bezczynne urządzenie. W przypadku wstrzymania selektywnego USB określ wartość PowerDeviceMaximum, co oznacza, że framework powinien używać wartości określonej przez sterownik magistrali.
    • IdleTimeout to liczba milisekund, przez którą urządzenie musi pozostawać bezczynne, zanim platforma przeniesie je do DxState.
    • UserControlOfIdleSettings do IdleAllowUserControl, jeśli sterownik umożliwia użytkownikom zarządzanie ustawieniami bezczynności lub w inny sposób IdleDoNotAllowUserControl.
    • Ustawiono naWdfUseDefault, aby domyślnie włączyć selektywne wstrzymanie, ale umożliwić użytkownikowi zastąpienie domyślnego ustawienia.

W poniższym przykładzie pokazano, jak sterownik IdleWake_PPO wywołuje tę metodę w wewnętrznej metodzie CMyDevice::SetPowerManagement:

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

Jeśli sprzęt urządzenia może wygenerować sygnał wznawiania, sterownik UMDF może również obsługiwać wznawianie systemu z S1, S2 lub S3. Aby uzyskać szczegółowe informacje, zobacz Wznawianie systemu w sterowniku UMDF.

Obsługa selektywnego wstrzymania USB w sterowniku UMDF innego niż PPO

Sterownik funkcji UMDF, który nie jest PPO, może obsługiwać selektywne wstrzymanie, korzystając z możliwości udostępnianych przez leżący u podstaw sterownik WinUSB.sys. Sterownik UMDF musi powiadomić WinUSB, że urządzenie i sterownik obsługują selektywne wstrzymanie i musi włączyć selektywne wstrzymanie w pliku INF lub przez ustawienie zasad zasilania na obiekcie urządzenia docelowego USB.

Jeśli sterownik funkcji UMDF włącza selektywne wstrzymanie, podstawowy sterownik WinUSB.sys określa, kiedy urządzenie jest w stanie bezczynności. WinUSB uruchamia licznik limitu czasu bezczynności, gdy żadne transfery nie oczekują lub gdy jedyne oczekujące transfery są transferami IN na końcówce przerwanej lub zbiorczej. Domyślnie limit czasu bezczynności wynosi 5 sekund, ale sterownik UMDF może zmienić tę wartość domyślną.

Gdy WinUSB.sys ustali, że urządzenie jest bezczynne, wysyła żądanie wstrzymania urządzenia do stosu urządzeń działających w trybie jądra. Kierowca autobusu zmienia stan sprzętu zgodnie z potrzebami. Jeśli wszystkie funkcje urządzenia na porcie zostały zawieszone, port przechodzi do stanu selektywnego wstrzymania USB.

Jeśli żądanie we/wy zostanie odebrane WinUSB.sys podczas wstrzymania urządzenia, WinUSB.sys wznowi operację urządzenia, jeśli urządzenie musi być obsługiwane w celu obsługi żądania. Sterownik UMDF nie wymaga żadnego kodu do wznowienia urządzenia, gdy system pozostaje w S0. Jeśli sprzęt urządzenia może wygenerować sygnał wznawiania, sterownik UMDF może również obsługiwać wznawianie systemu ze stanów S1, S2 lub S3. Aby uzyskać szczegółowe informacje, zobacz Wznawianie systemu w sterowniku UMDF.

Sterownik UMDF, który nie jest PPO, może obsługiwać selektywne wstrzymanie pracy, wykonując następujące dwa kroki:

  1. Powiadamianie WinUSB.sys, że urządzenie i sterownik obsługują selektywne zawieszenie.
  2. Włączanie selektywnego wstrzymania USB.

Ponadto sterownik może opcjonalnie:

  • Ustaw wartość limitu czasu dla urządzenia.
  • Zezwalaj użytkownikowi na włączanie lub wyłączanie selektywnego wstrzymania.

Aby zapoznać się z przykładem implementacji selektywnego zawieszenia USB w sterowniku funkcji UMDF, który nie jest PPO, zobacz przykład Fx2_Driver w zestawie WDK. Ten przykład znajduje się w lokalizacji%WinDDK%\BuildNumber\Src\Usb\OsrUsbFx2\Umdf\Fx2_Driver\ IdleWake_Non-PPO.

Aby powiadomić WinUSB o obsłudze selektywnego wstrzymania

Aby powiadomić WinUSB.sys, że urządzenie może obsługiwać wstrzymanie selektywne USB, INF urządzenia musi dodać wartość DeviceIdleEnabled do klucza sprzętowego urządzenia i ustawić wartość na 1. W poniższym przykładzie pokazano, jak przykład Fx2_Driver dodaje i ustawia tę wartość w pliku WUDFOsrUsbFx2_IdleWakeNon-PPO.Inx:

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

Aby włączyć selektywne wstrzymanie USB

Sterownik USB UMDF może włączyć selektywne wstrzymanie USB zarówno w trakcie działania, jak i podczas instalacji w pliku INF.

  • Aby włączyć obsługę w czasie wykonywania, sterownik funkcji wywołuje metodę IWDFUsbTargetDevice::SetPowerPolicy i ustawia parametr PolicyType na AUTO_SUSPEND, a parametr Value na TRUE lub 1. W poniższym przykładzie pokazano, jak przykład Fx2_Driver umożliwia selektywne wstrzymanie w pliku DeviceNonPpo.cpp:

    BOOL AutoSuspend = TRUE;
    hr = m_pIUsbTargetDevice->SetPowerPolicy( AUTO_SUSPEND,
                                              sizeof(BOOL),
                                             (PVOID) &AutoSuspend );
    
  • Aby włączyć obsługę podczas instalacji, INF zawiera dyrektywę AddReg, która dodaje wartość DefaultIdleState do klucza sprzętowego urządzenia i ustawia wartość 1. Przykład:

    HKR,,"DefaultIdleState",0x00010001,1
    

Aby ustawić wartość limitu czasu bezczynności

Domyślnie WinUSB zawiesza urządzenie po 5 sekundach, jeśli nie ma oczekujących transferów lub jeśli jedynymi oczekującymi transferami są transfery IN na punkcie końcowym przerwań lub zbiorczym. Sterownik UMDF może zmienić tę wartość limitu czasu bezczynności podczas instalacji w pliku INF lub w czasie wykonywania.

  • Aby ustawić limit czasu bezczynności podczas instalacji, INF zawiera dyrektywę AddReg, która dodaje wartość DefaultIdleTimeout do klucza sprzętowego urządzenia i ustawia wartość na interwał limitu czasu w milisekundach. Poniższy przykład ustawia limit czasu na 7 sekund:

    HKR,,"DefaultIdleTimeout",0x00010001,7000
    
  • Aby ustawić limit czasu bezczynności w czasie działania, sterownik wywołuje IWDFUsbTargetDevice::SetPowerPolicy z parametrem PolicyType ustawionym na SUSPEND_DELAY i z wartością równą limitowi czasu bezczynności w milisekundach. W poniższym przykładzie z pliku Device.cpp, przykładowy kod Fx2_Driver ustawia limit czasu do 10 sekund.

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

Aby zapewnić użytkownikowi kontrolę nad selektywnym wstrzymaniem USB**

Sterowniki USB UMDF korzystające z selektywnego wstrzymania WinUSB mogą pozwalać użytkownikowi na opcjonalne włączanie lub wyłączanie selektywnego wstrzymania. W tym celu dołącz dyrektywę AddReg w INF, która dodaje wartość UserSetDeviceIdleEnabled do klucza sprzętowego urządzenia i ustawia tę wartość na 1. Poniżej przedstawiono ciąg do użycia dla dyrektywy AddReg:

HKR,,"UserSetDeviceIdleEnabled",0x00010001,1

Jeśli parametr UserSetDeviceIdleEnabled jest ustawiony, okno dialogowe Właściwości urządzenia zawiera kartę Zarządzanie energią, która umożliwia użytkownikowi włączenie lub wyłączenie selektywnego wstrzymania USB.

Przebudzenie systemu w sterowniku UMDF

W sterowniku UMDF obsługa wznawiania systemu jest niezależna od obsługi selektywnego wstrzymania. Sterownik USB UMDF może obsługiwać zarówno budzenie systemu, jak i selektywne wstrzymanie, ani budzenie systemu, ani selektywnego wstrzymania, albo tylko budzenie systemu, albo tylko selektywne wstrzymanie. Urządzenie obsługujące wznawianie systemu może wznawiać system ze stanu uśpienia (S1, S2 lub S3).

Sterownik PPO USB UMDF może obsługiwać wznawianie systemu, zapewniając informacje o wznawianiu dla obiektu sterownika frameworku. Gdy zdarzenie zewnętrzne wyzwala wznawianie systemu, platforma zwraca urządzenie do stanu roboczego.

Sterownik USB inny niż PPO może korzystać z obsługi wznawiania systemu, którą implementuje sterownik WinUSB.sys.

Aby obsługiwać wznawianie systemu w sterowniku USB UMDF, który pełni rolę PPO**

Wywołaj metodę IWDFDevice2::AssignSxWakeSettings w obiekcie urządzenia platformy z następującymi parametrami:

  • DxState to stan zasilania, do którego urządzenie przechodzi, gdy system wchodzi w stan Sx z możliwością wybudzenia. W przypadku urządzeń USB określ wartość PowerDeviceMaximum , aby użyć określonej wartości sterownika magistrali.
  • UserControlOfWakeSettings na WakeAllowUserControl, jeśli sterownik umożliwia użytkownikom zarządzanie ustawieniami wybudzania, w przeciwnym razie na WakeDoNotAllowUserControl.
  • Włączono opcję WdfUseDefault , aby włączyć funkcję wznawiania domyślnie, ale aby zezwolić ustawieniu użytkownika na zastąpienie wartości domyślnej.

W poniższym przykładzie pokazano, jak sterownik IdleWake_PPO wywołuje tę metodę w wewnętrznej metodzie CMyDevice::SetPowerManagement :

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

Aby włączyć wznawianie systemu za pomocą WinUSB w sterowniku bez PPO**

Aby włączyć wznawianie systemu za pośrednictwem winUSB, funkcja INF sterownika dodaje wartość rejestru SystemWakeEnabled do klucza sprzętowego urządzenia i ustawia go na 1. Przykład IdleWake_Non-PPO umożliwia wznawianie systemu w następujący sposób:

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

Ustawiając tę wartość, sterownik włącza funkcję wznawiania systemu i umożliwia użytkownikowi kontrolowanie możliwości wznawiania systemu przez urządzenie. W Menedżerze urządzeń strona właściwości ustawień zarządzania energią dla urządzenia zawiera pole wyboru, za pomocą którego użytkownik może włączyć lub wyłączyć wznawianie systemu.