Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этой статье приведен обзор функций приостановки и функции удаленного пробуждения для устройств универсальной последовательной шины (USB) 3.0 с несколькими функциями (составные устройства). В этой статье вы узнаете о реализации этих функций в драйвере, который управляет составным устройством. Статья относится к составным драйверам, которые заменяют Usbccgp.sys.
Спецификация универсальной последовательной шины (USB) 3.0 определяет новую функцию, называемую приостановкой функции. Эта функция позволяет отдельной функции составного устройства входить в состояние низкой мощности независимо от других функций. Рассмотрим составное устройство, определяющее функцию клавиатуры и другую функцию для мыши. Пользователь сохраняет функцию клавиатуры в рабочем состоянии, но не перемещает мышь в течение определенного периода времени. Клиентский драйвер мыши может обнаружить состояние простоя функции и отправить функцию для приостановки состояния, пока функция клавиатуры остается в рабочем состоянии.
Все устройство может переходить к состоянию приостановки независимо от состояния питания любой функции на устройстве. Если определенная функция и все устройство входят в состояние приостановки, состояние приостановки функции сохраняется, пока устройство находится в состоянии приостановки, а также во всех процессах приостановки входа и выхода устройства.
Аналогично функции удаленного пробуждения устройства USB 2.0 (см. функцию удаленного пробуждения USB-устройств), отдельная функция в составном устройстве USB 3.0 может проснуться из состояния низкой мощности, не влияя на состояния питания других функций. Эта функция называется удаленное пробуждение. Эта функция явно включена узлом путем отправки запроса протокола, который задает удаленные биты пробуждения в встроенном ПО устройства. Этот процесс называется активацией функции для удаленного пробуждения. Сведения о битах, связанных с удаленным пробуждением, см. на рисунке 9-6 в официальной спецификации USB.
Если функция включена для удаленного пробуждения, функция (в состоянии приостановки) сохраняет достаточно мощности, чтобы сформировать сигнал для пробуждения при возникновении события пользователя на физическом устройстве. В результате этого сигнала возобновления драйвер клиента может выйти из состояния приостановки связанной функции. В примере функции мыши на составном устройстве, когда пользователь двигает мышь, которая находится в состоянии простоя, функция мыши отправляет сигнал продолжения на хост. На узле стек USB-драйверов обнаруживает, какая функция проснулась и распространяет уведомление на клиентский драйвер соответствующей функции. Затем драйвер клиента может проснуть функцию и ввести рабочее состояние.
Для клиентского драйвера шаги по приостановке функции и ее пробуждению похожи на те, которые делает драйвер устройства с одной функцией, переводя устройство в состояние приостановки. В следующей процедуре приведены общие сведения об этих шагах.
- Определите, когда связанная функция находится в состоянии простоя.
- Отправка пакета запроса ввода-вывода бездействия (IRP).
- Отправьте запрос на активацию его функции для удаленного пробуждения, отправив пакет запроса ввода-вывода wait-wake (IRP).
- Переключите функцию в режим низкого энергопотребления, отправив IRP питания Dx (D2 или D3).
Дополнительные сведения о предыдущих шагах см. в разделе "Отправка IRP запроса на бездействие USB" в документе USB выборочное приостановление. Составной драйвер создает объект физического устройства (PDO) для каждой функции в составном устройстве и обрабатывает запросы питания, отправленные драйвером клиента (FDO стека устройств-функций). Чтобы драйвер клиента успешно вошел и вышел из состояния приостановки для своей функции, составной драйвер должен поддерживать функции приостановки и удаленного пробуждения, а также обрабатывать полученные запросы на питание.
В Windows 8 стек USB-драйверов для устройств USB 3.0 поддерживает эти функции. Кроме того, в предоставленный Microsoft универсальный родительский драйвер USB (Usbccgp.sys), который является стандартным составным драйвером для Windows, добавлена реализация функций приостановки и удаленного пробуждения. Если вы пишете пользовательский составной драйвер, он должен обрабатывать запросы, связанные с приостановкой функции и запросами на удаленное пробуждение, в соответствии с следующей процедурой.
Шаг 1. Определение того, поддерживает ли стек USB-драйверов функцию приостановки
В подпрограмме начального устройства (IRP_MN_START_DEVICE) составного драйвера выполните следующие действия:
- Вызовите подпрограмму USBD_QueryUsbCapability , чтобы определить, поддерживает ли базовый стек USB-драйверов возможность приостановки функции. Для вызова требуется допустимый USBD-дескриптор, полученный в предыдущем вызове подпрограммы USBD_CreateHandle .
Успешный вызов USBD_QueryUsbCapability определяет, поддерживает ли базовый стек USB-драйверов приостановку функции. Вызов может возвращать код ошибки, указывающий, что стек USB-драйверов не поддерживает приостановку функции или подключенное устройство не является устройством с несколькими функциями USB 3.0.
- Если вызов USBD_QueryUsbCapability указывает, что функция приостановки поддерживается, зарегистрируйте составное устройство в базовом стеке драйверов USB. Чтобы зарегистрировать составное устройство, необходимо отправить запрос на управление ввода-вывода IOCTL_INTERNAL_USB_REGISTER_COMPOSITE_DEVICE. Дополнительные сведения об этом запросе см. в разделе "Регистрация составного устройства".
Запрос на регистрацию использует структуру REGISTER_COMPOSITE_DEVICE для указания сведений о составном драйвере. Убедитесь, что параметр CapabilityFunctionSuspend имеет значение 1, чтобы указать, что составной драйвер поддерживает приостановку функции.
Пример кода, показывающий, поддерживает ли стек USB-драйверов приостановку функции, см. USBD_QueryUsbCapability.
Шаг 2. Обработка бездействующей IRP
Драйвер клиента может отправлять неактивный IRP (см. IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION). Запрос отправляется после того, как драйвер клиента обнаружил состояние простоя для функции. IRP содержит указатель на подпрограмму завершения обратного вызова (называется бездействующим обратным вызовом), который реализуется драйвером клиента. В неактивном вызове клиент выполняет задачи, такие как отмена ожидающих передачи ввода-вывода, непосредственно перед отправкой функции для приостановки состояния.
Примечание.
Механизм бездействия IRP является необязательным для клиентских драйверов устройств USB 3.0. Однако большинство клиентских драйверов записываются для поддержки устройств USB 2.0 и USB 3.0. Чтобы поддерживать устройства USB 2.0, драйвер должен отправить бездействующий IRP, так как составной драйвер использует этот IRP для отслеживания состояния питания каждой функции. Если все функции неактивны, составной драйвер отправляет все устройство в состояние приостановки.
После получения неактивного IRP от драйвера клиента составной драйвер должен немедленно вызвать обратный вызов бездействия, чтобы уведомить драйвер клиента о том, что драйвер клиента может отправить функцию для приостановки состояния.
Шаг 3. Отправка запроса на удаленное уведомление о пробуждении
Драйвер клиента может отправить запрос, чтобы активировать функцию удаленного пробуждения, отправив IRP IRP_MJ_POWER с дополнительным кодом функции, установленным в IRP_MN_WAIT_WAKE (IRP ожидания). Драйвер клиента отправляет этот запрос только в том случае, если драйвер хочет ввести рабочее состояние в результате события пользователя.
После получения IRP составной драйвер ожидания должен отправить запрос управления вводом-выводом IOCTL_INTERNAL_USB_REQUEST_REMOTE_WAKE_NOTIFICATION в стек USB-драйверов. Запрос позволяет стеку USB-драйверов уведомлять составной драйвер, когда стек получает уведомление о сигнале возобновления. IOCTL_INTERNAL_USB_REQUEST_REMOTE_WAKE_NOTIFICATION использует структуру REQUEST_REMOTE_WAKE_NOTIFICATION для указания параметров запроса. Одно из значений, которые должен указывать составной драйвер, — это идентификатор функции для функции, настроенной для удаленного пробуждения. Составной драйвер получил этот идентификатор в предыдущем запросе для регистрации составного устройства в стеке драйверов USB. Дополнительные сведения о составных запросах на регистрацию драйверов см. в разделе "Регистрация составного устройства".
В IRP для запроса составной драйвер предоставляет указатель на подпрограмму завершения (удаленного пробуждения), которая реализуется составным драйвером.
В следующем примере кода показано, как отправить удаленный запрос на пробуждение.
/*++
Description:
This routine sends a IOCTL_INTERNAL_USB_REQUEST_REMOTE_WAKE_NOTIFICATION request
to the USB driver stack. The IOCTL is completed by the USB driver stack
when the function wakes up from sleep.
Parameters:
parentFdoExt: The device context associated with the FDO for the
composite driver.
functionPdoExt: The device context associated with the PDO (created by
the composite driver) for the client driver.
--*/
VOID
SendRequestForRemoteWakeNotification(
__inout PPARENT_FDO_EXT parentFdoExt,
__inout PFUNCTION_PDO_EXT functionPdoExt
)
{
PIRP irp;
REQUEST_REMOTE_WAKE_NOTIFICATION remoteWake;
PIO_STACK_LOCATION nextStack;
NTSTATUS status;
// Allocate an IRP
irp = IoAllocateIrp(parentFdoExt->topDevObj->StackSize, FALSE);
if (irp)
{
//Initialize the USBDEVICE_REMOTE_WAKE_NOTIFICATION structure
remoteWake.Version = 0;
remoteWake.Size = sizeof(REQUEST_REMOTE_WAKE_NOTIFICATION);
remoteWake.UsbdFunctionHandle = functionPdoExt->functionHandle;
remoteWake.Interface = functionPdoExt->baseInterfaceNumber;
nextStack = IoGetNextIrpStackLocation(irp);
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_REQUEST_REMOTE_WAKE_NOTIFICATION;
nextStack->Parameters.Others.Argument1 = &remoteWake;
// Caller's completion routine will free the IRP when it completes.
SetCompletionRoutine(functionPdoExt->debugLog,
parentFdoExt->fdo,
irp,
CompletionRemoteWakeNotication,
(PVOID)functionPdoExt,
TRUE, TRUE, TRUE);
// Pass the IRP
IoCallDriver(parentFdoExt->topDevObj, irp);
}
return;
}
Этот запрос IOCTL_INTERNAL_USB_REQUEST_REMOTE_WAKE_NOTIFICATION выполняется стеком USB-драйвера во время пробуждения при получении уведомления о сигнале возобновления. В течение этого времени стек USB-драйверов также вызывает подпрограмму завершения удаленного пробуждения.
Составной драйвер должен удерживать IRP ожидания-пробуждения в состоянии ожидания и поставить его в очередь для последующей обработки. Составной драйвер должен завершить выполнение IRP, когда стек драйверов USB вызывает его подпрограмму завершения удалённого пробуждения.
Шаг 4. Отправка запроса на вооружение функции для удаленного пробуждения
Чтобы отправить функцию в состояние низкой мощности, драйвер клиента отправляет IRP_MN_SET_POWER IRP с запросом на изменение состояния питания устройства модели драйверов Windows (WDM) на D2 или D3. Как правило, драйвер клиента отправляет D2 IRP, если драйвер ранее отправил IRP ожидания-пробуждения, чтобы запросить удаленное пробуждение. В противном случае драйвер клиента отправляет IRP D3 .
Получив D2 IRP, составной драйвер должен сначала определить, находится ли IRP ожидания-пробуждения в ожидании от предыдущего запроса, отправленного клиентским драйвером. Если этот IRP ожидается, составной драйвер должен настроить функцию на удаленное пробуждение. Для этого составной драйвер должен отправить запрос элемента управления SET_FEATURE в первый интерфейс функции, чтобы устройство отправляло сигнал возобновления. Чтобы отправить запрос управления, выделите структуру URB, вызвав подпрограмму USBD_UrbAllocate, затем вызовите макрос UsbBuildFeatureRequest, чтобы отформатировать URB для запроса SET_FEATURE. В вызове укажите URB_FUNCTION_SET_FEATURE_TO_INTERFACE в качестве кода операции и USB_FEATURE_FUNCTION_SUSPEND в качестве селектора компонентов. В параметре Index задайте бит 1 из наиболее значимых байтов. Это значение копируется в поле wIndex в пакете установки передачи.
В следующем примере показано, как отправить управляющий запрос SET_FEATURE.
/*++
Routine Description:
Sends a SET_FEATURE for REMOTE_WAKEUP to the device using a standard control request.
Parameters:
parentFdoExt: The device context associated with the FDO for the
composite driver.
functionPdoExt: The device context associated with the PDO (created by
the composite driver) for the client driver.
Returns:
NTSTATUS code.
--*/
VOID
NTSTATUS SendSetFeatureControlRequestToSuspend(
__inout PPARENT_FDO_EXT parentFdoExt,
__inout PFUNCTION_PDO_EXT functionPdoExt,
)
{
PURB urb
PIRP irp;
PIO_STACK_LOCATION nextStack;
NTSTATUS status;
status = USBD_UrbAllocate(parentFdoExt->usbdHandle, &urb);
if (!NT_SUCCESS(status))
{
//USBD_UrbAllocate failed.
goto Exit;
}
//Format the URB structure.
UsbBuildFeatureRequest (
urb,
URB_FUNCTION_SET_FEATURE_TO_INTERFACE, // Operation code
USB_FEATURE_FUNCTION_SUSPEND, // feature selector
functionPdoExt->firstInterface, // first interface of the function
NULL);
irp = IoAllocateIrp(parentFdoExt->topDevObj->StackSize, FALSE);
if (!irp)
{
// IoAllocateIrp failed.
status = STATUS_INSUFFICIENT_RESOURCES;
goto Exit;
}
nextStack = IoGetNextIrpStackLocation(irp);
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
// Attach the URB to the IRP.
USBD_AssignUrbToIoStackLocation(nextStack, (PURB)urb);
// Caller's completion routine will free the IRP when it completes.
SetCompletionRoutine(functionPdoExt->debugLog,
parentFdoExt->fdo,
irp,
CompletionForSuspendControlRequest,
(PVOID)functionPdoExt,
TRUE, TRUE, TRUE);
// Pass the IRP
IoCallDriver(parentFdoExt->topDevObj, irp);
Exit:
if (urb)
{
USBD_UrbFree( parentFdoExt->usbdHandle, urb);
}
return status;
}
Затем составной драйвер отправляет D2 IRP в стек USB-драйверов. Если все остальные функции находятся в состоянии приостановки, стек USB-драйверов приостанавливает порт, управляя определенными регистрами портов на контроллере.
Замечания
В примере функции мыши, так как функция удаленного пробуждения включена (см. шаг 4), функция мыши создает сигнал возобновления в вышестоящем канале к контроллеру узла при переключениях мыши. Затем контроллер уведомляет стек USB-драйверов, отправив пакет уведомлений, содержащий сведения о функции, которая проснулась. Сведения об уведомлении о пробуждении функции см. на рисунке 8-17 в спецификации USB 3.0.
После получения пакета уведомлений стек USB-драйвера завершает ожидающий запрос IOCTL_INTERNAL_USB_REQUEST_REMOTE_WAKE_NOTIFICATION (см. шаг 3) и вызывает подпрограмму обратного вызова завершения (удаленного пробуждения), указанную в запросе и реализованную составным драйвером. Когда уведомление достигает составного драйвера, он уведомляет соответствующий клиентский драйвер о том, что функция вошла в рабочее состояние, завершив IRP ожидания пробуждения, который ранее был отправлен клиентским драйвером.
В подпрограмме завершения (удаленного пробуждения) составной драйвер должен ставить рабочий элемент в очередь, чтобы завершить ожидание пробуждения ожидания. Для устройств USB 3.0 составной драйвер пробуждает только функцию, которая отправляет сигнал возобновления, оставляя остальные функции в состоянии приостановки. Очередь рабочего элемента обеспечивает совместимость с существующей реализацией для драйверов функций устройств USB 2.0. Сведения о очереди рабочего элемента см. в разделе IoQueueWorkItem.
Рабочий поток завершает IRP ожидания и вызывает подпрограмму завершения драйвера клиента. Затем подпрограмма завершения отправляет D0 IRP, чтобы перевести функцию в рабочее состояние. Перед завершением IRP пробуждения ожидания составной драйвер должен вызвать PoSetSystemWake , чтобы пометить IRP ожидания пробуждения как тот, который способствовал пробуждению системы от состояния приостановки. Power Manager регистрирует событие трассировки событий для Windows (ETW), которое можно просмотреть в глобальном канале системы, которое содержит сведения о устройствах, проснувшись в системе.