Windows下USB驱动基础知识
+ -

Windows系统UAC音频设备的初始化过程 USB麦克风USB声卡

2023-01-12 173 0

第一步当然是获取设备描述符了,使用UsbBuildGetDescriptorRequest函数初始化获取设备描述符的Urb,然后再调用SubmitUrbToUsbdSynch函数返回。当然获取的设备描述符必须保存。

第二步是获取配置描述符,方法和获取设备描述符一致,只是需要分2次获取。第一次只获取sizeof(USB_CONFIGURATION_DESCRIPTOR)大小的配置描述符内容,然后解析出配置描述符的总长度之后,再获取全部的配置描述符全部内容。

第三步就是选择配置。根据获取到的配置描述符解析出接口描述符的总数量,然后申请N+1个USBD_INTERFACE_LIST_ENTRY(最后一个必须会为NULL)内存空间。USBD_INTERFACE_LIST_ENTRY结构体的定义如下:

typedef struct _USBD_INTERFACE_LIST_ENTRY {
  PUSB_INTERFACE_DESCRIPTOR  InterfaceDescriptor;
  PUSBD_INTERFACE_INFORMATION  Interface;
} USBD_INTERFACE_LIST_ENTRY, *PUSBD_INTERFACE_LIST_ENTRY;

由于每人接口描述符都对应一个USBD_INTERFACE_LIST_ENTRY,故其成员InterfaceDescriptor指向的是获取的配置描述符中对应的接口描述符的指针。PUSBD_INTERFACE_INFORMATION是选择配置之后的接口描述符下的相关接口和USB端点信息。
以上都是USB设备统一的方法,而对于UAC这种复杂的复合设备,需要做一些特别的处理。这种表现在音频控制接口和音频流接口上。
使用USBD_ParseConfigurationDescriptorEx分别解析出音频流接口描述符和音频控制接口描述符的位置。
其对应的AudioClass为USB_DEVICE_CLASS_AUDIO=0x01,而SubClass分别为AUDIO_SUBCLASS_CONTROL=0x01和AUDIO_SUBCLASS_STREAMING=0x02,当然,搞了这么多,竟然只是为了验证配置描述符中是否有相关的信息。这从另一方面来讲,就是对于UAC设备,配置描述符中必须有音频流接口描述符和音频控制接口描述符

我印象是UVC规范中视频流接口描述符中可以为0,却不知道UAC中是否也这样。不过从Windows来看,好像必须得有,至少UAC设备必须有一个音频流接口描述符。

使用USBD_ParseConfigurationDescriptorEx获取Class=USB_DEVICE_CLASS_AUDIO的接口描述符(主要用于跳过IAD,当然像USBTreeViewer又不显示IAD),然后按循环解析以下的相关描述符。

  • 当SubClass=AUDIO_SUBCLASS_MIDISTREAMING,MIDI的,我们不关注。
  • 当SubClass=AUDIO_SUBCLASS_STREAMING,音频流的
  • 当SubClass=AUDIO_SUBCLASS_CONTROL,音频控制的,需要争析其UAC拓扑结构

当然,以上都得保存其存其相关的接口描述符到USBD_INTERFACE_LIST_ENTRY中。

所以说标准的接口描述符是分界面,保存在USBD_INTERFACE_LIST_ENTRY中,而其各对应类的如AUDIO_SUBCLASS_CONTROL的,就对应解析,形成一个树形关系。

生成了USBD_INTERFACE_LIST_ENTRY表格后,使用SubmitUrbToUsbdSynch选择配置。最后保存其句柄。

    pAudioDevice->ConfigurationHandle = pUrb->UrbSelectConfiguration.ConfigurationHandle;

最后,保留留选择配置后的PUSBD_INTERFACE_INFORMATION信息,至此选择配置SET_CONFIGURATION完成。

第三步,使用获取USB总线的接口信息,这由设备的总线驱动提供。生成的IRP默认说不支持,但可以通过MajorFunction= IRP_MJ_PNP和MinorFunction= IRP_MN_QUERY_INTERFACE来IoCallDriver到USB总线。
这玩意又分好多种版本,所以结构体也是随版本在扩展。

#define USB_BUSIF_USBDI_VERSION_0         0x0000
#define USB_BUSIF_USBDI_VERSION_1         0x0001
#define USB_BUSIF_USBDI_VERSION_2         0x0002
#define USB_BUSIF_USBDI_VERSION_3         0x0003

其结构体分别为:

typedef struct _USB_BUS_INTERFACE_USBDI_V0 {
  USHORT  Size;
  USHORT  Version;
  PVOID  BusContext;
  PINTERFACE_REFERENCE  InterfaceReference;
  PINTERFACE_DEREFERENCE  InterfaceDereference;
  PUSB_BUSIFFN_GETUSBDI_VERSION  GetUSBDIVersion;
  PUSB_BUSIFFN_QUERY_BUS_TIME  QueryBusTime;
  PUSB_BUSIFFN_SUBMIT_ISO_OUT_URB  SubmitIsoOutUrb;
  PUSB_BUSIFFN_QUERY_BUS_INFORMATION  QueryBusInformation;
} USB_BUS_INTERFACE_USBDI_V0, *PUSB_BUS_INTERFACE_USBDI_V0;

typedef struct _USB_BUS_INTERFACE_USBDI_V1 {
  USHORT  Size;
  USHORT  Version;
  PVOID  BusContext;
  PINTERFACE_REFERENCE  InterfaceReference;
  PINTERFACE_DEREFERENCE  InterfaceDereference;
  PUSB_BUSIFFN_GETUSBDI_VERSION  GetUSBDIVersion;
  PUSB_BUSIFFN_QUERY_BUS_TIME  QueryBusTime;
  PUSB_BUSIFFN_SUBMIT_ISO_OUT_URB  SubmitIsoOutUrb;
  PUSB_BUSIFFN_QUERY_BUS_INFORMATION  QueryBusInformation;
  PUSB_BUSIFFN_IS_DEVICE_HIGH_SPEED IsDeviceHighSpeed;
} USB_BUS_INTERFACE_USBDI_V1, *PUSB_BUS_INTERFACE_USBDI_V1;

typedef struct _USB_BUS_INTERFACE_USBDI_V2 {
  USHORT  Size;
  USHORT  Version;
  PVOID  BusContext;
  PINTERFACE_REFERENCE  InterfaceReference;
  PINTERFACE_DEREFERENCE  InterfaceDereference;
  PUSB_BUSIFFN_GETUSBDI_VERSION  GetUSBDIVersion;
  PUSB_BUSIFFN_QUERY_BUS_TIME  QueryBusTime;
  PUSB_BUSIFFN_SUBMIT_ISO_OUT_URB  SubmitIsoOutUrb;
  PUSB_BUSIFFN_QUERY_BUS_INFORMATION  QueryBusInformation;
  PUSB_BUSIFFN_IS_DEVICE_HIGH_SPEED IsDeviceHighSpeed;
  PUSB_BUSIFFN_ENUM_LOG_ENTRY  EnumLogEntry;
} USB_BUS_INTERFACE_USBDI_V2, *PUSB_BUS_INTERFACE_USBDI_V2;

typedef struct _USB_BUS_INTERFACE_USBDI_V3 {
    USHORT Size;
    USHORT Version;
    PVOID BusContext;
    PINTERFACE_REFERENCE InterfaceReference;
    PINTERFACE_DEREFERENCE InterfaceDereference;
    PUSB_BUSIFFN_GETUSBDI_VERSION GetUSBDIVersion;
    PUSB_BUSIFFN_QUERY_BUS_TIME QueryBusTime;
    PUSB_BUSIFFN_SUBMIT_ISO_OUT_URB SubmitIsoOutUrb;
    PUSB_BUSIFFN_QUERY_BUS_INFORMATION QueryBusInformation;  //V0
    PUSB_BUSIFFN_IS_DEVICE_HIGH_SPEED IsDeviceHighSpeed;     //V1
    PUSB_BUSIFFN_ENUM_LOG_ENTRY EnumLogEntry;               //V2
    PUSB_BUSIFFN_QUERY_BUS_TIME_EX QueryBusTimeEx;
    PUSB_BUSIFFN_QUERY_CONTROLLER_TYPE QueryControllerType; 
} USB_BUS_INTERFACE_USBDI_V3, *PUSB_BUS_INTERFACE_USBDI_V3;

看结构体,他们就是多了几个成员。这每个成员又都是相关的回调函数

HID人机交互QQ群:564808376    UAC音频QQ群:218581009    UVC相机QQ群:331552032    BOT&UASP大容量存储QQ群:258159197    STC-USB单片机QQ群:315457461    USB技术交流QQ群2:580684376    USB技术交流QQ群:952873936   

0 篇笔记 写笔记

Linux源码分析UVC摄像头的初始化流程分析
UVC摄像头的初始化发生在硬件被接入USB集线器中,设备初USB驱动识别为摄像头的后续初始化流程。和Windows的AddDevice驱动函数一样,Linux设备的创建和侦测是通过int uvc_probe函数实现的。其函数的调用关系如下://linux/v5.11.11/source/drive......
USB3.2 GEN1超高速链路初始化和训练
链路初始化和训练状态机如下图:链路层进行用于初始化和配置序列。其训练状态机主要执行以下操作:配置和初始化链路位锁和符号锁Rx均衡训练LAN的极性反转训练序列由用于初始化位对齐、符号对齐和优化均衡的有序集组成。训序序列的序列集不加扰频,但使用8b/108编码。位锁定是指时钟/数据恢复 (CDR) 电路......
USB3.2 GEN2超高速链路初始化和训练
GEN2的链路初始化和训练和GEN1为似,基主要操作如下:配置和初始化链路位锁和符号锁Rx均衡训练LAN的极性反转块对齐(Block alignment)训练序列由用于初始化位对齐、符号对齐、块对齐和优化均衡的有序集组成。USB3.2 GEN2相对于GEN1多了一个块对齐。位锁定是指时钟/数据恢复 ......
UVC规范USB摄像头扩展单元XU的初始化分析
USB摄像头的UVC的扩展单元用于UVC摄像头的自定义功能扩展,支持UVC扩展单元的摄像头在其UVC控制接口中都会有一个扩展单元描述符。该扩展单元描述符的字段描述符了其支持的选择子,GUID,扩展单元等相关信息。我们知道,UVC摄像头在接入PC机后,和其它USB设备一样,第一步是肯定是USB设备信......
UVC规范USB摄像头相机终端PTZ的初始化分析
USB摄像头采用的是UVC协议,使用UVC协议对UVC规范的USB摄像头进行PTZ控制是通过对UVC的相机终端特定类请求实现的。关于UVC PTZ功能:http://www.usbzh.com/article/detail-458.html本人手中有一UVC USB摄像头,其支持相对和绝对的P......
USBIP 虚拟根设备(VDEV_ROOT)FDO的初始化过程
AddDeviceUSBIP使用devcon安装根设备驱动后,会创建其对应的PDO,这时系统会加载我们的驱动调用AddDevice函数创建PDO,进入进行堆栈。devcon.exe install vaudio.inf "USBIPWIN oot"我们在之前的创建设备Add......
USBIP 虚拟控制器设备(VDEV_CPDO)PDO的初始化过程
IRP_MN_QUERY_ID/BusQueryDeviceIDPAGEABLE NTSTATUSpnp_query_id(pvdev_t vdev, PIRP irp, PIO_STACK_LOCATION irpstack){ NTSTATUS status = STATUS_......
USBIP 虚拟控制器设备(VDEV_VHCI)FDO的初始化过程
虚拟ROOT总线FDO创建了虚拟USB控制器PDO之后,系统通过各种IRP_MJ_PNP收集完物理设备的信息之后,开始根据其硬件ID进行设备驱动批配,批配成功后,装载驱动并调用其AddDevice之后,开始FDO的创建过程。通过前面的可知,USBIP实现的根驱动,USB控制器、HUB和设备PDO的S......
USBIP 集线器PDO(VDEV_HPDO)的初始化过程
USB集线器其实也是USB设备的一类,其设备分类分类为0x09。和USBIP虚拟的控制器(VDEV_CPDO)类似,USB控制器创建了其PDO之后,会通过IRP_MN_QUERY_DEVICE_RELATIONS返回USB集线器HUB的PDO设备列表。PNP管理器收到有新的设备之后,会开始收集这个P......
USBIP 虚拟集线器FDO(VDEV_VHUB )的初始化
AddDevice执行vhci_add_device,返回的设备类型为VDEV_VHUB,集线器HUB的FDO类型。然后初始化HUB的FDO,使用init_dev_vhub(vdev);函数实现static PAGEABLE voidinit_dev_vhub(pvdev_t vdev){ ......
USB全速STM32F407管脚初始化
STM32F407ZG的管脚PA11和PA12是一个复用功能引脚。其功能如下:管脚USBPA11OTG_FS_DM(D-)PA12OTG_FS_DP(D+)由于其内部D+有一个可配置上拉电阻,所以其硬件原图如下:故只需要分别将连接器P11的46管脚和35管脚短......
STM32F407 USB设备模块数据结构及初始化入口函数USBD_Init
本人以STM32F404自带的读卡器SLAVE代码为来解说。STM32F404支持OTG功能,其自带一个全速的USB功能。其USB初始化其实就是写相应的函数代码,这些函数代码却是通一个个的结构体整合起来成回调函数,这些函数是由我们自己写的。而STM32的库函数根据这些构体中的函数指针负责回调我们自......
STM32F407入口函数USBD_Init详解
从前面可知,USBD_Init是USB设备的初始化函数,这里USB后面的D是指DEVICE的意思。USBD_Init全代码为:void USBD_Init(USB_OTG_CORE_HANDLE *pdev, USB_OTG_CORE_ID_TypeDef core......
Windows系统UAC音频设备的初始化过程
第一步当然是获取设备描述符了,使用UsbBuildGetDescriptorRequest函数初始化获取设备描述符的Urb,然后再调用SubmitUrbToUsbdSynch函数返回。当然获取的设备描述符必须保存。第二步是获取配置描述符,方法和获取设备描述符一致,只是需要分2次获取。第一次只获取s......
USBIP 选择配置SetConfiguration
static NTSTATUSstore_urbr_submit(PIRP irp, struct urb_req *urbr){... case URB_FUNCTION_SELECT_CONFIGURATION: status = store_urb_select_......
关注公众号
取消
感谢您的支持,我会继续努力的!
扫码支持
扫码打赏,你说多少就多少

打开支付宝扫一扫,即可进行扫码打赏哦

您的支持,是我们前进的动力!