Linux USB Driver
1. USB简介
USB,是英文Universal Serial Bus(通用串行总线)的缩写,而其中文简称为“通串线”,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯。是应用在PC领域的接口技术。USB接口支持设备的即插即用和热插拔功能。(注:来自度娘)
USB是一个复杂的系统,它的复杂程度往往让很多开发人员人望而却步。如果有人说他精通USB,你基本上可以首先预判有可能他是大牛(不要放过任何求教的机会),然后深入了解后断定他是大大的吹牛。
2. USB拓扑结构
以下是描述USB分层的拓扑模型,以Host-root Hub 为起点,最多支持7层,也就是说任何一个USB系统最多可以允许5个USB HUB级联。一个复合设备将同时占据两层或更多层。
图1 USB 拓扑结构
3. USB数据传输机制
USB 采用轮询的广播机制传输数据,所有的传输都由主机发起,任何时刻整个 USB 体
系内仅允许一个数据包的传输,即不同物理传输线上看到的数据包都是同一被广播的数据包。
USB 采用“令牌包”-“数据包”-“握手包”的传输机制,在令牌包中指定数据包去向
或者来源的设备地址和端点(Endpoint),从而保证了只有一个设备对被广播的数据包/令牌包作出响应。握手包表示了传输的成功与否。
3.1. 数据包
USB 总线上数据传输的最小单位,包括SYNC、数据及EOP 三个部分。其中数据的格式针对不同的包有不同的格式。但都以8 位的PID 开始。PID 指定了数据包的类型(共16 种)。
3.2. 令牌包
即指PID 为IN/OUT/SETUP 的包。
3.3. 端点(Endpoint)
是USB 设备中的可以进行数据收发的最小单元,支持单向或者双向的数据传输。设备支持端点的数量是有限制的,除默认端点外低速设备最多支持2 组端点(2 个输入,2 个输出),高速和全速设备最多支持15 组端点
3.4. 管道
管道(Pipe)是主机和设备端点之间数据传输的模型,共有两种类型的管道:无格式的流管道(Stream Pipe)和有格式的信息管道(Message Pipe)。任何USB 设备一旦上电就存在一个信息管道,即默认的控制管道,USB 主机通过该管道来获取设备的描述、配置、状态,并对设备进行配置。
3.5. 枚举
USB 设备连接到 HOST 时,HOST 必须通过默认的控制管道对其进行枚举,完成获得其设备描述、进行地址分配、获得其配置描述、进行配置等操作方可正常使用。USB 设备的即插即用特性即依赖于此。
枚举:是USB 体系中一个很重要的活动,由一系列标准请求组成(若设备属于某个子类,还包含该子类定义的特殊请求)。通过枚举HOST 可以获得设备的基本描述信息,如支持的USB 版本、PID、VID、设备分类(Class)、供电方式、最大消耗电流、配置数量、各种类型端点的数量及传输能力(最大包长度)。HOST 根据PID 和VID 加载设备驱动程序,并对设备进行合适的配置。只有经过枚举的设备才能正常使用。对于总线供电设备,在枚举完成前最多可从总线获取100mA 的电流。
3.6. 传输类型
控制传输:主要用于在设备连接时对设备进行枚举以及其他因设备而已的特定操作。
中断传输:用于对延迟要求严格、小量数据的可靠传输,如键盘、游戏手柄等。
批量传输:用于对延迟要求宽松,大量数据的可靠传输,如U 盘等。
同步传输:用于对可靠性要求不高的实时数据传输,如摄像头、USB 音响等。
3.7.
4. USB协议简介
5. Linux USB 驱动层次
5.1. 主机侧与设备侧USB驱动
主机控制器– Host Controler
USB设备控制器-USB devicecontroler
每条总线上只能有一个主机控制器,负责协调主机和设备的通信,但是设备不能主动发送任何消息给主机。
从运行Linux的主机侧看 |
USB总线 |
从运行Linux设备侧看 |
USB设备驱动 Mass storage/CDC/HID |
Gadget Function驱动 |
|
Mass storage/CDC/HID |
||
|
|
|
USB核心 |
Gadget Function API |
|
|
|
|
USB主机驱动器驱动OHCI/EHCI/UHCI |
UDC驱动 |
|
|
|
|
USB主机控制器 |
USB设备控制器 |
5.2. 设备、配置、接口、端点
USB设备包括四个层次分别是设备、配置、接口、端点。
配置: 表现不同的功能组合,由一个或是多个接口组成。
接口:物理设备接口,包含一个或多个端点和一个或是多个配置
端点:实际的主机与设备通信的端口,有唯一的地址
各个层级有相应的描述符,例如\include\uapi\linux\usb\ch9.h
第一层级设备描述符,描述设备的通用信息
struct usb_device_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16bcdUSB;
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
__u8 bMaxPacketSize0;
__le16idVendor;
__le16idProduct;
__le16bcdDevice;
__u8 iManufacturer;
__u8 iProduct;
__u8 iSerialNumber;
__u8 bNumConfigurations;
} __attribute__ ((packed));
第二层级配置描述符,描述接口数,支持挂起和恢复功能的能力以及要求。
struct usb_config_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16wTotalLength;
__u8 bNumInterfaces;
__u8 bConfigurationValue;
__u8 iConfiguration;
__u8 bmAttributes;
__u8 bMaxPower;
} __attribute__ ((packed));
第三层级接口描述符,描述接口类,子类和适用的协议,接口备用配置的数目和端点数目。
struct usb_interface_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bInterfaceNumber;
__u8 bAlternateSetting;
__u8 bNumEndpoints;
__u8 bInterfaceClass;
__u8 bInterfaceSubClass;
__u8 bInterfaceProtocol;
__u8 iInterface;
} __attribute__ ((packed));
第四层级端点描述符,描述端点地址、方向和类型、支持的最大包大小,如果是终端类型的端点则还包括轮询频率。
struct usb_endpoint_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bEndpointAddress;
__u8 bmAttributes;
__le16wMaxPacketSize;
__u8 bInterval;
/*NOTE: these two are _only_ in audioendpoints. */
/*use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
__u8 bRefresh;
__u8 bSynchAddress;
} __attribute__ ((packed));
第五层级字符描述符,提供字符串的索引。
struct usb_string_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16wData[1]; /* UTF-16LE encoded*/
} __attribute__ ((packed));
6. Linux USB主机控制器驱动
6.1. USB主机控制器驱动的整体结构
USB主机控制器标准规定了主控制器的功能和接口(寄存器的序列及功能),只要驱动程序符合标某一标准,就可以驱动所有符合这个标准的主控制器。
例如一般的PC 中的 USB 系统作为主系统,而一般的USB 鼠标,U 盘则是典型的 USB 从系统。
USB主控制器很复杂,就是就因为很复杂从而需要形成一些标准去规范它。
支持以下标准规格:
标准名称 |
全称 |
标准版本 |
描述 |
IHCI |
Open Host ControlLer Interface |
1.1 |
非PC,SIS,Ali芯片组 |
UHCI |
Universal Host ControLler Interface |
1.1 |
主要用于PC主板 |
EHCI |
Enhanced Host ControlLer Interface - |
2.0 |
向前兼容,电路简单 |
xHCI |
eXtensible ControlLer Interface |
3.0 |
Intel开发,支持2.0 |
如上表描述,每块支持插入 USB 设备的主板或 PCI 卡都需要有 USB 主控制器芯片组。这个特别的芯片组与插入系统的 USB 设备进行相互操作,并负责处理允许 USB 设备与系统其它部分通信所必需的所有低层次细节。
6.1.1. 主机控制器驱动
由struct usb_hcd (\include\uapi\linux\usb\Hcd.h) 描述,它包括硬件资源信息,状态描述和最重要的主机控制器hc_driver(红色标注)
structusb_hcd {
/*
*housekeeping
*/
struct usb_bus self; /*hcd is-a bus */
struct kref kref; /* reference counter */
const char *product_desc; /* product/vendor string */
int speed; /* Speed for this roothub.
* May be different from
* hcd->driver->flags & HCD_MASK
*/
char irq_descr[24]; /* driver + bus # */
struct timer_list rh_timer; /* drivesroot-hub polling */
struct urb *status_urb; /* the current status urb */
#ifdefCONFIG_PM
struct work_struct wakeup_work; /* forremote wakeup */
#endif
/*
*hardware info/state
*/
const structhc_driver *driver; /* hw-specific hooks */
/*
* OTGand some Host controllers need software interaction with phys;
*other external phys should be software-transparent
*/
struct usb_phy *usb_phy;
struct phy *phy;
/* Flags that need to be manipulatedatomically because they can
*change while the host controller is running. Always use
*set_bit() or clear_bit() to change their values.
*/
unsigned long flags;
…
/* The HC driver's private data is stored atthe end of
* thisstructure.
*/
unsigned long hcd_priv[0]
__attribute__((aligned(sizeof(s64))));
};
structhc_driver 包括用于操作主机控制器的钩子函数
/*-------------------------------------------------------------------------*/
structhc_driver {
const char *description; /* "ehci-hcd" etc */
const char *product_desc; /* product/vendor string */
size_t hcd_priv_size; /* size of private data */
/* irq handler */
irqreturn_t (*irq)(struct usb_hcd *hcd);
int flags;
….
int (*disable_usb3_lpm_timeout)(structusb_hcd *,
struct usb_device *, enumusb3_link_state state);
int (*find_raw_port_number)(structusb_hcd *, int);
/* Call for power on/off the port ifnecessary */
int (*port_power)(structusb_hcd *hcd, int portnum, bool enable);
};
6.1.2. 实例:EHCI主机控制器驱动
EHCI主要是为了支持高速设备,如果一个控制器还要支持低速和全速设备,还需要有UHCI或OHCI的支持。
USB2.0中与EHCI配合使用支持低速和全速设备的OHCI/和UHCI叫作兼容控制器,下面这张有名的图很好的描述了USB2.0主控制器的组成。
6.1.3.
7. USB设备驱动
8.