URB の送信方法

このトピックでは、特定の要求を処理するために初期化された URB を USB ドライバー スタックに送信するために必要な手順について説明します。

クライアント ドライバーは、I/O 要求パケット (I/O 要求パケット) でデバイスに配信される IOCTL (I/O 制御コード) 要求を使用して、IRP_MJ_INTERNAL_DEVICE_CONTROL 型のデバイスと通信します。 選択構成要求などのデバイス固有の要求については、IRP に関連付けられている USB 要求ブロック (URB) で要求が記述されます。 URB を IRP に関連付け、USB ドライバー スタックに要求を送信するプロセスは、URB の送信と呼ばれます。 URB を送信するには、クライアント ドライバーでデバイス制御 コードとして IOCTL_INTERNAL_USB_SUBMIT_URB を使用する必要があります。 IOCTL は、デバイスとデバイスが接続されているポートを管理するためにクライアント ドライバーが使用する I/O インターフェイスを提供する "内部" 制御コードの 1 つです。 ユーザー モード アプリケーションは、これらの内部 I/O インターフェイスにアクセスできません。 カーネル モード ドライバーの制御コードの詳細については、「USB クライアント ドライバーの カーネル モード IOCTL」を参照してください

前提条件

ユニバーサル シリアル バス (USB) ドライバー スタックに要求を送信する前に、クライアント ドライバーは、要求の種類に応じて URB 構造と形式を割り当てる必要があります。 詳細については、「URB の 割り当てと構築」 および「ベスト プラクティス: URB の使用」を参照してください

Instructions

  1. IoAllocateIrp ルーチンを呼び出して、URB に IRP を割り当てる。 IRP を受け取るデバイス オブジェクトのスタック サイズを指定する必要があります。 IoAttachDeviceToDeviceStack ルーチンへの以前の呼び出しで、そのデバイス オブジェクトへのポインターを受け取った。 スタック サイズは、 構造体の StackSizeメンバー DEVICE_OBJECT されます。

  2. IoGetNextIrpStackLocation を呼び出して、IRP の最初のスタックIO_STACK_LOCATIONへのポインターを取得します。

  3. 関数構造体 の MajorFunction メンバーを IO_STACK_LOCATION設定IRP_MJ_INTERNAL_DEVICE_CONTROL

  4. メソッド構造体 の Parameters.DeviceIoControl.IoControlCodeメンバー をIO_STACK_LOCATION に設定IOCTL_INTERNAL_USB_SUBMIT_URB

  5. メソッド構造体 の Parameters.Others.Argument1メンバー をIO_STACK_LOCATION URB 構造体のアドレスに設定します。 URB に IRP を関連付ける場合は、URB が USBD_UrbAllocate、USBD_SelectConfigUrbAllocateAndBuild、または USBD_SelectInterfaceUrbAllocateAndBuild によって割り当てられた場合にのみ、USBD_AssignUrbToIoStackLocation を呼びUSBD_SelectInterfaceUrbAllocateAndBuild

  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 デバイスへの要求の送信