моя контактная информация
Почтамезофия@protonmail.com
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
В устройствах USB 2.0 и более ранних версиях групповая конечная точка может отправлять или получать один поток данных через конечную точку. В устройствах USB 3.0 групповая конечная точка способна отправлять и получать несколько потоков данных через конечную точку.
Стек драйверов USB, предоставляемый Microsoft в Windows, поддерживает несколько потоков. Это позволяет клиентским драйверам отправлять независимые запросы ввода-вывода в каждый поток, связанный с массовой конечной точкой на устройстве USB 3.0, без сериализации запросов к различным потокам.
Для драйвера клиента поток представляет несколько логических конечных точек с одинаковым набором характеристик. Чтобы отправить запрос к определенному потоку, драйверу клиента необходим дескриптор этого потока (аналогично дескриптору канала конечной точки). URB для потоковой передачи запросов ввода-вывода аналогичен URB для запросов ввода-вывода для массовых конечных точек. Единственное отличие – это ручка трубы. Чтобы отправить запрос ввода-вывода в поток, драйвер указывает в потоке дескриптор канала.
Во время настройки устройства драйвер клиента отправляет запрос выбора конфигурации и, при необходимости, запрос выбора интерфейса. Эти запросы получают набор дескрипторов каналов для конечных точек, определенных в настройках активности интерфейса. Для конечных точек, поддерживающих поток, дескриптор канала конечной точки можно использовать для отправки запросов ввода-вывода в поток по умолчанию (первый поток), пока драйвер не откроет поток.
Если драйвер клиента хочет отправлять запросы в потоки, отличные от потока по умолчанию, драйвер должен открыть и получить дескрипторы всех потоков. Для этого драйвер клиента отправляет запрос на открытие потока, указывая количество открываемых потоков. После того, как клиентский драйвер завершил использование потоков, он может закрыть их, отправив запрос на закрытие потока.
Платформа драйверов режима ядра (KMDF) изначально не поддерживает статические потоки. Клиентские драйверы должны использовать модель драйверов Windows (WDM) для открытия и закрытия потоков. Драйверы клиента User-mode Driver Framework (UMDF) не могут использовать функцию статической потоковой передачи.
Следующее может содержать некоторые комментарии с пометкой «Драйверы WDM». Эти инструкции описывают процедуры для драйвера USB-клиента на основе WDM, который хочет отправлять запросы потоковой передачи.
Прежде чем клиентский драйвер сможет открыть или закрыть поток, драйвер должен иметь:
1. Вызовите метод WdfUsbTargetDeviceCreateWithParameters. Для метода требуется версия клиентского протокола USBD_CLIENT_CONTRACT_VERSION_602. Указывая эту версию, клиентский драйвер должен соответствовать набору правил.
Вызов для получения дескриптора WDFUSBDEVICE объекта целевого USB-устройства платформы. Дескриптор необходим для последующих вызовов открытого потока. Обычно драйвер клиента регистрируется в процедуре обратного вызова событий EVT_WDF_DEVICE_PREPARE_HARDWARE драйвера.
Драйвер WDM: вызовите процедуру USBD_CreateHandle и получите дескриптор USBD, зарегистрированный драйвером в стеке драйверов USB.
2. Настроили устройство и получили дескриптор канала WDFUSBPIPE для массовой конечной точки, поддерживающей потоковую передачу. Чтобы получить дескриптор канала, вызовите метод WdfUsbInterfaceGetConfiguredPipe для текущих альтернативных настроек интерфейса в выбранной конфигурации.
Драйвер WDM: получает дескриптор канала USBD, отправляя запрос выбора конфигурации или интерфейса.
1. Определите, поддерживают ли базовый стек драйверов USB и хост-контроллер функцию статической потоковой передачи, вызвав метод WdfUsbTargetDeviceQueryUsbCapability. Обычно клиентские драйверы вызывают процедуры в процедуре обратного вызова событий EVT_WDF_DEVICE_PREPARE_HARDWARE драйвера.
Драйвер WDM: вызывает процедуру USBD_QueryUsbCapability. Обычно драйвер запрашивает функцию, которая будет использоваться в подпрограмме загрузочного устройства драйвера (IRP_MN_START_DEVICE).
Предоставьте следующую информацию:
Драйвер WDM: передайте дескриптор USBD, полученный при предыдущем вызове, в USBD_CreateHandle.
Если клиентский драйвер хочет использовать определенную функцию, он должен сначала запросить базовый стек драйверов USB, чтобы определить, поддерживают ли стек драйверов и хост-контроллер эту функцию. Если функция поддерживается, только тогда драйвер должен отправить запрос на использование этой функции. Для некоторых запросов требуются URB, например функция потоковой передачи, описанная в шаге 5. Для этих запросов обязательно используйте один и тот же дескриптор для запроса функции и выделения URB. Это связано с тем, что стек драйверов использует дескрипторы для отслеживания поддерживаемых функций, которые может использовать драйвер.
Например, если USBD_HANDLE был получен путем вызова USBD_CreateHandle, стек драйвера запрашивается путем вызова USBD_QueryUsbCapability, а URB выделяется путем вызова USBD_UrbAllocate. Передайте один и тот же USBD_HANDLE в обоих вызовах.
Если вы вызываете методы KMDF, WdfUsbTargetDeviceQueryUsbCapability и WdfUsbTargetDeviceCreateUrb, укажите один и тот же дескриптор WDFUSBDEVICE для целевого объекта платформы в этих вызовах методов.
2. Оцените возвращенное значение NTSTATUS. Если процедура завершается успешно, возвращается STATUS_SUCCESS, и поддерживается функция статической потоковой передачи. В противном случае метод возвращает соответствующий код ошибки.
3. Определите количество открываемых потоков. Максимальное количество потоков, которые можно открыть, ограничено:
Чтобы определить максимальное количество потоков, выберите меньшее из двух значений, поддерживаемых хост-контроллером и конечной точкой.
4. Выделите массив из n-элементных структур USBD_STREAM_INFORMATION, где n — количество открываемых потоков. Драйвер клиента отвечает за освобождение этого массива после того, как драйвер завершит использование потока.
5. Выделите URB для запроса на открытие потока, вызвав метод WdfUsbTargetDeviceCreateUrb. Если вызов завершается успешно, метод извлекает объект памяти WDF и адрес структуры URB, выделенный стеком драйвера USB.
Драйвер WDM: вызывает процедуру USBD_UrbAllocate.
6. Установите формат URB запроса на открытие потока. URB использует структуру _URB_OPEN_STATIC_STREAMS для определения запросов. Чтобы отформатировать URB, вам необходимо:
Чтобы отформатировать URB, вызовите UsbBuildOpenStaticStreamsRequest и передайте необходимую информацию в виде значений параметров. Убедитесь, что количество потоков, указанное в UsbBuildOpenStaticStreamsRequest, не превышает максимальное поддерживаемое количество потоков.
7. Отправьте URB как объект запроса WDF, вызвав метод WdfRequestSend. Чтобы отправить запрос синхронно, вместо этого вызовите метод WdfUsbTargetDeviceSendUrbSynchronous.
Драйвер WDM: связывает URB с IRP и отправляет IRP в стек драйверов USB.
8. После завершения запроса проверьте статус запроса.Если запрос стека USB-драйвера завершается неудачей, статус URB содержит соответствующий код ошибки.
Если статус запроса (объект запроса IRP или WDF) указывает USBD_STATUS_SUCCESS, запрос выполнен успешно. Массив структур USBD_STREAM_INFORMATION, полученный после завершения проверки. Массив заполняется информацией о запрошенном потоке. Стек драйвера USB заполняет каждую структуру массива информацией о потоке, такой как полученный дескриптор USBD_PIPE_HANDLE, идентификатор потока и максимальный числовой размер передачи. Теперь поток может передавать данные.
Для запросов открытого потока необходимо выделить URB и массивы. После завершения запроса на открытие потока драйвер клиента должен освободить URB, вызвав метод WdfObjectDelete для связанного объекта памяти WDF. Если драйвер отправляет запрос синхронно, вызывая WdfUsbTargetDeviceSendUrbSynchronous, объект памяти WDF должен быть освобожден после возврата метода. Если клиентский драйвер отправляет запрос асинхронно, вызывая WdfRequestSend, драйвер должен освободить объект памяти WDF в реализуемой драйвером процедуре завершения, связанной с запросом.
Массив потока можно освободить после того, как клиентский драйвер завершит использование потока, или его можно сохранить для запросов ввода-вывода. В приведенном ниже примере кода драйвер сохраняет массив потоков в контексте устройства. Драйвер освобождает контекст устройства перед освобождением объекта устройства.
Как передать данные в определенный поток
Для отправки запроса на передачу данных в конкретный поток необходим объект запроса WDF. Обычно клиентским драйверам не требуется выделять объекты запроса WDF. Когда диспетчер ввода-вывода получает запрос от приложения, он создает IRP для этого запроса. IRP был перехвачен платформой. Затем платформа выделяет объект запроса WDF для представления IRP. После этого платформа передает объект запроса WDF драйверу клиента. Затем клиентский драйвер может связать объект запроса с URB передачи данных и отправить его в стек драйверов USB.
Если клиентский драйвер не получает объект запроса WDF от платформы и хочет отправить запрос асинхронно, драйвер должен выделить объект запроса WDF, вызвав метод WdfRequestCreate. Отформатируйте новый объект, вызвав WdfUsbTargetPipeFormatRequestForUrb, и отправьте запрос, вызвав WdfRequestSend.
В синхронном случае передача объекта запроса WDF не является обязательной.
Для передачи данных в поток необходимо использовать URB. URB необходимо отформатировать, вызвав WdfUsbTargetPipeFormatRequestForUrb.
Потоки не поддерживают следующие методы WDF:
В следующей процедуре предполагается, что драйвер клиента получает объект запроса от платформы.
Драйвер WDM: выделяет URB, вызывая USBD_UrbAllocate, и форматирует его для массовой передачи (см. _URB_BULK_OR_INTERRUPT_TRANSFER). Чтобы отформатировать URB, вы можете вызвать UsbBuildInterruptOrBulkTransferRequest или вручную отформатировать структуру URB. Укажите дескриптор потока в элементе UrbBulkOrInterruptTransfer.PipeHandle URB.
Драйвер клиента может закрыть поток после того, как драйвер завершит его использование. Однако закрытие запроса на потоковую передачу не является обязательным. Стек драйверов USB закрывает все потоки, если конечная точка, связанная с потоком, не настроена. Конечные точки не настраиваются при выборе альтернативной конфигурации или интерфейса, удалении устройства и т. д. Если драйвер клиента хочет открыть другое количество потоков, он должен закрыть потоки. Отправьте запрос на закрытие потока:
1. Выделите структуру URB, вызвав WdfUsbTargetDeviceCreateUrb.
2. Установите формат URB для закрытия запроса потока. Членом UrbPipeRequest структуры URB является структура _URB_PIPE_REQUEST. Заполните его члены следующим образом:
3. Отправьте URB как запрос WDF, вызвав WdfRequestSend или WdfUsbTargetDeviceSendUrbSynchronous.
Дескриптор закрытия запрашивает закрытие всех потоков, ранее открытых клиентским драйвером. Драйвер клиента не может использовать запросы для закрытия определенного потока в конечной точке.
Стек драйверов USB выполняет проверку полученного URB. Чтобы избежать ошибок проверки, выполните следующие действия:
Иногда передача в конечную точку или из нее может завершиться неудачно. Такие сбои могут быть вызваны ошибками на конечной точке или хост-контроллере, например состоянием остановки или остановки. Чтобы устранить состояние ошибки, драйвер клиента сначала отменяет ожидающую передачу, а затем сбрасывает канал, связанный с конечной точкой. Чтобы отменить ожидающую передачу, драйвер клиента может отправить запрос на прерывание канала. Чтобы сбросить канал, драйвер клиента должен отправить запрос на сброс канала.
Для потоковой передачи запросы abort-pipe и reset-pipe не поддерживаются для отдельных потоков, связанных с массовой конечной точкой. Если передача по определенному каналу потока завершается неудачей, хост-контроллер останавливает передачу по всем другим каналам для других потоков. Чтобы восстановиться после состояния ошибки, драйвер клиента должен вручную отменить передачу в каждый поток. Затем необходимо использовать драйвер клиента. дескриптор канала для отправки запроса сброса канала на массовую конечную точку. Для этого запроса драйвер клиента должен указать дескриптор канала конечной точки в структуре _URB_PIPE_REQUEST и установить для функции URB (Hdr.Function) значение URB_FUNCTION_SYNC_RESET_PIPE_AND_CLEAR_STALL.
В следующем примере кода показано, как открыть поток.
- NTSTATUS
- OpenStreams (
- _In_ WDFDEVICE Device,
- _In_ WDFUSBPIPE Pipe)
- {
- NTSTATUS status;
- PDEVICE_CONTEXT deviceContext;
- PPIPE_CONTEXT pipeContext;
- USHORT cStreams = 0;
- USBD_PIPE_HANDLE usbdPipeHandle;
- WDFMEMORY urbMemory = NULL;
- PURB urb = NULL;
-
- PAGED_CODE();
-
- deviceContext =GetDeviceContext(Device);
- pipeContext = GetPipeContext (Pipe);
-
- if (deviceContext->MaxStreamsController == 0)
- {
- TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
- "%!FUNC! Static streams are not supported.");
-
- status = STATUS_NOT_SUPPORTED;
- goto Exit;
- }
-
- // If static streams are not supported, number of streams supported is zero.
-
- if (pipeContext->MaxStreamsSupported == 0)
- {
- status = STATUS_DEVICE_CONFIGURATION_ERROR;
-
- TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
- "%!FUNC! Static streams are not supported by the endpoint.");
-
- goto Exit;
- }
-
- // Determine the number of streams to open.
- // Compare the number of streams supported by the endpoint with the
- // number of streams supported by the host controller, and choose the
- // lesser of the two values. The deviceContext->MaxStreams value was
- // obtained in a previous call to WdfUsbTargetDeviceQueryUsbCapability
- // that determined whether or not static streams is supported and
- // retrieved the maximum number of streams supported by the
- // host controller. The device context stores the values for IN and OUT
- // endpoints.
-
- // Allocate an array of USBD_STREAM_INFORMATION structures to store handles to streams.
- // The number of elements in the array is the number of streams to open.
- // The code snippet stores the array in its device context.
-
- cStreams = min(deviceContext->MaxStreamsController, pipeContext->MaxStreamsSupported);
-
- // Allocate an array of streams associated with the IN bulk endpoint
- // This array is released in CloseStreams.
-
- pipeContext->StreamInfo = (PUSBD_STREAM_INFORMATION) ExAllocatePoolWithTag (
- NonPagedPool,
- sizeof (USBD_STREAM_INFORMATION) * cStreams,
- USBCLIENT_TAG);
-
- if (pipeContext->StreamInfo == NULL)
- {
- status = STATUS_INSUFFICIENT_RESOURCES;
-
- TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
- "%!FUNC! Could not allocate stream information array.");
-
- goto Exit;
- }
-
- RtlZeroMemory (pipeContext->StreamInfo,
- sizeof (USBD_STREAM_INFORMATION) * cStreams);
-
- // Get USBD pipe handle from the WDF target pipe object. The client driver received the
- // endpoint pipe handles during device configuration.
-
- usbdPipeHandle = WdfUsbTargetPipeWdmGetPipeHandle (Pipe);
-
- // Allocate an URB for the open streams request.
- // WdfUsbTargetDeviceCreateUrb returns the address of the
- // newly allocated URB and the WDFMemory object that
- // contains the URB.
-
- status = WdfUsbTargetDeviceCreateUrb (
- deviceContext->UsbDevice,
- NULL,
- &urbMemory,
- &urb);
-
- if (status != STATUS_SUCCESS)
- {
- TraceEvents(TRACE_LEVEL_ERROR, TRACE_DEVICE,
- "%!FUNC! Could not allocate URB for an open-streams request.");
-
- goto Exit;
- }
-
- // Format the URB for the open-streams request.
- // The UsbBuildOpenStaticStreamsRequest inline function formats the URB by specifying the
- // pipe handle to the entire bulk endpoint, number of streams to open, and the array of stream structures.
-
- UsbBuildOpenStaticStreamsRequest (
- urb,
- usbdPipeHandle,
- (USHORT)cStreams,
- pipeContext->StreamInfo);
-
- // Send the request synchronously.
- // Upon completion, the USB driver stack populates the array of with handles to streams.
-
- status = WdfUsbTargetPipeSendUrbSynchronously (
- Pipe,
- NULL,
- NULL,
- urb);
-
- if (status != STATUS_SUCCESS)
- {
- goto Exit;
- }
-
- Exit:
- if (urbMemory)
- {
- WdfObjectDelete (urbMemory);
- }
-
- return status;
- }