Windows下USB驱动同步URB转IRP请求函数代码
2021-08-30
520
0
URB和IRP类似,只不过一个应用于通用的Windows驱动,一个专职于USB。
USB的URB的负载是IRP,其通过负载到IRP时,然后使用通用的Windows IRP请求发向下层目标USB设备。
USB与IRP的关联是通过IRP的IO_STACK_LOCATION的 IoStack->Parameters.Others.Argument1字段建立联系的。
常见的代码如下:
IoStack = IoGetNextIrpStackLocation(Irp);
....
IoStack->Parameters.Others.Argument1 = (PVOID)UrbRequest;
这里我们对这层应用进行封装,形成一个私有公共函数,适用于Windows内核下USB设备驱动的开发。
SyncUrbRequest函数使用同步的方式调用,如果IRP被下层调备PENDING,则通过等待event事件来等待。
NTSTATUS
SyncUrbRequest(
IN PDEVICE_OBJECT DeviceObject,
OUT PURB UrbRequest)
{
PIRP Irp;
PIO_STACK_LOCATION IoStack;
KEVENT Event;
NTSTATUS Status;
/* Allocate irp */
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!Irp)
{
/* No memory */
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Initialize event */
KeInitializeEvent(&Event, NotificationEvent, FALSE);
/* Get next stack location */
IoStack = IoGetNextIrpStackLocation(Irp);
/* Initialize stack location */
IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
IoStack->Parameters.Others.Argument1 = (PVOID)UrbRequest;
IoStack->Parameters.DeviceIoControl.InputBufferLength = UrbRequest->UrbHeader.Length;
Irp->IoStatus.Status = STATUS_SUCCESS;
/* Setup completion routine */
IoSetCompletionRoutine(Irp,
IrpCompletionRoutine,
&Event,
TRUE,
TRUE,
TRUE);
/* Call driver */
Status = IoCallDriver(DeviceObject, Irp);
/* Check if request is pending */
if (Status == STATUS_PENDING)
{
/* Wait for completion */
KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
/* Update status */
Status = Irp->IoStatus.Status;
}
/* Free irp */
IoFreeIrp(Irp);
/* Done */
return Status;
}
同步等待的event是在IRP的完成函数中激活,代码比较简单。
NTSTATUS
IrpCompletionRoutine(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
UNREFERENCED_PARAMETER(Irp);
UNREFERENCED_PARAMETER(DeviceObject);
PKEVENT event = (PKEVENT)Context;
if (event != NULL)
{
KeSetEvent(event, IO_NO_INCREMENT, FALSE);
}
return STATUS_MORE_PROCESSING_REQUIRED;
}
测试代码
在做USB驱动开发的时候,在IRP_MN_START_DEVICE中启动设备时,是需要将该IRP下发给底层的PDO。
如IRP_MN_START_DEVICE对应的回调函数:FdoStartDevice
NTSTATUS
FdoStartDevice(
PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
NTSTATUS status;
PIO_STACK_LOCATION IoStack ;
PFDO_DEVICE_EXTENSION FDODeviceExtension;
status = STATUS_SUCCESS;
IoStack = IoGetCurrentIrpStackLocation(Irp);
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
do
{
status = SyncForwardIrp(FDODeviceExtension->NextDeviceObject, Irp);
if (!NT_SUCCESS(status))
{
DPrint1(("SyncForwardIrp err:[%08x]\n", status));
break;
}
..
}while(0);
...
}
HID人机交互QQ群:564808376
UAC音频QQ群:218581009
UVC相机QQ群:331552032
BOT&UASP大容量存储QQ群:258159197
STC-USB单片机QQ群:315457461
USB技术交流QQ群2:580684376
USB技术交流QQ群:952873936