当前位置: 首页 > article >正文

Linux内核编程(二十一)USB应用及驱动开发

       

一、基础知识 

1. USB接口是什么?

        USB接口(Universal Serial Bus)是一种通用串行总线,广泛使用的接口标准,主要用于连接计算机与外围设备(如键盘、鼠标、打印机、存储设备等)之间的数据传输和电力供应。它旨在简化计算机与外部设备之间的连接方式,同时提供更高的传输速度和更好的兼容性。

         在1990年代初,计算机外围设备通常使用专用接口,如鼠标和键盘常见的PS/2接口,打印机使用的LPT接口(并口)等。这些接口虽然在当时各自具有一定的专用性和高效性,但也存在很多问题,随着技术的发展,通用性更强的接口逐渐成为主流,USB(Universal Serial Bus)便是这一发展潮流的代表。 

        1996年,由Intel微软康柏DECIBMNEC北方电信公司等七家业界巨头组成的非盈利组织USB标准化组织(USB Implementers Forum,简称USB-IF)开始推动USB(Universal Serial Bus)接口的标准化工作。USB的诞生标志着计算机外围设备连接方式的革命性转变。

USB 1.0/1.1最早的版本,传输速度为12 Mbps。
USB 2.0

提供更高的传输速度(最高480 Mbps),广泛应用于各种设备。

USB 3.0/3.1提供更高的数据传输速率,最高可达5 Gbps及以上,支持更大的电流供电。
USB 4.0最新的USB版本,支持更高的传输速率,最高可达40 Gbps,并且兼容Thunderbolt 3协议。

2. USB命名规则

        在2013年,USB 3.0USB 3.1推出后,USB实现了更高的传输速度和更多功能,但随着技术的进步和市场的需求,USB-IF(USB Implementers Forum)为了更清晰地区分不同的版本和性能,进行了命名上的调整。

第一次命名改变:

                USB 3.0 改名为 USB 3.1 Gen 1

                USB 3.1 改名为 USB 3.1 Gen 2

第二次命名改变:

                USB 3.1 Gen1 = USB 3.2 Gen1
                USB 3.1 Gen2 = USB 3.2 Gen2
                USB 3.2 = USB 3.2 Gen2x2

        其本质上就是, USB 3.0 就是 USB 3.2 Gen1 ,USB 3.1是USB 3.2 Gen2,USB 3.2是USB 3.2 Gen2x2。

3. USB HOST和USB OTG

        USB Host(主设备):是指具备控制和管理USB总线的设备。它负责控制所有USB连接的设备,发起数据传输,并管理设备间的通信。USB Host的核心功能是控制和调度USB数据的流向。典型的USB Host设备包括:计算机(台式机、笔记本电脑等)、打印机(具有USB接口的)等。在USB通信中,Host设备通过发送命令来请求从设备发送或接收数据。Host设备管理USB总线上的电源供给和数据传输。

        USB Slave(从设备):是指依赖于主设备控制的设备。USB从设备由主设备管理,它没有独立的数据传输能力,所有的数据传输都必须经过主设备发起或协调。USB从设备通常是外设设备,例如:键盘、鼠标、U盘等。

        USB OTG(On-The-Go):是一项功能,使得USB设备在需要时可以切换角色,既可以作为主设备,也可以作为从设备,从而直接与其他USB设备进行通信。USB OTG标准通常适用于移动设备,如智能手机、平板电脑等。它允许用户无需通过传统的主设备(如计算机)即可实现设备间的直接连接和数据交换。例如,一台支持OTG的手机可以在连接U盘时充当主设备,而在连接键盘时又可以充当从设备。

4. USB集线器(hub)

        USB Hub(集线器)是一种设备,允许多个USB设备通过一个USB端口与计算机进行连接。它实际上是一个多端口的USB接口扩展器,可以将计算机的一个USB端口扩展为多个端口,方便用户连接多个USB设备。 集线器是为了扩展更多的接口。但是并不是可以无休止的可以扩展,USB2.0协议中最多扩展七层。每一层所有设备相加不能超过127个(包括集线器) 。

        所有从机都必须经过集线器(hub)才能与主机连接,也就是设备不能直接和主机相连接。根集线器:与主机直接连接的集线器叫做根集线器,用户外接的叫做普通集线器。

下图的集线器就是普通集线器。

下图中集线器就是根集线器, 例如U盘的插入就是连接到根集线器上。

     

5. USB描述符

        描述符通常是一种数据结构,在 Linux里面就是一个结构体,使用结构体来描述当前的设备有哪些特征,用于描述某个对象或设备的属性和特征。在USB和其他通信协议中,描述符扮演着重要的角色,它们包含了设备的基本信息,如设备类别、供应商ID、产品ID等,这些信息对于主机来说至关重要,因为主机需要依靠这些信息来识别和管理连接的设备。例如下述内容。

/* USB Device Descriptor */
struct usb_device_descriptor {
    uint8_t  bLength;              // 描述符的长度(以字节为单位),对于设备描述符来说总是18字节
    uint8_t  bDescriptorType;      // 描述符类型,对于设备描述符来说总是0x01
    uint16_t bcdUSB;               // USB规范版本号,以二进制编码的十进制数表示
    uint8_t  bDeviceClass;         // 设备类别代码
    uint8_t  bDeviceSubClass;      // 设备子类代码
    uint8_t  bDeviceProtocol;      // 设备协议代码
    uint8_t  bMaxPacketSize0;      // 端点0的最大数据包大小(以字节为单位)
    uint16_t idVendor;             // 供应商ID
    uint16_t idProduct;            // 产品ID
    uint16_t bcdDevice;            // 设备版本号,以二进制编码的十进制数表示
    uint8_t  iManufacturer;        // 供应商字符串描述符的索引
    uint8_t  iProduct;             // 产品字符串描述符的索引
    uint8_t  iSerialNumber;        // 序列号字符串描述符的索引
    uint8_t  bNumConfigurations;   // 支持的配置数量
} __attribute__((packed));

        USB 描述符主要有:设备描述符,配置描述符,接口描述符,端点描述符。这些描述符共同构建了USB设备的特征和功能,通过读取这些描述符,系统可以配置驱动和参数,使得操作系统可以正确识别设备和通信。

(1)设备描述符:是USB设备中最重要的描述符之一,它包含了设备的基本信息,如设备类型、供应商ID、产品ID、设备版本等。这个描述符通常位于设备的EEPROM或闪存中,并在设备枚举过程中被主机读取。通过读取设备描述符,主机可以了解设备的基本属性,并决定如何与设备进行通信。设备描述符是设备连接到主机时第一个被请求和返回的信息。它提供了设备的本特征。

(2)配置描述符:描述设备支持的不同配置。

(3)接口描述符:描述了配置中的一个接口。

(4)端点描述符:描述接口中的一个端点。端点是数据在设备和主机之间传输的终点。一个具体的端点只能属于四种传输模式中的一种。

注意:
        一个USB设备有1个设备描述符。
        一个USB设备有1个或多个配置描述符。
        一个USB配置有1个或多个接口描述符。
        一个USB接口有0个或多个点描述符(不括端点0)。

6. 传输模式

 USB有四种传输模式:批量传输、中断传输、实时传输、控制传输。

(1)批量传输:适用于大数据量传输,且对实时性要求不高。主要用于传输不需要定时保证的数据,传输时没有时间限制,可以在空闲带宽下传输数据。常见应用:U盘、外部硬盘等。

(2)中断传输:用于传输少量、具有时间限制的数据,主机定期请求数据,传输间隔由设备和主机协商。实时性要求较高,但数据量较小,且数据传输频率是固定的。常见应用:鼠标、键盘、游戏手柄等输入设备。

(3)实时传输:适用于需要固定传输速率的场景,实时性要求高,但允许一定程度的丢包或误差。一般用于音频、视频等流式数据传输,确保数据能够以固定速率传输,尽管可能会丢失一些数据。常见应用:音视频设备、USB音响、摄像头等。

(4)控制传输(Control Transfer):用于设备配置、查询和命令的传输,数据量较小,且是双向传输。常用于 USB 设备的初始化和命令交换,传输的内容通常较为简单。常见应用:设备配置、读取设备状态、设置设备功能等。控制传输分为三个阶段:①建立阶段。②数据阶段。③确认阶段。

7. USB数据格式

        US8通信数据格式由域、包、事务、传输组成。多个域组成包,多个包组成事务,多个事务组成传输。所以域是 USB 数据传输中最小的单位。事务是最基本的单位,对于我们开发人员来说关注事务和传输就可以了。

(1)域(Domain)

  • 是 USB 数据传输中的最小单位。每个域有特定的作用和格式,可以包含一个或多个字段。
  • 七种类型的域
    • 同步域(SYNC):用于同步传输时钟,确保数据传输的时序性。
    • 地址域(ADDR):标识 USB 设备的地址,通常用于指定数据的目标设备。
    • 端点域(ENDPT):指定数据的目标端点,用于区分设备的不同数据流。
    • 帧号域(FRAME):用于标识当前传输的帧号,在多帧传输中起到区分作用。
    • 标识域(ID):用于标识不同的传输或者数据包。
    • 数据域(Data):实际的数据内容区域,是传输的核心部分。
    • 校验域(CRC):包含用于检验数据完整性的校验码,确保数据传输过程中没有错误。

(2)包(Packet)

        包是由多个域组成的数据单元。根据包的不同类型,域的结构会有所不同。USB 包有四种主要类型:

令牌包(Token Packet):用于向设备发送请求或命令,包含地址和端点等信息。

数据包(Data Packet):用于传输实际的数据,包含数据域和校验域。

握手包(Handshake Packet):用于确认数据传输的结果,常见的有 ACK(确认)和 NAK(未确认)等。

特殊包(Special Packet):用于特殊的控制或管理操作,例如 RESET 或 SOF(帧开始信号)。

        

        在 USB 中,PID 代表 Packet ID,即 数据包标识符。它用于标识 USB 数据包的类型,并且是在令牌包(Token Packet)和握手包(Handshake Packet)中必不可少的字段。常见的 PID 类型:

  • 令牌包(Token Packet)

    • OUT:用于主机向设备传输数据。
    • IN:用于设备向主机传输数据。
    • SETUP:用于设置设备的控制传输。
  • 数据包(Data Packet)

    • DATA0:表示数据包的第一个数据包,常用于控制传输。
    • DATA1:表示数据包的第二个数据包。
  • 握手包(Handshake Packet)

    • ACK:确认数据包传输成功。
    • NAK:表示数据包传输失败。
    • STALL:表示设备在处理数据时发生错误,无法完成请求。
  • 特殊包(Special Packet)

    • PRE:预留包(用于扩展等特殊用途)。

(3)事务(Transaction)

  • 事务是 USB 数据传输的基本单位,是由令牌包、数据包和握手包组成的。事务是传输过程中最小的可操作单元。
  • 事务的结构
    • 令牌包(Token Packet):发起事务,标识目标设备、端点等信息。
    • 数据包(Data Packet):可选,用于传输实际的数据。
    • 握手包(Handshake Packet):可选,用于确认数据传输是否成功。
  • 对开发者而言,事务是关注的重点,因为它直接影响数据的传输成功与否。

(4)传输(Transfer)

  • 传输是更高层次的概念,通常由多个事务组成,多个事务之间在时间上有一定的顺序。
  • 一个完整的传输可能涉及多个包、事务和域,最终确保数据从主机到设备(或反向)成功传送。

举例:

8. USB枚举

        USB枚举(USB Enumeration)是指USB设备连接到计算机时,操作系统对该设备进行识别和配置的过程。这个过程包括一系列步骤,确保计算机能够正确识别设备、安装必要的驱动程序并为设备分配资源。

        在USB枚举过程中主要使用控制传输模式。通常用于设备和主机之间的命令和状态交换。它的工作流程分为三个阶段:建立阶段(Setup)数据阶段(Data)确认阶段(Status)

(1)建立阶段。

        由USB主机发起,该阶段使用的是一个SETUP数据包,其结构包含了请求的命令、参数、设备的目标等信息。通过SETUP数据包,主机向设备发送命令,或者设备准备接收或发送数据。

        如果是输入请求(例如获取设备信息),则设备会准备好数据供主机接收。如果是输出请求(例如配置设备),则设备会准备好数据接收主机发出的命令。

(2)数据阶段。

        如果建立阶段是输入请求,则数据阶段由设备向主机传输数据。如果建立阶段是输出请求,则数据阶段由主机向设备传输数据。如果没有实际的数据传输需求(即请求的长度为零),此阶段依然会发送一个长度为0的数据包来表示数据传输完成。

(3)确认阶段。

        确认阶段刚好跟建立阶段相反。如果数据阶段是输入请求(即主机接收设备数据),那么确认阶段是设备向主机发送一个输出数据包。如果数据阶段是输出请求(即主机向设备发送数据),那么确认阶段是主机向设备发送一个输入数据包。

        确认阶段的主要目的是验证数据是否已经正确传输。如果传输成功,确认阶段不会包含任何数据;它只是作为一种状态确认,以告知数据传输是否正常完成。通常,成功的确认阶段只包含一个零长度数据包,这意味着数据传输完成且没有错误。

查看USB枚举过程中的数据内容,如下所示:

(1)传输。

(2) 传输和事务。

(3) 传输、事务、包和域。

 

 ★举例USB枚举过程:

二、应用编程 

1. libusb库安装

  libusb 是一个用 C 语言编写的开源库,主要用于简化 USB 设备的操作。通过 libusb,开发者可以方便地与 USB 设备进行通信,而不需要深入了解 USB 协议的底层细节。

  libusb 提供了跨平台的 API,可以在 Linux、macOS 和 Windows 等操作系统中使用,极大地提升了应用的可移植性。libusb 提供了一套简洁的 API,支持从 USB 1.0 到 USB 3.1 等不同版本的 USB 协议。无论是在传输数据、控制 USB 设备还是处理设备的其他操作时,API 接口保持一致,使用起来非常方便。

(1)下载。

        下载地址:libusb官网。如下图所示,下载最新的版本即可。

(2)编译安装(X86下)。

        我们下载所得到的就是libusb库的源码包,我们需要对源码包进行编译操作。在不同平台上使用的编译器不同,例如X86使用gcc,ARM使用交叉编译器。

<1> 安装依赖包。

sudo apt install -y libudev-dev

<2> 指定编译环境,这里为x86_64-linux 架构。

./configure --build=x86_64-linux

<3> 编译和安装。

make
sudo make install

<4> 验证:进入/usr/local/lib查看。

(3)编译安装(ARM下)。 

 <1> 安装依赖包。

sudo apt install -y libudev-dev

<2> 指定编译环境,这里为ARM架构。(先在源码包路径下新建install文件夹,用于存放编译后的libusb库)

//--build:编译平台
//--host:目标平台
//--prefix:安装路径
//CC: 编译器
//CXX:g++编译器
//--disable-udev:用于禁用对 udev 的支持
./configure --build=x86_64-linux --host=arm-linux --prefix=/home/qjl/libusb/libusb-1.0.27/install CC=arm-linux-gnueabihf-gcc CXX=arm-linux-gnueabihf-g++ --disable-udev

<3> 编译和安装。

make
sudo make install

<4> 使用验证。

        将源码目录下的example中的一个测试源码(例如listdevs.c)拷贝到install文件夹中。然后使用交叉编译器编译这个源码生成可执行文件。如下所示。将生产的可执行文件使用命令file来查看格式是否正确。将可执行文件传至开发板运行。

//-I ./include/libusb-1.0 :头文件路径
//-L ./lib :静态库路径
//-lusb-1.0 -lpthread -static 连接usb静态库 和线程thread库

arm-linux-gnueabihf-gcc listdevs.c -o listdevs -I ./include/libusb-1.0  -L ./lib  -lusb-1.0 -lpthread -static

http://www.kler.cn/a/507980.html

相关文章:

  • 如何使用 useMemo 和 memo 优化 React 应用性能?
  • Vue.js组件开发-实现输入框与筛选逻辑
  • Java并发编程——线程池(基础,使用,拒绝策略,命名,提交方式,状态)
  • vue 纯前端导出 Excel
  • 《AI赋能鸿蒙Next,打造极致沉浸感游戏》
  • maven常见知识点
  • Leetcode3097:或值至少为 K 的最短子数组 II
  • C 语言运算符的优先级和结合性
  • 解答二重积分
  • 智能化量化模型的前沿探索:中阳的崛起
  • [BrainShadow-V1] VR头戴设备统计报告
  • 分布式系统、微服务、SOA初步理解
  • ubuntu设置代理服务器
  • “深入浅出”系列之设计模式篇:(0)什么是设计模式
  • Objective-C语言的数据类型
  • windows蓝牙驱动开发-BLE音频(一)
  • Linux测试处理fps为30、1920*1080、一分钟的视频性能
  • BGP边界网关协议(Border Gateway Protocol)概念、邻居建立
  • 【西藏乡镇界面】图层arcgis格式shp数据有乡镇名称和编码2020年wgs84坐标内容测评
  • C++/C语言判断重复数组(zznu)⭐
  • Java算法 二叉树入门 力扣简单题相同的树 翻转二叉树 判断对称二叉树 递归求二叉树的层数
  • 刷题记录 回溯算法-16:47. 全排列 II
  • 从玩具到工业控制--51单片机的跨界传奇【3】
  • NLP入门书籍《掌握NLP:从基础到大语言模型》免费下载pdf
  • MySQL的日期时间类型
  • 《汽车维修技师》是什么级别的期刊?是正规期刊吗?能评职称吗?