Windows下USB驱动同步URB转IRP请求函数代码

10 0 2021-06-29 本文地址:http://www.usbzh.com/fun/detail-31.html

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);

    ...

}
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!