USB集线器的每个下游端口的D+和D-上,分别接了一个15K的下拉电阻到低。当集线器的端口悬空(即没有设备插入)时,输入端就被此两个下拉电阻拉到低电平。在USB设备端,在D+或D-上接入1.5K的上拉电阻到3.3V的电源。1.5K的上拉电阻接在D+或D-上,由设备的速度决定。对于全速设备和高速设备,上拉电阻接在D+上,而低速设备的上拉电阻则是接在D-上。可简单记为:速度快的,上拉电阻接正;速度慢的,上拉电阻接负的。
当设备插入到集线器时,接了上拉电阻的数据线的电压由1.5K的上拉电阻和15K的下拉电阻分压决定,结果大概为3V。在集线器的接收端来说,是一个高电平信号。集线器检测到此状态后,就报告给USB主控制器,此时就检测到设备的插入。USB高速设备先是识别成全速设备,然后在通过集线器和设备两者的确认,在切换到高速模式下。在高速模式下,是电流传输模式,此时需要将D+上的上拉电阻断开。
1) USB主机检测到USB设备插入后,会先对设备进行复位。
USB设备在总线复位后其地址为0,此时主机可通过地址0和该设备进行通信。USB主机往地址0的设备的端点0发送获取设备描述符的标准请求(这是控制传输的建立过程)。设备收到该请求后,会按主机请求的参数,在数据过程将设备描述符返回给主机。主机在成功获取到该数据包的设备描述符并且确认没有错误后,就会返回一个0长度的确认数据包(状态过程)给设备,从而进入到接下来的设置地址阶段。注意:第一次主机只会读取一个数据包的设备描述符,标准的设备描述符有18byte,有些USB设备的端点0大小不足18byte(但至少具有8byte),这种情况下,USB主机也只发送一次数据输入请求,多余的数据将不会再次请求。因此,如果当设备断电0大小不足18字节时,就需要注意该问题,也就是说在第一次获取设备描述符时,只需要返回一次数据即可,不需要再等主句继续获取剩余数据(如果还有),因为主机不会这么干的。房主急成功获取到设备描述符的前8byte之后,他就知道端点0的最大包长度了,因为端点0最大包长度刚好在设备描述符的第八字节处。
2) USB主机对设备又一次复位,开始设置地址阶段。
USB主机往地址为0的设备的端点0发出一个设置地址的请求(控制传输的建立过程),新的设备地址包含在建立过程的数据包中。具体的地址有USB主机负责管理,主机会分配一个唯一的地址给刚接入的设备。USB设备在收到这个建立过程之后,就直接进入到状态过程,因为此控制传输没有数据过程。设备等待主机请求状态返回(一个输入令牌包),收到输入令牌包后,设备就返回0长度的状态数据包。如果主机确认该状态包已经正确收到,就会发送应答包ACK给设备,设备在收到这个ACK之后,就要启用新的设备地址了。这样设备就分配到了一个唯一的设备地址,以后主机就通过他来访问该设备。
3) USB主机重新发送获取设备描述符的命令,读取完整设备描述符。
主机向新地址重新发送Get_Device_Descriptor命令,此次读取其设备描述符的全部字段,以了解该设备的总体信息,如VID,PID。
4) USB主机获取配置描述符。
配置描述符总共9byte。主机在获取到配置描述符之后,根据配置描述符中描述的配置集合总长度,获取配置集合。获取配置描述符和获取配置描述符集合的请求是差不多的,只是指定的长度不一样。
5) USB主机获取设备字符串,获得描述字符集。
描述字符集包括了产商、产品描述、型号等信息。
6) USB主机展示新设备信息。
此时主机将会弹出窗口,展示发现新设备的信息、产商、产品描述、型号等。
7) PC判断能够提供该类USB的驱动。
根据设备描述符和配置描述符,PC判断是否能够提供USB的Driver,一般能提供几大类的设备,如游戏操作杆、存储、打印机、扫描仪等。
8) USB主机发送配置命令,请求为设备选择一个配置
加载USB设备驱动以后,主机发送Set_Configuration(x)命令请求为该设备选择一个合适的配置。如果配置成功,USB设备进入“配置”状态,并可以和客户软件进行数据传输。
struct usb_ctrlrequest {
__u8 bRequestType = 0x80;// 这是一个主机发给设备(bit0~bit4)的一个标准(bit5~bit6)的请求命令,请求的结果是要求设备给Host返回(bit7 == 1)
__u8 bRequest = 0x06;// 是一个GET_DESCRIPTOR,即获取描述符的请求
__le16 wValue = 0x0100;// 高字节表示描述符类型,01表示设备,02表示配置;低字节表示索引。
__le16 wIndex = 0x0000;
__le16 wLength = 0x0040;
} __attribute__ ((packed));
struct usb_device_descriptor {
__u8 bLength = 0x12; ///长度
__u8 bDescriptorType = 0x01; ///描述符类型
__le16 bcdUSB = 0x0200; //该位表示版本号,使用BCD码表示,即USB2.0版本
__u8 bDeviceClass = 0x02;///设备类信息
__u8 bDeviceSubClass = 0x00;///设备子类型
__u8 bDeviceProtocol = 0x00;///协议 码,0表示没指定任何协议
__u8 bMaxPacketSize0 = 0x40;///端点0最大传输大小
__le16 idVendor = 0x0525;///厂商 ID
__le16 idProduct = 0xa4a7;///设备 ID
__le16 bcdDevice = 0x0414;/// 设备版本号
__u8 iManufacturer = 0x01; ///描述厂商信息的字符串描述符的索引值
__u8 iProduct = 0x02;///描述产品信息的字串描述符的索引值
__u8 iSerialNumber = 0x00;///描述设备序列号信息的字串描述符的索引值-03
__u8 bNumConfigurations = 0x01;///设备当前速度模式下支持的配置数量。有的设备可以在多个速度模式下操作,这里包括的只是当前速度模式下的配置数目,不是总的配置数目
} __attribute__ ((packed));
host通过驱动数据线到复位状态(D+和D-全为低电平 ),并持续至少10ms。
struct usb_ctrlrequest {
__u8 bRequestType = 0x00;// 这是一个主机发给设备(bit0~bit4)的一个标准(bit5~bit6)的请求命令,请求的结果是要求设备给Host返回(bit7 == 1)
__u8 bRequest = 0x05;// 是一个SET_ADDRESS,即配置设备地址描述符
__le16 wValue = 0x0025;// 表示设备地址为0x25。
__le16 wIndex = 0x0000;
__le16 wLength = 0x0000;
} __attribute__ ((packed));
这次要注意,这里以及使用新分配的设备地址3了,而不是默认地址0。同时后面也都会使用新分配的地址来通信。
struct usb_ctrlrequest {
__u8 bRequestType = 0x80;// 这是一个主机发给设备(bit0~bit4)的一个标准(bit5~bit6)的请求命令,请求的结果是要求设备给Host返回(bit7 == 1)
__u8 bRequest = 0x06;// 是一个GET_DESCRIPTOR,即获取描述符的请求
__le16 wValue = 0x0002;// 高字节表示描述符类型,01表示设备,02表示配置。
__le16 wIndex = 0x0000;
__le16 wLength = 0x00FF;
} __attribute__ ((packed));
struct usb_config_descriptor {
__u8 bLength = 0x09; //此描述符长度为9
__u8 bDescriptorType = 0x02; // 2代表的配置描述符
__le16 wTotalLength = 0x4b; //此配置信息的总长为34字节(包括配置,接口,端点和设备类及厂商定义的描述符)
__u8 bNumInterfaces = 0x02; //表示有一个接口描述符
__u8 bConfigurationValue = 0x02; //在SetConfiguration()请求中用2作参数来选定此配置-0x01
__u8 iConfiguration = 0x04; //描述此配置的字串描述表索引-0x00
__u8 bmAttributes = 0xC0; //D7: 保留(设为一)D6: 自给电源 D5: 远程唤醒 D4..0:保留(设为一) 表示这是一个由总线供电,并支持远程唤醒功能(可以睡眠节约电)
__u8 bMaxPower = 0x64; //在此配置下的总线电源耗费量。以 2mA 为一个单位 即2 * 50 = 100ms
} __attribute__ ((packed));
struct usb_interface_assoc_descriptor {
__u8 bLength = 0x08;
__u8 bDescriptorType = 0x0b; //IAD描述符类型
__u8 bFirstInterface = 0x00; //起始接口
__u8 bInterfaceCount = 0x02; //接口数量
__u8 bFunctionClass = 0x02; //类型代码
__u8 bFunctionSubClass = 0x02; //子类型代码
__u8 bFunctionProtocol = 0x01; //协议代码
__u8 iFunction = 0x07; //描述字符串索引
} __attribute__ ((packed));
struct usb_interface_descriptor {
__u8 bLength = 0x09; //该描述符的字节数
__u8 bDescriptorType = 0x04; //描述符类型,4代表接口描述符
__u8 bInterfaceNumber = 0x00; //接口号,当前配置支持的接口数组索引(从零开始)
__u8 bAlternateSetting = 0x00; //可选设置的索引值,这里无
__u8 bNumEndpoints = 0x01; //端点描述符数量,1个
__u8 bInterfaceClass = 0x02; //接口所属的类值,由USB说明保留, 2代表CDC contrl
__u8 bInterfaceSubClass = 0x02; //子类码 这些值的定义视bInterfaceClass域而定
__u8 bInterfaceProtocol = 0x01; //协议码:bInterfaceClass 和bInterfaceSubClass 域的值而定
__u8 iInterface = 0x05; //描述此接口的字串描述表的索引值
} __attribute__ ((packed));
/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */
struct usb_cdc_header_desc {
__u8 bLength = 0x05;
__u8 bDescriptorType = 0x24; /* bDescriptorType: CS_INTERFACE */
__u8 bDescriptorSubType = 0x00; /* bDescriptorSubtype: Header Func Desc */
__le16 bcdCDC = 0x0110; /* bcdCDC: spec release number */
} __attribute__ ((packed));
/* "Abstract Control Management Descriptor" from CDC spec 5.2.3.3 */
struct usb_cdc_acm_descriptor {
__u8 bLength = 0x04;
__u8 bDescriptorType = 0x24;
__u8 bDescriptorSubType = 0x02; /* bDescriptorSubtype: Abstract Control Management desc */
__u8 bmCapabilities 0x02;
} __attribute__ ((packed));
/* "Union Functional Descriptor" from CDC spec 5.2.3.8 */
struct usb_cdc_union_desc {
__u8 bLength = 0x05;
__u8 bDescriptorType = 0x24;
__u8 bDescriptorSubType = 0x06; /* bDescriptorSubtype: Union func desc */
__u8 bMasterInterface0 = 0x00;
__u8 bSlaveInterface0 = 0x01;
/* ... and there could be other slave interfaces */
} __attribute__ ((packed));
/* "Call Management Descriptor" from CDC spec 5.2.3.2 */
struct usb_cdc_call_mgmt_descriptor {
__u8 bLength = 0x05;
__u8 bDescriptorType = 0x24; /* bDescriptorType: CS_INTERFACE */
__u8 bDescriptorSubType = 0x01; /* bDescriptorSubtype: Call Management Func Desc */
__u8 bmCapabilities = 0x00; /* bmCapabilities: D0+D1 */
__u8 bDataInterface = 0x01; /* bDataInterface: 1 *
} __attribute__ ((packed));
/* USB_DT_ENDPOINT: Endpoint descriptor */
struct usb_endpoint_descriptor { ///USB 端点描述符(每个USB设备最多有16个端点)
__u8 bLength = 0x07; ///描述符的字节长度
__u8 bDescriptorType = 0x05;///描述符类型,对于端点就是USB_DT_ENDPOINT
__u8 bEndpointAddress = 0x83;///bit0~3表示端点地址,bit8 表示方向,输入还是输出
__u8 bmAttributes = 0x03;///属性(bit0、bit1构成传输类型,00--控制,01--等时,10--批量,11--中断)
__le16 wMaxPacketSize = 0x000a;///端点一次可以处理的最大字节数
__u8 bInterval = 0x20;///希望主机轮询自己的时间间隔
/* NOTE: these two are _only_ in audio endpoints. */
/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
__u8 bRefresh;
__u8 bSynchAddress;
} __attribute__ ((packed));
struct usb_interface_descriptor {
__u8 bLength = 0x09; //该描述符的字节数
__u8 bDescriptorType = 0x04; //描述符类型,4代表接口描述符
__u8 bInterfaceNumber = 0x01; //接口号,当前配置支持的接口数组索引(从零开始)
__u8 bAlternateSetting = 0x00; //可选设置的索引值,这里无
__u8 bNumEndpoints = 0x02; //端点描述符数量,2个
__u8 bInterfaceClass = 0x0A; //接口所属的类值,由USB说明保留, 2代表CDC data
__u8 bInterfaceSubClass = 0x00; //子类码 这些值的定义视bInterfaceClass域而定
__u8 bInterfaceProtocol = 0x00; //协议码:bInterfaceClass 和bInterfaceSubClass 域的值而定
__u8 iInterface = 0x06; //描述此接口的字串描述表的索引值
} __attribute__ ((packed));
/* USB_DT_ENDPOINT: Endpoint descriptor */
struct usb_endpoint_descriptor { ///USB 端点描述符(每个USB设备最多有16个端点)
__u8 bLength = 0x07; ///描述符的字节长度
__u8 bDescriptorType = 0x05;///描述符类型,对于端点就是USB_DT_ENDPOINT
__u8 bEndpointAddress = 0x02;///bit0~3表示端点地址,bit8 表示方向,输入还是输出
__u8 bmAttributes = 0x02;///属性(bit0、bit1构成传输类型,00--控制,01--等时,10--批量,11--中断)
__le16 wMaxPacketSize = 0x40;///端点一次可以处理的最大字节数
__u8 bInterval = 0x00;///希望主机轮询自己的时间间隔
/* NOTE: these two are _only_ in audio endpoints. */
/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
__u8 bRefresh;
__u8 bSynchAddress;
} __attribute__ ((packed));
/* USB_DT_ENDPOINT: Endpoint descriptor */
struct usb_endpoint_descriptor { ///USB 端点描述符(每个USB设备最多有16个端点)
__u8 bLength = 0x07; ///描述符的字节长度
__u8 bDescriptorType = 0x05;///描述符类型,对于端点就是USB_DT_ENDPOINT
__u8 bEndpointAddress = 0x81;///bit0~3表示端点地址,bit8 表示方向,输入还是输出
__u8 bmAttributes = 0x02;///属性(bit0、bit1构成传输类型,00--控制,01--等时,10--批量,11--中断)
__le16 wMaxPacketSize = 0x40;///端点一次可以处理的最大字节数
__u8 bInterval = 0x00;///希望主机轮询自己的时间间隔
/* NOTE: these two are _only_ in audio endpoints. */
/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
__u8 bRefresh;
__u8 bSynchAddress;
} __attribute__ ((packed));
struct usb_ctrlrequest {
__u8 bRequestType = 0x80;// 这是一个主机发给设备(bit0~bit4)的一个标准(bit5~bit6)的请求命令,请求的结果是要求设备给Host返回(bit7 == 1)
__u8 bRequest = 0x06;// 是一个GET_DESCRIPTOR,即获取描述符的请求
__le16 wValue = 0x0300;// 高字节表示描述符类型,01表示设备,02表示配置,3表示字符串;低字节表示索引。
__le16 wIndex = 0x0000;
__le16 wLength = 0x00FF;
} __attribute__ ((packed));
/* USB_DT_STRING: String descriptor */
struct usb_string_descriptor {
__u8 bLength = 0x04;
__u8 bDescriptorType = 0x03;
__le16 wData[1] = 0x0409;/* UTF-16LE encoded 代表0x0409的语言编码 */
} __attribute__ ((packed));
struct usb_ctrlrequest {
__u8 bRequestType = 0x80;// 这是一个主机发给设备(bit0~bit4)的一个标准(bit5~bit6)的请求命令,请求的结果是要求设备给Host返回(bit7 == 1)
__u8 bRequest = 0x06;// 是一个GET_DESCRIPTOR,即获取描述符的请求
__le16 wValue = 0x0301;// 高字节表示描述符类型,01表示设备,02表示配置,3表示字符串;低字节表示索引。
__le16 wIndex = 0x0000;
__le16 wLength = 0x00FF;
} __attribute__ ((packed));
/* USB_DT_STRING: String descriptor */
struct usb_string_descriptor {
__u8 bLength = 0x04;
__u8 bDescriptorType = 0x03;
__le16 wData[1] = “Gadget Serial v2.4”;/
} __attribute__ ((packed));
无。
同上。
同上。
struct usb_ctrlrequest {
__u8 bRequestType = 0x00;// 这是一个主机发给设备(bit0~bit4)的一个标准(bit5~bit6)的请求命令,请求的结果是要求设备给Host返回(bit7 == 1)
__u8 bRequest = 0x09;// 是一个SET_CONFIGURATION,即配置设备。
__le16 wValue = 0x0001;// 表示选中的配置Index
__le16 wIndex = 0x0000;
__le16 wLength = 0x0000;
} __attribute__ ((packed));
struct usb_ctrlrequest {
__u8 bRequestType = 0xA1;// 这是一个主机发给设备(bit0~bit4)的一个标准(bit5~bit6)的请求命令,请求的结果是要求设备给Host返回(bit7 == 1)
__u8 bRequest = 0x21;
__le16 wValue = 0x0000;
__le16 wIndex = 0x0000;
__le16 wLength = 0x0007;
} __attribute__ ((packed));
/* Line Coding Structure from CDC spec 6.2.13 */
struct usb_cdc_line_coding {
__le32 dwDTERate = 0x00;
__u8 bCharFormat = 0x00;
#define USB_CDC_1_STOP_BITS 0
#define USB_CDC_1_5_STOP_BITS 1
#define USB_CDC_2_STOP_BITS 2
__u8 bParityType = 0x00;
#define USB_CDC_NO_PARITY 0
#define USB_CDC_ODD_PARITY 1
#define USB_CDC_EVEN_PARITY 2
#define USB_CDC_MARK_PARITY 3
#define USB_CDC_SPACE_PARITY 4
__u8 bDataBits = 0x00;
} __attribute__ ((packed));
struct usb_ctrlrequest {
__u8 bRequestType = 0x21;// 这是一个主机发给设备(bit0~bit4)的一个标准(bit5~bit6)的请求命令,请求的结果是要求设备给Host返回(bit7 == 1)
__u8 bRequest = 0x22;
__le16 wValue = 0x0000;
__le16 wIndex = 0x0000;
__le16 wLength = 0x0000;
} __attribute__ ((packed));