windows USB 設備驅動開發-USB復合設備的注冊

USB 多功能設備的驅動程序(稱為復合驅動程序)可以向基礎 USB 驅動程序堆棧注冊和注銷復合設備。 Microsoft 提供的驅動程序(Usbccgp.sys)是由 Windows 加載的默認復合驅動程序。 本文中的過程適用于替換Usbccgp.sys的基于 WDM的自定義 Windows 驅動程序模型 。

通用串行總線 (USB) 設備可以提供多個同時處于活動狀態的功能。 此類多功能設備也稱為 復合設備。 例如,復合設備可能為鍵盤功能定義一個函數,為鼠標定義另一個函數。 復合驅動程序枚舉設備的功能。 復合驅動程序可以在整體模型中管理這些函數本身,或為每個函數創建物理設備對象 (PDO) 。 這些單獨的 PDO 由各自的 USB 功能驅動程序、鍵盤驅動程序和鼠標驅動程序管理。

USB 3.0 規范定義了 函數暫停和遠程喚醒功能 ,使各個函數能夠進入和退出低功耗狀態,而不會影響其他功能或整個設備的電源狀態。?

若要使用該功能,復合驅動程序需要將設備注冊到基礎 USB 驅動程序堆棧。 由于該功能適用于 USB 3.0 設備,因此復合驅動程序必須確保基礎堆棧支持版本USBD_INTERFACE_VERSION_602。 通過注冊請求,復合驅動程序:

  • 通知基礎 USB 驅動程序堆棧,驅動程序負責發送請求,以支持功能驅動進行遠程喚醒。 遠程喚醒請求由 USB 驅動程序堆棧處理,該堆棧將必要的協議請求發送到設備;
  • 獲取 (USB 驅動程序堆棧分配的每個函數) 一個函數句柄的列表。 然后,復合驅動程序可以在驅動程序的請求中使用函數句柄,以便遠程喚醒與句柄關聯的函數;

通常,復合驅動程序在驅動程序的 AddDevice 或啟動設備例程中發送注冊請求來處理 IRP_MN_START_DEVICE。 因此,復合驅動程序會釋放在驅動程序的卸載例程,例如 stop-device (IRP_MN_STOP_DEVICE ) 或 remove-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.分配 REGISTER_COMPOSITE_DEVICE 結構,并通過調用 USBD_BuildRegisterCompositeDevice 例程初始化 結構 。 在調用中,指定 USBD 句柄、初始化 COMPOSITE_DEVICE_CAPABILITIES 結構和函數數;

4.通過調用 IoAllocateIrp (IRP) 分配 I/O 請求數據包,并通過調用 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_LOCATION 的 Parameters.DeviceIoControl.IoControlCode 成員設置為IOCTL_INTERNAL_USB_UNREGISTER_COMPOSITE_DEVICE來生成請求;
  3. 調用 IoCallDriver ,通過將 IRP 傳遞到下一個堆棧位置來發送請求;

復合驅動程序在 remove-device 例程的上下文中發送一次 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;  
}

在后續會講述復合設備的電源管理問題。?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/44039.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/44039.shtml
英文地址,請注明出處:http://en.pswp.cn/web/44039.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

c語言的簡易教法—— 函數遞歸

文章目錄 一、什么是遞歸?1.1遞歸的思想1.2遞歸的限制條件 二、遞歸案例2.1 案例1:求n的階層2.1.1分析2.1.2 遞歸函數(Fact)的代碼實現2.1.3 測試:main函數實現2.1.4 運行結果和畫圖推演2.1.5 擴展:迭代方法…

【66個開源+44個閉源Agent項目】

開源AI?Agent 1.AgentGPT 基于瀏覽器的 AutoGPT 實現,可通過無代碼平臺訪問。https://agentgpt.reworkd.ai/zh 2.AI Legion 一個讓智能體協同工作的平臺,其類似于 AutoGPT 和 Baby AGI,但用 TypeScript 編寫。https://github.com/eumemi…

如何使用BERT進行下游任務 - Transformer教程

BERT,即Bidirectional Encoder Representations from Transformers,是谷歌于2018年發布的預訓練語言模型。BERT的出現標志著自然語言處理領域的一個重要里程碑,因為它大幅提高了多種語言任務的性能。本文將詳細介紹如何使用BERT進行下游任務&…

華為如何做成數字化轉型?

目錄 企業數字化轉型是什么? 華為如何定義數字化轉型? 為什么做數字化轉型? 怎么做數字化轉型? 華為IPD的最佳實踐之“金蝶云” 企業數字化轉型是什么? 先看一下案例,華為經歷了多次戰略轉型&#xf…

前端工程化:Webpack配置全攻略

前端工程化:Webpack配置全攻略 前端小伙伴們,今天我們來聊聊那個讓人又愛又恨的 Webpack。沒錯,就是那個配置起來讓你想砸鍵盤,但又離不開它的構建工具。別擔心,跟著我來,保證讓你從 Webpack 小白變成配置…

人臉識別與檢測(保姆級教程--附帶源碼)

人臉識別與檢測(保姆級教程–附帶源碼) 項目背景 因項目需要招聘了一些日結工人,因此需要對工地現場的工人進行考勤管理,但工地只有海康攝像頭沒有專業考勤設備,因此需要基于視頻流開發人臉識別與檢測功能&#xff1…

Windows 虛擬機服務器項目部署

目錄 一、部署JDK下載JDK安裝JDK1.雙擊 jdk.exe 安裝程序2.點擊【下一步】3.默認安裝位置,點擊【下一步】4.等待提取安裝程序5.默認安裝位置,點擊【下一步】6.等待安裝7.安裝成功,點擊【關閉】 二、部署TomcatTomcat主要特點包括:…

奇怪的錯誤記錄

https://github.com/meta-llama/llama3/issues/80 讀模型沒問題,推理時出現: RuntimeError: “triu_tril_cuda_template” not implemented for ‘BFloat16’ ———————————————— 事發原因 我嘗試了解transformers的AutoProcessor時&a…

感應觸摸芯片集成為MCU,深度應用觸控按鍵技術的VR眼鏡

VR(Virtual Reality)即虛擬現實,簡稱VR,其具體內涵是綜合利用計算機圖形系統和各種現實及控制等接口設備,在計算機上生成的、可交互的三維環境中提供沉浸感覺的技術。它的工作原理是將左右眼圖像交互顯示在屏幕上的方式…

技術速遞|宣布為 .NET 升級助手提供第三方 API 和包映射支持

作者:Marco Goertz 排版:Alan Wang .NET 升級助手是一個 Visual Studio 擴展和命令行工具,可幫助您將應用從之前的 .NET 和 .NET Framework 升級到最新版本的 .NET。正如我們在之前的文章中所描述的那樣,它為升級 Microsoft 庫和框…

技術總結(1)——方向與成長思考

不知不覺已經發了30篇技術博客,本來最開始想的是回顧自己的技術生涯,怎樣做到失敗的生涯,但是后面發現,開始逐步寫技術博客,慢慢的開始沉浸里面這種回顧技術的感覺。做技術的人通常不喜歡研究市場,而做市場…

模型剪枝知識點整理

模型剪枝知識點整理 剪枝是深度學習模型優化的兩種常見技術,用于減少模型復雜度和提升推理速度,適用于資源受限的環境。 剪枝(Pruning) 剪枝是一種通過移除模型中不重要或冗余的參數來減少模型大小和計算量的方法。剪枝通常分為…

編程是學什么:探索編程世界的四大核心領域

編程是學什么:探索編程世界的四大核心領域 在數字化時代的浪潮中,編程已成為一項重要的技能。但很多人對于編程的學習內容仍然感到困惑,那么,編程究竟是學什么呢?本文將從四個方面、五個方面、六個方面和七個方面&…

探索TASKCTL和 DataStage 的ETL任務調度協同

在復雜多變的企業環境中,高效、準確的數據處理是支撐業務決策與運營的核心。本文將深入探討任務調度平臺TASKCTL與ETL工具DataStage的深度融合,通過詳盡的代碼示例、結合細節以及實際案例的具體描述,展示這兩個工具如何攜手打造企業數據處理生…

Xcode構建設置自定義:打造個性化的編譯環境

標題:Xcode構建設置自定義:打造個性化的編譯環境 在軟件開發過程中,根據不同的開發階段和需求,經常需要調整編譯設置以優化構建過程。Xcode作為蘋果官方的集成開發環境(IDE),提供了豐富的自定義…

簡述 Java 內存模型(JMM),特別是堆與棧的區別?

Java內存模型(JMM)是Java平臺定義的一種多線程之間的通信規范,它確保了在不同的線程之間能夠正確地共享和協調對內存的訪問。 JMM的關鍵目標是解決并發編程中的可見性、原子性和有序性問題。 簡單來說,它規定了如何在硬件內存、…

【C語言】 —— 預處理詳解(下)

【C語言】 —— 預處理詳解(下) 前言七、# 和 \##7.1 # 運算符7.2 ## 運算符 八、命名約定九、# u n d e f undef undef十、命令行定義十一、條件編譯11.1、單分支的條件編譯11.2、多分支的條件編譯11.3、判斷是否被定義11.4、嵌套指令 十二、頭文件的包…

淺層神經網絡示例

輸出層采用sigmoid激活,隱藏層采用tanh激活 import h5py import numpy as npfrom project_02.code.planar_utils import load_planar_dataset, plot_decision_boundarydef sigmoid(z):s 1 / (1 np.exp(-z))return sdef init_parameters(n_x, n_h, n_y):"&qu…

如何在 Objective-C 中實現多態性,并且它與其他面向對象編程語言的多態性實現有何差異?

在Objective-C中,多態性可以通過使用父類的指針來調用子類的方法來實現。具體來說,可以定義一個父類的指針,然后將子類的實例賦值給這個指針。這樣,即使使用父類的指針來調用方法,實際上會調用子類的方法。 需要注意的…

Day1每日編程題日記:數字統計、兩個數組的交集、點擊消除

前言:該篇用于記錄自看。曾回看昨天的做題代碼,竟然會覺得陌生,這竟然是我寫的,細細讀了一下,原來我當時是這么想的。因此我覺得記代碼沒有實際用處,重點是領悟了思想,這樣子代碼就在心中&#…