Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
В этом разделе описаны шаги, необходимые для отправки инициализированного URB в стек USB-драйверов для обработки конкретного запроса.
Драйвер клиента взаимодействует с устройством с помощью запросов управления ввода-вывода (IOCTL), которые доставляются на устройство в пакетах запросов ввода-вывода (IRPs) типа IRP_MJ_INTERNAL_DEVICE_CONTROL. Для конкретного устройства, например запроса на выборку конфигурации, запрос описывается в блоке USB-запросов (URB), связанном с IRP. Процесс связывания URB с IRP и отправка запроса в стек USB-драйверов называется отправкой URB. Чтобы отправить URB, драйвер клиента должен использовать IOCTL_INTERNAL_USB_SUBMIT_URB в качестве кода элемента управления устройством. IOCTL — это один из "внутренних" кодов управления, предоставляющих интерфейс ввода-вывода, используемый драйвером клиента для управления устройством и портом, к которому подключено устройство. Приложения в пользовательском режиме не имеют доступа к внутреннему интерфейсу ввода-вывода. Дополнительные коды управления для драйверов режима ядра см. в разделеKernel-Mode IOCTLs для драйверов USB-клиента.
Предпосылки
Перед отправкой запроса в стек драйверов универсальной последовательной шины (USB) драйвер клиента должен выделить структуру URB и формат этой структуры в зависимости от типа запроса. Дополнительные сведения см. в разделе "Выделение и создание URL-адресов" и "Рекомендации по использованию URI".
Инструкции
Выделите IRP для URB, вызвав функцию IoAllocateIrp. Необходимо указать размер стека объекта устройства, который получает IRP. Вы получили указатель на этот объект устройства в предыдущем вызове подпрограммы IoAttachDeviceToDeviceStack . Размер стека хранится в элементе StackSize структуры DEVICE_OBJECT .
Получите указатель на первое расположение стека IRP (IO_STACK_LOCATION), вызвав IoGetNextIrpStackLocation.
Установите для элемента MajorFunction структуры IO_STACK_LOCATION значение IRP_MJ_INTERNAL_DEVICE_CONTROL.
Установите в элементе Parameters.DeviceIoControl.IoControlCode структуры IO_STACK_LOCATION значение IOCTL_INTERNAL_USB_SUBMIT_URB.
Задайте элемент Parameters.Others.Argument1 структуры IO_STACK_LOCATION к адресу инициализированной структуры URB. Чтобы связать IRP с URB, можно также вызвать USBD_AssignUrbToIoStackLocation только в том случае, если URB был выделен USBD_UrbAllocate, USBD_SelectConfigUrbAllocateAndBuild или USBD_SelectInterfaceUrbAllocateAndBuild.
Задайте подпрограмму завершения, вызвав IoSetCompletionRoutineEx.
Если вы отправляете URB асинхронно, передайте указатель на функцию завершения, реализованную вызывающей стороной, и её контекст. Вызывающий освобождает IRP в своей функции завершения.
Если вы отправляете IRP синхронно, реализуйте подпрограмму завершения и передайте указатель на эту подпрограмму в вызове IoSetCompletionRoutineEx. Вызов также требует инициализированного объекта KEVENT в параметре Context . В подпрограмме завершения задайте для события сигнальное состояние.
Вызовите IoCallDriver , чтобы перенаправить заполненный IRP в следующий нижний объект устройства в стеке устройств. Для выполнения синхронного вызова, после вызова IoCallDriver, ожидайте события, вызывая KeWaitForSingleObject, чтобы получить уведомление о событии.
По завершении IRP проверьте элемент IRP IoStatus.Status и оцените результат. Если IoStatus.Status имеет значение STATUS_SUCCESS, запрос выполнен успешно.
Синхронная отправка USB
В следующем примере показано, как отправлять URB синхронно.
// The SubmitUrbSync routine submits an URB synchronously.
//
// Parameters:
// DeviceExtension: Pointer to the caller's device extension. The
// device extension must have a pointer to
// the next lower device object in the device stacks.
//
// Irp: Pointer to an IRP allocated by the caller.
//
// Urb: Pointer to an URB that is allocated by USBD_UrbAllocate,
// USBD_IsochUrbAllocate, USBD_SelectConfigUrbAllocateAndBuild,
// or USBD_SelectInterfaceUrbAllocateAndBuild.
// CompletionRoutine: Completion routine.
//
// Return Value:
//
// NTSTATUS
NTSTATUS SubmitUrbSync( PDEVICE_EXTENSION DeviceExtension,
PIRP Irp,
PURB Urb,
PIO_COMPLETION_ROUTINE SyncCompletionRoutine)
{
NTSTATUS ntStatus;
KEVENT kEvent;
PIO_STACK_LOCATION nextStack;
// Get the next stack location.
nextStack = IoGetNextIrpStackLocation(Irp);
// Set the major code.
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
// Set the IOCTL code for URB submission.
nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
// Attach the URB to this IRP.
// The URB must be allocated by USBD_UrbAllocate, USBD_IsochUrbAllocate,
// USBD_SelectConfigUrbAllocateAndBuild, or USBD_SelectInterfaceUrbAllocateAndBuild.
USBD_AssignUrbToIoStackLocation (DeviceExtension->UsbdHandle, nextStack, Urb);
KeInitializeEvent(&kEvent, NotificationEvent, FALSE);
ntStatus = IoSetCompletionRoutineEx ( DeviceExtension->NextDeviceObject,
Irp,
SyncCompletionRoutine,
(PVOID) &kEvent,
TRUE,
TRUE,
TRUE);
if (!NT_SUCCESS(ntStatus))
{
KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "IoSetCompletionRoutineEx failed. \n" ));
goto Exit;
}
ntStatus = IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
if (ntStatus == STATUS_PENDING)
{
KeWaitForSingleObject ( &kEvent,
Executive,
KernelMode,
FALSE,
NULL);
}
ntStatus = Irp->IoStatus.Status;
Exit:
if (!NT_SUCCESS(ntStatus))
{
// We hit a failure condition,
// We will free the IRP
IoFreeIrp(Irp);
Irp = NULL;
}
return ntStatus;
}
// The SyncCompletionRoutine routine is the completion routine
// for the synchronous URB submit request.
//
// Parameters:
//
// DeviceObject: Pointer to the device object.
// Irp: Pointer to an I/O Request Packet.
// CompletionContext: Context for the completion routine.
//
// Return Value:
//
// NTSTATUS
NTSTATUS SyncCompletionRoutine ( PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context)
{
PKEVENT kevent;
kevent = (PKEVENT) Context;
if (Irp->PendingReturned == TRUE)
{
KeSetEvent(kevent, IO_NO_INCREMENT, FALSE);
}
KdPrintEx(( DPFLTR_IHVDRIVER_ID, DPFLTR_INFO_LEVEL, "Request completed. \n" ));
return STATUS_MORE_PROCESSING_REQUIRED;
}
Асинхронная передача данных USB
В следующем примере показано, как асинхронно отправить URB.
// The SubmitUrbASync routine submits an URB asynchronously.
//
// Parameters:
//
// Parameters:
// DeviceExtension: Pointer to the caller's device extension. The
// device extension must have a pointer to
// the next lower device object in the device stacks.
//
// Irp: Pointer to an IRP allocated by the caller.
//
// Urb: Pointer to an URB that is allocated by USBD_UrbAllocate,
// USBD_IsochUrbAllocate, USBD_SelectConfigUrbAllocateAndBuild,
// or USBD_SelectInterfaceUrbAllocateAndBuild.
// CompletionRoutine: Completion routine.
//
// CompletionContext: Context for the completion routine.
//
//
// Return Value:
//
// NTSTATUS
NTSTATUS SubmitUrbASync ( PDEVICE_EXTENSION DeviceExtension,
PIRP Irp,
PURB Urb,
PIO_COMPLETION_ROUTINE CompletionRoutine,
PVOID CompletionContext)
{
// Completion routine is required if the URB is submitted asynchronously.
// The caller's completion routine releases the IRP when it completes.
NTSTATUS ntStatus = -1;
PIO_STACK_LOCATION nextStack = IoGetNextIrpStackLocation(Irp);
// Attach the URB to this IRP.
nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
// Attach the URB to this IRP.
nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
// Attach the URB to this IRP.
(void) USBD_AssignUrbToIoStackLocation (DeviceExtension->UsbdHandle, nextStack, Urb);
// Caller's completion routine will free the irp when it completes.
ntStatus = IoSetCompletionRoutineEx ( DeviceExtension->NextDeviceObject,
Irp,
CompletionRoutine,
CompletionContext,
TRUE,
TRUE,
TRUE);
if (!NT_SUCCESS(ntStatus))
{
goto Exit;
}
(void) IoCallDriver(DeviceExtension->NextDeviceObject, Irp);
Exit:
if (!NT_SUCCESS(ntStatus))
{
// We hit a failure condition,
// We will free the IRP
IoFreeIrp(Irp);
Irp = NULL;
}
return ntStatus;
}