usb声卡驱动(一)

前面看了内核的启动,接下来就是驱动的学习。

正好手边有一个USB声卡,就准备以此为基础,进行usb声卡驱动的学习。

因此,在学些usb声卡之前,先看看usb驱动。然后再是alsa驱动,然后再是两者的结合

usb的关键数据结构

任何usb设备,都有一段数据,用来描述自己。比如自己有什么功能,自己的厂商ID是多少等等

有个组织,定义了这段数据的组织形式和意义,这段数据称为USB描述符。这个组织叫USB-IF(USB Implementers Forum)

USB描述符的组织形式

usb描述符,逻辑上分成三个层级:配置,接口,端点

一个usb设备描述符,可能包含多个配置,一个配置可能包含多个接口,一个接口可能包含多个端点。

上述每一个逻辑体,在linux中都有一个数据结构与之对应。

配置描述符:

struct usb_config_descriptor {__u8  bLength;//描述符的长度__u8  bDescriptorType;//描述符的类型,有两种值:USB_DT_CONFIG,USB_DT_OTHER_SPEED_CONFIG (表示高速设备操作在低速或者全速模式时的配置信息)__le16 wTotalLength;//所有描述符的总长度__u8  bNumInterfaces;//配置包含的接口数目__u8  bConfigurationValue;//表示这个配置的一个数字。使用该值,调用SET_CONFIGURATION请求来设置此配置为当前配置__u8  iConfiguration;//描述配置信息的字符串描述符的索引值__u8  bmAttributes;//表示配置的一些特点,如bit6为1表示self-power;bit5为1表示支持远程唤醒__u8  bMaxPower;//设备正常运作时,从hub分得的最大电流,单位2mA。//那么当设备请求的电流,大于hub能给予的最大值时,hub就会直接拒绝//而保存hub当前能给出的最大电流保存在struct usb_device的bus_mA中。
} __attribute__ ((packed));

接口描述符:

struct usb_interface_descriptor {__u8  bLength;//该描述符的长度__u8  bDescriptorType;//描述符的类型__u8  bInterfaceNumber;//每个配置里面可以包含多个接口,这个值可以表示对应的接口索引号__u8  bAlternateSetting;//接口使用的可选设置号。默认为0__u8  bNumEndpoints;//接口拥有的端点个数,不包括0端点(后续说明原因)//下面三个,用于表示这个接口,具备的功能。由于各个功能其实有很多共同点,因此将其抽象出三个层级:class,subclass,protocol.//同一个class下面,可以有很多subclass,同一个subclass下,也可以根据protocol的不同,分成很多的设备__u8  bInterfaceClass;__u8  bInterfaceSubClass;__u8  bInterfaceProtocol;__u8  iInterface;//接口对应的字符串描述符的索引值
} __attribute__ ((packed));

端点描述符:

struct usb_endpoint_descriptor {__u8  bLength;//描述符的长度__u8  bDescriptorType;//端点的类型__u8  bEndpointAddress;//该字段含有,端点方向信息,地址信息,端点号信息__u8  bmAttributes;//bit1,bit0 表示传输类型:00控制类型,01登时,10批量,11中断__le16 wMaxPacketSize;//端点一次处理的最大字节数__u8  bInterval;//希望主机轮询自己的时间间隔。/* NOTE:  these two are _only_ in audio endpoints. *//* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. *///下面两个字段,用于在音频设备中,主要用于等时同步端点,会在后面介绍audio协议的时候,引入介绍__u8  bRefresh;__u8  bSynchAddress;
} __attribute__ ((packed));

除了上面的三个描述以外,还有一个重要的描述,那就是设备描述符:

struct usb_device_descriptor {__u8  bLength;//描述符的长度__u8  bDescriptorType;//描述符的类型__le16 bcdUSB;//USB spc的版本号//和接口描述符中的class,subclass,protocol意义类似__u8  bDeviceClass;__u8  bDeviceSubClass;__u8  bDeviceProtocol;__u8  bMaxPacketSize0;//端点0一次可以处理的最大字节数.因为端点0没有对应的描述符,所以,将端点0的相关信息,放在了设备描述符中__le16 idVendor;//厂商ID__le16 idProduct;//产品ID__le16 bcdDevice;//设备版本号__u8  iManufacturer;//制造商对应的字符串描述符的索引值__u8  iProduct;//产品对应的字符串描述符的索引值__u8  iSerialNumber;//序列号对应的字符串描述符的索引值__u8  bNumConfigurations;//该设备当前速度模式下的配置数量
} __attribute__ ((packed));

现在我们知道了usb设备大概有哪些信息,接下来查看一下,应该怎么才能获取到上面的这些

USB描述符的获取

当一个新的设备,插入USB 总线后,这些信息该如何获取呢?

第一步:如何检测到硬件已经被插入

常规的usb接口,有四根线,gnd线,vcc线,D+线,D-线。在hub端D+,D-分别接了一个15k的下拉电阻到地。

而在设备端,D+或者D-端接了一个1.5k的上拉电阻。低速设备接在D-端。高速和全速设备接在D+端。

当设备插入hub时,hub能通过D+,D-上面的变化来区分设备的类型。

第二步:如何区分全速设备和高速设备

对于全速设备和高速设备而言,他们的上拉电阻都接在了D+端。为了进一步区分这两种设备。需要进行一定的通信。

为了简化通信的细节,现在大致描述如下:

  1. 当设备进入复位状态之后,设备持续一段时间的向hub发送信号。这个信号就是给D-持续输出17.87mA的电流。

  2. hub因为有自己的电阻,所以,它能检查到一定的电压,大概为800mV

  3. hub在检查到持续了一段时间的800mV的电压之后,就知道,哦,原来这是一个高速设备。

  4. hub在接下来100us内,进行响应。告诉设备,我已经知道你是高速设备了,并且我也切换到了高速模式下了。

  5. 设备在接受到hub的响应之后,就将自己切换到高速设备的电路上。

上面所述的5个步骤,在电气信号上面的详细描述,可以参考:
https://blog.csdn.net/flydream0/article/details/71512852

第三步:获取设备描述符

现在,设备已经连上,接下来,就是获取设备的信息(设备描述符)。但是在此之前,需要明白一个东西:那就是usb的数据包,到底是怎么组织的。

usb数据包的组织

我们都知道电信号只能传递0和1的逻辑值。在usb的世界里,将这些0和1排列组合,组成7种基本的信息,称为域,分别叫做:同步域(SYNC),标识域(PID),地址域(ADDR),端点域(ENDP),帧号域(FRAME),数据域(DATA),校验域(CRC)

在这些域的上层,则定义4种包:令牌包,数据包,握手包,特殊包。这些包都是由上面介绍的域组合而成。

令牌包有四种,分别为:输入,输出,设置,帧起始。前面三种的域的组成情况一样,为SYNC+PID+ADDR+ENDP+CRC.第四种的域组成为,SYNC+PID+FRAME+CRC

数据包有两种,分别为:DATA0,DATA1。他们的域组成一样都为:SYNC+PID+DATA+CRC

握手包,只有一种,它的域组成为:SYNC+PID

现在有了这些包之后,我们使用这4种包来定义各种不同的事务。目前就定义了3种事务,称为:IN事务,OUT事务,SETUP事务。

每种事务,都由三个阶段组成:令牌包阶段,数据包阶段,握手包阶段

令牌包阶段:启动输入、输出、设置事务

数据包阶段:按照输入、输出发送相应的数据

握手包阶段:返回数据的接收情况

现在知道了3种事务之后,就可以使用这3中事务,进行传输了,传输也分成了4种:中断传输,批量传输,同步传输,控制传输

中断传输:由OUT事务和IN事务构成

批量传输:由OUT事务和IN事务构成

同步传输:由OUT事务和IN事务构成

控制传输:由SETUP事务,(OUT事务,IN事务)构成

现在知道了上面的东西,就可以进一步知道,怎么获取设备描述符了。

注意:上面只是介绍了各个数据包的组成成分,对于这些成分的具体二进制值没有介绍。因为我关心的是整个过程的理解,而不是具体的二进制是什么样子的。如果需要查看具体的二进制,可以参考对应的文章

在设备才连上hub时,此时设备还处于一种默认的状态,它没有地址,为了能够响应主机发出的请求。它将地址0作为默认地址。

那么获取设备描述的过程,大致描述如下:

第一阶段

  1. 首先使用一个Get_Descriptor这个请求。这个请求使用的是SETUP事务,它由令牌包,数据包,握手包组成.

  2. 然后再次发一个数据输入的请求。这个请求使用的是IN事务,它同样由令牌包,数据包,握手包组成。

  3. 然后再次发送一个数据输出请求——用于通知设备,Get_Descriptor请求的状态。这次使用的是OUT事务,它同样有三个阶段

  4. 现在主机已经拥有了usb设备的描述符信息。

第二阶段

  1. 已经知道了部分数据之后,需要为该设备分配地址。

  2. 发出一个Set_Address请求。这个请求跟第一阶段的第一步几乎一样,使用的是SETUP事务

  3. 本次的数据为地址,但是地址已经放在了Set_Address请求中了。所以不需要传输数据。

  4. 为了获得Set_Address请求是否成功,需要接受设备的响应。因此发送一个数据输入请求,即跟第一阶段的第二步一样。

第三阶段

  1. 当一切正常之后,就使用新的地址,重新获取设备描述符。获取设备描述符的过程见第一阶段,长度稍有不同,不过不影响整个过程的理解

  2. 除了设备描述符以外,还需要获取其他的描述符。如配置描述符,接口描述符,端点描述符,字符串描述符等。

  3. 根据这些描述符的内容,选择不同的驱动程序

至此,整个设备才算是完完全全的能被使用了。

注意,注意:上面所有的步骤,建立在两个前提下。1.默认所有的操作都正常;2.描述过程时使用的是数据包中的更加抽象的语言。并没有引入具体的二进制数值

本篇相当于,usb设备的一个枚举过程。

接下来一篇,用于说明,音频设备描述符的相关细节

usb声卡驱动(一):USB描述符相关推荐

  1. USB声卡驱动(二):USB音频设备描述符

    USB声卡驱动(二)USB音频设备描述符 本篇笔记,分两部分,第一部分,是基本知识的记录.第二部分是一个实际的例子. 一.基本知识 一个音频设备(Audio Device)含有多个音频功能(Audio ...

  2. usb声卡驱动(六):usb声卡中的pcm打开和关闭

    usb声卡驱动(六) 前面记录了usb声卡驱动的注册过程. 下面,查看usb声卡里面pcm的打开和关闭,都做了什么工作. 一点基础前提 因为本系列文章的核心是,usb声卡驱动.所以并不会深入到alsa ...

  3. USB声卡驱动(四):alsa概述

    USB声卡驱动(四) 前面记录了usb相关的东西. 现在记录一下alsa相关的东西. 将Audio Function 放在一个硬件电路板里面,将这个电路板称为一个声卡.通过各种各样的接口(可能是非us ...

  4. usb声卡驱动_iCON ProDrive第三代USB声卡驱动全新发布!

    2019年3月,iCON官方发布了一款全球首创--全新一代"ProDrive III"USB声卡驱动,iCON所有系列USB声卡(包括带声卡的MIDI键盘)已全面启用ProDriv ...

  5. 七,USB设备驱动 - 分析USB储存驱动程序

    前面学习了USB驱动的一些基础概念与重要的数据结构,那么究竟如何编写一个USB 驱动程序呢?编写与一个USB设备驱动程序的方法和其他总线驱动方式类似,驱动程序把驱动程序对象注册到USB子系统中,稍后再 ...

  6. USB 3G驱动和USB HOST驱动加载

    ********************************LoongEmbedded******************************** 作者:LoongEmbedded(kandi ...

  7. usb声卡驱动_来自MOTU的温馨提示:如果你的声卡在Windows系统下不稳定,你可以这样做!...

    武汉大学来自MOTU的温馨提示:如果你的声卡在Windows系统下不稳定,你可以这样做! 在我们日常使用外置声卡时,特别是USB接口的外置声卡,相信绝大多数朋友都遇到过声卡掉线.卡死.无故停止工作等各 ...

  8. USB设备多个配置描述符的获取过程

    多配置USB设备枚举过程和多字符串描述符的枚举是相同的,过程如下: 1. 总线复位: 2. 获取设备描述符: 3. 总线复位: 4. 设置地址: 5. 获取设备描述符: 6. 获取配置描述符1: 7. ...

  9. linux usb声卡驱动安装失败,声卡驱动安装出现错误?

    声卡驱动安装出现错误? 发布时间:2007-12-03 08:49:07来源:红联作者:jerrya 之前一打开什么音频视频,Amarok啊,Xine啊,Kaffeine啊就跟我玩崩溃 昨晚上按照一个 ...

最新文章

  1. 扑克牌排序_JAVA 扑克牌排序打印,并进行洗牌
  2. 利用union判断系统的大小端
  3. .依存句法分析--提取用户评论
  4. 2021年自然语言处理(NLP)算法学习路线!
  5. Kali Linux中的VEIL Framework绕过防病毒软件实验
  6. Android解压boot.img
  7. 关于OpenCV中图像的widthStep
  8. BP神经网络简单应用实例,bp神经网络的应用案例
  9. Java中new一个对象的过程
  10. html编辑器菜鸟工具,富文本编辑器TinyMCE菜鸟使用教程
  11. 焊接技巧 -- 拖焊
  12. 目标检测(object detection)—— RCNN总结
  13. 【Mysql】Mysql GTID复制进程出现异常,出现断点
  14. 小米 红米4(标准版)线刷兼救砖_解账户锁_纯净刷机包_教程
  15. Matplotlib 绘图 笔记
  16. php 7.1 国内下载地址,PHP下载|PHP for windowsV7.1.4官方版
  17. 网管员必看:三款常见网管工具的对比
  18. 西门子300系列:复杂数据类型UDT
  19. Arduino三位数码管
  20. UML交流群2月14日讨论内容!

热门文章

  1. 漫画|图灵奖是怎么来的?
  2. Android activity设置透明背景
  3. 收藏备用 | 提高效率的建筑工地技巧
  4. vant weapp example 配置
  5. C#学生管理系统——班级列表(查询功能)
  6. 协方差的意义和计算公式 .
  7. 哪款蓝牙耳机防水比较好?四款适合运动佩戴的蓝牙耳机推荐
  8. 【编程实践】每日JK打卡程序操作说明
  9. 2023年武汉大学新闻与传播硕士考研上岸前辈备考经验指导
  10. 大数据的乘法应用——阶乘(初学者的情怀)