Partager via


Comment inscrire un appareil composite

Cette rubrique décrit comment un pilote d’un périphérique usb multi-fonction, appelé pilote composite, peut inscrire et annuler l’inscription du périphérique composite auprès de la pile de pilotes USB sous-jacente. Le pilote fourni par Microsoft, Usbccgp.sys, est le pilote composite par défaut chargé par Windows. La procédure décrite dans cette rubrique s’applique à un pilote composite wdM (Windows Driver Model) personnalisé qui remplace Usbccgp.sys.

Un périphérique USB (Universal Serial Bus) peut fournir plusieurs fonctions actives simultanément. Ces appareils multi-fonctions sont également appelés appareils composites. Par exemple, un appareil composite peut définir une fonction pour la fonctionnalité clavier et une autre fonction pour la souris. Les fonctions de l’appareil sont énumérées par le pilote composite. Le pilote composite peut gérer ces fonctions lui-même dans un modèle monolithique ou créer des objets d’appareil physique (PPO) pour chacune des fonctions. Ces PPO individuels sont gérés par leurs pilotes de fonction USB respectifs, le pilote de clavier et le pilote de souris.

La spécification USB 3.0 définit la fonctionnalité de suspension de fonction et de mise en éveil à distance qui permet à des fonctions individuelles d’entrer et de quitter des états de faible puissance sans affecter l’état d’alimentation d’autres fonctions ou de l’ensemble de l’appareil. Pour plus d’informations sur la fonctionnalité, consultez How to Implement Function Suspend in a Composite Driver.

Pour utiliser cette fonctionnalité, le pilote composite doit inscrire le périphérique auprès de la pile de pilotes USB sous-jacente. Étant donné que la fonctionnalité s’applique aux périphériques USB 3.0, le pilote composite doit s’assurer que la pile sous-jacente prend en charge la version USBD_INTERFACE_VERSION_602. Par le biais de la demande d’inscription, le pilote composite :

  • Informe la pile de pilotes USB sous-jacente que le pilote est responsable de l’envoi d’une demande d’armage d’une fonction pour la mise en éveil à distance. La demande de mise en éveil à distance est traitée par la pile de pilotes USB, qui envoie les demandes de protocole nécessaires à l’appareil.
  • Obtient la liste des descripteurs de fonction (un par fonction) attribués par la pile de pilotes USB. Le pilote composite peut ensuite utiliser un handle de fonction dans la demande de mise en éveil à distance du pilote de la fonction associée au handle.

En règle générale, un pilote composite envoie la demande d’inscription dans la routine AddDevice ou start-device du pilote pour gérer IRP_MN_START_DEVICE. Par conséquent, le pilote composite libère les ressources qui sont allouées pour l’inscription dans les routines de déchargement du pilote, telles que la routine stop-device (IRP_MN_STOP_DEVICE) ou remove-device routine (IRP_MN_REMOVE_DEVICE).

Prérequis

Avant d’envoyer la demande d’inscription, assurez-vous que :

  • Vous avez le nombre de fonctions dans l’appareil. Ce nombre peut être dérivé des descripteurs récupérés par la demande get-configuration.
  • Vous avez obtenu un handle USBD lors d’un appel précédent à USBD_CreateHandle.
  • La pile de pilotes USB sous-jacente prend en charge les périphériques USB 3.0. Pour ce faire, appelez USBD_IsInterfaceVersionSupported et transmettez USBD_INTERFACE_VERSION_602 comme version à case activée.

Pour obtenir un exemple de code, consultez How to Implement Function Suspend in a Composite Driver.

Instructions

Inscrire un appareil composite

La procédure suivante décrit comment générer et envoyer une demande d’inscription pour associer un pilote composite à la pile de pilotes USB.

  1. Allouez une structure COMPOSITE_DEVICE_CAPABILITIES et initialisez-la en appelant la macro COMPOSITE_DEVICE_CAPABILITIES_INIT .

  2. Définissez le membre CapabilityFunctionSuspend de COMPOSITE_DEVICE_CAPABILITIES sur 1.

  3. Allouez une structure REGISTER_COMPOSITE_DEVICE et initialisez la structure en appelant la routine USBD_BuildRegisterCompositeDevice . Dans l’appel, spécifiez le handle USBD, la structure COMPOSITE_DEVICE_CAPABILITIES initialisée et le nombre de fonctions.

  4. Allouez un paquet de demandes d’E/S (IRP) en appelant IoAllocateIrp et obtenez un pointeur vers le premier emplacement de pile (IO_STACK_LOCATION) de l’IRP en appelant IoGetNextIrpStackLocation.

  5. Allouez de la mémoire pour une mémoire tampon suffisamment grande pour contenir un tableau de handles de fonction (USBD_FUNCTION_HANDLE). Le nombre d’éléments dans le tableau doit être le nombre de PPO.

  6. Générez la requête en définissant les membres suivants du IO_STACK_LOCATION :

    • Spécifiez le type de requête en définissant Parameters.DeviceIoControl.IoControlCode sur IOCTL_INTERNAL_USB_REGISTER_COMPOSITE_DEVICE.
    • Spécifiez le paramètre d’entrée en définissant Parameters.Others.Argument1 sur l’adresse de la structure REGISTER_COMPOSITE_DEVICE initialisée.
    • Spécifiez le paramètre de sortie en définissant AssociatedIrp.SystemBuffer sur la mémoire tampon qui a été allouée à l’étape 5.
  7. Appelez IoCallDriver pour envoyer la demande en passant l’IRP à l’emplacement de pile suivant.

Une fois l’opération terminée, examinez le tableau de poignées de fonction retourné par la pile de pilotes USB. Vous pouvez stocker le tableau dans le contexte de périphérique du pilote pour une utilisation ultérieure.

L’exemple de code suivant montre comment générer et envoyer une demande d’inscription. L’exemple suppose que le pilote composite stocke le nombre obtenu précédemment de fonctions et le handle USBD dans le contexte du périphérique du pilote.

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;  
}

Annuler l’inscription de l’appareil composite

  1. Allouez un IRP en appelant IoAllocateIrp et obtenez un pointeur vers le premier emplacement de pile (IO_STACK_LOCATION) de l’IRP en appelant IoGetNextIrpStackLocation.
  2. Générez la requête en définissant le membre Parameters.DeviceIoControl.IoControlCode de IO_STACK_LOCATION sur IOCTL_INTERNAL_USB_UNREGISTER_COMPOSITE_DEVICE.
  3. Appelez IoCallDriver pour envoyer la demande en passant l’IRP à l’emplacement de pile suivant.

La demande IOCTL_INTERNAL_USB_UNREGISTER_COMPOSITE_DEVICE est envoyée une seule fois par le pilote composite dans le contexte de la routine remove-device. L’objectif de la requête est de supprimer l’association entre la pile de pilotes USB et le pilote composite et sa fonction énumérée. La demande nettoie également toutes les ressources qui ont été créées pour conserver cette association et tous les handles de fonction qui ont été retournés dans la demande d’inscription précédente.

L’exemple de code suivant montre comment générer et envoyer une demande de désinscription de l’appareil composite. L’exemple suppose que le pilote composite a été précédemment inscrit par le biais d’une demande d’inscription, comme décrit plus haut dans cette rubrique.

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