深入,并且广泛-沉默犀牛

USB设备驱动分类

USB驱动程序可以粗分为两类:
一、主机(Host)系统上的驱动程序 ,这个驱动程序控制插入其中的USB设备
二、设备(Device)上的驱动程序,这个驱动程序控制USB设备如何与主机通信

为了举一个形象的例子,我得先展示一张图片,更细致的介绍一下以上的两种分类:

Host Device
USB设备驱动(Mass storage/CDC/HID) Gadget Function 驱动(serial…)
USB核心 Gadet Funtion API
USB Host Controller 驱动(OHCI/EHCI/UHCI) UDC驱动(omap/pxa2xx…)
USB Host Controller UDC

在这个图中,主机侧与设备侧又分别分为了两个驱动:
Host:USB设备驱动、USB Host Controller 驱动
Device:Gadget Function 驱动、UDC驱动

USB设备驱动和USB Host Controller驱动之间的USB core负责了USB驱动管理和协议处理的主要工作。
1.它通过定义一些数据结构体、宏和功能函数,向上为设备驱动提供编程接口,向下为USB Host Controller驱 动提供编程接口;
2.维护整个系统的USB设备信息;
3.完成设备热拔插控制、总线数据传输控制等

Gadet Function API现在是UDC驱动程序回调函数的包装

举一个生活中的例子:当用Android系统的手机 通过USB线 连接Linux系统的PC

Host(PC)的动作:

1.如果你插入了USB2.0的设备,则Host的USB Host Controller 驱动要使能EHCI,如果是USB1.1的设备,就要使能OHCI
/UHCI,不过一般做法是全都使能。在这里我们手机插入后,Host Controller 驱动会启用EHCI

2.这个USB设备驱动,会根据插入的设备不同,而选择不同的驱动。默认已经有的驱动有存储设备、键盘、鼠标、游戏
杆、网络设备和调制解调器。如果是其他的设备,则需要自己写驱动了。在我们的例子里,手机通过USB连接到PC上
后,可以选择几个不同的模式,当选择仅限充电时,Host的USB设备驱动就走充电的驱动,当选择传输文件(MTP)
时,Host的USB设备驱动就走传输文件的驱动,当选择当做摄像头时(现在大部分手机不会设置这个功能了),Host
的USB设备驱动就走摄像头的驱动。

Device(手机)的动作:

1.当我的手机通过USB连接电脑以后,手机的底层USB控制器行使UDC功能,这时运行在底层的是UDC驱动.

2.然后我再选择手机的模式,当选择仅充电时,Device的Gadget Function驱动就走充电的驱动,当选择文件传输时,
Device的Gadget Function驱动就走文件传输的驱动(Mass storage)

现在我们已经理清了这四种驱动都是在哪用的(Host/Device)、都是何时用的、都是干什么的。

USB设备基础

USB设备是非常复杂的,它由许多不同的逻辑单元组成,这些逻辑单元之间的关系可以简单地描述如下:

  1. 设备通常具有一个或者多个配置
  2. 配置经常具有一个或者多个接口
  3. 接口通常具有一个或者多个设置
  4. 接口没有或者具有一个以上端点

接下来就以上提到的概念详细分析:

端点:

USB通信的最基本形式是通过一个名为端点(endpoint)的东西,USB端点只能往一个方向传送数据,从Host到Device称为OUT端点,从Device到Host称为IN端点,端点可以看做是单项的管道它有四种不同的类型,分别具有不同的传送数据的方式:

控制:

控制端点用来控制对USB设备的不同部分的访问。它们通常用于配置设备、获取设备信息、发送命令到设备,或者获取设备的状态报告。这些端点一般体积较小,每个USB设备都有一个名为“端点0”的控制端点,USB核心使用该端点在插入时进行设备的配置。USB协议保证这些传输始终有足够的传输带宽以传送数据到设备,这里关于端点0的功能举一个例子:在手机插入PC的例子中,我选择charge模式后,就是通过端点0来告诉PC的,切换成MTP模式后,也是通过端点0来告诉PC的,PC知道后就会进行相应的配置,这个配置就是调用上述相应的driver

中断

每当USB Host要求设备传输数据时,中断端点就以一个固定的速率来传送少量的数据。这些端点是USB键盘和鼠标所使用的主要传输方式。它们通常还用于发送数据到USB设备以控制设备,不过一般不用来传输大量的数据。USB协议保证这些传输始终有足够的保留带宽以传送数据

批量

批量(bulk)端点传送大批量的数据。这些端点通常比中断端点大得多(它们可以一次持有更多的字符)。它们常见于需要确保没有数据丢失的传输的设备。USB协议不保证这些传输始终可以在特定的时间内完成。如果总线上的空间不足以发送整个批量包,它将被分割为多个包进行传输。这些端点通常出现在打印机、存储设备和网络设备上

等时

等时(isochronous)端点同样可以传送大批量的数据,但数据是否达到是没有保证的。这些端点用于可以应付数据丢失情况的设备,这类设备更注重于保持一个恒定的数据流。实时的数据手记(例如音频和视频设备)几乎毫无例外都使用这类端点。

我们知道“端点”是逻辑上的意义,在代码中是如何实现的呢?或者说,用什么东西来代表端点呢?我之后还会再多啰嗦一下其他的类似“逻辑上的意义”这种问题。现在先来看描述端点的东西吧!其实就是结构体啦,我会结合《LDD3》和《Linux设备驱动开发详解》中的描述进行注释

/* USB_DT_ENDPOINT: Endpoint descriptor */
struct usb_endpoint_descriptor {__u8  bLength;          //描述符长度__u8  bDescriptorType;       //描述符类型__u8  bEndpointAddress;      //端点地址:0-3位是端点号,第7位是方向(0为out,1为in)__u8  bmAttributes;        //端点属性(类型):bit[0:1] 00表示控制 01表示等时 10表示批量 11表示中断__le16 wMaxPacketSize;      //该端点一次可以处理的最大字节数。注意:driver可以发送数量大于此值的数据到端点,但是在实际传输到设备的时候,数据将被分割为wMaxPacketSize大小的块。__u8  bInterval;       //轮询数据传送端点的时间间隔对于批量和控制的端点,忽略此域对于等时的端点,必须为1对于中断的端点,必须为1-255/* NOTE:  these two are _only_ in audio endpoints. *//* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */__u8  bRefresh;__u8  bSynchAddress;
} __attribute__ ((packed));

接口:

USB端点被捆绑为接口。USB接口只处理一种USB逻辑连接,例如鼠标、键盘或者音频流。一些USB设备具有多个接口,例如USB扬声器可以包括两个接口:一个USB键盘用于按键和一个USB音频流。因为一个USB接口代表了一个基本功能,而每个USB驱动程序控制一个接口,因此,以扬声器为例,Linux需要两个不同的驱动程序来处理一个硬件

接下来看看接口的结构体:

/* USB_DT_INTERFACE: Interface descriptor */
struct usb_interface_descriptor {__u8  bLength;             //描述符长度__u8  bDescriptorType;           //描述符类型__u8  bInterfaceNumber;          //接口的编号__u8  bAlternateSetting;     //备用的接口描述符编号__u8  bNumEndpoints;            //接口使用的端点数,不包括端点0__u8  bInterfaceClass;          //接口类型__u8  bInterfaceSubClass;     //接口子类型__u8  bInterfaceProtocol;        //接口所遵循的协议__u8  iInterface;         //描述该接口的字符串索引值
} __attribute__ ((packed));

配置

USB接口本身被捆绑为配置。一个USB设备可以有多个配置,而且可以在配置之间切换以改变设备的状态。比如手机可以选择charge only 、MTP、PTP、Camera这几个配置。用usb_config_descriptor结构体来描述配置。USB设备驱动程序通常不需要改变这个结构体中的任何值,因此在这里不详述了。

这里顺便提一嘴怎么看你设备中的usb设备的这些结构体信息:
1.lsusb 查看每一个设备的 bus号 和 device号

2.lsusb -s -v [Bus:Device] 就可以显示出你填入的Bus和Device指定的设备的信息

以上是先要准备的有关USB的基础知识,下两篇文章我们分析一下驱动的源码,这四个驱动中有两个是我们不会去改动的:Host Controller driver 和 UDC 因为这都是默认的,只需要config一下就可以了。所以我们的目标放在了另外的两个驱动上: USB设备驱动 和 Function 驱动

这里多说一下上文提到的“逻辑上的意义”,在我学习Linux驱动这三个月以来,我感觉到Device、Driver这样的东西对于Kernel来说,都是逻辑上的,只要我把Device的信息写到DTS中,那Linux的Kernel启动时,就会展开DTS,并且把这些node最终解析为device结构体,然后注册(这时是注册platform_device,其他总线上的Device是(在对应总线注册时)注册的 ),你看,kernel并不知道这些我们硬件上到底有没有连接这些Device,我想表达的就是,在Kernel看来,这些最终解析成的device结构体,就是有意义的。但是这些node在我们看来,只有逻辑上的意义。有了它们,Kernel才能认识Device。同理的去理解本文中的结构体,和Kernel中的其他结构体,它们都是只有逻辑上的意义

那么既然Kernel并不知道Device到底存不存在,那也不能让Kernel去控制一个不存在的Device吧,这个问题怎么解决的呢?这就是Driver的用处之一了。Driver也都是体现成了结构体。比如usb_driver、i2c_driver等等,所以Driver也是在我们的眼中看来,它们也是逻辑上的并不像是我们用来控制游戏人物的键盘、鼠标那么具体。Driver写好后,Kernel就认为这是一个Device的“控制器”了,但是它不会对应现实世界的任何实物。那么Driver是怎么解决“到底有没有真实的Device连接在硬件上?”这个问题的呢?Driver通过向真实器件读取信息来判断到底有没有真实的Device,如果没有真实的Device,那Driver就读不出来正确的数据,那我Kernel就认为没有这个真实器件,也正是这个原因,我们调试某器件的时候发现driver没有加载上,就是因为Device的配置有问题,导致Kernel误认为没有这个真实器件

为了更好的解释这个问题,我用我所接触过的两个例子,来再次阐述:
1.TouchPanel: 大部分TouchPanel是挂载在i2c上的,所以TP的Driver->probe函数中,会通过i2c总线向TP硬件的IC读取一些信息,这就起到了验证硬件在不在的作用,如果读出的数据不对,直接return
2.LCD:LCD会面对一个问题,就是一套代码,要适应多个屏幕,(因为咱们手机或者其他嵌入式设备的配置不同,高配的用好一点的,低配的用差一点的)那一套代码怎么适应不同的屏幕呢?就是从LCD的硬件IC读取一些信息,比如硬件的编号,GPIO的高低等等,然后用这个编号来找对应的配置,读取编号的时候,不就可以验证硬件在不在了吗。

这篇博文参考了《Linux设备驱动开发详解》《Linux Device Driver 3》和《Linux那些事儿-我是USB》

(一)USB驱动程序_USB基础知识相关推荐

  1. USB驱动程序(基础)

    以前阅读过<圈圈教你学USB>,介绍USB比较详细,但一直没有总结,今天简单总结一下~ USB支持热插拔,使用方便,越来越受欢迎 USB2.0支持60M/B/s的速率. 最新的USB3.0 ...

  2. USB 协议 (三) 基础知识

    文章目录 USB 各层次数据 USB 请求的发起端 USB 自插入后到数据传输的过程 枚举 数据传输 USB 常用术语 USB host controller hub root hub usb por ...

  3. USB(一)——USB通用串行总线基础知识详述

    目录 1. USB简介 2. USB的特性 2.1 USB的性能特点 2.2. USB的电气特性 3.  USB总线系统中的设备 4. USB2.0 传输协议 4.1 包(package)是什么? 4 ...

  4. 联想计算机usb启动怎么办,联想电脑bios怎么设置USB启动_电脑基础知识_IT计算机_专业资料...

    联想电脑bios怎么设置USB启动_电脑基础知识_IT计算机_专业资料 (4页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 9.9 积分 联想电脑bios ...

  5. STM32 USB基础知识

    文章目录 拓展阅读 前言 一.USB基础知识 二.USB2.0 1.usb2.0模式说明 2.USB2.0全速USB和高速USB的识别过程分析 3.usb协议关系 4.USB2.0与USB1.x 硬件 ...

  6. linux来源usb驱动在哪下载,Linux USB驱动程序基础

    非常好的linux驱动入门,介绍详尽 Linux USB驱动程序基础 来源: ChinaUnix博客日期:2008.04.10 23:55(共有条评论) 我要评论 ( Linux USB Driver ...

  7. 【嵌入式Linux】嵌入式Linux驱动开发基础知识之LED模板驱动程序的改造:设备树

    文章目录 前言 1.驱动的三种编写方法 2.怎么使用设备树写驱动程序 2.1.设备树节点要与platform_driver能匹配 2.2.修改platform_driver的源码 3.实验和调试技巧 ...

  8. 【STM32H7】第8章 学习USB协议栈前要了解的基础知识

    论坛原始地址(持续更新):http://www.armbbs.cn/forum.php?mod=viewthread&tid=99710 第8章   学习USB协议栈前要了解的基础知识 本章节 ...

  9. 【STM32F407】第8章 学习USB协议栈前要了解的基础知识

    论坛原始地址(持续更新):http://www.armbbs.cn/forum.php?mod=viewthread&tid=99710 第8章   学习USB协议栈前要了解的基础知识 本章节 ...

最新文章

  1. 狂宴终有尽时,留一份清醒一份醉 比特币现金BCH凸显投资价值
  2. 事物(Jdbc) 例子
  3. Android自定义View绘制闪闪发光的文字
  4. 两个相邻盒子的边框怎么只显示一个_【前端小课堂】0044 盒子
  5. kali2020设置root用户登录
  6. 开关电源磁性元件理论及设计pdf_2020年开关电源需求活跃 通讯运营商已多轮集采...
  7. mysql 三表inner join_MySql的join(连接)查询 (三表 left join 写法)
  8. 卷积神经网络——第一周 卷积神经网络基础——第四部分
  9. 进阶之路(基础篇) - 020 放弃Arduino IDE,拥抱Sublime Text 3
  10. 利用python开发微信JS-JDK(基于python3.6)
  11. linux中用tailf实时观看tomcat日志
  12. 自组织神经网络算法-SOM
  13. 计算机常用英语词汇 短语,四级英语常用词汇短语
  14. js获取当前月有几周(附带一个小组件)
  15. 苏州大学未来校区来了!
  16. Arduino提高篇23—OLED电子时钟
  17. 蒙纳士大学 英伟达发布 2021 年医疗视觉问答
  18. 【论文泛读97】建立具有情感原因的在线移情聊天机器人
  19. Eclipse 修改注释的 date time 日期时间格式,即${date}变量格式
  20. 研发安全环境解决方案(一):网络接入的安装和配置

热门文章

  1. 智慧医疗以小见大 | 联想智慧医疗的青葱岁月
  2. 【Ubuntu20.04网络配置】
  3. 马来西亚外劳市场现状
  4. C# 中String Builder 和string对象
  5. 【Java游戏开发项目-01贪吃蛇】强烈推荐Java小白练手!!!
  6. php程序员自我描述_PHP程序员面试自我介绍
  7. (附源码)计算机毕业设计SSM自动组卷系统
  8. Java基础第六课(关于包名的讲解)
  9. 计算机组成原理 — 服务器 — DELL 服务器使用 iDRAC 进行 Firmware 和 BIOS 版本升级
  10. 振荡器在电路中的作用是什么