URB の送信方法

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

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

前提条件

USB (Universal Serial Bus) ドライバースタックに要求を送信する前に、クライアントドライバーは、要求の種類に応じて、 URB 構造を割り当て、その構造をフォーマットする必要があります。 詳細については、「 URBs の割り当てとビルド 」と「 ベストプラクティス: URBs を使用する」を参照してください。

Instructions

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

  2. Iogetnextiシャードの場所を呼び出すことにより、IRP の最初のスタック位置 (IO _ スタックの _ 場所) へのポインターを取得します。

  3. IO _ スタックの _ 場所の構造体の MajorFunction メンバーを、 IRP _ MJ _ 内部 _ デバイス _ コントロールに設定します。

  4. IO _ スタックの _ 場所の構造体の DeviceIoControl のパラメーターIOCTL _ 内部 _ USB 送信の _ _ URBに設定します。

  5. IO _ スタックの _ 場所の構造体の 引数 1 メンバーを、初期化された URB構造体のアドレスに設定します。 IRP を URB に関連付けるには、 USBD _ urUSBDUSBD _ SelectConfigUrbAllocateAndBuild、または USBD _ SelectInterfaceUrbAllocateAndBuildによって URB が割り当てられている場合にのみ、またはの割り当て _ urbtoiostacklocationを呼び出すことができます。

  6. IoSetCompletionRoutineExを呼び出して、完了ルーチンを設定します。

    URB を非同期に送信する場合は、呼び出し元によって実装された完了ルーチンとそのコンテキストへのポインターを渡します。 呼び出し元は、完了ルーチンで IRP を解放します。

    IRP を同期的に送信する場合は、完了ルーチンを実装し、 IoSetCompletionRoutineExへの呼び出しでそのルーチンへのポインターを渡します。 この呼び出しでは、 コンテキスト パラメーターに初期化された KEVENT オブジェクトも必要です。 完了ルーチンで、イベントをシグナル状態に設定します。

  7. IoCallDriverを呼び出して、設定された IRP をデバイススタック内の次に小さいデバイスオブジェクトに転送します。 同期呼び出しの場合は、 IoCallDriver を呼び出した後、 KeWaitForSingleObject を呼び出してイベント通知を取得することによって、イベントオブジェクトを待機します。

  8. IRP の完了後に、IRP の iostatus. Status メンバーを確認し、結果を評価します。 Iostatus の状態が _ [成功] の場合、要求は成功しました。

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