学习目标:参考lsusb源码,打印USB摄像头的设备描述符、配置描述符、接口联合描述符、端点描述符;
一、lsusb命令和源码
使用命令lsusb可以看看设备的id,并执行 # lsusb -v -d 0x1b3b:2977 命令查看usb摄像头的描述符。
二、源码
打印以下描述符:
程序主要正在probe执行printk函数进行打印:
static int myuvc_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
static int cnt = ;
struct usb_device *dev = interface_to_usbdev(intf);
struct usb_device_descriptor *descriptor = &dev->descriptor;
struct usb_host_config *hostconfig;
struct usb_config_descriptor *config;
struct usb_interface_assoc_descriptor *assoc_desc;
struct usb_interface_descriptor *interface;
struct usb_endpoint_descriptor *endpoint;
int i, j, k, l, m;
unsigned char *buffer;
int buflen;
int desc_len;
int desc_cnt; printk("myuvc_probe : cnt = %d\n", cnt++); /* 打印设备描述符 */
printk("Device Descriptor:\n"
" bLength %5u\n"
" bDescriptorType %5u\n"
" bcdUSB %2x.%02x\n"
" bDeviceClass %5u \n"
" bDeviceSubClass %5u \n"
" bDeviceProtocol %5u \n"
" bMaxPacketSize0 %5u\n"
" idVendor 0x%04x \n"
" idProduct 0x%04x \n"
" bcdDevice %2x.%02x\n"
" iManufacturer %5u\n"
" iProduct %5u\n"
" iSerial %5u\n"
" bNumConfigurations %5u\n",
descriptor->bLength, descriptor->bDescriptorType,
descriptor->bcdUSB >> , descriptor->bcdUSB & 0xff,
descriptor->bDeviceClass,
descriptor->bDeviceSubClass,
descriptor->bDeviceProtocol,
descriptor->bMaxPacketSize0,
descriptor->idVendor, descriptor->idProduct,
descriptor->bcdDevice >> , descriptor->bcdDevice & 0xff,
descriptor->iManufacturer,
descriptor->iProduct,
descriptor->iSerialNumber,
descriptor->bNumConfigurations); for (i = ; i < descriptor->bNumConfigurations; i++)
{
hostconfig = &dev->config[i]; //第i个配置
config = &hostconfig->desc;
printk(" Configuration Descriptor %d:\n"
" bLength %5u\n"
" bDescriptorType %5u\n"
" wTotalLength %5u\n"
" bNumInterfaces %5u\n"
" bConfigurationValue %5u\n"
" iConfiguration %5u\n"
" bmAttributes 0x%02x\n",
i,
config->bLength, config->bDescriptorType,
le16_to_cpu(config->wTotalLength),
config->bNumInterfaces, config->bConfigurationValue,
config->iConfiguration,
config->bmAttributes); assoc_desc = hostconfig->intf_assoc[]; //IAD
printk(" Interface Association:\n"
" bLength %5u\n"
" bDescriptorType %5u\n"
" bFirstInterface %5u\n"
" bInterfaceCount %5u\n"
" bFunctionClass %5u\n"
" bFunctionSubClass %5u\n"
" bFunctionProtocol %5u\n"
" iFunction %5u\n",
assoc_desc->bLength,
assoc_desc->bDescriptorType,
assoc_desc->bFirstInterface,
assoc_desc->bInterfaceCount,
assoc_desc->bFunctionClass,
assoc_desc->bFunctionSubClass,
assoc_desc->bFunctionProtocol,
assoc_desc->iFunction); for (j = ; j < intf->num_altsetting; j++)
{
interface = &intf->altsetting[j].desc; //第j个设置的描述符 接口描述符
printk(" Interface Descriptor altsetting %d:\n"
" bLength %5u\n"
" bDescriptorType %5u\n"
" bInterfaceNumber %5u\n"
" bAlternateSetting %5u\n"
" bNumEndpoints %5u\n"
" bInterfaceClass %5u\n"
" bInterfaceSubClass %5u\n"
" bInterfaceProtocol %5u\n"
" iInterface %5u\n",
j,
interface->bLength, interface->bDescriptorType, interface->bInterfaceNumber,
interface->bAlternateSetting, interface->bNumEndpoints, interface->bInterfaceClass,
interface->bInterfaceSubClass, interface->bInterfaceProtocol,
interface->iInterface);
/* 打印端点描述符 */
for (m = ; m < interface->bNumEndpoints; m++)
{
endpoint = &intf->altsetting[j].endpoint[m].desc;
dump_endpoint(endpoint);
} }
/*自定义描述符*/
buffer = intf->cur_altsetting->extra;
buflen = intf->cur_altsetting->extralen;
printk("extra buffer of interface %d:\n", cnt-);
k = ;
desc_cnt = ;
while (k < buflen)
{
desc_len = buffer[k];
printk("extra desc %d: ", desc_cnt);
for (l = ; l < desc_len; l++, k++)
{
printk("%02x ", buffer[k]);
}
desc_cnt++;
printk("\n");
}
//模拟lsusb打印内核usb摄像头信息
interface = &intf->cur_altsetting->desc;
if ((buffer[] == USB_DT_CS_INTERFACE) && (interface->bInterfaceSubClass == ))
{
parse_videocontrol_interface(intf, buffer, buflen);
}
if ((buffer[] == USB_DT_CS_INTERFACE) && (interface->bInterfaceSubClass == ))
{
parse_videostreaming_interface(intf, buffer, buflen);
} } return ;
}
分析:
1. VideoControl Interface的自定义描述符:
[318044.582155] extra buffer of interface :
[318044.582156] extra desc : 0d 4d c3 c9
[318044.582161] extra desc : 0e
[318044.582166] extra desc :
[318044.582170] extra desc : 0b 7f
[318044.582174] extra desc : 1a ad cc b1 c2 f6 ab b8 8e d4 f3 a3 fe ec 3f
解析:
extra buffer of interface 0:
extra desc 0: 0d 24 01 00 01 4d 00 80 c3 c9 01 01 01
VC_HEADER
extra desc 1: 12 24 02 01 01 02 00 00 00 00 00 00 00 00 03 0e 00 00
VC_INPUT_TERMINAL ID
extra desc 2: 09 24 03 02 01 01 00 04 00
VC_OUTPUT_TERMINAL ID wTerminalType bAssocTerminal bSourceID
extra desc 3: 0b 24 05 03 01 00 00 02 7f 14 00
VC_PROCESSING_UNIT ID bSourceID wMaxMultiplier bControlSize bmControls --->UVC 1.5 Class specification 69页
extra desc 0: 0d 24 01 00 01 4d 00 80 c3 c9 01 01 01
VC_HEADER
extra desc 1: 12 24 02 01 01 02 00 00 00 00 00 00 00 00 03 0e 00 00
VC_INPUT_TERMINAL ID
extra desc 2: 09 24 03 02 01 01 00 04 00
VC_OUTPUT_TERMINAL ID wTerminalType bAssocTerminal bSourceID
extra desc 3: 0b 24 05 03 01 00 00 02 7f 14 00
VC_PROCESSING_UNIT ID bSourceID wMaxMultiplier bControlSize bmControls --->UVC 1.5 Class specification 69页
bControlSize =2表示,后面2个字节,支持哪些功能,该位设为1表示为支持此功能;
extra desc 4: 1a 24 06 04 ad cc b1 c2 f6 ab b8 48 8e 37 32 d4 f3 a3 fe ec 08 01 03 01 3f 00
VC_EXTENSION_UNIT ID GUID bNumControls bNrInPins baSourceID
VC_EXTENSION_UNIT ID GUID bNumControls bNrInPins baSourceID
从而可知数据流向:IT(01) ===> PU(03) ===> EU(04) ===> OT(02)
1)第1字节为长度;
2)第2个字节表示为自定义的;
3)第3个字节为VC定义的子类:Video Class-Specific VC Interface Descriptor Subtypes 172页
VC_DESCRIPTOR_UNDEFINED 0x00
VC_HEADER 0x01
VC_INPUT_TERMINAL 0x02
VC_OUTPUT_TERMINAL 0x03
VC_SELECTOR_UNIT 0x04
VC_PROCESSING_UNIT 0x05
VC_EXTENSION_UNIT 0x06
VC_ENCODING_UNIT 0x07
4)第4个字节为bSourceID,来源
5)后面字节要根据手册分析;
2. VideoStreaming Interface的自定义描述符:
[318044.582312] extra buffer of interface :
[318044.582313] extra desc : 0e df
[318044.582317] extra desc : 1b aa 9b
[318044.582325] extra desc : 1e e0 ca ca
[318044.582333] extra desc : 1e e6 e6
[318044.582342] extra desc : 1e f0
[318044.582350] extra desc : 1e b0 a0 b9 a0 b9 c6
[318044.582358] extra desc : 1e a0 a0 8c a0 8c
[318044.582367] extra desc : 1a e0 f0 b0 a0
[318044.582374] extra desc : 0d
分析:
第3个字节:数据来源
VS_INPUT_HEADER 0x01
VS_STILL_IMAGE_FRAME 0x03 // 表示支持静态图片,拍照功能
VS_FORMAT_UNCOMPRESSED 0x04 // 表示格式
VS_FRAME_UNCOMPRESSED 0x05 frame //表示一种格式下可支持多种分辨率
VS_COLORFORMAT 0x0D
VS_STILL_IMAGE_FRAME 0x03 // 表示支持静态图片,拍照功能
VS_FORMAT_UNCOMPRESSED 0x04 // 表示格式
VS_FRAME_UNCOMPRESSED 0x05 frame //表示一种格式下可支持多种分辨率
VS_COLORFORMAT 0x0D