共用方式為


如何提交 URB

本主題描述將初始化的 URB 提交至 USB 驅動程式堆疊以處理特定要求所需的步驟。

用戶端驅動程式會使用 I/O 控制程式碼與裝置通訊, (IOCTL) 在 I/O 要求封包中傳遞至裝置的要求, (I/O 要求封包) 類型 為 IRP_MJ_INTERNAL_DEVICE_CONTROL。 針對裝置特定要求,例如選取組態要求,要求會在與 IRP 相關聯的 USB 要求區塊 (URB) 中說明。 將 URB 與 IRP 產生關聯,並將要求傳送至 USB 驅動程式堆疊的程式稱為提交 URB。 若要提交 URB,用戶端驅動程式必須使用 IOCTL_INTERNAL_USB_SUBMIT_URB 作為裝置控制程式代碼。 IOCTL 是其中一個「內部」控制代碼,可提供用戶端驅動程式用來管理其裝置和裝置所連線埠的 I/O 介面。 使用者模式應用程式無法存取這些內部 I/O 介面。 如需核心模式驅動程式的更多控制程式代碼,請參閱 USB 用戶端驅動程式的核心模式 IOCTL

必要條件

將要求傳送至通用序列匯流排 (USB) 驅動程式堆疊之前,用戶端驅動程式必須根據要求類型來配置 URB 結構和格式。 如需詳細資訊,請參閱 配置和建置 URL最佳做法:使用 URB

指示

  1. 呼叫 IoAllocateIrp 常式,為 URB 配置 IRP。 您必須提供接收 IRP 之裝置物件的堆疊大小。 您在先前呼叫 IoAttachDeviceToDeviceStack 常式中收到該裝置物件的指標。 堆疊大小會儲存在DEVICE_OBJECT結構的StackSize成員中。

  2. 藉由呼叫IoGetNextIrpStackLocation,取得 IRP 第一個堆疊位置的指標 (IO_STACK_LOCATION) 。

  3. IO_STACK_LOCATION結構的MajorFunction成員設定為IRP_MJ_INTERNAL_DEVICE_CONTROL

  4. IO_STACK_LOCATION結構的Parameters.DeviceIoControl.IoControlCode成員設定為IOCTL_INTERNAL_USB_SUBMIT_URB

  5. IO_STACK_LOCATION結構的Parameters.Others.Argument1成員設定為初始化URB結構的位址。 若要將 IRP 與 URB 產生關聯,您只能在URB 由USBD_UrbAllocate、USBD_SelectConfigUrbAllocateAndBuild或USBD_SelectInterfaceUrbAllocateAndBuild配置時呼叫USBD_AssignUrbToIoStackLocation

  6. 藉由呼叫 IoSetCompletionRoutineEx來設定完成常式。

    如果您以非同步方式提交 URB,請將指標傳遞至呼叫端實作的完成常式及其內容。 呼叫端會在其完成常式中釋放 IRP。

    如果您要同步提交 IRP,請實作完成常式,並在呼叫 IoSetCompletionRoutineEx中傳遞該常式的指標。 呼叫也需要 CoNtext 參數中初始化的 KEVENT 物件。 在您的完成常式中,將事件設定為已發出訊號的狀態。

  7. 呼叫 IoCallDriver ,將填入的 IRP 轉送至裝置堆疊中的下一個較低裝置物件。 針對同步呼叫,在呼叫 IoCallDriver之後,呼叫 KeWaitForSingleObject 以等候事件物件,以取得事件通知。

  8. 完成 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;
}

將要求傳送至 USB 裝置