Linux之 USB驱动框架-USB总线(2)

一、linux 下,通过系统查看usb 总线

ls /sys/bus/usb/devices/也包含了很多信息:

其中usb1、usb2代表系统注册了2条usb总线,即有2个USB主机控制器,1和2用于区分不同总线,是USB的总线号。

每插入一个usb设备,/sys/bus/usb/devices/就有新的文件夹生成。其中“2-1:1.0”代表usb总线号为2,devpath为1,配置号为1,接口号为0,即2号总线的1号端口的设备,使用的是1号配置,接口号为0。而“2-1:1.0”代表的是一个hub设备,可根据下面得知:

/sys/bus/usb/devices # cat 2-1:1.0/bInterfaceClass
09(其中09代表Hub,又如,08代表mass storage class(U盘...)等)

       那么当hub的端口上又接入usb设备,那么在linux下又怎么表示呢?我们可以看到还有一个“2-1.1:1.0”,这就是利用了devpath的作用,顶级设备的devpath就是其连在Root Hub上的端口号,而次级的设备就是其父hub的devpath后面加上其端口号,即2-1:1.0是一个Hub,那么它下面的1号端口的设备就是的上面的“2-1.1:1.0”,2号端口的设备就可以是“2-1.2:1.0”等

总之:该文件下面的设备信息的命名规则遵循下面2条原则,内核中的USB设备命名规则也遵循下面2条原则。

1、usbn: 表示USB总线,如果是USB3.0控制器,则会有2条总线,分别是usbn和usbn+1。
2、bus-port.port…:configuration:interface(总线-端口.端口…:配置:接口): Root Hub的端口号为0,其他Hub的下行端口从1开始编号。
下图是一个示例,设备信息可进入文件查看。

usb1表示USB1总线。
1-0:1.0表示usb1总线的Root Hub,使用配置1和接口0。
1-1表示USB1总线Root Hub下面接的设备,端口编号为1,属于第1级Hub。
1-1:1.0表示第1级Hub使用配置1和接口0。
1-1.1表示第1级Hub的端口1。
1-1.1:1.0表示第1级Hub的端口1下面的设备使用配置1和接口0。
1-1.3表示第1级Hub的端口3。
1-1.3:1.0表示第1级Hub的端口3下面的设备使用配置1和接口0。

 二、USB总线框架

usb驱动架构图:

2.1、USB core

USBCore这个模块是纯软件部份,并不代表一个设备,是独立于硬件的合同栈,它是所有USB设备赖以生存的模块,即USB子系统的核心。代码坐落kernel/drivers/usb/core目录下。

USBCore为设备驱动程序提供服务,提供一个用于访问和控制USB硬件的插口,而不用考虑系统当前使用的哪种HOSTController。USBCore将用户的恳求映射到相关的HCD,用户不能直接访问HCD。USBCore就是HCD与USB设备的桥梁。

2.2 USB主机控制器驱动

1、OHCI(Open Host Controller Inerface):微软主导的低速USB1.0(1.5Mbps)和全速USB1.1(12Mbps),OHCI接口的硬件简单,软件复杂。

2、UHCI(Universal Host Controller Interface):Intel主导的低速USB1.0(1.5Mbps)和全速USB1.1(12Mbps),而UHCI接口的软件简单,硬件复杂。

3、EHCI(Enhace Host Controller Interface):高速USB2.0(480Mbps)。

4、xHCI(eXtensible Host Controller Interface):USB3.0(5.0Gbps),采用了9针脚设针,同时也支持USB2.0、1.1等。

 2.3 USB设备描述符

USB协议中共定义了以下四种描述符:

1) 设备描述符

2) 配置描述符

3) 接口描述符

4) 端点描述符

其关系如下图所示:

 2.4 主机端的驱动架构

 USB核心(USBD)是整个USB驱动的核心部分,从上图可知,一方面USBD对接收到USB主机控制器的数据进行处理,并传递给上层的设备端驱动软件;同时也接收来自上层的非USB格式数据流,进行相应的数据处理后传递给USB主机控制器驱动。

上图中 HCD 是通过platform 总线注册的主机控制器驱动 和root hub driver。

2.5 主机驱动调用流程

USB数据传输都以URB(USB Request Block)请求、URB生成、URB递交、URB释放为主线。从上图可知,当加载控制器驱动之后,注册根据集线器,hub和hcd驱动成为一个整体。接着,主机通过控制传输获取设备的控制描述符等信息,接着详述整个控制传输的流程。usb_submit_urb依据是否连接到根集线器来决定调用urb_enqueue或rh_urb_enqueue函数。

USB从设备通过集线器或根集线器连接到USB主机上。比如:主机通过根集线器与外界进行数据交互,根集线器通过探测数据线状态的变化来通知USB主机是否有USB外围设备接入。

在主机端控制器驱动加载的过程中,注册了根集线器,然后匹配了相应的hub驱动程序,同时完成了对Hub的轮询函数和状态处理函数的设置。这样,一旦hub集线器的状态发生变化,就会产生相应的中断,主机端控制器就会执行相应的中断处理函数,下图为hub驱动程序的流程图。

 

 USB Core中的usb_init()函数中完成了对hub线程(khubd,在usb_hub_init函数中真正地创建)的创建,然后完成相应设备的探测。主机端控制器驱动进行探测时,将hub驱动和主机端控制器驱动结合在一起,相互之间完成调用。 相对于大容量存储设备与主机之间通过控制/批量传输,集线器与主机之间通过中断/控制方式完成数据交互。

补充:对于内核 5.10 高版本内核,已经不使用 khubd 了, 使用的是hub_wq 工作队列,这个可以看我后面的文章有分析。

三、USB初始化过程

USB驱动作为一个系统,集成了众多的驱动模块,注册过程非常复杂。从USB系统的角度来说,USB主机驱动主要包含:

1) USB核驱动

2) 主机控制器驱动

3) 集线器驱动

驱动的加载执行流程如下图所示:

USB初始化过程

1、 USB Core的初始化

USB驱动从USB子系统的初始化开始,USB子系统的初始化在文件driver/usb/core/usb.c

subsys_initcall(usb_init);

module_exit(usb_exit);

subsys_initcall()是一个宏,可以理解为module_init()。由于此部分代码非常重要,开发者把它看作一个子系统,而不仅仅是一个模块。USB Core这个模块代表的不是某一个设备,而是所有USB设备赖以生存的模块。在Linux中,像这样一个类别的设备驱动被归结为一个子系统。subsys_initcall(usb_init)告诉我们,usb_init才是真正的初始化函数,而usb_exit将是整个USB子系统结束时的清理函数。

2、 主机控制器的初始化及驱动执行(以EHCI为例)

module_init(otg_init); 模块注册

static init __init otg_init(void);

platform_driver_register(); 平台注册

static int __init otg_probe(struct platform_device *pdev); 探测处理函数

reg = platform_get_resource(pdev, IORESOURCE_MEM, 0); 获取寄存器信息

data = platform_get_resource(pdev,IORESOURCE_MEM, 1); 获取内存信息

irq = platform_get_irq(pdev,0); 获取中断号

usb_create_hcd(&otg_hc_driver, &pdev->dev, pdev->dev.bus_id);

分配和初始化HCD结构体。对设备数据空间进行分配,初始化计数器、总线、定时器、hcd结构体各成员值。

ret = usb_add_hcd(hcd,irq,SA_INTERRUPT);

完成HCD结构体的初始化和注册。申请buffer,注册总线、分配设备端内存空间,向中断向量表中申请中断,注册根集线器,对根集线器状态进行轮询。

3、 注册集线器

register_root_hub(hcd);

在USB系统驱动加载的过程中,创建了集线器的线程(khubd),并且一直查询相应的线程事务。HCD驱动中,将集线器作为一个设备添加到主机控制器驱动中,然后进行集线器端口的初始化。在USB主机看来,根集线器本身也是USB主机的设备。USB主机驱动加载完成之后,即开始注册根集线器,并且作为一个设备加载到主机驱动之中。

USB主机和USB设备之间进行数据交互,USB设备本身并没有总线控制权,U盘被动地接收USB主机发送过来的信息并做出响应。USB主机控制器与根集线器构成了主机系统,然后外接其它的USB设备。

为了更好地探测到根集线器的状态变化,USB主机控制器驱动增加了状态轮询函数,以一定的时间间隔轮询根集线器状态是否发生变化。一旦根集线器状态发生变化,主机控制器就会产生相应的响应。

USB主机和USB设备之间的数据传输以URB(USB Request Block)的形式进行。

4、URB传输过程

USB初始化过程中,无论是主机控制器驱动还是根集线器驱动,都是通过URB传输获取设备信息。

4.1 申请URB

struct urb *usb_alloc_urb(int iso_packets, gfp_t mem_flags)

为urb分配内存并执行初始化。

4.2 初始化URB

初始化具体的urb包

static inline void usb_fill_bulk_urb(struct urb *urb,

struct usb_device *dev,

unsigned int pipe,

void *transfer_buffer,

int buffer_length,

usb_complete_t complete_fn,

void *context)

static inline void usb_fill_control_urb(struct urb *urb,

struct usb_device *dev,

unsigned int pipe,

unsigned char *setup_packet,

void *transfer_buffer,

int buffer_length,

usb_complete_t complete_fn,

void *context)

static inline void usb_fill_int_urb(struct urb *urb,

struct usb_device *dev,

unsigned int pipe,

void *transfer_buffer,

int buffer_length,

usb_complete_t complete_fn,

void *context,

int interval)

不同的传输模式下,驱动为之申请不同的URB。其中,Linux内核只支持同步传输外的三种传输事件,ISO事务需要手工进行初始化工作。控制传输事务、批量传输事务、中断传输事务API如上所示。

三种事务传输模式下的URB初始化函数有很多相似之处,主要参数含义如下:

• urb: 事务传输中的urb

• dev: 事务传输的目的设备

• pipe: USB主机与USB设备之间数据传输的通道

• transfer_buffer: 发送数据所申请的内存缓冲区首地址

• length: 发送数据缓冲区的长度

• context: complete函数的上下文

• complete_fn: 调用完成函数

• usb_fill_control_urb()的setup_packet: 即将被发送的设备数据包

• usb_fill_int_urb()的interval: 中断传输中两个URB调度的时间间隔

5、提交URB

URB初始化完成之后,USBD开始通过usb_start_wait_urb()提交urb请求(它调用usb_submit_urb来真正的发送URB请求),添加completition函数。

接下来,从message.c传到主机控制器(hcd.c),开始真正的usb_hcd_submit_urb()。此时,根据是否为根集线器,进入不同的工作队列。

usb_start_wait_urb->usb_submit_urb->usb_hcd_submit_urb

a) root_hub传输

若为root hub,将调用rh_urb_enqueue(),共有两种传输事务(控制传输和中断传输)

static int rh_urb_enqueue (struct usb_hcd *hcd, struct urb *urb)

{

if (usb_endpoint_xfer_int(&urb->ep->desc)) // 中断传输

return rh_queue_status (hcd, urb);

if (usb_endpoint_xfer_control(&urb->ep->desc)) // 控制传输

return rh_call_control (hcd, urb);

return -EINVAL;

}

b) 非root_hub传输

对于非常root_hub传输,它调用:

status = hcd->driver->urb_enqueue(hcd, urb, mem_flags);

c) 批量传输

root_hub本身没有批量传输流程,按照控制传输流程,控制传输最终要通过switch语句跳转到Bulk-Only传输流程中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/2284.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深度学习-数据操作

目录 张量通过shape属性访问张量的形状通过shape属性访问张量中元素的总数reshape改变张量的形状(不改变元素数量和元素值)使用全0、全1、其他常量或者从特定分布中随机采样的数字通过提供包含数值的Python列表为所需张量中的每个元素赋予确定值。张量的…

半导体存储器整理

半导体存储器用来存储大量的二值数据,它是计算机等大型数字系统中不可缺少的组成部分。按照集成度划分,半导体存储器属于大规模集成电路。 目前半导体存储器可以分为两大类: 只读存储器(ROM,Read Only Memory&#xff…

如何判断客户需求能不能做出来产品?

在做G端产品的过程中,为了让产品可以符合客户实际需求,我们需要经历客户需求调研的这个环节。那么,需求收集后,我们要从什么维度判断客户的需求是否真的可以产品化呢? 我们做G端产品,新产品的方向几乎100%来自于政策。所以才会有“政策带来产品,产品催生政绩”。 可就算…

解锁ApplicationContext vs BeanFactory: 谁更具选择性?

目录 一、聚焦源码回顾 (一)源码分析和理解 (二)简短的回顾对比建议 二、ApplicationContext vs BeanFactory特性对比 (一)主要特性总结 (二)直接建议 三、案例简单说明 &am…

OpenTelemetry-1.介绍

目录 1.是什么 2.为什么使用 OpenTelemetry 3.数据类型 Tracing Metrics Logging Baggage 4.架构图 5.核心概念 6.相关开源项目 ​编辑 7.分布式追踪的起源 8.百花齐放的分布式追踪 Zipkin Skywalking Pinpoint Jaeger OpenCensus OpenTracing 9.Openteleme…

虚假新闻检测——Adapting Fake News Detection to the Era of Large Language Models

论文地址:https://arxiv.org/abs/2311.04917 1.概论 尽管大量的研究致力于虚假新闻检测,这些研究普遍存在两大局限性:其一,它们往往默认所有新闻文本均出自人类之手,忽略了机器深度改写乃至生成的真实新闻日益增长的现…

【北京迅为】《iTOP-3588开发板系统编程手册》-第20章 socket 应用编程

RK3588是一款低功耗、高性能的处理器,适用于基于arm的PC和Edge计算设备、个人移动互联网设备等数字多媒体应用,RK3588支持8K视频编解码,内置GPU可以完全兼容OpenGLES 1.1、2.0和3.2。RK3588引入了新一代完全基于硬件的最大4800万像素ISP&…

TI_DSP_F2808学习笔记1: GPIO

1. 初始化设置 1.1 控制寄存器 GPxMUX功能选择寄存器/多功能复用选择 GPxDIR 方向选择寄存器/输入输出选择 0 输入 1 输出GPxPUD 上拉功能选择寄存器/是否启用内部上拉 0 有上拉,1禁止上拉GPxQSeln输入限定选择寄存器 输入n次为0或1才有效,滤波 1.2 数…

PDF 书签制作与调整

本文是对以前发表的旧文拆分,因为原文主题太多,过长,特另起一篇分述。 第一部分 由可编辑 PDF 文档创建书签 方法 1. Adobe Acrobat Pro autobookmark AutoBookmark 是一个可用于 Adobe Acrobat 自动生成书签的插件。 官方下载地址&…

corona渲染器锐化模糊设置,corona高效出图方法

​在使用Corona渲染器进行效果图渲染时,锐化和模糊是两种常用的设置,它们主要用于调整图像的清晰度和柔化效果。锐化参数可以增强图像中的细节,使画面看起来更加清晰锋利;而模糊参数则可以用来柔化图像边缘,减少图像噪…

Etsy多账号关联怎么办?Etsy店铺防关联解决方法

Etsy虽然相对于其他跨境电商平台来说比较小众,但因为平台是以卖手工艺品为主的,所以成本较低,利润很高。许多跨境卖家都纷纷入驻,导致平台规则越发严格,操作不当就会封号,比如一个卖家操作多个账号会出现关…

10.接口自动化测试学习-Pytest框架(2)

1.mark标签 如果在每一个模块,每一个类,每一个方法和用例之前都加上mark标签,那么在pytest运行时就可以只运行带有该mark标签的模块、类、接口。 这样可以方便我们执行自动化时,自主选择执行全部用例、某个模块用例、某个流程用…

二分查找知识点及练习题

知识点讲解 一、没有相同元素查找 请在一个有序递增数组中(不存在相同元素),采用二分查找,找出值x的位置,如果x在数组中不存在,请输出-1! 输入格式 第一行,一个整数n,代…

家用洗地机买什么牌子的好?四大业内顶尖品牌推荐

家庭清洁一直是必不可少的,但用传统的手动拖地清洁,费时又费力。现在出现了洗地机,确实改变了我们对家庭清洁的看法。它不仅能扫地、拖地,还能吸水,甚至能够自动清洁滚刷解放我们双手,提供高效清洁的同时还…

【Linux系列】 离线安装vnc 可视化桌面

离线安装vnc 可视化桌面 缘下载安装vnc初始化链接 缘 项目需要下载 下载地址: http://mirror.centos.org/centos/7/updates/x86_64/Packages/tigervnc-license-1.8.0-31.el7_9.noarch.rpm http://mirror.centos.org/centos/7/os/x86_64/Packages/libXfont2-2.0.…

【Day 6】MySQL 基础

1 MySQL DataBase(DB)是存储和管理数据的仓库 DataBaseManagementSystem(DBMS)数据库管理系统,操纵和管理数据库的大型软件 SOL(Structured QueryLanguage)操作关系型数据库的编程语言&#…

C++/Qt 小知识记录5

工作中遇到的一些小问题,总结的小知识记录:C/Qt 小知识5 Windows下查看端口占用情况C调用Python三方库测试库有没有被加上的测试方法初始化使用Python的env环境,用Py_SetPythonHome设置GDAL相关的,需要把osgeo、rasterio的路径加入…

【iOS开发】(一)2024 从一无所有开始,到ios开发(react Native)

​ 2024 从一无所有开始,到ios开发(react Native) 目录标题 1 工具简介2 基础环境搭建1 安装 brew2 安装 Node.js3 安装 Yarn4 安装 React Native 脚手架 3 ios环境搭建4创建并启动一个app 在这里插入图片描述 1 工具简介 Homebrew (brew)&a…

OpenHarmony实战开发-页面布局检查器ArkUI Inspector使用指导

DevEco Studio内置ArkUI Inspector工具,开发者可以使用ArkUI Inspector,在DevEco Studio上查看应用在真机上的UI显示效果。利用ArkUI Inspector工具,开发者可以快速定位布局问题或其他UI相关问题,同时也可以观察和了解不同组件之间…

Matlab分段微分方程组拟合【案例源码+视频教程】

专栏导读 作者简介:工学博士,高级工程师,专注于工业软件算法研究本文已收录于专栏:《复杂函数拟合案例分享》本专栏旨在提供 1.以案例的形式讲解各类复杂函数拟合的程序实现方法,并提供所有案例完整源码;2.…