Condividi tramite


Come inviare UN'istanza DI

In questo argomento vengono descritti i passaggi necessari per inviare un'istanza di URB inizializzata allo stack di driver USB per elaborare una richiesta specifica.

Un driver client comunica con il dispositivo usando il codice di controllo I/O (IOCTL) richieste recapitate al dispositivo nei pacchetti di richiesta I/O (IRP) di tipo IRP_MJ_INTERNAL_DEVICE_CONTROL. Per una richiesta specifica del dispositivo, ad esempio una richiesta di configurazione selezionata, la richiesta viene descritta in un blocco richiesta USB associato a un'IRP. Il processo di associazione di UN'ISTANZA a un'IRP e l'invio della richiesta allo stack di driver USB viene definito invio di un ISTANZA. Per inviare un'istanza DI, il driver client deve usare IOCTL_INTERNAL_USB_SUBMIT_URB come codice di controllo del dispositivo. IOCTL è uno dei codici di controllo "interni" che forniscono un'interfaccia di I/O usata da un driver client per gestire il dispositivo e la porta a cui è connesso il dispositivo. Le applicazioni in modalità utente non hanno accesso a tali interfacce di I/O interne. Per altri codici di controllo per i driver in modalità kernel, vedere IOCTLs in modalità kernel per i driver client USB.

Prerequisiti

Prima di inviare una richiesta allo stack di driver USB (Universal Serial Bus), il driver client deve allocare una struttura e un formato CHE dipendono dal tipo di richiesta. Per altre informazioni, vedere Allocazione e compilazione di UR eprocedure consigliate: Uso degli URL.

Istruzioni

  1. Allocare un'IRP per l'ISTANZA chiamando la routine IoAllocateIrp . È necessario specificare le dimensioni dello stack dell'oggetto dispositivo che riceve l'IRP. È stato ricevuto un puntatore a tale oggetto dispositivo in una chiamata precedente alla routine IoAttachDeviceToDeviceToDeviceStack . Le dimensioni dello stack vengono archiviate nel membro StackSize della struttura DEVICE_OBJECT .

  2. Ottenere un puntatore alla prima posizione dello stack di IRP (IO_STACK_LOCATION) chiamando IoGetNextIrpStackLocation.

  3. Impostare il membro MajorFunction della struttura IO_STACK_LOCATIONsu IRP_MJ_INTERNAL_DEVICE_CONTROL.

  4. Impostare il membro Parameters.DeviceIoControl.IoControlCode della struttura IO_STACK_LOCATION su IOCTL_INTERNAL_USB_SUBMIT_URB.

  5. Impostare il membro Parameters.Others.Argument1 della struttura di IO_STACK_LOCATION sull'indirizzo della struttura DELL'AREA di configurazione inizializzata. Per associare l'IRP a URB, è possibile chiamare in alternativa USBD_AssignUrbToIoStackLocation solo se è stato allocato da USBD_UrbAllocate, USBD_SelectConfigUrbAllocateAndBuild o USBD_SelectInterfaceUrbAllocateAndBuild.

  6. Impostare una routine di completamento chiamando IoSetCompletionRoutineEx.

    Se si invia IN modo asincrono l'ORDINAMENTO, passare un puntatore alla routine di completamento implementata dal chiamante e al relativo contesto. Il chiamante rilascia l'IRP nella routine di completamento.

    Se si invia l'IRP in modo sincrono, implementare una routine di completamento e passare un puntatore a tale routine nella chiamata a IoSetCompletionRoutineEx. La chiamata richiede anche un oggetto KEVENT inizializzato nel parametro Context . Nella routine di completamento impostare l'evento sullo stato segnalato.

  7. Chiamare IoCallDriver per inoltrare l'IRP popolato all'oggetto dispositivo inferiore successivo nello stack di dispositivi. Per una chiamata sincrona, dopo aver chiamato IoCallDriver, attendere l'oggetto evento chiamando KeWaitForSingleObject per ottenere la notifica dell'evento.

  8. Al termine dell'IRP, controllare il membro IoStatus.Status di IRP e valutare il risultato. Se L'IoStatus.Status è STATUS_SUCCESS, la richiesta ha avuto esito positivo.

Invio sincrono USB

Nell'esempio seguente viene illustrato come inviare in modo sincrono UN'istanza di 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;
}

Invio asincrono USB

Nell'esempio seguente viene illustrato come inviare in modo asincrono un oggetto 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;
}

Invio di richieste a un dispositivo USB