USB Audio 2.0 Drivers - Windows drivers
Driver on

How to Register a Composite Device – Windows drivers

This matter describes how a driver of a USB multi-function gadget, known as a composite driver, can register and unregister the composite gadget with the underlying USB driver stack. The Microsoft-provided driver, Usbccgp.sys, is the default composite driver that’s loaded by Home windows. The process on this matter applies to a customized Home windows Driver Mannequin (WDM)-based composite driver that replaces Usbccgp.sys.

A Common Serial Bus (USB) gadget can present a number of capabilities which can be lively concurrently. Such multi-function units are also called composite units. For instance, a composite gadget may outline a operate for the keyboard performance and one other operate for the mouse. The capabilities of the gadget are enumerated by the composite driver. The composite driver can handle these capabilities itself in a monolithic mannequin or create bodily gadget objects (PDOs) for every of the capabilities. These particular person PDOs are managed by their respective USB operate drivers, the keyboard driver and the mouse driver.

The USB 3.zero specification defines the operate droop and distant wake-up function that allows particular person capabilities to enter and exit low-power states with out affecting the facility state of different capabilities or your entire gadget. For extra details about the function, see Learn how to Implement Perform Droop in a Composite Driver.

To make use of the function, the composite driver must register the gadget with the underlying USB driver stack. As a result of the function applies to USB 3.zero units, the composite driver should be sure that the underlying stack helps model USBD_INTERFACE_VERSION_602. By means of the registration request, the composite driver:

  • Informs the underlying USB driver stack that the driving force is chargeable for sending a request to arm a operate for distant wake-up. The distant wake-up request is processed by the USB driver stack, which sends the mandatory protocol requests to the gadget.
  • Obtains a listing of operate handles (one per operate) assigned by the USB driver stack. The composite driver can then use a operate deal with within the driver’s the request for distant wake-up of the operate related to the deal with.

Usually a composite driver sends the registration request within the driver’s AddDevice or the start-device routine to deal with IRP_MN_START_DEVICE. Consequently, the composite driver releases the assets which can be allotted for the registration within the driver’s unload routines reminiscent of stop-device (IRP_MN_STOP_DEVICE) or remove-device routine (IRP_MN_REMOVE_DEVICE).

Conditions

Earlier than sending the registration request, be sure that:

  • You’ve the variety of capabilities within the gadget. That quantity might be derived the descriptors retrieved by the get-configuration request.
  • You’ve obtained a USBD deal with in a earlier name to USBD_CreateHandle.
  • The underlying USB driver stack helps USB 3.zero units. To take action, name USBD_IsInterfaceVersionSupported and move USBD_INTERFACE_VERSION_602 because the model to examine.

Register a Composite Gadget

The next process describes how it’s best to construct and ship a registration request to affiliate a composite driver with the USB driver stack.

  1. Allocate a COMPOSITE_DEVICE_CAPABILITIES construction and initialize it by calling the COMPOSITE_DEVICE_CAPABILITIES_INIT macro.

  2. Set the CapabilityFunctionSuspend member of COMPOSITE_DEVICE_CAPABILITIES to 1.

  3. Allocate a REGISTER_COMPOSITE_DEVICE construction and initialize the construction by calling the USBD_BuildRegisterCompositeDevice routine. Within the name, specify the USBD deal with, the initialized COMPOSITE_DEVICE_CAPABILITIES construction, and the variety of capabilities.

  4. Allocate an I/O request packet (IRP) by calling IoAllocateIrp and get a pointer to the IRP’s first stack location (IO_STACK_LOCATION) by calling IoGetNextIrpStackLocation.

  5. Allocate reminiscence for a buffer that’s giant sufficient to carry an array of operate handles (USBD_FUNCTION_HANDLE). The variety of parts within the array should be the variety of PDOs.

  6. Construct the request by setting the next members of the IO_STACK_LOCATION:

    • Specify the kind of request by setting Parameters.DeviceIoControl.IoControlCode to IOCTL_INTERNAL_USB_REGISTER_COMPOSITE_DEVICE.
    • Specify the enter parameter by setting Parameters.Others.Argument1 to the tackle of the initialized REGISTER_COMPOSITE_DEVICE construction.
    • Specify the output parameter by setting AssociatedIrp.SystemBuffer to the buffer that was allotted in step 5.
  7. Name IoCallDriver to ship the request by passing the IRP to the subsequent stack location.

Upon completion, examine the array of operate handles that’s returned by the USB driver stack. You’ll be able to retailer the array within the driver’s gadget context for future use.

The next code instance exhibits easy methods to construct and ship a registration request. The instance assumes that the composite driver shops the beforehand obtained variety of capabilities and the USBD deal with within the driver’s gadget context.

VOID  RegisterCompositeDriver(PPARENT_FDO_EXT parentFdoExt)  
{  
    PIRP                            irp;  
    REGISTER_COMPOSITE_DRIVER       registerInfo;  
    COMPOSITE_DRIVER_CAPABILITIES   capabilities;  
    NTSTATUS                        standing;  
    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,  
        ®isterInfo);  

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

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

    nextSp = IoGetNextIrpStackLocation(irp);  

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

    buffer = ExAllocatePoolWithTag (NonPagedPool, bufSize, POOL_TAG);  

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

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

    //Set the enter buffer in Argument1      
    nextSp->Parameters.Others.Argument1 = ®isterInfo;  

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

    // Move the IRP all the way down to the subsequent gadget object within the stack. Not proven.
    standing = CallNextDriverSync(parentFdoExt, irp, FALSE);  

    if (!NT_SUCCESS(standing))
    {  
        //Did not register the composite driver.
        goto ExitRegisterCompositeDriver;    
    }  

    parentFdoExt->compositeDriverRegistered = TRUE;  

    parentFdoExt->functionHandleArray = (PUSBD_FUNCTION_HANDLE) buffer;  

Finish:  
    if (!NT_SUCCESS(standing)) 
    {  
        if (buffer != NULL) 
        {  
            ExFreePoolWithTag (buffer, POOL_TAG);  
            buffer = NULL;  
        }  
    }  

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

    return;  
}

Unregister the Composite Gadget

  1. Allocate an IRP by calling IoAllocateIrp and get a pointer to the IRP’s first stack location (IO_STACK_LOCATION) by calling IoGetNextIrpStackLocation.
  2. Construct the request by setting the Parameters.DeviceIoControl.IoControlCode member of IO_STACK_LOCATION to IOCTL_INTERNAL_USB_UNREGISTER_COMPOSITE_DEVICE.
  3. Name IoCallDriver to ship the request by passing the IRP to the subsequent stack location.

The IOCTL_INTERNAL_USB_UNREGISTER_COMPOSITE_DEVICE request is shipped as soon as by the composite driver within the context of remove-device routine. The aim of the request is to take away the affiliation between the USB driver stack and the composite driver and its enumerated operate. The request additionally cleans up any assets that have been created to keep up that affiliation and all operate handles that have been returned within the earlier registration request.

The next code instance exhibits easy methods to construct and ship a request to unregister the composite gadget. The instance assumes that the composite driver was beforehand registered by way of a registration request as described earlier on this matter.

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

    PAGED_CODE();  

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

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

    nextSp = IoGetNextIrpStackLocation(irp);  

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

    // Move the IRP all the way down to the subsequent gadget object within the stack. Not proven.
    standing = CallNextDriverSync(parentFdoExt, irp, FALSE);  

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

    IoFreeIrp(irp);  

    return;  
}

IOCTL_INTERNAL_USB_REGISTER_COMPOSITE_DEVICE
IOCTL_INTERNAL_USB_UNREGISTER_COMPOSITE_DEVICE

Leave a Reply

Your email address will not be published. Required fields are marked *