USB设备枚举
这里简单介绍一下usb设备从插入到被识别后可以正常使用的过程. 下面的状态机展示了usb设备状态转换的过程, 后面的介绍也围绕着这些状态转换展开(所有状态用红颜色字体表示).

- 检查USB设备插入和断开
我们先看看usb hub是如何察觉到有usb设备插入usb hub接口的. 如下图所示, 标准的USB使用4根线:Vbus电源线负责供电, GND接地, D+和D-是数据线.(在USB OTG中, 又增加了一种mini接口,使用的是5根线,比标准的USB多了一根身份识别ID线.)


1.1 插入设备
在一个usb hub接口里面, D+和D-都连接着下拉电阻, 如果没有任何设备接入, 这两个线的电压都为0. 如果是全速或者高速设备(full-speed/high-speed), 他们的D+线上有一个上拉电阻, 插入接口之后, D+线的电压变高, usb hub就知道此时有全速或者高速设备插入了(此时D+和D-电压一高一低, 形成了差分电路). 如果是高速设备, 接入之后还会额外发送信号给usb hub, 表明自己是高速设备, 如果usb hub也支持高速设备, 会返回相应的信号, 否则高速设备只能被当做全速设备使用. 类似的, usb低速设备在D-线上有上拉电阻, 当D-线电压变高就是有低速设备(low-speed)接入了.

1.2 断开设备
当hub检测到D+或者D-的电压从高变低时, 就知道相应的设备被拔出了.
1.3 供电
插上usb设备之后, 主机会给设备供电, 此时设备的状态从Attached切换到了Powered, 但是这时候应该是按照默认的供电值供电, 等得到设备的配置之后, 会根据设备的需求供电, 有的设备可能有自己的供电渠道, 不需要供电.
- 枚举
得到供电之后, 主机还需要通过获取一系列的描述符了解设备的配置、接口、端点等信息,从而了解设备,为设备加载合适的驱动程序, 这个过程称为枚举. 要获取上述的描述符信息. 首先需要解决和设备的通信问题。一台主机可以通过多级的usb hub形成如下图所示的拓扑结构, 挂载很多usb设备, 想要和某个设备通信, 需要给该设备分配一个独有的地址才能通过地址找到它.

复位
在一个新接入的设备获得自己独有的地址之前, 主机会给设备发一个复位(reset)信号, 设备复位后的地址暂时是0, 状态是Default.
主机第一次请求设备描述符,获取设备端最大包的大小
这时主机会给默认地址0的端点0发送GET_Descriptor请求,第一次请求设备发送设备描述符。一般的设备描述符总共有18字节,这一次主机收到设备描述符之后,只关注其中的第8字节,里面包含了该设备的端点0能传输的最大数据包的大小这个信息,以后主机和设备通信会根据这个最大包的大小来通信。
分配地址
之后主机通过地址0, 给设备发出一个设置地址的请求, 地址包含在建立包中, 具体的地址主机会负责管理, 它会分配一个唯一的地址给新的设备. USB设备在收到地址后, 返回0长度的状态包, 主机收到0长度的状态包之后, 会返回一个ACK给设备. 设备在收到这个ACK之后, 就可以启用新的地址了. 这样设备就分配到了一个唯一的设备地址, 以后主机就通过它来进行访问该设备, 此时的设备是Addressed状态.
获取设备描述符
主机可以和设备进行通信之后, 主机需要知道设备是什么样的设备, 有哪些接口,从而为每个接口加载合适的驱动程序. 对配置 接口 端点 设备以及他们之间关系的详细介绍, 参考文档USB Overview. 首先需要获取设备描述符,对于这个过程的详细介绍可以参考文档USB传输协议的第三部分 。
获取其它的描述符
获取设备描述符之后,接下来会获取设备所有的配置描述符,接口描述符,端点描述符等,这里不详细说了。
设置配置
在获得了设备的配置之后,发出SET_CONFIGURATION请求,为设备设置合适的配置,之后设备就进入了Configured状态。