Come registrare un dispositivo composito

Questo argomento descrive come un driver di un dispositivo a più funzioni USB, denominato driver composito, può registrare e annullare la registrazione del dispositivo composito con lo stack di driver USB sottostante. Il driver fornito da Microsoft, Usbccgp.sys, è il driver composito predefinito caricato da Windows. La procedura descritta in questo argomento si applica a un driver composito basato su Windows Driver Model (WDM) personalizzato che sostituisce Usbccgp.sys.

Un dispositivo USB (Universal Serial Bus) può fornire più funzioni attive contemporaneamente. Tali dispositivi a più funzioni sono noti anche come dispositivi compositi. Ad esempio, un dispositivo composito potrebbe definire una funzione per la funzionalità della tastiera e un'altra funzione per il mouse. Le funzioni del dispositivo vengono enumerate dal driver composito. Il driver composito può gestire tali funzioni in un modello monolitico o creare oggetti dispositivo fisico (PDO) per ognuna delle funzioni. I singoli PDO sono gestiti dai rispettivi driver di funzione USB, dal driver della tastiera e dal driver del mouse.

La specifica USB 3.0 definisce la funzionalità di sospensione della funzione e riattivazione remota che consente alle singole funzioni di entrare ed uscire da stati a basso consumo senza influire sullo stato di alimentazione di altre funzioni o dell'intero dispositivo. Per altre informazioni sulla funzionalità, vedere How to Implement Function Suspend in a Composite Driver.For more information about the feature, see How to Implement Function Suspend in a Composite Driver.

Per usare la funzionalità, il driver composito deve registrare il dispositivo con lo stack di driver USB sottostante. Poiché la funzionalità si applica ai dispositivi USB 3.0, il driver composito deve assicurarsi che lo stack sottostante supporti la versione USBD_INTERFACE_VERSION_602. Tramite la richiesta di registrazione, il driver composito:

  • Informa lo stack di driver USB sottostante che il driver è responsabile dell'invio di una richiesta al braccio di una funzione per la riattivazione remota. La richiesta di riattivazione remota viene elaborata dallo stack di driver USB, che invia le richieste di protocollo necessarie al dispositivo.
  • Ottiene un elenco di handle di funzione (uno per funzione) assegnato dallo stack di driver USB. Il driver composito può quindi usare un handle di funzione nella richiesta di riattivazione remota della funzione associata all'handle del driver.

In genere un driver composito invia la richiesta di registrazione nel componente AddDevice del driver o nella routine del dispositivo di avvio per gestire IRP_MN_START_DEVICE. Di conseguenza, il driver composito rilascia le risorse allocate per la registrazione nelle routine di scaricamento del driver, ad esempio stop-device (IRP_MN_STOP_DEVICE) o remove-device routine (IRP_MN_REMOVE_DEVICE).

Prerequisiti

Prima di inviare la richiesta di registrazione, assicurarsi che:

  • Il numero di funzioni nel dispositivo è disponibile. Tale numero può essere derivato dai descrittori recuperati dalla richiesta get-configuration.
  • Hai ottenuto un handle USBD in una chiamata precedente a USBD_CreateHandle.
  • Lo stack di driver USB sottostante supporta i dispositivi USB 3.0. A tale scopo, chiamare USBD_IsInterfaceVersionSupported e passare USBD_INTERFACE_VERSION_602 come versione da controllare.

Per un esempio di codice, vedere How to Implement Function Suspend in a Composite Driver.For a code example, see How to Implement Function Suspend in a Composite Driver.

Istruzioni

Registrare un dispositivo composito

La procedura seguente descrive come compilare e inviare una richiesta di registrazione per associare un driver composito allo stack di driver USB.

  1. Allocare una struttura COMPOSITE_DEVICE_CAPABILITIES e inizializzarla chiamando la macro COMPOSITE_DEVICE_CAPABILITIES_INIT .

  2. Impostare il membro CapabilityFunctionSuspend di COMPOSITE_DEVICE_CAPABILITIES su 1.

  3. Allocare una struttura REGISTER_COMPOSITE_DEVICE e inizializzare la struttura chiamando la routine USBD_BuildRegisterCompositeDevice . Nella chiamata specificare l'handle USBD, la struttura COMPOSITE_DEVICE_CAPABILITIES inizializzata e il numero di funzioni.

  4. Allocare un pacchetto di richiesta di I/O chiamando IoAllocateIrp e ottenere un puntatore alla prima posizione dello stack di IRP (IO_STACK_LOCATION) chiamando IoGetNextIrpStackLocation.

  5. Allocare memoria per un buffer sufficientemente grande da contenere una matrice di handle di funzione (USBD_FUNCTION_HANDLE). Il numero di elementi nella matrice deve essere il numero di PDO.

  6. Compilare la richiesta impostando i membri seguenti del IO_STACK_LOCATION:

    • Specificare il tipo di richiesta impostando Parameters.DeviceIoControl.IoControlCode su IOCTL_INTERNAL_USB_REGISTER_COMPOSITE_DEVICE.
    • Specificare il parametro di input impostando Parameters.Others.Argument1 sull'indirizzo della struttura REGISTER_COMPOSITE_DEVICE inizializzata.
    • Specificare il parametro di output impostando AssociatedIrp.SystemBuffer sul buffer allocato nel passaggio 5.
  7. Chiamare IoCallDriver per inviare la richiesta passando l'IRP alla posizione successiva dello stack.

Al termine, esaminare la matrice di handle di funzione restituiti dallo stack di driver USB. È possibile archiviare la matrice nel contesto di dispositivo del driver per un uso futuro.

Nell'esempio di codice seguente viene illustrato come compilare e inviare una richiesta di registrazione. L'esempio presuppone che il driver composito archivii il numero di funzioni ottenuto in precedenza e l'handle USBD nel contesto di dispositivo del driver.

VOID  RegisterCompositeDriver(PPARENT_FDO_EXT parentFdoExt)  
{  
    PIRP                            irp;  
    REGISTER_COMPOSITE_DRIVER       registerInfo;  
    COMPOSITE_DRIVER_CAPABILITIES   capabilities;  
    NTSTATUS                        status;  
    PVOID                           buffer;  
    ULONG                           bufSize;  
    PIO_STACK_LOCATION              nextSp;  

    buffer = NULL;  

    COMPOSITE_DRIVER_CAPABILITIES_INIT(&capabilities);  
    capabilities.CapabilityFunctionSuspend = 1;  

    USBD_BuildRegisterCompositeDriver(parentFdoExt->usbdHandle,  
        capabilities,  
        parentFdoExt->numFunctions,  
        &registerInfo);  

    irp = IoAllocateIrp(parentFdoExt->topDevObj->StackSize, FALSE);  

    if (irp == NULL) 
    {  
        //IoAllocateIrp failed.
        status = STATUS_INSUFFICIENT_RESOURCES;  
        goto ExitRegisterCompositeDriver;    
    }  

    nextSp = IoGetNextIrpStackLocation(irp);  

    bufSize = parentFdoExt->numFunctions * sizeof(USBD_FUNCTION_HANDLE);  

    buffer = ExAllocatePoolWithTag (NonPagedPool, bufSize, POOL_TAG);  

    if (buffer == NULL) 
    {  
        // Memory alloc for function-handles failed.
        status = STATUS_INSUFFICIENT_RESOURCES;  
        goto ExitRegisterCompositeDriver;    
    }  

    nextSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;     
    nextSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_REGISTER_COMPOSITE_DRIVER;  

    //Set the input buffer in Argument1      
    nextSp->Parameters.Others.Argument1 = &registerInfo;  

    //Set the output buffer in SystemBuffer field for USBD_FUNCTION_HANDLE.      
    irp->AssociatedIrp.SystemBuffer = buffer;  

    // Pass the IRP down to the next device object in the stack. Not shown.
    status = CallNextDriverSync(parentFdoExt, irp, FALSE);  

    if (!NT_SUCCESS(status))
    {  
        //Failed to register the composite driver.
        goto ExitRegisterCompositeDriver;    
    }  

    parentFdoExt->compositeDriverRegistered = TRUE;  

    parentFdoExt->functionHandleArray = (PUSBD_FUNCTION_HANDLE) buffer;  

End:  
    if (!NT_SUCCESS(status)) 
    {  
        if (buffer != NULL) 
        {  
            ExFreePoolWithTag (buffer, POOL_TAG);  
            buffer = NULL;  
        }  
    }  

    if (irp != NULL) 
    {  
        IoFreeIrp(irp);  
        irp = NULL;  
    }  

    return;  
}

Annullare la registrazione del dispositivo composito

  1. Allocare un IRP chiamando IoAllocateIrp e ottenere un puntatore alla prima posizione dello stack (IO_STACK_LOCATION) di IoGetNextIrpStackLocation.
  2. Compilare la richiesta impostando il membro Parameters.DeviceIoControl.IoControlCode di IO_STACK_LOCATION su IOCTL_INTERNAL_USB_UNREGISTER_COMPOSITE_DEVICE.
  3. Chiamare IoCallDriver per inviare la richiesta passando l'IRP alla posizione successiva dello stack.

La richiesta di IOCTL_INTERNAL_USB_UNREGISTER_COMPOSITE_DEVICE viene inviata una volta dal driver composito nel contesto della routine remove-device. Lo scopo della richiesta è rimuovere l'associazione tra lo stack di driver USB e il driver composito e la relativa funzione enumerata. La richiesta pulisce anche tutte le risorse create per mantenere tale associazione e tutti gli handle di funzione restituiti nella richiesta di registrazione precedente.

L'esempio di codice seguente illustra come compilare e inviare una richiesta per annullare la registrazione del dispositivo composito. Nell'esempio si presuppone che il driver composito sia stato registrato in precedenza tramite una richiesta di registrazione, come descritto in precedenza in questo argomento.

VOID  UnregisterCompositeDriver(  
    PPARENT_FDO_EXT parentFdoExt )  
{  
    PIRP                irp;  
    PIO_STACK_LOCATION  nextSp;  
    NTSTATUS            status;  

    PAGED_CODE();  

    irp = IoAllocateIrp(parentFdoExt->topDevObj->StackSize, FALSE);  

    if (irp == NULL) 
    {  
        //IoAllocateIrp failed.
        status = STATUS_INSUFFICIENT_RESOURCES;  
        return;  
    }  

    nextSp = IoGetNextIrpStackLocation(irp);  

    nextSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;     
    nextSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_UNREGISTER_COMPOSITE_DRIVER;  

    // Pass the IRP down to the next device object in the stack. Not shown.
    status = CallNextDriverSync(parentFdoExt, irp, FALSE);  

    if (NT_SUCCESS(status)) 
    {  
        parentFdoExt->compositeDriverRegistered = FALSE;      
    }  

    IoFreeIrp(irp);  

    return;  
}

IOCTL_INTERNAL_USB_REGISTER_COMPOSITE_DEVICE
IOCTL_INTERNAL_USB_UNREGISTER_COMPOSITE_DEVICE