USB主机是如何检测到设备的插⼊的呢?
USB设备的插⼊检测机制
⾸先,在USB集线器的每个下游端⼝的D+和D-上,分别接了⼀个15K欧姆的下拉电阻到地。这样,在集线器的端⼝悬空时,就被这两个下拉电阻拉到了低电平。⽽在USB设备端,在D+或者D-上接了1.5K欧姆上拉电阻.对于全速和⾼速设备,上拉电阻是接在D+上;⽽低速设备则是上拉电阻接在D-上。这样,当设备插⼊到集线器时,由1.5K的上拉电阻和15K的下拉电阻分压,结果就将差分数据线中的⼀条拉⾼了。集线器检测到这个状态后,它就报告给USB主控制器(或者通过它上⼀层的集线器报告给USB主控制器),这样就检测到设备的插⼊了。USB⾼速设备先是被识别为全速设备,然后通过HOST和DEVICE两者之间的确认,再切换到⾼速模式的。在⾼速模式下,是电流传输模式,这时将D+上的上拉电阻断开。
⼀个简单的实验:只⽤⼀个上拉电阻接在USB的+5V和D+或者D-上,WINDOWS也会提⽰发现新硬件,但是⽆法到驱动程序。这时去设备管理器⾥⾯看,有显⽰未知USB设备,并且其VID和PID为0。根据这个,我们可以简单的判断设备是否枚举成功。如下图所⽰,分别是枚举不成功和枚举成功的图。
USB设备的枚举过程:
USB主机在检测到USB设备插⼊后,就要对设备进⾏枚举了。为什么要枚举呢?枚举就是从设备读取⼀些信息,知道设备是什么样的设备,如何进⾏通信,这样主机就可以根据这些信息来加载合适的驱
动程序。调试USB设备,很重要的⼀点就是USB的枚举过程,只要枚举成功了,那么就已经成功⼤半了。
在说枚举之前,先⼤概说⼀下USB的⼀种传输模式——控制传输。这种传输在USB中是⾮常重要的,它要保证数据的正确性,在设备的枚举过程中都是使⽤控制传输。控制传输分
为三个过程:①建⽴过程。②可选的数据过程。③状态过程。建⽴(Setup)过程都是由
USB主机发起,它开始于⼀个Setup令牌包,后⾯紧跟⼀个DATA0包。如果是控制输⼊传
输,那么数据过程就是输⼊数据;如果是控制输出传输,那么数据过程是输出数据。如果在
设置过程中,指定了数据长度为0,则没有数据过程。数据过程之后是状态过程。状态过程刚
好与数据过程的数据传输⽅向相反:如果是控制输⼊传输,则状态过程是⼀个输出数据包;
如果是控制输出传输,则状态过程是⼀个输⼊数据包。状态阶段⽤来确认所有的数据都已经
正确传输。
枚举的详细过程。
⾸先,USB主机检测到USB设备插⼊后,就会先对设备复位。设备复位后,USB主机就
会对地址为0的设备发送获取设备描述符的标准请求。所有的USB设备在总线复位后其地址都
为0,这样主机就可以跟那些刚刚插⼊的设备通过地址0通信。主机在建⽴阶段发出获取设备
描述符的输⼊请求,设备收到该请求后,在数据过程将设备描述符返回给主机。主机在成功
获取到⼀个数据包的设备描述符后并且确认没有什么错误后(注意:有些USB设备的端点0⼤
⼩不⾜18字节(但⾄少具有8字节),⽽标准的设备描述有18字节,在这种情况下,USB设
备只能暂时按最⼤包将部分设备描述符返回,⽽主机在成功获取到前⾯⼀部分描述符后,就
不会再请求剩下的设备描述符部分,⽽是进⼊设置地址阶段),就会返回⼀个0长度的状态数
据包给设备。
然后主机再对设备复位⼀下,接下来就会进⼊到设置地址阶段。这时USB主机发出⼀个
设置地址的请求(建⽴过程,设置地址⽆数据过程),地址包含在建⽴包中,具体的地址USB主机会
负责管理,它会分配⼀个唯⼀的地址给新的设备。USB设备在收到地址后,返回0长度的状态包,主机收到0长度的状态包之后,会返回⼀个ACK给设备。设备在收到这个ACK
之后,就可以启⽤了。这样设备就分配到了⼀个唯⼀的设备地址,以后主机就通过
它来进⾏访问该设备。然后主机再次获取设备描述符,这次跟第⼀次可能有点不⼀样,这次
需要获取完全部的18个字节的设备描述符。当然,如果你的端点0缓冲⼤于18字节的话,那就
跟第⼀次的情形⼀样了。
接下来,主机就会获取配置描述符。配置描述符总共为9字节。主机在获取到配置描述符后,根据⾥⾯的配置集合总长度,再获取配置集合。配置集合包括配置描述符,接⼝描述符,端点描符等等。如果有字符串描述符的话,还要获取字符串描述符。另外HID设备还有HID描述符等。使⽤BUSHOUND以及通过串⼝返回信息,很容易看到具体的过程。总之是主机请求什么,你的程序就响应什么.
USB是个通⽤的总线,端⼝都是统⼀的。但是USB设备却各种各样,例如USB⿏
标,USB键盘,U盘等等,那么USB主机是如何识别出不同的设备的呢?这就要依赖于描述
符了。USB的描述符主要有设备描述符,配置描述符,接⼝描述符,端点描述符,字符串描
述符,HID描述符,报告描述符等等.
⼀个USB设备有⼀个设备描述符,设备描述符⾥⾯决定了该设备有多少种配置,每种配置
描述符对应着配置描述符;⽽在配置描述符中⼜定义了该配置⾥⾯有多少个接⼝,每个接⼝
有对应的接⼝描述符;在接⼝描述符⾥⾯⼜定义了该接⼝有多少个端点,每个端点对应⼀个
端点描述符;端点描述符定义了端点的⼤⼩,类型等等。由此我们可以看出,USB的描述符
林俊杰炮king是真的吗之间的关系是⼀层⼀层的,最上⼀层是设备描述符,下⾯是配置描述符,再下⾯是接⼝描述
符,再下⾯是端点描述符。在获取描述符时,先获取设备描述符,然后再获取配置描述符,
根据配置描述符中的配置集合长度,⼀次将配置描述符、接⼝描述符、端点描述符⼀起⼀次
读回。其中可能还会有获取设备序列号,⼚商字符串,产品字符串等。每种描述符都有⾃⼰
独⽴的编号,如下:
#defineDEVICE_DESCRIPTOR 0x01 //设备描述符
#defineCONFIGURATION_DESCRIPTOR 0x02 //配置描述符
#defineSTRING_DESCRIPTOR 0x03 //字符串描述符
#defineINTERFACE_DESCRIPTOR 0x04 //接⼝描述符
希夷剑#defineENDPOINT_DESCRIPTOR 0x05 //端点描述符
下⾯分别详细介绍⼀下各描述符。
1.设备描述符
//定义标准的设备描述符结构
typedefstruct_DEVICE_DCESCRIPTOR_STRUCT
{
BYTEblength; //设备描述符的字节数⼤⼩
BYTEbDescriptorType; //设备描述符类型编号
WORDbcdUSB; //USB版本号
BYTEbDeviceClass; //USB分配的设备类代码
BYTEbDeviceSubClass; //USB分配的⼦类代码
BYTEbDeviceProtocol; //USB分配的设备协议代码
BYTEbMaxPacketSize0; //端点0的最⼤包⼤⼩
WORDidVendor; //⼚商编号
WORDidProduct; //产品编号
WORDbcdDevice; //设备出⼚编号
BYTEiManufacturer; //设备⼚商字符串的索引
BYTEiProduct; //描述产品字符串的索引
BYTEiSerialNumber; //描述设备序列号字符串的索引
BYTEbNumConfigurations; //可能的配置数量
}
DEVICE_DESCRIPTOR_STRUCT,*pDEVICE_DESCRIPTOR_STRUCT;
//实际的设备描述符⽰例
codeDEVICE_DESCRIPTOR_STRUCTdevice_descriptor= //设备描述符
{
何猷佳怎么了sizeof(DEVICE_DESCRIPTOR_STRUCT), //设备描述符的字节数⼤⼩,这⾥是18字节DEVICE_DESCRIPTOR, //设备描述符类型编号,设备描述符是01
0x1001, //USB版本号,这⾥是USB01.10,即USB1.1。由于51是⼤端模式,所以⾼低字节交换
0x00, //USB分配的设备类代码,0表⽰类型在接⼝描述符中定义
0x00, //USB分配的⼦类代码,上⾯⼀项为0时,本项也要设置为0
0x00, //USB分配的设备协议代码,上⾯⼀项为0时,本项也要设置为0
0x10, //端点0的最⼤包⼤⼩,这⾥为16字节
0x7104, //⼚商编号,这个是需要跟USB组织申请的ID号,表⽰⼚商代号。
0xf0ff, //该产品的编号,跟⼚商编号⼀起配合使⽤,让主机注册该设备并加载相应的驱动程序
0x0100, //设备出⼚编号
0x01, //设备⼚商字符串的索引,在获取字符串描述符时,使⽤该索引号来识别不同的字符串
0x02, //描述产品字符串的索引,同上
0x03, //描述设备序列号字符串的索引,同上
0x01 //可能的配置数为1,即该设备只有⼀个配置
};
2.配置描述符
//定义标准的配置描述符结构
typedefstruct_CONFIGURATION_DESCRIPTOR_STRUCT
{
BYTEbLength; //配置描述符的字节数⼤⼩
BYTEbDescriptorType; //配置描述符类型编号
WORDwTotalLength; //此配置返回的所有数据⼤⼩
BYTEbNumInterfaces; //此配置所⽀持的接⼝数量
BYTEbConfigurationValue; //Set_Configuration命令所需要的参数值BYTEiConfiguration; //描述该配置的字符串的索引值
BYTEbmAttributes; //供电模式的选择
BYTEMaxPower; //设备从总线提取的最⼤电流
}
CONFIGURATION_DESCRIPTOR_STRUCT,*pCONFIGURATION_DESCRIPTOR_STRUCT;
3.接⼝描述符
//定义标准的接⼝描述符结构
typedefstruct_INTERFACE_DESCRIPTOR_STRUCT
{
BYTEbLength; //接⼝描述符的字节数⼤⼩
BYTEbDescriptorType; //接⼝描述符的类型编号
BYTEbInterfaceNumber; //该接⼝的编号
BYTEbAlternateSetting; //备⽤的接⼝描述符编号
BYTEbNumEndpoints; //该接⼝使⽤的端点数,不包括端点0
BYTEbInterfaceClass; //接⼝类型
BYTEbInterfaceSubClass; //接⼝⼦类型
BYTEbInterfaceProtocol; //接⼝遵循的协议
BYTEiInterface; //描述该接⼝的字符串索引值
}
INTERFACE_DESCRIPTOR_STRUCT,*pINTERFACE_DESCRIPTOR_STRUCT;
4.端点描述符
//定义标准的端点描述符结构
typedefstruct_ENDPOINT_DESCRIPTOR_STRUCT
{
BYTEbLegth; //端点描述符字节数⼤⼩
BYTEbDescriptorType; //端点描述符类型编号
BYTEbEndpointAddress; //端点地址及输⼊输出属性
BYTEbmAttributes; //端点的传输类型属性
WORDwMaxPacketSize; //端点收、发的最⼤包⼤⼩
BYTEbInterval; //主机查询端点的时间间隔
泰妍事件}
ENDPOINT_DESCRIPTOR_STRUCT,*pENDPOINT_DESCRIPTOR_STRUCT;
下⾯是⼀个配置描述符集合的定义
typedefstruct_CON_INT_ENDP_DESCRIPTOR_STRUCT
{
CONFIGURATION_DESCRIPTOR_STRUCTconfiguration_descriptor;
INTERFACE_DESCRIPTOR_STRUCT interface_descritor;
ENDPOINT_DESCRIPTOR_STRUCT endpoint_descriptor[ENDPOINT_NUMBER];
}CON_INT_ENDP_DESCRIPTOR_STRUCT;
配置描述符集合的⽰例
codeCON_INT_ENDP_DESCRIPTOR_STRUCTcon_int_endp_descriptor= //配置描述符集合
{
//configuration_descriptor //配置描述符
{
sizeof(CONFIGURATION_DESCRIPTOR_STRUCT), //配置描述符的字节数⼤⼩,这⾥为9
CONFIGURATION_DESCRIPTOR, //配置描述符类型编号,配置描述符为2
(sizeof(CONFIGURATION_DESCRIPTOR_STRUCT)+
sizeof(INTERFACE_DESCRIPTOR_STRUCT)+
sizeof(ENDPOINT_DESCRIPTOR_STRUCT)*ENDPOINT_NUMBER)*256+
(sizeof(CONFIGURATION_DESCRIPTOR_STRUCT)+
sizeof(INTERFACE_DESCRIPTOR_STRUCT)+
sizeof(ENDPOINT_DESCRIPTOR_STRUCT)*ENDPOINT_NUMBER)/256, //配置描述符集合的总⼤⼩
0x01, //只包含⼀个接⼝
0x01, //该配置的编号
张杰谢娜几岁0x00, //iConfiguration字段
0x80, //采⽤总线供电,不⽀持远程唤醒
0xC8 //从总线获取最⼤电流400mA
},
//interface_descritor //接⼝描述符
{
sizeof(INTERFACE_DESCRIPTOR_STRUCT), //接⼝描述符的字节数⼤⼩,这⾥为9 INTERFACE_DESCRIPTOR, //接⼝描述符类型编号,接⼝描述符为3
0x00, //接⼝编号为4
0x00, //该接⼝描述符的编号为0
ENDPOINT_NUMBER, //⾮0端点数量为2,只使⽤端点主端点输⼊和输出
0x08, //定义为USB⼤容量存储设备
0x06, //使⽤的⼦类,为简化块命令
0x50, //使⽤的协议,这⾥使⽤单批量传输协议
0x00 //接⼝描述符字符串索引,为0,表⽰没有字符串
},
//endpoint_descriptor[]
{
{ //主端点输⼊描述
淘宝一键上传sizeof(ENDPOINT_DESCRIPTOR_STRUCT), //端点描述符的字节数⼤⼩,这⾥为7 ENDPOINT_DESCRIPTOR, //端点描述符类型编号,端点描述符为5
MAIN_POINT_IN, //端点号,主输⼊端点
ENDPOINT_TYPE_BULK, //使⽤的传输类型,批量传输
0x4000, //该端点⽀持的最⼤包尺⼨,64字节
0x00 //中断扫描时间,对批量传输⽆效
},
{ //主端点输出描述
sizeof(ENDPOINT_DESCRIPTOR_STRUCT), //端点描述符的字节数⼤⼩,这⾥为7 ENDPOINT_DESCRIPTOR, //端点描述符类型编号,端点描述符为5
MAIN_POINT_OUT, //端点号,主输出端点
ENDPOINT_TYPE_BULK, //使⽤的传输类型,批量传输
0x4000, //该端点⽀持的最⼤包尺⼨,64字节
0x00 //中断扫描时间,对批量传输⽆效
}
发布评论