Linux USB 基础概念与协议简介

引言

  因需将搭载Linux系统的开发板作为USB从设备(虚拟串口)使用,故在利用Linux 内核中Gadget驱动设备之前,普及USB的基础概念显得十分必要。此外,USB设备驱动开发过程中,也因借助BUS Hound工具对USB设备进行抓包处理,分析USB设备的接收到的协议帧。




基础概念

1. USB是主从结构:
  a. 所有的USB传输,都是从USB主机这方发起;
  b. USB设备没有"主动"通知USB主机的能力。
例子:USB鼠标滑动一下立刻产生数据,但是它没有能力通知PC机来读数据,只能被动地等得PC机来读。


2. USB四种传输类型:
  a. 控制传输:可靠,时间有保证,比如:USB设备的识别过程
  b. 批量传输: 可靠, 时间没有保证, 比如:U盘
  c. 中断传输:可靠,实时,比如:USB鼠标
  d. 实时传输:不可靠,实时,比如:USB摄像头


3. USB传输的对象:端点(endpoint)
  a. 我们说"读U盘"、“写U盘”,可以细化为:把数据写到U盘的端点1,从U盘的端点2里读出数据
  b. 除了端点0外,每一个端点只支持一个方向的数据传输;
  c. 端点0用于控制传输,既能输出也能输入;
  d. 每一个端点都有传输类型,传输方向;
  e. 端点是USB设备通信的基本单位,所有通信都是从端点发起的。


4. 程序里说的输入(IN)、输出(OUT), “都是” 基于USB主机的立场说的。
例子:比如鼠标的数据是从鼠标传到PC机, 对应的端点称为"输入端点"


5. 按USB协议栈的层次划分:
  a. 一个Host可能有一个或者多个Device;
  b. 一个Device可能有一个或者多个Interface;
  c. 一个Interface可能有一个或者多个Endpoint。


6. 主要USB 控制器标准:
  a. OHCI(Open Host Controller Interface)
  b. UHCI(Universal Host Controller Interface)
  c. EHCI( Enhanced Host Controller Interface)
  d. xHCI(eXtensible Host Controller Interface),xHCI 支持所有速度种类的 USB 设备,xHCI 出现的目的就是为了替换前面三个。




协议简介

1. USB驱动开发常见的五大结构体:
  ①、设备描述符用于描述 USB 设备的一般信息,USB 设备只有一个设备描述符。设备描述符里面记录了设备的 USB 版本号、设备类型、VID(厂商 ID)、PID(产品 ID)、设备序列号等。

struct usb_device_descriptor {
  			__u8  bLength;						//  此设备描述符长度,18 个字节
  			__u8  bDescriptorType;				// 描述符类型,为 0X01
  			__u16 bcdUSB;						// USB 版本号,BCD 码
  			__u8  bDeviceClass;					// 设备类
  			__u8  bDeviceSubClass;				// 设备子类
  			__u8  bDeviceProtocol;				// 设备协议
  			__u8  bMaxPacketSize0;				// 端点 0 的最大包长度
  			__u16 idVendor;						// 厂商 ID
  			__u16 idProduct;					// 产品 ID
  			__u16 bcdDevice;					// 设备版本号
  			__u8  iManufacturer;				// 厂商信息字符串描述符索引值
  			__u8  iProduct;						// 产品信息字符串描述符索引值
  			__u8  iSerialNumber;				// 产品序列号字符串描述符索引值
  			__u8  bNumConfigurations;			// 可能的配置描述符数目
} __attribute__ ((packed));

  ②、设备描述符的 bNumConfigurations 域定义了一个 USB 设备的配置描述符数量,一个 USB设备至少有一个配置描述符。配置描述符描述了设备可提供的接口(Interface)数量、配置编号、供电信息等。

struct usb_config_descriptor {
  			__u8  bLength;						// 此配置描述符长度,9 个字节
  			__u8  bDescriptorType;				// 配置描述符类型,为 0X02
  		
  			__le16 wTotalLength;				// 整个配置信息总长度(包括配置、接口、端点、设备类和厂家定义的描述符)
  			__u8  bNumInterfaces;				// 此配置所支持的接口数
  			__u8  bConfigurationValue;			// 该配置的值,一个设备支持多种配置,通过配置值来区分不同的配置。
  			__u8  iConfiguration;				// 描述此配置的字符串描述索引
  			__u8  bmAttributes;					// 该设备的属性:	D7:保留	D6:自给电源	D5:远程唤醒	D4:0:保留
  			__u8  bMaxPower;					// 此配置下所需的总线电流(单位 2mA)
} __attribute__ ((packed));

  ③、字符串描述符是可选的,字符串描述符用于描述一些方便人们阅读的信息,比如制造商、设备名称啥的。如果一个设备没有字符串描述符,那么其他描述符中和字符串有关的索引值都必须为 0。

struct usb_string_descriptor {
  			__u8  bLength;						// 此字符串描述符长度
  			__u8  bDescriptorType;				// 字符串描述符类型,为 0X03
  		
  			__le16 wData[1];					/* UTF-16LE encoded */
} __attribute__ ((packed));

  ④、配置描述符中指定了该配置下的接口数量,配置可以提供一个或多个接口,接口描述符用于描述接口属性。接口描述符中一般记录接口编号、接口对应的端点数量、接口所述的类等。

struct usb_interface_descriptor {
			__u8  bLength;						// 此接口描述符长度,9 个字节
			__u8  bDescriptorType;				// 描述符类型,为 0X04
			
			__u8  bInterfaceNumber;				// 当前接口编号,从 0 开始
			__u8  bAlternateSetting;			// 当前接口备用编号
			__u8  bNumEndpoints;				// 当前接口的端点数量
			__u8  bInterfaceClass;				// 当前接口所属的类
			__u8  bInterfaceSubClass;			// 当前接口所属的子类
			__u8  bInterfaceProtocol;			// 当前接口所使用的协议
			__u8  iInterface;					// 当前接口字符串的索引值
} __attribute__ ((packed));

  ⑤、接口描述符定义了其端点数量,端点是设备与主机之间进行数据传输的逻辑接口,除了端点 0 是双向端口,其他的端口都是单向的。端点描述符描述了树传输类型、方向、数据包大小、端点号等信息。

struct usb_endpoint_descriptor {
			__u8  bLength;						// 此端点描述符长度,7 个字节
			__u8  bDescriptorType;				// 描述符类型,为 0X05
		
			__u8  bEndpointAddress;				// 端点地址和方向:		bit3:0:端点号		bit6:4:保留,为零。		bit7:方向,0 输出端点(主机到设备),1 输入端点(设备到主机)
			__u8  bmAttributes;					// 端点属性,bit1:0 表示传输类型:		00:控制传输		01:同步传输		10:批量传输		11:中断传输		其他位保留
			__le16 wMaxPacketSize;				// 端点能发送或接收的最大数据包长度
			__u8  bInterval;					// 端点数据传输中周期时间间隙值,此域对于批量传输和控制传输无效,同步传输的话此域必须为 1ms,中断传输此域可以设置 1ms~255ms。
		
			/* NOTE:  these two are _only_ in audio endpoints. */
			/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
			__u8  bRefresh;								
			__u8  bSynchAddress;					
} __attribute__ ((packed));

2. USB 枚举:
  当 USB 设备与 USB 主机连接以后主机就会对 USB 设备进行枚举,通过枚举来获取设备的描述符信息,主机得到这些信息以后就知道该加载什么样的驱动、如何进行通信等。USB 枚举过程如下:
  ①、第一回合,当 USB 主机检测到 USB 设备插入以后机会发出总线复位信号来复位设备USB 设备复位完成以后地址为 0,主机向地址 0 的端点 0 发送数据,请求设备的描述符。设备得到请求以后就会按照主机的要求将设备描述符发送给主机,主机得到设备发送过来的设备描述符以后,如果确认无误就会向设备返回一个确认数据包(ACK)。
   ②、第二回合,主机再次复位设备,进入地址设置阶段。 主机向地址 0 的端点 0 发送设置地址请求数据包,新的设备地址就包含在这个数据包中,因此没有数据过程。设备进入状态过程,等待主机请求状态返回,收到以后设备就会向主机发送一个 0 字节状态数据包,表明设备已经设置好地址了,主机收到这个 0 字节状态数据包以后会返回一个确认包(ACK)。设备收到主机发送的 ACK 包以后就会使用这个新的设备地址,至此设备就得到了一个唯一的地址。
  ③、第三回合,主机向新的设备地址端点 0 发送请求设备描述符数据包,这一次主机要获取整个设备描述符,一共是 18 个字节
  ④、和第③步类似,接下来依次获取配置描述符、配置集合、字符串描述符等等。




USB 抓包工具(BUS Hound)

  一个便利的USB抓帧工具,能让我们在USB驱动开发过程中事半功倍。以下为BUS Hound 抓取数据帧的界面:


在这里插入图片描述




  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值