关于这个概念也没有一个准确的定义,可以理解为与 “被描述物” 相关联的一组数据或数据结构,用来记录被描述物的 “属性”。
具体体现如下(举例说明,并非所有):
对于usb描述符,用来描述该usb设备的属性,如:设备类型、设备型号、配置、容量大小等等
对于一个usb设备,其必有如下固定描述符:
struct usb_device_descriptor {
__u8 bLength; //本描述符的size
__u8 bDescriptorType; //描述符的类型,这里是设备描述符DEVICE
__u16 bcdUSB; //指明usb的版本,比如usb2.0
__u8 bDeviceClass; //类
__u8 bDeviceSubClass; //子类
__u8 bDeviceProtocol; //指定协议
__u8 bMaxPacketSize0; //端点0对应的最大包大小
__u16 idVendor; //厂家ID
__u16 idProduct; //产品ID
__u16 bcdDevice; //设备的发布号
__u8 iManufacturer; //字符串描述符中厂家ID的索引
__u8 iProduct; //字符串描述符中产品ID的索引
__u8 iSerialNumber; //字符串描述符中设备序列号的索引
__u8 bNumConfigurations; //配置描述符的个数,表示有多少个配置描述符
} __attribute__ ((packed));
usb_device->config[ ](所有配置).desc
usb_device->actconfig(当前激活的配置)->desc
struct usb_config_descriptor {
__u8 bLength; //描述符的长度
__u8 bDescriptorType; //描述符类型的编号
__le16 wTotalLength; //配置 所返回的所有数据的大小
__u8 bNumInterfaces; //配置 所支持的接口个数, 表示有多少个接口描述符
__u8 bConfigurationValue; //Set_Configuration命令需要的参数值
__u8 iConfiguration; //描述该配置的字符串的索引值
__u8 bmAttributes; //供电模式的选择
__u8 bMaxPower; //设备从总线提取的最大电流
} __attribute__ ((packed));
usb_interface->cur_altsetting(当前激活的接口)->desc
usb_interface->altsetting[ ](所有的接口).desc
struct usb_interface_descriptor {
__u8 bLength; //描述符的长度
__u8 bDescriptorType; //描述符类型的编号
__u8 bInterfaceNumber; //接口的编号
__u8 bAlternateSetting; //备用的接口描述符编号,提供不同质量的服务参数.
__u8 bNumEndpoints; //要使用的端点个数(不包括端点0), 表示有多少个端点描述符,比如鼠标就只有一个端点
__u8 bInterfaceClass; //接口类型,与驱动的id_table
__u8 bInterfaceSubClass; //接口子类型
__u8 bInterfaceProtocol; //接口所遵循的协议
__u8 iInterface; //描述该接口的字符串索引值
} __attribute__ ((packed)
usb_interface->cur_altsetting(当前激活的接口)->endpoint[] (所有端点).desc
struct usb_endpoint_descriptor {
__u8 bLength; //描述符的长度
__u8 bDescriptorType; //描述符类型的编号
__u8 bEndpointAddress; //端点编号,比如端点1,就是1
__u8 bmAttributes; //端点的属性, 比如中断传输类型,输入类型
__le16 wMaxPacketSize; //一个端点的最大包大小,
__u8 bInterval; //间隔时间,用在中断传输上,比如间隔时间查询鼠标的数据
/* NOTE: these two are _only_ in audio endpoints. */
/* use USB_DT_ENDPOINT*_SIZE in bLength, not sizeof. */
__u8 bRefresh;
__u8 bSynchAddress;
} __attribute__ ((packed));
四者的关系如下:
参考手册,得到如下图:其中白色底为固定的描述符,灰色底为此设备拓展的描述符。
使用到的USB摄像头为百问网的usb-cmos二合一摄像头,参考libusb-1.0.16-rc10
源码
/*******************************************************************************
* Copyleft (c) 2021 Kcode
*
* @file myuvc.c
* @brief 打印usb的设备、配置、IAD、接口、自定义、端点描述符并解析自定义描述符
* @author K
* @version 0.0.1
* @date 2021-07-21
* @license MulanPSL-1.0
*
* 文件修改历史:
* <时间> | <版本> | <作者> | <描述>
* 2021-07-21 | v0.0.1 | Kcode | 打印并解析描述符
* -----------------------------------------------------------------------------
******************************************************************************/
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
/*!
* 所支持的usb设备类
*/
static struct usb_device_id myuvc_ids[] = {
/* Generic USB Video Class */
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) }, /**< VideoControl interface */
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 2, 0) }, /**< VideoStreaming interface */
{}
};
static const char *get_guid(const unsigned char *buf)
{
static char guid[39];
/* NOTE: see RFC 4122 for more information about GUID/UUID
* structure. The first fields fields are historically big
* endian numbers, dating from Apollo mc68000 workstations.
*/
sprintf(guid, "{%02x%02x%02x%02x"
"-%02x%02x"
"-%02x%02x"
"-%02x%02x"
"-%02x%02x%02x%02x%02x%02x}",
buf[0], buf[1], buf[2], buf[3],
buf[4], buf[5],
buf[6], buf[7],
buf[8], buf[9],
buf[10], buf[11], buf[12], buf[13], buf[14], buf[15]);
return guid;
}
/*!
* 解析VideoControl Interface接口的自定义描述符
*/
static void parse_videocontrol_interface(struct usb_interface *intf,
unsigned char *buf, int buflen)
{
static const char * const ctrlnames[] = {
"Brightness", "Contrast", "Hue", "Saturation", "Sharpness", "Gamma",
"White Balance Temperature", "White Balance Component", "Backlight Compensation",
"Gain", "Power Line Frequency", "Hue, Auto", "White Balance Temperature, Auto",
"White Balance Component, Auto", "Digital Multiplier", "Digital Multiplier Limit",
"Analog Video Standard", "Analog Video Lock Status"
};
static const char * const camctrlnames[] = {
"Scanning Mode", "Auto-Exposure Mode", "Auto-Exposure Priority",
"Exposure Time (Absolute)", "Exposure Time (Relative)", "Focus (Absolute)",
"Focus (Relative)", "Iris (Absolute)", "Iris (Relative)", "Zoom (Absolute)",
"Zoom (Relative)", "PanTilt (Absolute)", "PanTilt (Relative)",
"Roll (Absolute)", "Roll (Relative)", "Reserved", "Reserved", "Focus, Auto",
"Privacy"
};
static const char * const stdnames[] = {
"None", "NTSC - 525/60", "PAL - 625/50", "SECAM - 625/50",
"NTSC - 625/50", "PAL - 525/60" };
unsigned int i, ctrls, stds, n, p, termt, freq;
/*!
* 打印所有的在VideoControl Interface接口下的自定义描述符
*/
while (buflen > 0) {
if (buf[1] != USB_DT_CS_INTERFACE)
printk(" Warning: Invalid descriptor\n");
else if (buf[0] < 3)
printk(" Warning: Descriptor too short\n");
printk(" VideoControl Interface Descriptor:\n"
" bLength %5u\n"
" bDescriptorType %5u\n"
" bDescriptorSubtype %5u ",
buf[0], buf[1], buf[2]);
switch (buf[2]) {
case 0x01: /* HEADER */
printk("(HEADER)\n");
n = buf[11];
if (buf[0] < 12+n)
printk(" Warning: Descriptor too short\n");
freq = buf[7] | (buf[8] << 8) | (buf[9] << 16) | (buf[10] << 24);
printk(" bcdUVC %2x.%02x\n"
" wTotalLength %5u\n"
" dwClockFrequency %5u.%06uMHz\n"
" bInCollection %5u\n",
buf[4], buf[3], buf[5] | (buf[6] << 8), freq / 1000000,
freq % 1000000, n);
for (i = 0; i < n; i++)
printk(" baInterfaceNr(%2u) %5u\n", i, buf[12+i]);
break;
case 0x02: /* INPUT_TERMINAL */
printk("(INPUT_TERMINAL)\n");
termt = buf[4] | (buf[5] << 8);
n = termt == 0x0201 ? 7 : 0;
if (buf[0] < 8 + n)
printk(" Warning: Descriptor too short\n");
printk(" bTerminalID %5u\n"
" wTerminalType 0x%04x\n"
" bAssocTerminal %5u\n",
buf[3], termt, buf[6]);
printk(" iTerminal %5u\n",
buf[7]);
if (termt == 0x0201) {
n += buf[14];
printk(" wObjectiveFocalLengthMin %5u\n"
" wObjectiveFocalLengthMax %5u\n"
" wOcularFocalLength %5u\n"
" bControlSize %5u\n",
buf[8] | (buf[9] << 8), buf[10] | (buf[11] << 8),
buf[12] | (buf[13] << 8), buf[14]);
ctrls = 0;
for (i = 0; i < 3 && i < buf[14]; i++)
ctrls = (ctrls << 8) | buf[8+n-i-1];
printk(" bmControls 0x%08x\n", ctrls);
for (i = 0; i < 19; i++)
if ((ctrls >> i) & 1)
printk(" %s\n", camctrlnames[i]);
}
break;
case 0x03: /* OUTPUT_TERMINAL */
printk("(OUTPUT_TERMINAL)\n");
termt = buf[4] | (buf[5] << 8);
if (buf[0] < 9)
printk(" Warning: Descriptor too short\n");
printk(" bTerminalID %5u\n"
" wTerminalType 0x%04x\n"
" bAssocTerminal %5u\n"
" bSourceID %5u\n"
" iTerminal %5u\n",
buf[3], termt, buf[6], buf[7], buf[8]);
break;
case 0x04: /* SELECTOR_UNIT */
printk("(SELECTOR_UNIT)\n");
p = buf[4];
if (buf[0] < 6+p)
printk(" Warning: Descriptor too short\n");
printk(" bUnitID %5u\n"
" bNrInPins %5u\n",
buf[3], p);
for (i = 0; i < p; i++)
printk(" baSource(%2u) %5u\n", i, buf[5+i]);
printk(" iSelector %5u\n",
buf[5+p]);
break;
case 0x05: /* PROCESSING_UNIT */
printk("(PROCESSING_UNIT)\n");
n = buf[7];
if (buf[0] < 10+n)
printk(" Warning: Descriptor too short\n");
printk(" bUnitID %5u\n"
" bSourceID %5u\n"
" wMaxMultiplier %5u\n"
" bControlSize %5u\n",
buf[3], buf[4], buf[5] | (buf[6] << 8), n);
ctrls = 0;
for (i = 0; i < 3 && i < n; i++)
ctrls = (ctrls << 8) | buf[8+n-i-1];
printk(" bmControls 0x%08x\n", ctrls);
for (i = 0; i < 18; i++)
if ((ctrls >> i) & 1)
printk(" %s\n", ctrlnames[i]);
stds = buf[9+n];
printk(" iProcessing %5u\n"
" bmVideoStandards 0x%2x\n", buf[8+n], stds);
for (i = 0; i < 6; i++)
if ((stds >> i) & 1)
printk(" %s\n", stdnames[i]);
break;
case 0x06: /* EXTENSION_UNIT */
printk("(EXTENSION_UNIT)\n");
p = buf[21];
n = buf[22+p];
if (buf[0] < 24+p+n)
printk(" Warning: Descriptor too short\n");
printk(" bUnitID %5u\n"
" guidExtensionCode %s\n"
" bNumControl %5u\n"
" bNrPins %5u\n",
buf[3], get_guid(&buf[4]), buf[20], buf[21]);
for (i = 0; i < p; i++)
printk(" baSourceID(%2u) %5u\n", i, buf[22+i]);
printk(" bControlSize %5u\n", buf[22+p]);
for (i = 0; i < n; i++)
printk(" bmControls(%2u) 0x%02x\n", i, buf[23+p+i]);
printk(" iExtension %5u\n",
buf[23+p+n]);
break;
default:
printk("(unknown)\n"
" Invalid desc subtype:");
break;
}
buflen -= buf[0];
buf += buf[0];
}
}
/*!
* 打印端点描述符
*/
static void dump_endpoint(const struct usb_endpoint_descriptor *endpoint)
{
static const char * const typeattr[] = {
"Control",
"Isochronous",
"Bulk",
"Interrupt"
};
static const char * const syncattr[] = {
"None",
"Asynchronous",
"Adaptive",
"Synchronous"
};
static const char * const usage[] = {
"Data",
"Feedback",
"Implicit feedback Data",
"(reserved)"
};
static const char * const hb[] = { "1x", "2x", "3x", "(?\?)" };
unsigned wmax = le16_to_cpu(endpoint->wMaxPacketSize);
printk(" Endpoint Descriptor:\n"
" bLength %5u\n"
" bDescriptorType %5u\n"
" bEndpointAddress 0x%02x EP %u %s\n"
" bmAttributes %5u\n"
" Transfer Type %s\n"
" Synch Type %s\n"
" Usage Type %s\n"
" wMaxPacketSize 0x%04x %s %d bytes\n"
" bInterval %5u\n",
endpoint->bLength,
endpoint->bDescriptorType,
endpoint->bEndpointAddress,
endpoint->bEndpointAddress & 0x0f,
(endpoint->bEndpointAddress & 0x80) ? "IN" : "OUT",
endpoint->bmAttributes,
typeattr[endpoint->bmAttributes & 3],
syncattr[(endpoint->bmAttributes >> 2) & 3],
usage[(endpoint->bmAttributes >> 4) & 3],
wmax, hb[(wmax >> 11) & 3], wmax & 0x7ff,
endpoint->bInterval);
/* only for audio endpoints */
if (endpoint->bLength == 9)
printk(" bRefresh %5u\n"
" bSynchAddress %5u\n",
endpoint->bRefresh, endpoint->bSynchAddress);
}
/*!
* 解析VideoStreaming Interface接口的自定义描述符
*/
static void parse_videostreaming_interface(struct usb_interface *intf,
unsigned char *buf, int buflen)
{
static const char * const colorPrims[] = { "Unspecified", "BT.709,sRGB",
"BT.470-2 (M)", "BT.470-2 (B,G)", "SMPTE 170M", "SMPTE 240M" };
static const char * const transferChars[] = { "Unspecified", "BT.709",
"BT.470-2 (M)", "BT.470-2 (B,G)", "SMPTE 170M", "SMPTE 240M",
"Linear", "sRGB"};
static const char * const matrixCoeffs[] = { "Unspecified", "BT.709",
"FCC", "BT.470-2 (B,G)", "SMPTE 170M (BT.601)", "SMPTE 240M" };
unsigned int i, m, n, p, flags, len;
/*!
* 打印所有的在VideoSteaming Interface接口下的自定义描述符
*/
while (buflen > 0) {
if (buf[1] != USB_DT_CS_INTERFACE)
printk(" Warning: Invalid descriptor\n");
else if (buf[0] < 3)
printk(" Warning: Descriptor too short\n");
printk(" VideoStreaming Interface Descriptor:\n"
" bLength %5u\n"
" bDescriptorType %5u\n"
" bDescriptorSubtype %5u ",
buf[0], buf[1], buf[2]);
switch (buf[2]) {
case 0x01: /* INPUT_HEADER */
printk("(INPUT_HEADER)\n");
p = buf[3];
n = buf[12];
if (buf[0] < 13+p*n)
printk(" Warning: Descriptor too short\n");
printk(" bNumFormats %5u\n"
" wTotalLength %5u\n"
" bEndPointAddress %5u\n"
" bmInfo %5u\n"
" bTerminalLink %5u\n"
" bStillCaptureMethod %5u\n"
" bTriggerSupport %5u\n"
" bTriggerUsage %5u\n"
" bControlSize %5u\n",
p, buf[4] | (buf[5] << 8), buf[6], buf[7], buf[8],
buf[9], buf[10], buf[11], n);
for (i = 0; i < p; i++)
printk(
" bmaControls(%2u) %5u\n",
i, buf[13+p*n]);
break;
case 0x02: /* OUTPUT_HEADER */
printk("(OUTPUT_HEADER)\n");
p = buf[3];
n = buf[8];
if (buf[0] < 9+p*n)
printk(" Warning: Descriptor too short\n");
printk(" bNumFormats %5u\n"
" wTotalLength %5u\n"
" bEndpointAddress %5u\n"
" bTerminalLink %5u\n"
" bControlSize %5u\n",
p, buf[4] | (buf[5] << 8), buf[6], buf[7], n);
for (i = 0; i < p; i++)
printk(
" bmaControls(%2u) %5u\n",
i, buf[9+p*n]);
break;
case 0x03: /* STILL_IMAGE_FRAME */
printk("(STILL_IMAGE_FRAME)\n");
n = buf[4];
m = buf[5+4*n];
if (buf[0] < 6+4*n+m)
printk(" Warning: Descriptor too short\n");
printk(" bEndpointAddress %5u\n"
" bNumImageSizePatterns %3u\n",
buf[3], n);
for (i = 0; i < n; i++)
printk(" wWidth(%2u) %5u\n"
" wHeight(%2u) %5u\n",
i, buf[5+4*i] | (buf[6+4*i] << 8),
i, buf[7+4*i] | (buf[8+4*i] << 8));
printk(" bNumCompressionPatterns %3u\n", n);
for (i = 0; i < m; i++)
printk(" bCompression(%2u) %5u\n",
i, buf[6+4*n+i]);
break;
case 0x04: /* FORMAT_UNCOMPRESSED */
case 0x10: /* FORMAT_FRAME_BASED */
if (buf[2] == 0x04) {
printk("(FORMAT_UNCOMPRESSED)\n");
len = 27;
} else {
printk("(FORMAT_FRAME_BASED)\n");
len = 28;
}
if (buf[0] < len)
printk(" Warning: Descriptor too short\n");
flags = buf[25];
printk(" bFormatIndex %5u\n"
" bNumFrameDescriptors %5u\n"
" guidFormat %s\n"
" bBitsPerPixel %5u\n"
" bDefaultFrameIndex %5u\n"
" bAspectRatioX %5u\n"
" bAspectRatioY %5u\n"
" bmInterlaceFlags 0x%02x\n",
buf[3], buf[4], get_guid(&buf[5]), buf[21], buf[22],
buf[23], buf[24], flags);
printk(" Interlaced stream or variable: %s\n",
(flags & (1 << 0)) ? "Yes" : "No");
printk(" Fields per frame: %u fields\n",
(flags & (1 << 1)) ? 1 : 2);
printk(" Field 1 first: %s\n",
(flags & (1 << 2)) ? "Yes" : "No");
printk(" Field pattern: ");
switch ((flags >> 4) & 0x03) {
case 0:
printk("Field 1 only\n");
break;
case 1:
printk("Field 2 only\n");
break;
case 2:
printk("Regular pattern of fields 1 and 2\n");
break;
case 3:
printk("Random pattern of fields 1 and 2\n");
break;
}
printk(" bCopyProtect %5u\n", buf[26]);
if (buf[2] == 0x10)
printk(" bVariableSize %5u\n", buf[27]);
break;
case 0x05: /* FRAME UNCOMPRESSED */
case 0x07: /* FRAME_MJPEG */
case 0x11: /* FRAME_FRAME_BASED */
if (buf[2] == 0x05) {
printk("(FRAME_UNCOMPRESSED)\n");
n = 25;
} else if (buf[2] == 0x07) {
printk("(FRAME_MJPEG)\n");
n = 25;
} else {
printk("(FRAME_FRAME_BASED)\n");
n = 21;
}
len = (buf[n] != 0) ? (26+buf[n]*4) : 38;
if (buf[0] < len)
printk(" Warning: Descriptor too short\n");
flags = buf[4];
printk(" bFrameIndex %5u\n"
" bmCapabilities 0x%02x\n",
buf[3], flags);
printk(" Still image %ssupported\n",
(flags & (1 << 0)) ? "" : "un");
if (flags & (1 << 1))
printk(" Fixed frame-rate\n");
printk(" wWidth %5u\n"
" wHeight %5u\n"
" dwMinBitRate %9u\n"
" dwMaxBitRate %9u\n",
buf[5] | (buf[6] << 8), buf[7] | (buf[8] << 8),
buf[9] | (buf[10] << 8) | (buf[11] << 16) | (buf[12] << 24),
buf[13] | (buf[14] << 8) | (buf[15] << 16) | (buf[16] << 24));
if (buf[2] == 0x11)
printk(" dwDefaultFrameInterval %9u\n"
" bFrameIntervalType %5u\n"
" dwBytesPerLine %9u\n",
buf[17] | (buf[18] << 8) | (buf[19] << 16) | (buf[20] << 24),
buf[21],
buf[22] | (buf[23] << 8) | (buf[24] << 16) | (buf[25] << 24));
else
printk(" dwMaxVideoFrameBufferSize %9u\n"
" dwDefaultFrameInterval %9u\n"
" bFrameIntervalType %5u\n",
buf[17] | (buf[18] << 8) | (buf[19] << 16) | (buf[20] << 24),
buf[21] | (buf[22] << 8) | (buf[23] << 16) | (buf[24] << 24),
buf[25]);
if (buf[n] == 0)
printk(" dwMinFrameInterval %9u\n"
" dwMaxFrameInterval %9u\n"
" dwFrameIntervalStep %9u\n",
buf[26] | (buf[27] << 8) | (buf[28] << 16) | (buf[29] << 24),
buf[30] | (buf[31] << 8) | (buf[32] << 16) | (buf[33] << 24),
buf[34] | (buf[35] << 8) | (buf[36] << 16) | (buf[37] << 24));
else
for (i = 0; i < buf[n]; i++)
printk(" dwFrameInterval(%2u) %9u\n",
i, buf[26+4*i] | (buf[27+4*i] << 8) |
(buf[28+4*i] << 16) | (buf[29+4*i] << 24));
break;
case 0x06: /* FORMAT_MJPEG */
printk("(FORMAT_MJPEG)\n");
if (buf[0] < 11)
printk(" Warning: Descriptor too short\n");
flags = buf[5];
printk(" bFormatIndex %5u\n"
" bNumFrameDescriptors %5u\n"
" bFlags %5u\n",
buf[3], buf[4], flags);
printk(" Fixed-size samples: %s\n",
(flags & (1 << 0)) ? "Yes" : "No");
flags = buf[9];
printk(" bDefaultFrameIndex %5u\n"
" bAspectRatioX %5u\n"
" bAspectRatioY %5u\n"
" bmInterlaceFlags 0x%02x\n",
buf[6], buf[7], buf[8], flags);
printk(" Interlaced stream or variable: %s\n",
(flags & (1 << 0)) ? "Yes" : "No");
printk(" Fields per frame: %u fields\n",
(flags & (1 << 1)) ? 2 : 1);
printk(" Field 1 first: %s\n",
(flags & (1 << 2)) ? "Yes" : "No");
printk(" Field pattern: ");
switch ((flags >> 4) & 0x03) {
case 0:
printk("Field 1 only\n");
break;
case 1:
printk("Field 2 only\n");
break;
case 2:
printk("Regular pattern of fields 1 and 2\n");
break;
case 3:
printk("Random pattern of fields 1 and 2\n");
break;
}
printk(" bCopyProtect %5u\n", buf[10]);
break;
case 0x0a: /* FORMAT_MPEG2TS */
printk("(FORMAT_MPEG2TS)\n");
len = buf[0] < 23 ? 7 : 23;
if (buf[0] < len)
printk(" Warning: Descriptor too short\n");
printk(" bFormatIndex %5u\n"
" bDataOffset %5u\n"
" bPacketLength %5u\n"
" bStrideLength %5u\n",
buf[3], buf[4], buf[5], buf[6]);
if (len > 7)
printk(" guidStrideFormat %s\n",
get_guid(&buf[7]));
break;
case 0x0d: /* COLORFORMAT */
printk("(COLORFORMAT)\n");
if (buf[0] < 6)
printk(" Warning: Descriptor too short\n");
printk(" bColorPrimaries %5u (%s)\n",
buf[3], (buf[3] <= 5) ? colorPrims[buf[3]] : "Unknown");
printk(" bTransferCharacteristics %5u (%s)\n",
buf[4], (buf[4] <= 7) ? transferChars[buf[4]] : "Unknown");
printk(" bMatrixCoefficients %5u (%s)\n",
buf[5], (buf[5] <= 5) ? matrixCoeffs[buf[5]] : "Unknown");
break;
default:
printk(" Invalid desc subtype:");
break;
}
buflen -= buf[0];
buf += buf[0];
}
}
static int myuvc_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
unsigned char *buffer;
int i, j, k, l, m;
int buflen;
int desc_len;
int desc_cnt;
static int cnt = 0;
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;
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 >> 8, descriptor->bcdUSB & 0xff,
descriptor->bDeviceClass,
descriptor->bDeviceSubClass,
descriptor->bDeviceProtocol,
descriptor->bMaxPacketSize0,
descriptor->idVendor, descriptor->idProduct,
descriptor->bcdDevice >> 8, descriptor->bcdDevice & 0xff,
descriptor->iManufacturer,
descriptor->iProduct,
descriptor->iSerialNumber,
descriptor->bNumConfigurations);
/*!
* 打印配置描述符
*/
for (i = 0; i < descriptor->bNumConfigurations; i++) {
hostconfig = &dev->config[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);
/*!
* 打印IAD描述符
*/
assoc_desc = hostconfig->intf_assoc[0];
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);
/*!
* 可能有多个接口,根据intf->num_altsetting数
* 打印每一个接口的描述符
*/
for (j = 0; j < intf->num_altsetting; j++) {
interface = &intf->altsetting[j].desc;
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 = 0; 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-1);
k = 0;
desc_cnt = 0;
while (k < buflen)
{
desc_len = buffer[k];
printk("extra desc %d: ", desc_cnt);
for (l = 0; l < desc_len; l++, k++) {
printk("%02x ", buffer[k]);
}
desc_cnt++;
printk("\n");
}
interface = &intf->cur_altsetting->desc; /**< 获取接口描述符 */
/*!
* 解析VideoControl Interface接口下的自定义描述符
*/
if ((buffer[1] == USB_DT_CS_INTERFACE) && (interface->bInterfaceSubClass == 1))
parse_videocontrol_interface(intf, buffer, buflen);
/*!
* 解析VideoStreaming Interface接口下的自定义描述符
*/
if ((buffer[1] == USB_DT_CS_INTERFACE) && (interface->bInterfaceSubClass == 2))
parse_videostreaming_interface(intf, buffer, buflen);
}
return 0;
}
static void myuvc_disconnect(struct usb_interface *intf)
{
static int cnt = 0;
printk("myuvc_disconnect : cnt = %d\n", cnt++);
}
struct usb_driver myuvc_driver = {
.name = "myuvcvideo",
.probe = myuvc_probe,
.disconnect = myuvc_disconnect,
.id_table = myuvc_ids,
};
static int myuvc_init(void)
{
int result;
result = usb_register(&myuvc_driver);
if (result == 0)
printk("USB register error!\n");
return result;
}
static void myuvc_cleanup(void)
{
usb_deregister(&myuvc_driver);
}
module_init(myuvc_init);
module_exit(myuvc_cleanup);
MODULE_LICENSE("GPL")
KERN_DIR = /usr/src/linux-headers-4.13.0-41-generic
all:
make -C $(KERN_DIR) M=`pwd` modules
clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order
obj-m += myuvc.o
执行make
,生成驱动文件并插入USB摄像头之后,卸载原先虚拟机的摄像头驱动sudo rmmod uvcvideo
,装载新驱动sudo insmod myuvc.ko
,后执行dmesg > dmesg.txt
把信息输出到txt中。
整理后的dmesg.txt
信息如下:
由于代码中支持列表中填写了VideoControl Interface
和VideoStreaming Interface
,且摄像头都支持,所以会打印两次设备描述符(两次打印的是同一个设备描述符),实际使用只需要保留第一个
对于使用的摄像头
VideoControl Interface
和VideoStreaming Interface
接口下的自定义配置 myuvc_disconnect : cnt = 0
myuvc_disconnect : cnt = 1
myuvc_probe : cnt = 0
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 239
bDeviceSubClass 2
bDeviceProtocol 1
bMaxPacketSize0 64
idVendor 0x1b3b
idProduct 0x2977
bcdDevice 1.0a
iManufacturer 0
iProduct 0
iSerial 0
bNumConfigurations 1
Configuration Descriptor 0:
bLength 9
bDescriptorType 2
wTotalLength 492
bNumInterfaces 4
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
Interface Association:
bLength 8
bDescriptorType 11
bFirstInterface 0
bInterfaceCount 2
bFunctionClass 14
bFunctionSubClass 3
bFunctionProtocol 0
iFunction 0
Interface Descriptor altsetting 0:
bLength 9
bDescriptorType 4
bInterfaceNumber 0
bAlternateSetting 0
bNumEndpoints 1
bInterfaceClass 14
bInterfaceSubClass 1
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x81 EP 1 IN
bmAttributes 3
Transfer Type Interrupt
Synch Type None
Usage Type Data
wMaxPacketSize 0x0040 1x 64 bytes
bInterval 6
extra buffer of interface 0:
extra desc 0:
0d 24 01 00 01 4d 00 80 8d 5b 00 01 01
extra desc 1:
12 24 02 01 01 02 00 00 01 00 03 00 01 00 03 80 2a 00
extra desc 2:
0b 24 05 03 01 00 00 02 3f 05 00
extra desc 3:
1a 24 06 04 3a ab 91 99 ef b2 c9 48 8f e9 8f e3 63 47 71 d0 08 01 03 01 0f 00
extra desc 4:
09 24 03 02 01 01 00 04 00
VideoControl Interface Descriptor:
bLength 13
bDescriptorType 36
bDescriptorSubtype 1
(HEADER)
bcdUVC 1.00
wTotalLength 77
dwClockFrequency 6.000000MHz
bInCollection 1
baInterfaceNr( 0) 1
VideoControl Interface Descriptor:
bLength 18
bDescriptorType 36
bDescriptorSubtype 2
(INPUT_TERMINAL)
bTerminalID 1
wTerminalType 0x0201
bAssocTerminal 0
iTerminal 0
wObjectiveFocalLengthMin 1
wObjectiveFocalLengthMax 3
wOcularFocalLength 1
bControlSize 3
bmControls 0x00002a80
Iris (Absolute)
Zoom (Absolute)
PanTilt (Absolute)
Roll (Absolute)
VideoControl Interface Descriptor:
bLength 11
bDescriptorType 36
bDescriptorSubtype 5
(PROCESSING_UNIT)
Warning: Descriptor too short
bUnitID 3
bSourceID 1
wMaxMultiplier 0
bControlSize 2
bmControls 0x0000053f
Brightness
Contrast
Hue
Saturation
Sharpness
Gamma
Backlight Compensation
Power Line Frequency
iProcessing 0
bmVideoStandards 0x1a
NTSC - 525/60
SECAM - 625/50
NTSC - 625/50
VideoControl Interface Descriptor:
bLength 26
bDescriptorType 36
bDescriptorSubtype 6
(EXTENSION_UNIT)
bUnitID 4
guidExtensionCode {3aab9199-efb2-c948-8fe9-8fe3634771d0}
bNumControl 8
bNrPins 1
baSourceID( 0) 3
bControlSize 1
bmControls( 0) 0x0f
iExtension 0
VideoControl Interface Descriptor:
bLength 9
bDescriptorType 36
bDescriptorSubtype 3
(OUTPUT_TERMINAL)
bTerminalID 2
wTerminalType 0x0101
bAssocTerminal 0
bSourceID 4
iTerminal 0
myuvc_probe : cnt = 1
Device Descriptor:
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 239
bDeviceSubClass 2
bDeviceProtocol 1
bMaxPacketSize0 64
idVendor 0x1b3b
idProduct 0x2977
bcdDevice 1.0a
iManufacturer 0
iProduct 0
iSerial 0
bNumConfigurations 1
Configuration Descriptor 0:
bLength 9
bDescriptorType 2
wTotalLength 492
bNumInterfaces 4
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
Interface Association:
bLength 8
bDescriptorType 11
bFirstInterface 0
bInterfaceCount 2
bFunctionClass 14
bFunctionSubClass 3
bFunctionProtocol 0
iFunction 0
Interface Descriptor altsetting 0:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 0
bNumEndpoints 0
bInterfaceClass 14
bInterfaceSubClass 2
bInterfaceProtocol 0
iInterface 0
Interface Descriptor altsetting 1:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 1
bNumEndpoints 1
bInterfaceClass 14
bInterfaceSubClass 2
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 5
Transfer Type Isochronous
Synch Type Asynchronous
Usage Type Data
wMaxPacketSize 0x0080 1x 128 bytes
bInterval 1
Interface Descriptor altsetting 2:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 2
bNumEndpoints 1
bInterfaceClass 14
bInterfaceSubClass 2
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 5
Transfer Type Isochronous
Synch Type Asynchronous
Usage Type Data
wMaxPacketSize 0x0100 1x 256 bytes
bInterval 1
Interface Descriptor altsetting 3:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 3
bNumEndpoints 1
bInterfaceClass 14
bInterfaceSubClass 2
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 5
Transfer Type Isochronous
Synch Type Asynchronous
Usage Type Data
wMaxPacketSize 0x0200 1x 512 bytes
bInterval 1
Interface Descriptor altsetting 4:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 4
bNumEndpoints 1
bInterfaceClass 14
bInterfaceSubClass 2
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 5
Transfer Type Isochronous
Synch Type Asynchronous
Usage Type Data
wMaxPacketSize 0x0258 1x 600 bytes
bInterval 1
Interface Descriptor altsetting 5:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 5
bNumEndpoints 1
bInterfaceClass 14
bInterfaceSubClass 2
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 5
Transfer Type Isochronous
Synch Type Asynchronous
Usage Type Data
wMaxPacketSize 0x0320 1x 800 bytes
bInterval 1
Interface Descriptor altsetting 6:
bLength 9
bDescriptorType 4
bInterfaceNumber 1
bAlternateSetting 6
bNumEndpoints 1
bInterfaceClass 14
bInterfaceSubClass 2
bInterfaceProtocol 0
iInterface 0
Endpoint Descriptor:
bLength 7
bDescriptorType 5
bEndpointAddress 0x82 EP 2 IN
bmAttributes 5
Transfer Type Isochronous
Synch Type Asynchronous
Usage Type Data
wMaxPacketSize 0x03bc 1x 956 bytes
bInterval 1
extra buffer of interface 1:
extra desc 0:
0e 24 01 01 79 00 82 00 02 00 00 01 01 00
extra desc 1:
0b 24 06 01 03 00 01 00 00 00 00
extra desc 2:
1e 24 07 01 01 80 02 e0 01 00 28 23 00 00 28 23 00 00 2c 01 00 15 16 05 00 01 15 16 05 00
extra desc 3:
1e 24 07 02 01 40 01 f0 00 00 ca 08 00 00 ca 08 00 00 4b 00 00 15 16 05 00 01 15 16 05 00
extra desc 4:
1e 24 07 03 01 a0 00 78 00 80 32 02 00 80 32 02 00 c0 12 00 00 15 16 05 00 01 15 16 05 00
extra desc 5:
06 24 0d 01 01 04
VideoStreaming Interface Descriptor:
bLength 14
bDescriptorType 36
bDescriptorSubtype 1
(INPUT_HEADER)
bNumFormats 1
wTotalLength 121
bEndPointAddress 130
bmInfo 0
bTerminalLink 2
bStillCaptureMethod 0
bTriggerSupport 0
bTriggerUsage 1
bControlSize 1
bmaControls( 0) 11
VideoStreaming Interface Descriptor:
bLength 11
bDescriptorType 36
bDescriptorSubtype 6
(FORMAT_MJPEG)
bFormatIndex 1
bNumFrameDescriptors 3
bFlags 0
Fixed-size samples: No
bDefaultFrameIndex 1
bAspectRatioX 0
bAspectRatioY 0
bmInterlaceFlags 0x00
Interlaced stream or variable: No
Fields per frame: 1 fields
Field 1 first: No
Field pattern:
Field 1 only
bCopyProtect 0
VideoStreaming Interface Descriptor:
bLength 30
bDescriptorType 36
bDescriptorSubtype 7
(FRAME_MJPEG)
bFrameIndex 1
bmCapabilities 0x01
Still image supported
wWidth 640
wHeight 480
dwMinBitRate 2304000
dwMaxBitRate 2304000
dwMaxVideoFrameBufferSize 76800
dwDefaultFrameInterval 333333
bFrameIntervalType 1
dwFrameInterval( 0) 333333
VideoStreaming Interface Descriptor:
bLength 30
bDescriptorType 36
bDescriptorSubtype 7
(FRAME_MJPEG)
bFrameIndex 2
bmCapabilities 0x01
Still image supported
wWidth 320
wHeight 240
dwMinBitRate 576000
dwMaxBitRate 576000
dwMaxVideoFrameBufferSize 19200
dwDefaultFrameInterval 333333
bFrameIntervalType 1
dwFrameInterval( 0) 333333
VideoStreaming Interface Descriptor:
bLength 30
bDescriptorType 36
bDescriptorSubtype 7
(FRAME_MJPEG)
bFrameIndex 3
bmCapabilities 0x01
Still image supported
wWidth 160
wHeight 120
dwMinBitRate 144000
dwMaxBitRate 144000
dwMaxVideoFrameBufferSize 4800
dwDefaultFrameInterval 333333
bFrameIntervalType 1
dwFrameInterval( 0) 333333
VideoStreaming Interface Descriptor:
bLength 6
bDescriptorType 36
bDescriptorSubtype 13
(COLORFORMAT)
bColorPrimaries 1 (BT.709,sRGB)
bTransferCharacteristics 1 (BT.709)
bMatrixCoefficients 4 (SMPTE 170M (BT.601))