USB设备的枚举过程分析
USB协议定义了设备的6种状态,仅在枚举过程种,设备就经历了4个状态的迁移:上电状态(Powered),默认状态(Default),地址状态(Address)和配置状态(Configured)(其他两种是连接状态和挂起状态(Suspend))
详情可见:http://www.usbzh.com/article/detail-110.html
当一个USB设备被接入USB集线器端口后,USB设备开始被枚举,过程大概如下:
1.主机集线器检测到新设备
主机集线器监视着每个端口的信号电压,当有新设备接入时便可觉察
2.主机发送GET_STATUS请求
每个集线器用中断传输来报告在集线器上的事件。当主机知道了这个事件,它给集线器发送一个GET_STATUS请求来了解更多的消息。返回的消息告诉主机一个设备是什么时候连接的。
3.主机发送SET_FEATURE请求,集线器重启端口
当主机知道有一个新的设备时,主机给集线器发送一个SET_FEATURE请求,请求集线器来重启端口。集线器使得设备的USB数据线处于重启(Reset)状态至少10ms。
4.集线器在设备和主机之间建立一个信号通路
主机发送一个GET_STATUS请求来验证设备是否激起重启状态。返回的数据有一位表示设备仍然处于重启状态。当集线器释放了重启状态,设备就处于默认状态了,设备已经准备好通过Endpoint 0 的默认流程响应控制传输,即设备现在使用默认地址0x0与主机通信。
5.集线器检测设备速度
集线器通过测定哪根信号线(D+或D-)在空闲时有更高的电压来检测设备是低速设备还是全速设备。(全速和高速设备D+有上拉电阻,低速设备D-有上拉电阻)。
6.获取最大数据包长度
PC 向address 0发送USB协议规定的GET_DESCRIPTOR命令获取设备描述符,以取得缺省控制管道所支持的最大数据包长度,并在有限的时间内等待USB设备的响应。该长度包含在设备描述符的bMaxPacketSize0字段中,其地址偏移量为7,所以这时主机只需读取该描述符的前8个字节。注意,主机一次只能枚举一个USB设备,所以同一时刻只能有一个USB设备使用缺省地址0。
7.主机分配一个新的地址给设备
主机通过发送一个SET_ADDRESS请求来分配一个唯一的地址给设备。设备读取这个请求,返回一个确认,并保存新的地址。从此开始所有通信都使用这个新地址。
8.主机重新发送GET_DESCRIPTOR命令读取完整设备描述符
主机向新地址重新发送GET_DESCRIPTOR命令,此次读取其设备描述符的全部字段,以了解该设备的总体信息,如VID,PID。
9.主机发送GET_DESCRIPTOR命令,获取完整配置信息
主机向设备循环发送GET_DESCRIPTORn命令,要求USB设备回答,以读取全部配置信息。
10.主机发送GET_DESCRIPTOR命令,获得字符描述符(unicode)
描述字符集包括了产商、产品描述、型号
11.主机展示新设备信息
此时主机将会弹出窗口,展示发现新设备的信息,产商、产品描述、型号
12.PC判断能否提供该类USB的驱动
根据设备描述符和配置描述符应答,PC判断是否能够提供USB的Driver
13.主机发送SET_CONFIGURATION(x)命令,请求为设备选择一个配置
加载了USB设备驱动以后,主机发送SET_CONFIGURATION(x)命令请求为该设备选择一个合适的配置(x代表非0的配置值)。如果配置成功,USB设备进入“配置”状态,并可以和客户软件进行数据传输。
枚举的过程用到总线的“控制传输(Control Transfer)”的传输方式。用于配置/命令/状态等情形,其中的设置操作setup和状态操作status过程的数据包具有USB协议定义的数据结构,控制传输只能通过消息管道进行。
枚举握手过程:
•1复位总线
主机setup包(发往地址0端点0),主机数据包(请求设备描述符),设备握手包ack设备产生端点0 数据输出中断,固件程序要根据数据包中的主机要求做好准备,这里是在端点0输入缓冲区准备好设备描述符数据过程:主机发一个in令牌包,设备发一个数据包(这个数据已准备好,sie收到in令牌后直接到达总线),主机发送ack包。此时sie产生端点0数据输入中断,表明主机已取走设备所准备的数据,用户也可以在该中断处理程序中做自己的处理主机直接受一次数据,最少8字节,如果用户数据没发完,又在控制输入缓冲区准备了数据,主机也不理会状态过程:主机发out包(通知设备要输出),主机发0字节状态数据包(0字节表示自己没收到设备描述符),设备发握手包ack包此时设备不会产生端点0数据输出中断,此时没有数据
•2设置地址
主机setup包(发送地址0端点0),主机数据包(请求设置地址),设备握手包ack包。Setup包后跟一个主机setup包的目的数据包(get/set)。
设备产生端点0数据输出中断,固件程序要根据数据包中主机的要求做好准备,根据主机发来的地址写入自己的地址控制寄存器
数据过程:本次传输无数据
状态过程:主机发in包(通知设备要返回数据),设备发0字节状态数据(表明地址设置已成功),主机发握手ack包(地址设置已生效)
此时设备不会产生端点0数据输入中断,此时无数据
•3取描述符
主机setup包(发往新地址端点0),主机数据包(请求设备描述符),设备握手ack包设备产生端点0数据输出中断,固件程序要根据数据包中主机要求做好准备,在端点0输入缓冲区准备好描述符数据过程:主机发一个in令牌包,设备发一个数据包(这个数据已经准备好,sie收到in令牌后,直接送到总线上),主机发ack包此时sie产生端点0数据输入中断,表明主机已取走设备所准备的数据用户可以在中断处理程序中做如下处理(如果一次没有把描述送完,要再次将剩下的内容填充端点0输入缓冲区区)
主机接着再发个in令牌包,设备发一个数据包,主机发ack包
此时sie再次产生端点0数据输入中断,如果数据已发完,不需处理
状态过程:主机发送out包(通知设备要输出),主机发0字节状态数据包(表明已收到设备描述符),设备发握手ack包
用户将一个USB设备插入USB端口,主机为端口供电,设备此时处于上电状态。
- 主机检测设备。
- 集线器使用中断通道将事件报告给主机。
- 主机发送Get_Port_Status(读端口状态)请求,以获取更多的设备信息。
- 集线器检测设备是低速运行还是高速运行,并将此信息送给主机,这是对Get_Port_Status请求的响应。
- 主机发送Set_Port_Feature(写端口状态)请求给集线器,要求它复位端口。
- 集线器对设备复位。
- 主机使用Chirp K信号来了解全速设备是否支持高速运行。
- 主机发送另一个Get_Port_Status请求,确定设备是否已经从复位状态退出。
- 设备此时处于缺省状态,且已准备好在零端点通过缺省通道响应主机控制传输。缺省地址为00h,设备能从总线获取高达100mA的电流。
- 主机发送Get_Descriptor(读设备描述符)报文,以便确定最大数据包大小。设备描述符的八个字节是bMaxPacketSize。
- 通过发送Set_Address(写地址)请求,主机分配地址,设备此时处于地址状态。
- 主机发送Get_Descriptor报文,以获取更多的设备信息。主机通过发送描述符响应设备请求,随后发送全部的次级描述符。
- 主机分配并加载设备驱动程序。
- 通过发送Set_Configuration(写配置)请求,主机的设备驱动程序选择一个有效配置,设备此时处于配置状态。
- 主机为复合设备接口分配驱动程序。
- 如果集线器检测到有过流现象,或者主机要求集线器关闭电源,则USB总线切断设备供电电源。在这种情况下,设备与主机无法通信,但设备处于连接状态。
- 如果在3毫秒内设备在总线上未见任何动作,则它将进入挂起状态,在挂起状态设备消耗的总线电能最少。