如何註冊複合裝置
本主題描述 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 驅動程式堆疊的關聯。
配置 COMPOSITE_DEVICE_CAPABILITIES 結構,並藉由呼叫 COMPOSITE_DEVICE_CAPABILITIES_INIT 宏加以初始化。
將COMPOSITE_DEVICE_CAPABILITIES的 CapabilityFunctionSuspend成員設定為 1。
呼叫USBD_BuildRegisterCompositeDevice常式,配置REGISTER_COMPOSITE_DEVICE結構並初始化 結構。 在 呼叫中,指定 USBD 控制碼、初始化 的 COMPOSITE_DEVICE_CAPABILITIES 結構,以及函式數目。
呼叫IoAllocateIrp以配置 I/O 要求封包 (IRP) ,並藉由呼叫IoGetNextIrpStackLocation來取得 IRP 第一個堆疊位置的指標 (IO_STACK_LOCATION) 。
為足以保存函式控制碼陣列的緩衝區配置記憶體 (USBD_FUNCTION_HANDLE) 。 陣列中的專案數目必須是 PDO 的數目。
藉由設定 下列IO_STACK_LOCATION成員來建置要求:
- 將 Parameters.DeviceIoControl.IoControlCode 設定為 IOCTL_INTERNAL_USB_REGISTER_COMPOSITE_DEVICE,以指定要求類型。
- 將 Parameters.Others.Argument1 設定為初始化 REGISTER_COMPOSITE_DEVICE 結構的位址,以指定輸入參數。
- 將 AssociatedIrp.SystemBuffer 設定為步驟 5 中所配置的緩衝區,以指定輸出參數。
呼叫 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,
®isterInfo);
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 = ®isterInfo;
//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;
}
取消註冊複合裝置
- 呼叫IoAllocateIrp以配置 IRP,並藉由呼叫IoGetNextIrpStackLocation來取得 IRP 第一個堆疊位置的指標 (IO_STACK_LOCATION) 。
- 將IO_STACK_LOCATION的Parameters.DeviceIoControl.IoControlCode成員設定為IOCTL_INTERNAL_USB_UNREGISTER_COMPOSITE_DEVICE,以建置要求。
- 呼叫 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
意見反應
https://aka.ms/ContentUserFeedback。
即將登場:在 2024 年,我們將逐步淘汰 GitHub 問題作為內容的意見反應機制,並將它取代為新的意見反應系統。 如需詳細資訊,請參閱:提交並檢視相關的意見反應