1 总线简介
1.1 背景
- 发展背景
外部设备的接口五花八门,USB的远大志愿就是取代这些五花八门的接口,无需安装驱动,无需螺丝加固,即插即用,所以取名为Universal.也就是USB的首个字母~U,就是通过,最好所有的设备都能使用的意思。于是UBS开启了它漫长的奋斗之路.
- 发展历程
低速usb1.0: 1995年,第一代USB问世,取名为Low Speed USB,传输速度约为1.5 Mbps,因为自身问题太多,基本没什么人用,也没能引多大的重视.
全速sub1.0: 1998年,三年磨一剑,USB1.1版本问世,取名为Full Speed USB,它是最早被采用的修订版,传输速度约为12 Mbps.
高速usb2.0: 2000年,推出的Hi-Speed,也就是USB 2.0,理论传输速度翻了40倍,达到了480Mbps。
高速usb3.0: 2008年推出的USB 3.0理论传输速度再翻十倍,达到了惊人的5Gbps。
1.2 特点
- 它是串行总线,usb2.0及之前是半双工的,usb3.0是全双工的。
- usb总线属于外部总线,CPU无法直接访问,需要通过"USB控制器"来访问usb设备。
- USB的设计为非对称式的,它由一个主机控制器和若干通过集线器设备以树形连接的设备组成。一个控制器下最多可以有5级Hub,包括Hub在内,最多可以连接128个设备。
- 在任何时候,信息在usb上的传输,只能由usb控制器发起,usb设备只能被动接受。
- 凡是支持usb的外部设备,即usb设备。都带有usb通信控制器,里面实际包含一个微处理器. hub是一种特殊的usb设备。
1.3 信息传输方式
- 控制型:主要用于设备的"配置"和控制。比如usb控制器与usb设备建立连接的过程。
- 等时型:主要用于事实音频和视频信号。比如usb相机,网络电话等。
- 中断型:名曰"中断"型,实际上是用于对USB设备的周期性查询。比如键盘,操纵杆和鼠标等,这类传输一般都是单向的。
- 成块型:用于信息量较大,没有很强的时间要求,但是要求信息的可靠性。比如USB打印机、扫描仪、大容量存储设备。
2 usb描述符
分为四种:设备描述符、配置描述符、接口描述符、端点描述符。
USB协议规定每个usb接口的设备必须支持这四种描述符, 这些描述符存放在usb设备的EEPROM中,在usb设备枚举时,主机控制器会获取设备上的这些描述符,以给这个设备安装对应的驱动。
2.1 接口描述符
内核中使用usb_interface_descriptor结构表示接口描述符:
struct usb_interface_descriptor {
__u8 bLength; // 表示接口描述符的字节长度。规定为9
__u8 bDescriptorType; // 表示描述符类型。接口描述符为0x04
__u8 bInterfaceNumber; // 接口号。每个配置包含多个接口,这个值是它们的索引值
__u8 bAlternateSetting; // 接口使用哪个可选设置,协议规定,默认使用设置为0的设置
__u8 bNumEndpoints; // 接口拥有的端点数量。这里不包含端点0,端点0是所有USB设备必须提供的
__u8 bInterfaceClass; // 接口协议相关
__u8 bInterfaceSubClass; // 接口协议相关
__u8 bInterfaceProtocol; // 接口协议相关
__u8 iInterface; // 字符串描述符的索引,字符串描述符一般记录厂商,序列号等字符串
} __attribute__ ((packed));
2.2 端点描述符
内核中使用usb_endpoint_descriptor结构表示端点描述符:
struct usb_endpoint_descriptor {
__u8 bLength; // 端点描述符的字节长度
__u8 bDescriptorType; // 描述符类型,端点描述符类型为0x05
__u8 bEndpointAddress; // 含有端点的地址,端点的端口号,端点为输入/输出
__u8 bmAttributes; // 属性:表示传输类型
__le16 wMaxPacketSize; // 端点一次可以处理的最大字节数
__u8 bInterval; // 设备希望主机控制器轮训自己的时间间隔
__u8 bRefresh;
__u8 bSynchAddress;
} __attribute__ ((packed));
2.3 设备描述符
struct usb_device_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 bcdUSB;
__u8 bDeviceClass;
__u8 bDeviceSubClass;
__u8 bDeviceProtocol;
__u8 bMaxPacketSize0;
__le16 idVendor;
__le16 idProduct;
__le16 bcdDevice;
__u8 iManufacturer;
__u8 iProduct;
__u8 iSerialNumber;
__u8 bNumConfigurations;
} __attribute__ ((packed));
2.4 配置描述符
struct usb_config_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__le16 wTotalLength;
__u8 bNumInterfaces;
__u8 bConfigurationValue;
__u8 iConfiguration;
__u8 bmAttributes;
__u8 bMaxPower;
} __attribute__ ((packed));
3 USB驱动模型
- USB总线
usb子系统初始化时,会向内核注册usb总线:
bus_register(&usb_bus_type);
总线类型用usb_bus_type表示,总线用usb_bus表示,内核中只有一种usb总线类型,但是可以有多条总线。一般一个usb控制器代表一条usb总线,对应一个struct usb_bus xxx变量,是在主机控制驱动加载时注册到内核的。
- USB驱动
内核中有两种USB驱动:usb设备驱动,usb接口驱动。
usb设备驱动用结构体usb_device_driver表示,注册用usb_register_device_driver函数。特别注意的是linux中只有一个usb设备驱动,是在usb子系统初始化时注册的。
问1:那这个usb设备驱动仅有一个,它是用来做什么的?为什么一个就可以支持这么多设备?
usb接口驱动用结构体usb_driver表示,注册用usb_register函数。比如鼠标、键盘等都需要注册一个单独的接口驱动。
问2:这两种驱动如何区分呢?为什么需要这两种驱动?在匹配驱动时如何知道是匹配哪种驱动呢?
- USB设备
内核有两种USB设备:usb设备,usb接口设备。
我们常用的一般都是usb接口设备,比如键盘,鼠标等。
usb设备用结构体usb_device表示,注册用usb_alloc_dev函数。
usb接口用结构体usb_interface表示,注册用usb_register_dev函数。