共用方式為


如何註冊複合裝置

本主題描述 USB 多重功能裝置的驅動程式,稱為複合驅動程式,如何向基礎 USB 驅動程式堆疊註冊和取消註冊複合裝置。 Microsoft 提供的驅動程式Usbccgp.sys是 Windows 載入的預設複合驅動程式。 本主題中的程式適用于取代Usbccgp.sys的自訂 Windows 驅動程式模型 (WDM) 型複合驅動程式。

通用序列匯流排 (USB) 裝置可以提供多個同時作用中的功能。 這類多重函式裝置也稱為 複合裝置。 例如,複合裝置可能會定義鍵盤功能的函式,以及滑鼠的另一個函式。 複合驅動程式會列舉裝置的功能。 複合驅動程式可以在整合型模型中管理這些函式本身,或為每個函式建立實體裝置物件 (PDO) 。 這些個別 PDO 是由各自的 USB 函式驅動程式、鍵盤驅動程式和滑鼠驅動程式所管理。

USB 3.0 規格會定義 函式暫止和遠端喚醒功能 ,讓個別函式進入和結束低電源狀態,而不會影響其他函式或整個裝置的電源狀態。 如需此功能的詳細資訊,請參閱 如何在複合驅動程式中實作函式暫停

若要使用此功能,複合驅動程式需要向基礎 USB 驅動程式堆疊註冊裝置。 由於此功能適用于 USB 3.0 裝置,因此複合驅動程式必須確定基礎堆疊支援版本USBD_INTERFACE_VERSION_602。 透過註冊要求,複合驅動程式:

  • 通知基礎 USB 驅動程式堆疊,驅動程式負責傳送要求給遠端喚醒的函式。 遠端喚醒要求是由 USB 驅動程式堆疊處理,此堆疊會將必要的通訊協定要求傳送至裝置。
  • 取得每個函式) 由 USB 驅動程式堆疊指派的函式控制碼清單 (一個。 然後,複合驅動程式就可以在驅動程式的要求中使用函式控制碼,以遠端喚醒與控制碼相關聯的函式。

複合驅動程式通常會在驅動程式的 AddDevice 或 start-device 常式中傳送註冊要求,以處理 IRP_MN_START_DEVICE。 因此,複合驅動程式會釋放配置給驅動程式卸載常式中的註冊資源,例如停止裝置 (IRP_MN_STOP_DEVICE ) 或移除裝置常式 (IRP_MN_REMOVE_DEVICE) 。

必要條件

傳送註冊要求之前,請確定:

  • 您有裝置中的函式數目。 該數位可以衍生 get-configuration 要求所擷取的描述元。
  • 您已在先前呼叫 USBD_CreateHandle中取得 USBD 控制碼。
  • 基礎 USB 驅動程式堆疊支援 USB 3.0 裝置。 若要這樣做,請呼叫 USBD_IsInterfaceVersionSupported ,並傳遞USBD_INTERFACE_VERSION_602作為要檢查的版本。

如需程式碼範例,請參閱 如何在複合驅動程式中實作函式暫停

指示

註冊複合裝置

下列程式描述您應該如何建置和傳送註冊要求,以建立複合驅動程式與 USB 驅動程式堆疊的關聯。

  1. 配置 COMPOSITE_DEVICE_CAPABILITIES 結構,並藉由呼叫 COMPOSITE_DEVICE_CAPABILITIES_INIT 宏加以初始化。

  2. COMPOSITE_DEVICE_CAPABILITIES的 CapabilityFunctionSuspend成員設定為 1。

  3. 呼叫USBD_BuildRegisterCompositeDevice常式,配置REGISTER_COMPOSITE_DEVICE結構並初始化 結構。 在 呼叫中,指定 USBD 控制碼、初始化 的 COMPOSITE_DEVICE_CAPABILITIES 結構,以及函式數目。

  4. 呼叫IoAllocateIrp以配置 I/O 要求封包 (IRP) ,並藉由呼叫IoGetNextIrpStackLocation來取得 IRP 第一個堆疊位置的指標 (IO_STACK_LOCATION) 。

  5. 為足以保存函式控制碼陣列的緩衝區配置記憶體 (USBD_FUNCTION_HANDLE) 。 陣列中的專案數目必須是 PDO 的數目。

  6. 藉由設定 下列IO_STACK_LOCATION成員來建置要求:

    • Parameters.DeviceIoControl.IoControlCode 設定為 IOCTL_INTERNAL_USB_REGISTER_COMPOSITE_DEVICE,以指定要求類型。
    • Parameters.Others.Argument1 設定為初始化 REGISTER_COMPOSITE_DEVICE 結構的位址,以指定輸入參數。
    • AssociatedIrp.SystemBuffer 設定為步驟 5 中所配置的緩衝區,以指定輸出參數。
  7. 呼叫 IoCallDriver 將 IRP 傳遞至下一個堆疊位置,以傳送要求。

完成時,檢查 USB 驅動程式堆疊所傳回的函式控制碼陣列。 您可以將陣列儲存在驅動程式的裝置內容中,以供日後使用。

下列程式碼範例示範如何建置和傳送註冊要求。 此範例假設複合驅動程式會將先前取得的函式數目和 USBD 控制碼儲存在驅動程式的裝置內容中。

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

取消註冊複合裝置

  1. 呼叫IoAllocateIrp以配置 IRP,並藉由呼叫IoGetNextIrpStackLocation來取得 IRP 第一個堆疊位置的指標 (IO_STACK_LOCATION) 。
  2. IO_STACK_LOCATIONParameters.DeviceIoControl.IoControlCode成員設定為IOCTL_INTERNAL_USB_UNREGISTER_COMPOSITE_DEVICE,以建置要求。
  3. 呼叫 IoCallDriver 將 IRP 傳遞至下一個堆疊位置,以傳送要求。

IOCTL_INTERNAL_USB_UNREGISTER_COMPOSITE_DEVICE要求是由複合驅動程式在移除裝置常式的內容中傳送一次。 要求的目的是要移除 USB 驅動程式堆疊與其列舉函式之間的關聯。 要求也會清除任何建立的資源,以維護該關聯,以及先前註冊要求中傳回的所有函式控制碼。

下列程式碼範例示範如何建置和傳送要求以取消註冊複合裝置。 此範例假設複合驅動程式先前是透過註冊要求註冊,如本主題稍早所述。

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