0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

USB在Linux里的结构框架是什么样的?USB Core和Hub是什么?

Q4MP_gh_c472c21 来源:未知 作者:易水寒 2018-07-27 16:08 次阅读

USB博大精深不是一篇文章就能够解释清楚的。想要深入研究USB的话,USB协议(外加Host和OTG协议)是必要的知识,另外,国内有本<>也写的很好很详细(点击阅读原文,21ic嵌入式论坛下载),唯一美中不足的就是写得太详细了反而感觉思路架构不是很清晰了。今天我们来简单地把USB在Linux里的结构框架大致整理下,其中重点解析下USB Core和Hub。

0. 预备理论

说实话,读USB协议还是蛮痛苦的,它仅仅是一个协议,一个在USB世界里制定的游戏规则,就像法律条文一样,它并不是为了学习者而写的,可读性很差。这里总结以下几个重点基本点。

0.1 拓扑结构 (ch4.1.1)

·之所以要规定这个树形拓扑结构是为了避免环形连接。

·一条USB总线有且只有一个USB Host,对应一个RootHub

·USB设备分为两类,Hub和Functions,Hub通过端口Port连接更多USB设备,Functions即USB外接从设备。

·层次最多7层,且第7层不能有Hub,只能有functions。

·Compound Device - 一个Hub上接多个设备组成一个小设备。

·Composite Device - 一个USB外接设备具有多个复用功能。

0.2 机械性能 (ch5)

·连接件connector,就是设备上的那个连接口。

·插头plug,就是USB电缆线两头的插口。

·Mini-AB, Micro-AB指的是支持A和B两类插头的连接件。

0.3 电气性能 (ch6)

·VBUS - +5V电源供电

·D+ D- - 用于数据传输的电缆线。

·低速 low-speed 10-100Kb/s 应用于鼠标和键盘等

·全速 full-speed 500Kb-10Mb/s应用于音频和麦克等

·高速high-speed 25-400Mb/s 应用于存储和视频等 (USB3.0比之块10倍)

0.4 四大描述符 (ch9.5)

协议规定了USB的四个描述符descriptor - 设备device,配置configure,接口interface,端点endpoint。

终端下输入命令 # ls /sys/bus/usb/devices

usb1 1-0:1.0 usb2 2-0:1.0 // USB总线(RootHub) No.2,USB port端口号No.0,配置号No.1,接口号No.0。

·区别port和endpoint,port之于hub,endpoint是每个USB设备用于数据传输所必需的端点。

·设备device>配置configure>接口interface>设置setting>端点endpoint。

·设备可以有多个配置,配置可以有一个或多个接口,接口可以有一个或多个设置。

·一个接口对应一个驱动,接口是端点的集合。

0.5 启动流程 (ch9.1,9.2)

·attached->powered->default->address->configured

·启动流程与其他设备比如SD卡相比,最大的不同在于Hub,主机Host通过Hub状态的变化判断USB外接设备的有无。

·USB外接设备插入和拔出整个实现过程称为总线枚举Bus Enumeration。

0.6 数据流传输 (ch5)

·endpoint分零端点和非零端点,零端点作为默认的控制方法用于初始化和操控USB逻辑设备。

·数据流传输分 control/bulk/interrupt/isochronous data transfer。

0.7 数据包 (ch8)

·数据包分Token, Data, Handshake, Special,四种包有自己的数据组织方式。

·Token令牌包只能由主机传送给设备,分IN, OUT, SOF和SETUP。

·SETUP包实现主机向设备发出的请求request,也要满足特定的格式。(ch9.3,9.4)

1. USB Core

先啰嗦几句,回答一个困扰我很久的问题,读Linux源码究竟要读到什么程度?这是个永恒的话题,每个同道中人都有自己的看法。以吾辈之见,如何阅读源码主要取决于自己的职业定位,是研发还是开发,是为Linux社区作贡献还是用已有的方案开发?我想大多数驱动工程师属于后者,那么,面对已经很完善的核心层源码,还有必要看吗,或者有必要去深入研究吗?我认为既然我们已经站在了巨人的肩膀上,至少要知道这宽阔的肩膀是如何炼成的,它所存在的价值以及如何去使用它。

既然如此,那USB核心层到底是什么,它都默默地做了些什么,我们要如何使用它?这里主要有两个重点,USB总线和urb。

1.1 USB子系统结构

协议里说,HCD提供主控制器驱动的硬件抽象,它只对USB Core一个负责,USB Core将用户的请求映射到相关的HCD,用户不能直接访问HCD。换句话说,USB Core就是HCD与USB设备唯一的桥梁。

1.2 USB子系统的初始化

USB core源码位于./drivers/usb/core,其中的Makefile摘要如下,

usbcore这个模块代表的不是某一个设备,而是所有USB设备赖以生存的模块,它就是USB子系统。

./drivers/usb/core/usb.c里实现了初始化,伪代码如下,

usbcore注册了USB总线,USB文件系统,USB Hub以及USB的设备驱动usb generic driver等。

1.3 USB总线

注册USB总线通过bus_register(&usb_bus_type);

struct bus_type usb_bus_type = {.name ="usb",.match =usb_device_match, // 这是个很重要的函数,用来匹配USB设备和驱动。.uevent =usb_uevent,.pm =&usb_bus_pm_ops,};下面总结下USB设备和驱动匹配的全过程,

-> step 1 - usb device driver

USB子系统初始化的时候就会注册usb_generic_driver, 它的结构体类型是usb_device_driver,它是USB世界里唯一的一个USB设备驱动,区别于struct usb_driver USB驱动。

·USB设备驱动(usb device driver)就只有一个,即usb_generice_driver这个对象,所有USB设备都要绑定到usb_generic_driver上,它的使命可以概括为:为USB设备选择一个合适的配置,让设备进入configured状态。

·USB驱动(usb driver)就是USB设备的接口驱动程序,比如adb驱动程序,u盘驱动程序,鼠标驱动程序等等。

-> step 2 - usb driver

Linux启动时注册USB驱动,在xxx_init()里通过usb_register()将USB驱动提交个设备模型,添加到USB总线的驱动链表里。

-> step3 - usb device

USB设备连接在Hub上,Hub检测到有设备连接进来,为设备分配一个struct usb_device结构体对象,并将设备添加到USB总线的设备列表里。

-> step4 - usb interface

USB设备各个配置的详细信息在USB core里的漫漫旅途中已经被获取并存放在相关的几个成员里。

usb_generic_driver得到了USB设备的详细信息,然后把准备好的接口送给设备模型,Linux设备模型将接口添加到设备链表里,然后去轮询USB总线另外一条驱动链表,针对每个找到的驱动去调用USB总线的match函数,完成匹配。

1.4 USB Request Block (urb)

USB主机与设备间的通信以数据包(packet)的形式传递,Linux的思想就是把这些遵循协议的数据都封装成数据块(block)作统一调度,USB的数据块就是urb,结构体struct urb,定义在,其中的成员unsigned char *setup_packet指针指向SETUP数据包。下面总结下使用urb完成一次完整的USB通信需要经历的过程,

-> step 1 - usb_alloc_urb()

创建urb,并指定USB设备的目的端点。

-> step 2 - usb_control_msg()

将urb提交给USB core, USB core将它交给HCD主机控制器驱动。

-> step3 - usb_parse_configuration()

HCD解析urb,拿到数据与USB设备通信。

-> step 4

HCD把urb的所有权交还给驱动程序。

协议层里最重要的函数就是usb_control/bulk/interrupt_msg(),这里就简单地理一条线索,

usb_control_msg() => usb_internal_control_msg() => usb_start_wait_urb() => usb_submit_urb() => usb_hcd_submit_urb => hcd->driver->urb_enqueue() HCD主控制器驱动根据具体平台实现USB数据通信。

2. USB Hub

Hub集线器用来连接更多USB设备,硬件上实现了USB设备的总线枚举过程,软件上实现了USB设备与接口在USB总线上的匹配。

下面总结下USB Hub在Linux USB核心层里的实现机制,

USB子系统初始化时,usb_hub_init()开启一个名为"khubd"的内核线程,

内核线程khubd从Linux启动后就自始至终为USB Hub服务,没有Hub事件时khubd进入睡眠,有USB Hub事件触发时将会经由hud_irq() => hub_activate() => kick_khubd() 最终唤醒khubd,将事件加入hub_event_list列表,并执行hub_events()。hub_events()会不停地轮询hub_events_list列表去完成hub触发的事件,直到这个列表为空时退出结束,回到wait_event_xxx继续等待。

处理hub事件的全过程大致可分为两步,

·第一步 判断端口状态的变化

通过hub_port_status()得到hub端口的状态。

源码里类似像hub_port_status(), hub_hub_status()等功能函数,都调用了核心层的usb_control_msg()去实现主控制器与USB设备间的通信。

·第二步处理端口的变化

hub_port_connect_change()是核心函数,以端口发现有新的USB设备插入为例,USB Hub为USB设备做了以下几步重要的工作,注意这里所谓的USB设备是指插入USB Hub的外接USB设备(包括Hub和Functions),接下来Hub都在为USB设备服务。

1) usb_alloc_dev() 为USB设备申请一个sturct usb_device结构。

2) usb_set_device_state() 设置USB设备状态为上电状态。(硬件上设备已进入powered状态)。

3) choose_address() 为USB设备选择一个地址,利用一个轮询算法为设备从0-127里选择一个地址号。

4)hub_port_init() 端口初始化,实质就是获取设备描述符device descriptor。

5) usb_get_status() 这个有点特殊,它是专门给Hub又外接Hub而准备的。

6)usb_new_device() 这时USB设备已经进入了Configured状态,调用device_add()在USB总线上寻找驱动,若匹配成功,则加载对应的驱动程序。

3. USB OTG

引入OTG的概念是为了让设备可以充当主从两个角色,主设备即HCD,从设备即UDC,也就是Gadget。这里就简单梳理下协议和源码。

3.1 协议

1) Protocol

OTG的传输协议有三类 - ADP,SRP,HNP。

·ADP(Attach Detection Protocol)当USB总线上没有供电时,ADP允许OTG设备或USB设备决定连接状态。

·SRP(Session Request Protocol) 允许从设备也可以控制主设备。

·HNP(Host Negotiation Protocol)允许两个设备互换主从角色。

2) Device role

协议定义两种角色,OTG A-device和OTG B-device,A-device为电源提供者,B-device为电源消费者,默认配置下,A-device作为主设备,B-device作为从设备,之后可以通过HNP互换。

3) OTG micro plug

协议上说"An OTG product must have a single Micro-AB receptacle and no other USB receptacles."这句话有点问题。。。应该还包括mini-AB receptacle,以下所有micro都可以是mini。

OTG电缆一端为micro-A plug,另一端为micro-B plug。

OTG加了第5个pin脚,名为ID-pin,micro-A plug的ID-pin接地,micro-B plug的ID-pin悬空。

OTG设备被接上micro-A plug后被称为micro-A device,被接上micro-B plug后被称为micro-B device。

3.2 源码浅析

OTG控制器集成在CPU内,Linux下的源码驱动由各家开发平台提供,位于./drivers/usb/otg/下。

以Freescale平台为例,主要的思路就是,当有OTG线插入OTG设备时产生中断,中断处理函数上半部通过读取OTG控制器寄存器相应值判断OTG设备属于Host(HCD)还是Gadget(UDC),下半部通过工作队列由回调函数类似host->resume()或gadget->resume()重启Host或Gadget控制器,resume()具体的实现过程在HCD或UDC相关驱动里实现。

4. USB Host

USB主控制器(HCD)同样集成在CPU内,由开发平台厂商提供驱动,源码位于./drivers/usb/host/下。

主控制器主要有四类:EHCI, FHCI, OHCI, UHCI, 它们各自的寄存器接口协议不同,嵌入式设备多为EHCI。

该驱动的结构体类型为struct hc_driver,其中的成员(*urb_enqueue)最为重要,它是主控制器HCD将数据包urb传向USB设备的核心实现函数,之前已经提到,协议层里最主要的函数usb_control_msg()最终就会回调主控制器的(*urb_enqueue)。

usb_control_msg() => usb_internal_control_msg() => usb_start_wait_urb() => usb_submit_urb() => usb_hcd_submit_urb => hcd->driver->urb_enqueue()

5. USB Gadget

Gadget源码位于./drivers/usb/gadget/下,涉及的驱动程序和数据结构相对较多。

驱动主要有,

·平台相关的Gadget控制器驱动

·平台无关的复用设备驱动composite.c

·android平台的复用设备驱动android.c

·adb驱动f_adb.c,U盘驱动f_mass_storage.c等一些复用的USB驱动

数据结构主要有,

·struct usb_gadget 里面主要有(*ops)和struct usb_ep *ep0。

·struct usb_gadget_driver 其中的(*bind)绑定复用设备驱动,(*setup)完成USB枚举操作。

·struct usb_compostie_driver 其中的(*bind)绑定比如android复用设备驱动。

·struct usb_request USB数据请求包,类似urb。

·struct usb_configuration 就是这个gadget设备具有的配置,其中的struct usb_function *interface[]数组记录着它所拥有的USB接口/功能/驱动。

·struct usb_function 其中的(*bind)绑定相关的USB接口,(*setup)完成USB枚举操作。

整体框架可概括为,(mv_gadget为gadget控制器的数据)

6. USB Mass Storage

全世界只有一个Linux U盘驱动,位于./drivers/usb/storage/usb.c,伪代码如下,这里需要注意的是,在进行U盘驱动的初始化probe之前,USB core和hub已经对这个U盘做了两大工作,即

1) 完成了USB设备的枚举,此时U盘已经进入configured状态,U盘数据存放在struct usb_interface。

2) 完成了USB总线上设备和驱动的匹配,这时总线上已经找到了接口对应的驱动即U盘驱动。

·土黄色部分由SCSI子系统封装实现最终的U盘驱动注册。

·usb_stor_scan_thread 扫描U盘的线程,等待5秒,如果5秒内不拔出就由SCSI进行全盘扫描,

·usb_stor_contro_thread 一个核心的线程,具体参看《USB那些事》...

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • usb
    usb
    +关注

    关注

    59

    文章

    7378

    浏览量

    257490
  • Linux
    +关注

    关注

    87

    文章

    10943

    浏览量

    206546
  • Core
    +关注

    关注

    0

    文章

    173

    浏览量

    42552
  • hub
    hub
    +关注

    关注

    1

    文章

    104

    浏览量

    41021

原文标题:Linux USB的那些事之设备驱动子系统终极篇

文章出处:【微信号:gh_c472c2199c88,微信公众号:嵌入式微处理器】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    实现了多媒体数据的同步传输的USB3.0 HUB设计方案

    的,所以它有完整的USB2.0 HUB设计,而Super Speed HUB部分就是USB3.0 HUB区别于
    的头像 发表于 11-01 08:10 1.1w次阅读
    实现了多媒体数据的同步传输的<b class='flag-5'>USB</b>3.0 <b class='flag-5'>HUB</b>设计方案

    USB驱动程序框架介绍

    《ARM嵌入式Linux系统开发详解》第25章USB驱动开发,本章讲解了Linux内核USB驱动体系结构
    发表于 07-11 07:38

    USB的低层结构

    USB的低层结构 USB设备USB的设备可以接在PC上的任意的USB接口上。而使用HUB还可以
    发表于 05-06 16:06 590次阅读

    USB结构框架

    USB结构框架               
    发表于 05-06 17:05 808次阅读

    usb hub是什么意思

    usb hub是什么意思 USB HUB就是USB接口扩展器。 这个参数是指键盘上是否带有USB
    发表于 05-29 01:18 1.9w次阅读

    什么是键盘USB HUB

    什么是键盘USB HUB 这个参数是指键盘上是否带有USB HUB。计算机上的USB接口通常是在机箱的前面板或者机箱的背后,如果要连接
    发表于 12-28 11:14 4259次阅读

    嵌入式LinuxUSB驱动设计

    本文主要介绍了 Linux 平台的USB设备驱动开发的一般步骤方法和技巧,通过详细介绍USB的相关概念和LinuxUSB设备驱动程序的数据
    发表于 06-08 17:15 49次下载
    嵌入式<b class='flag-5'>Linux</b>的<b class='flag-5'>USB</b>驱动设计

    八合一USB HUB扩展坞解决了USB HUB的接口不足问题

    福音Gospelwin USB HUB ODM厂商此前推出有多款USB HUB产品,今天要为大家介绍的是其近期推出的八合一USB
    发表于 05-21 10:24 1403次阅读

    Linux USB驱动框架分析(一)

    链路,但两者通过一个驱动控制。在Linux上,接口使用struct usb_interface来描述,以下是该结构体中比较重要的字段: struct usb
    发表于 04-02 14:35 517次阅读

    微雪电子USB集线器|USB HUB HAT简介

    树莓派USB扩展板 HUB 集线器 带USB转串口 外扩4个USB口;5V供电 型号 USB
    的头像 发表于 12-30 14:17 2582次阅读
    微雪电子<b class='flag-5'>USB</b>集线器|<b class='flag-5'>USB</b> <b class='flag-5'>HUB</b> HAT简介

    如何使用Linux内核实现USB驱动程序框架

    Linux内核提供了完整的USB驱动程序框架USB总线采用树形结构,在一条总线上只能有唯一的主机设备。
    发表于 11-06 17:59 19次下载
    如何使用<b class='flag-5'>Linux</b>内核实现<b class='flag-5'>USB</b>驱动程序<b class='flag-5'>框架</b>

    USB3.0 HUB的资料

    USB3.0 HUB的资料
    发表于 11-16 17:31 123次下载

    USB Hub

    USB Hub
    发表于 12-28 19:42 7次下载
    <b class='flag-5'>USB</b> <b class='flag-5'>Hub</b>

    USB HUB一扩四/USB转以太网(PHY)简介

    3.0 HUB支持USB3.0,向下兼容USB2.0/1.1,理论带宽达5Gbps; USB3.1 HUB支持
    发表于 03-17 23:22 5053次阅读

    USB2.0 HUB高速4端口USB HUB集线器

    NS1.1S是一个高性能的符合USB 2.0高速4端口USB HUB集线器控制器.4个端口功能可同时工作,低功耗 采用NS1.1S USB2.0 H
    的头像 发表于 04-03 15:38 1353次阅读
    <b class='flag-5'>USB</b>2.0 <b class='flag-5'>HUB</b>高速4端口<b class='flag-5'>USB</b> <b class='flag-5'>HUB</b>集线器