打印

Host发送了个索引238的获取字符串描述符的请求【已解决】

[复制链接]
6396|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 kokoromi 于 2013-6-12 09:25 编辑

前端时间调试USB发现一个问题,就是第一次插入设备枚举时,总是在获取完配置描述符后复位设备...因为第一次插入USB的设备在加载驱动之前无法用分析总线的软件查看数据情况,所以后来买了一个USB分析仪,从得到的数据里看出一个奇怪的地方,就是Host在获取了完整的配置描述符后发送了一个索引是238的获取字符串描述符的请求,然后就复位设备....问题是我用到的字符串索引没有238啊,0是语言ID,1、2、3分别是厂商、产品和序列号的字符串索引,我单片机挂起端点 或者 返回0长度包 或者不处理 都阻止不了设备复位...
有人遇到这种情况吗? 这个请求的代码是:80 06 EE 03 00 00 12 00
求高人指点...

USB分析仪截取的数据如下: 设备获取完全部配置描述符之后发了一个索引为238的获取字符串描述符请求,因为我程序里根本没有这个索引的字符串,所以就直接应答STALL了,之后主机就复位了... 我尝试应答NAK或者返回0长度包,都是一个结果,就是主机复位设备...  这个现象只发生在USB设备第一次连接Host的时候(就是插入USB后电脑右下角会显示发现新硬件),如果拔出来再插入枚举时就没有这个现象了,到底怎么回事呢,有人遇到这情况吗?求高人指点~~~




描述符如下:

//定义设备描述符
const BYTE DeviceDescriptor[18] =
{
  0x12,                                   //描述符长度(18字节)
  0x01,                                   //描述符类型(设备描述符)
  0x10, 0x01,                         //USB协议版本(1.1)
  0x00,                                   //设备使用的类代码
  0x00,                                   //设备使用的子类代码
  0x00,                                   //设备使用的协议代码
  0x08,                                   //端点0最大包长
  0xA0, 0xAA,                         //厂商 ID                                 
  0x01, 0xA0,                         //产品 ID
  0x00, 0x01,                         //设备版本号(1.0)
  0x01,                                   //厂商字符串索引
  0x02,                                   //产品字符串索引
  0x03,                                   //设备序列号字符窜索引
  0x01                                    //设备拥有的配置数
};

//定义配置描述符集合
const BYTE ConfigurationDescriptorGroup[34] =
{
  //配置描述符
  0x09,                                   //描述符长度(9字节)
  0x02,                                   //描述符类型(配置描述符)
  0x22, 0x00,                         //描述符总长度(不固定)
  0x01,                                   //该配置支持的接口数
  0x01,                                   //该配置的值
  0x00,                                   //该配置的字符串索引
  0x80,                                   //总线供电,不支持远程唤醒
  0xFA,                                   //总线最大电流输出(500mA)
  
  //接口描述符
  0x09,                                   //描述符长度(9字节)
  0x04,                                   //描述符类型(接口描述符)
  0x00,                                   //该接口的编号
  0x00,                                   //该接口的备用编号
  0x01,                                   //该接口使用的端点数
  0x03,                                   //该接口使用的类(自定义 HID类)
  0x00,                                   //该接口使用的子类
  0x00,                                   //该接口使用的协议
  0x00,                                   //该接口的字符串索引
  
  //HID描述符
  0x09,                                   //描述符长度(9字节)
  0x21,                                   //描述符类型(HID描述符)
  0x11, 0x01,                         //HID协议版本(1.11)
  0x00,                                   //国家代码(无)
  0x01,                                   //下级描述符数量(1个)
  0x22,                                   //下级描述符类型(报告描述符)
  0x15, 0x00,                         //下级描述符长度(不固定)
  
  //端点描述符
  0x07,                                   //描述符长度(7字节)
  0x05,                                   //描述符类型(端点描述符)
  0x81,                                   //端点地址(输入端点 1)
  0x03,                                   //端点类型(中断传输端点)
  0x40, 0x00,                         //端点最大包长 64字节
  0x0A                                    //端点查询时间(10ms)
};

//定义字符串描述符
const BYTE StringDescriptorID0[4] =
{
  //语言 ID描述符(索引 0)
  0x04,                                   //描述符长度(4字节,不固定)
  0x03,                                   //描述符类型(字符串描述符)
  0x09, 0x04                          //语言 ID号(美式英语)
};
const BYTE StringDescriptorID1[10] =
{
  //厂商字符串描述符(索引 1)
  0x0A,                                   //描述符长度(10字节)
  0x03,                                   //描述符类型(字符串描述符)
  0x44, 0x00,                         //D
  0x46, 0x00,                         //F
  0x4D, 0x00,                         //M
  0x43, 0x00                          //C
};
const BYTE StringDescriptorID2[42] =
{
  //产品字符串描述符(索引 2)
  0x2A,                                   //描述符长度(42字节)
  0x03,                                   //描述符类型(字符串描述符)
  0x48, 0x00,                             //H
  0x41, 0x00,                             //A
  0x52, 0x00,                             //R
  0x54, 0x00,                             //T
  0x20, 0x00,                             //
  0x48, 0x00,                             //H
  0x61, 0x00,                             //a
  0x6E, 0x00,                             //n
  0x64, 0x00,                             //d
  0x68, 0x00,                             //h
  0x65, 0x00,                             //e
  0x6C, 0x00,                             //l
  0x64, 0x00,                             //d
  0x20, 0x00,                             //
  0x44, 0x00,                             //D
  0x65, 0x00,                             //e
  0x76, 0x00,                             //v
  0x69, 0x00,                             //i
  0x63, 0x00,                             //c
  0x65, 0x00                              //e
};
const BYTE StringDescriptorID3[18] =
{
  //设备序列号字符串描述符(索引 3)
  0x12,                                   //描述符长度(18字节)
  0x03,                                   //描述符类型(字符串描述符)
  0x32, 0x00,                             //2
  0x30, 0x00,                             //0
  0x31, 0x00,                             //1
  0x33, 0x00,                             //3
  0x30, 0x00,                             //0
  0x34, 0x00,                             //4
  0x32, 0x00,                             //2
  0x36, 0x00                              //6
};

//定义报告描述符(自定义 HID设备)
const BYTE ReportDescriptor[21] =
{
  0x05, 0x01,                             // USAGE_PAGE (Generic Desktop)
  0x09, 0x00,                             // USAGE (Undefined)
  0xa1, 0x01,                             // COLLECTION (Application)
  0x15, 0x00,                             //   LOGICAL_MINIMUM (0)
  0x25, 0x7f,                              //   LOGICAL_MAXIMUM (127)
  0x19, 0x01,                             //   USAGE_MINIMUM (1)
  0x29, 0x08,                             //   USAGE_MAXIMUM (8)
  0x75, 0x08,                             //   REPORT_SIZE (8)
  0x95, 0x01,                             //   REPORT_COUNT (1)
  0x81, 0x02,                             //   INPUT (Data,Var,Abs)
  0xc0                                        // END_COLLECTION
};

相关帖子

沙发
kokoromi|  楼主 | 2013-5-30 09:07 | 只看该作者
就没有人遇到这种情况吗?

使用特权

评论回复
板凳
john_lee| | 2013-5-30 09:34 | 只看该作者
贴描述符

使用特权

评论回复
地板
kokoromi|  楼主 | 2013-5-30 09:52 | 只看该作者
john_lee 发表于 2013-5-30 09:34
贴描述符

贴了,感觉描述符应该没啥问题,否则的话,无论哪次连接USB都会出现问题,现在诡异的是,只有第一次连接USB有这个问题,拔出来在插入就没问题了。。。。

使用特权

评论回复
5
STARM| | 2013-6-9 15:24 | 只看该作者
若要将 USB 设备标识为 WinUSB 设备,设备固件必须具有这些 Microsoft OS 描述符。

1) 支持 OS 字符串描述符

为了让 USB 驱动程序堆栈了解设备支持扩展的特征描述符,
设备必须定义存储在字符串索引 0xEE 处的 OS 字符串描述符。
在枚举过程中,驱动程序堆栈查询字符串描述符。
如果存在描述符,驱动程序堆栈会假定设备包含一个或多个
OS 特征描述符和检索这些特征描述符所需要的数据。

检索的字符串描述符具有 bMS_VendorCode 字段值。
该值表示 USB 驱动程序堆栈必须用来检索扩展特征描述符的供应商代码。

#define bMS_VendorCode              ( 0x01 )
// "MSFT100" : index : 0xEE : langId : 0x0000
const U8 OS_StringDescritpor[ ] =
{ 0x12,  0x03,  'M',  0,  'S',  0,  'F',  0,  'T',  0,  '1',  0,  '0',  0,  '0',  0,  bMS_VendorCode,  0 };
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\usbflags\<VVVVPPPPRRRR>

osvc : 01 01

使用特权

评论回复
6
STARM| | 2013-6-9 15:26 | 只看该作者
Indicates whether the operating system queried the device for Microsoft-Defined USB Descriptors.
If the previously-attempted OS descriptor query was successful, the value contains the vendor code
from the OS string descriptor.

0x0000: The device did not provide a valid response to the Microsoft OS string descriptor request.

0x01xx: The device provided a valid response to the Microsoft OS string descriptor request,
where xx is the bMS_VendorCode contained in the response.

为什么必须将 OS 字符串描述符存储在索引 0xEE 上?
一台支持 Microsoft OS 描述符的设备必须包含一个 OS 字符串描述符,
存储在字符串索引 0xEE 位置。
该 OS 字符串描述符是一个标准的 USB 字符串描述符,具有以下功能:
1) 其存在表明该设备包含一个或多个 OS 功能描述符。
2) 它包含检索相关的 OS 功能描述符所需的数据。
3) 它包含一个签名字段,该字段可将 OS 字符串描述符和其他 IHV 可能选择存储在 0xEE 的字符串别开来。
4) 它包含一个允许未来修改 Microsoft OS 描述符的版本号。

如果在 0xEE 没有字符串描述符,或者该索引位置的字符串描述符
不是有效的 OS 字符串描述符,则 Windows 假设该设备不包含任何 OS 功能描述符。

使用特权

评论回复
7
STARM| | 2013-6-9 15:35 | 只看该作者
How does USB stack enumerate a device?

MS OS Descriptor Query

Microsoft has defined a set of vendor specific USB descriptors called Microsoft OS Feature Descriptors, which are queried for at the time of device enumeration.
If the USB Device Descriptor’s bcdUSB field is equal to 0x0100 or 0x0110, the hub driver will skip the query for the MS OS Descriptor and move to the “Serial Number String Descriptor Query” state.
If the hub driver has never before enumerated a device with the same VID/PID/Revision as the device being enumerated, it will query the device for the MS OS String Descriptor (GET_DESCRIPTOR for Descriptor Type STRING), which uses index 0xEE.  It will specify a language ID of 0x00.
If the device returns an MS OS Descriptor, the hub driver will validate the descriptor as follows:
  • The MicrosoftString field must be equal to “MSFT100”.
Once validated, the value in the descriptor’s bVendorCode field will be stored in the registry on a per VID/PID/Revision basis, under the USBFLAGS registry subkey in the “osvc” registry value.  Subsequent enumerations of any device with the same VID/PID/Revision will read the bVendorCode from this registry value rather than querying the device.
The hub driver will then move to the “Serial Number String Descriptor Query” state.




使用特权

评论回复
8
wxws| | 2013-6-11 00:43 | 只看该作者
我的C8051F 也这样,后来实在没法,我加了个判断取字符串的序号时,超过我的实际个数,我就返回第0个.

使用特权

评论回复
9
kokoromi|  楼主 | 2013-6-12 09:23 | 只看该作者
本帖最后由 kokoromi 于 2013-6-12 17:30 编辑
STARM 发表于 2013-6-9 15:24
若要将 USB 设备标识为 WinUSB 设备,设备固件必须具有这些 Microsoft OS 描述符。

1) 支持 OS 字符串描述 ...


哥们,太感谢了,你的这个回复让我的USB水平又提高了一截,长见识了。我根据你给的内容,在微软官网上找到了更为详细的关于 OS字符串描述符的内容,详见此贴:https://bbs.21ic.com/icview-566421-1-1.html

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

111

主题

344

帖子

3

粉丝