说到USB设备,不得不提到各种描述符(descriptors), 一般来说,描述符有如下几种:
1:设备描述符(Device Descriptors)
2:配置描述符(Configuration Descriptors)
2:接口描述符(Interface Descriptors)
3:端点描述符(Endpoint Descriptors)
一个USB设备只有一个设备描述符,设备描述符里面定义了该设备有多少种配置,每种配置描述符对应着配置描述符;而在配置描述符中又定义了该配置里面有多少个接口,每个接口有对应的接口描述符;在接口描述符里面又定义了该接口有多少个端点,每个端点对应一个端点描述符;端点描述符定义了端点的大小,类型等等。由此我们可以看出,USB的描述符之间的关系是一层一层的,最上一层是设备描述符,下面是配置描述符,再下面是接口描述符,再下面是端点描述符。在获取描述符时,先获取设备描述符,然后再获取配置描述符,根据配置描述符中的配置集合长度,一次将配置描述符、接口描述符、端点描述符一起一次读回。其中可能还会有获取设备序列号,厂商字符串,产品字符串等。
详细关系如下图所示:
下面我们从软件的角度来看看这些描述符的详细定义(以下定义取自Window系统, Linux下命名稍有区别,成员内容一致)
设备描述符结构体如下:
配置描述符结构体如下:
接口描述符结构体如下:
端点描述符结构体如下:
除以上四种描述符之外,还有一种字符串描述符,对于一个USB设备来说, 该描述符不是必须实现的(当不实现时,应将该描述符设置成0,以表明该功能未实现)。
typedef struct _USB_STRING_DESCRIPTOR {
UCHAR bLength; //字符串描述符字节数
UCHAR bDescriptorType; //字符串描述符类型编号(0x03)
WCHAR bString[1]; //unicode字符串
} USB_STRING_DESCRIPTOR, *PUSB_STRING_DESCRIPTOR;
转载:http://blog.youkuaiyun.com/saloon_yuan/article/details/7837492
参考资料:
USB(Universal Serial BUS,通用串行总线)协议规定,所有的USB设备都有VID(Vendor ID,供应商识别码)和PID(Product ID,产品识别码)。VID由供应商向USB-IF(Implementers Forum,应用者论坛)申请。每个供应商的VID是唯一的,PID由供应商自行决定。主机通过VID和PID来识别不同设备,根据它们(以及设备的版本号),可以给设备加载或安装相应的驱动程序。VID和PID的长度都是两个字节的。
常见的各大供应商的VID和PID,可以在这里查询到:http://www.linux-usb.org/usb.ids
USB定义了种类代码信息,它被用来识别设备的功能,根据这些功能,以加载设备驱动。这种信息包含在名为基类,子类和协议的3个字节里(注意:“基类”在本文中,用来标识三个字节的种类代码的的首字节;在USB规范中没有使用这个术语)。设备中有两个地方可以存放种类代码信息,一个是设备描述符,另一个是接口描述符。已经定义的种类代码,有些只能用在设备描述符里,有些只能用在接口描述符里,有些两种描述符里都可用。下表给出现在已经定了的基类的值的集合,通常用法是什么,基类用在什么场合(设备描述符或接口描述符)。
其具体定义参见USB官方网址:http://www.usb.org/developers/defined_class
各种类的定义参见:http://www.usb.org/developers/devclass_docs
Base Class | Descriptor Usage | Description |
00h | Device | Use class information in the Interface Descriptors 种类信息定义在接口描述符中 |
01h | Interface | Audio 音频设备 |
02h | Both | Communications & CDC 通信设备(手机,Class_02&SubClass_02&Prot_01) |
03h | Interface | HID (Human Interface Device) 人机接口设备 |
05h | Interface | Physical 物理设备 |
06h | Interface | Image 图像设备(可能是IPhone手机,Class_06&SubClass_01&Prot_01) |
07h | Interface | Printer 打印机 |
08h | Interface | Mass Storage 大容量存储(可能是手机,Class_08&SubClass_06&Prot_50) |
09h | Device | Hub 集线器 |
0Ah | Interface | CDC-Data 通信设备(手机,Class_0A&SubClass_00&Prot_00) |
0Bh | Interface | Smart Card 智能卡 |
0Dh | Interface | Content Security 内容安全设备 |
0Eh | Interface | Video 视频设备(摄像头,Class_0e&SubClass_03&Prot_00) |
0Fh | Interface | Personal Healthcare 个人健康设备 |
10h | Interface | Audio/Video Devices 音频/视频设备 |
DCh | Both | Diagnostic Device 诊断设备(USB2兼容设备) |
E0h | Interface | Wireless Controller 无线控制器(蓝牙设备等) |
EFh | Both | Miscellaneous 杂项(ActiveSync,PalmSync,各种协会等) |
FEh | Interface | Application Specific 应用专有规范(固件升级,红外,USB测试与测量等) |
FFh | Both | Vendor Specific 供应商自定义规范(手机,Class_FF&SubClass_FF&Prot_FF) |
//============================================================================
// 文件名: USBDESC.C
// 用 途: USB描述符
// 作 者: shenfei5
// 时 间: 2007.2.3
// 版 本: V1.10
//============================================================================
#include <RTL.h>
#include "usb.h" // USB模块
#include "hid.h" // HID设备
#include "usbcfg.h" // 配置USB
#include "usbdesc.h" // USB描述符
//
// HID报文描述符
//
const U8 HID_ReportDescriptor[] = {
HID_UsagePageVendor(0x00), // 报告页版本: 0X06 0X00 0XFF
HID_Usage(0x01), // 用途页: 0X05 0X01
// 如果是MOUSE,KEY,在这里应该有用法索引
HID_Collection(HID_Application), // 用法集合开始: 0XA1 0X01
HID_UsagePage(HID_USAGE_PAGE_BUTTON), // BUTTON用法页
HID_UsageMin(1), // 用法最小值
HID_UsageMax(3), // 用法最小值
HID_LogicalMin(0), // 逻辑最小值
HID_LogicalMax(1), // 逻辑最大值
HID_ReportCount(3), // 报告计数(3)
HID_ReportSize(1), // 报告页大小 (1)
HID_Input(HID_Data | HID_Variable | HID_Absolute), // 输入 (2)
HID_ReportCount(1), // 报告计数值
HID_ReportSize(5), // 报告大小
HID_Input(HID_Constant), // 输入 1
HID_UsagePage(HID_USAGE_PAGE_LED), // LED用法页
HID_Usage(HID_USAGE_LED_GENERIC_INDICATOR), // 用法页
HID_LogicalMin(0), // 用法最小值
HID_LogicalMax(1), // 用法最大值
HID_ReportCount(8), // 报告计数值
HID_ReportSize(1), // 报告大小 (1)
HID_Output(HID_Data | HID_Variable | HID_Absolute), // 输出 (2)
HID_EndCollection, // 报告结束
};
// HID报告描述符大小
const U16 HID_ReportDescSize = sizeof(HID_ReportDescriptor);
//
// USB 设备描述符
//
const U8 USB_DeviceDescriptor[] = {
USB_DEVICE_DESC_SIZE, // bLength 描述符长度 = 12H
USB_DEVICE_DESCRIPTOR_TYPE, // bDescriptorType 描述符类型 = 1H
WBVAL(0x0110), // 1.10 // bcdUSB 设备版本号 = 你发行的版本的号
0x00, // bDeviceClass 类型代码 = 由USB指定
0x00, // bDeviceSubClass 子类型代码 = 由USB分配
0x00, // bDeviceProtocol 协议代码 = 由USB分配
USB_MAX_PACKET0, // bMaxPacketSize0 端点0的容量 = 64(只能是 8,16,32,64)
WBVAL(0x1977), // idVendor 供应商ID(同USB协会分配,我就自己分配一份)
WBVAL(0X1006), // idProduct 产品ID(由厂商分配)
WBVAL(0x0100), // 1.00 // bcdDevice ( 设备出厂编号 )
0x04, // iManufacturer ( 厂商描述字符串索引, 用来在字符串索引中查找字符串 )
0x20, // iProduct ( 产品描述字符串索引, 用来在字符串索引中查找字符串 )
0x42, // iSerialNumber ( 设备序列号描述字符串索引, 用来在字符串索引中查找字符串 )
0x01 // bNumConfigurations ( 配置字符串的个数 )
};
//
// USB 描述符集
// 所有描述符 (配置描述符, 接口描述符, 端点描述符, USB类描述符, 设备描述符
//
const U8 USB_ConfigDescriptor[] = {
// 配置描述符
USB_CONFIGUARTION_DESC_SIZE, // bLength 描述符长度 = 9H
USB_CONFIGURATION_DESCRIPTOR_TYPE, // bDescriptorType 描述符类型 = 2H
WBVAL( // wTotalLength
USB_CONFIGUARTION_DESC_SIZE + // 返回描述符串集的长度, 配置描述字符长度
USB_INTERFACE_DESC_SIZE + // 接口描述字符长度
HID_DESC_SIZE + // HID描述字符长度
USB_ENDPOINT_DESC_SIZE // 端点描述字符长度
),
0x01, // bNumInterfaces
// 支持接口数
0x01, // bConfigurationValue
// 配置值
0x00, // iConfiguration
// 配置字符串描述索相
// 0: 不使用
// 如果使用,必须在字符串描述符中添加相应的字符串.
USB_CONFIG_BUS_POWERED | // bmAttributes 设置的供电特性
USB_CONFIG_REMOTE_WAKEUP, // 总线供电
// 有唤醒功能
USB_CONFIG_POWER_MA(100), // bMaxPower 设备从供电总线吸取的电流值
当前配置为 100MA
// 接口类描述符
// 接口 0 ,位置 0 , HID类
// Interface 0, Alternate Setting 0, HID Class
USB_INTERFACE_DESC_SIZE, // bLength 描述符长度 = 9H
USB_INTERFACE_DESCRIPTOR_TYPE, // bDescriptorType 描述符类型 = 4H
0x00, // bInterfaceNumber ( 接口编号 )
0x00, // bAlternateSetting ( 可代替位置 )
0x01, // bNumEndpoints 使用端点(不含端点0)
USB_DEVICE_CLASS_HUMAN_INTERFACE, // bInterfaceClass
// USB 类
// USB_DEVICE_CLASS_HUMAN_INTERFACE == 3
// HID类
HID_SUBCLASS_NONE, // bInterfaceSubClass
// 子类,没有.
HID_PROTOCOL_NONE, // bInterfaceProtocol
// 协议代码
0x5C, // iInterface
// 字符串描述符索引,要使用该字符串必须在字符串描述符里添加相应的字符串
// HID类描述符
// HID_DESC_OFFSET = 0x0012
// HID类描述符的偏移量
HID_DESC_SIZE, // bLength 描述符长度 =
HID_HID_DESCRIPTOR_TYPE, // bDescriptorType HID描述符类型 = 21H
WBVAL(0x0100), // 1.00 // bcdHID HID版本号
0x00, // bCountryCode 国家代码
0x01, // bNumDescriptors 支持其它类描述符个数
HID_REPORT_DESCRIPTOR_TYPE, // bDescriptorType 从属类描述类型 = 报告描述符22H
WBVAL(HID_REPORT_DESC_SIZE), // wDescriptorLength 从属类描述的长度
// Endpoint, HID Interrupt In
// HID 端点描述描,端点1输入
USB_ENDPOINT_DESC_SIZE, // bLength 端点描述符长度
USB_ENDPOINT_DESCRIPTOR_TYPE, // bDescriptorType 端点描述符类型 = 5H
USB_ENDPOINT_IN(1), // bEndpointAddress 逻辑端点号 BIT.7 = DIR
// BIT.0..3 端点号
// 这个值是用来把逻辑端点号换成物理端点号
USB_ENDPOINT_TYPE_INTERRUPT, // bmAttributes 端点属性 = 中断
WBVAL(0x0004), // wMaxPacketSize 端点容量
10, // 10ms // bInterval
// 传输间隔时间.只对中断端点有效
// Terminator
0 // bLength
// 结果码.
};
//
// USB 字符串描述符 (可选)
// 字符描述符结构:
// {
// 字符串描述符 1 大小
// 描述符类型 = 字符串描述符(0X03)
// 描述符内容.
// ... ...
// 字符串描述符n 1 大小
// 描述符类型n = 字符串描述符(0X03)
// 描述符内容n.
// }
//
const U8 USB_StringDescriptor[] = {
// 字符串索引: 0x00:
// 字符串用途: 语言代码
0x04, // 描述符长度 bLength
USB_STRING_DESCRIPTOR_TYPE, // bDescriptorType,描述符类型:3(字符串描述符)
//WBVAL(0x0409), // 使用 English 语言// 描述符内容 wLANGID
WBVAL(0x0804), // 试一下中文的行不行,改了之后,在硬件属性里看不到,在客户端可以看到,不明原因.
// 字符串索引: 0x04:
// 字符串用途: 生产产商字符描述符
0x1C, // 描述符长度 bLength
USB_STRING_DESCRIPTOR_TYPE, // bDescriptorType,描述符类型:3(字符串描述符)
0xc1,0,
0xd6,0,
0xca,0,
0xa4,0,
0xb7,0,
0xe1,0,
' ',0,
' ',0,
' ',0,
' ',0,
' ',0,
' ',0,
' ',0,
// 字符串索引: 0x20
// 字符串用途: 产品名称
0x22, // 描述符长度 bLength
USB_STRING_DESCRIPTOR_TYPE, // bDescriptorType,描述符类型:3(字符串描述符)
0xc1,0,
0xd6,0,
0xca,0,
0xa4,0,
0xb7,0,
0xe1,0,
' ',0,
' ',0,
' ',0,
' ',0,
' ',0,
' ',0,
' ',0,
'H',0,
'I',0,
'D',0,
// 字符串索引: 0x42
// 字符串用途: 产品系列号
0x1A, // 描述符长度 bLength
USB_STRING_DESCRIPTOR_TYPE, // bDescriptorType,描述符类型:3(字符串描述符)
'T',0,
'E',0,
'S',0,
'T',0,
'0',0,
'0',0,
'0',0,
'0',0,
'0',0,
'0',0,
'0',0,
'0',0,
// 字符串索引号 0x5C
// 接口 Interface 0, 位置 Alternate Setting 0
0x08, // 描述符长度 bLength
USB_STRING_DESCRIPTOR_TYPE, // bDescriptorType,描述符类型:3(字符串描述符)
'H',0,
'I',0,
'D',0,
};