linux系统上插上USB摄像头设备后,内存就会有相应的设备描述符信息,后期可以根据这些信息进一步写驱动程序。

流程:Device(设备) -> Configuration(配置) -> IAD I/F(接口联合体描述符-对接口的管理,比如数量和调用顺序等)

查看UVC 1.5 Cloass Specification 规范手册
框架调用流程:IT(01) -> PU(03) -> EU(04) -> OT(02)

<Video Control Interface> 处理函数 parse_videocontrol_interface()--------------------------------------------

VideoControl Interface的自定义描述符:
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
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_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

<Video Streaming Interface> 处理函数 parse_videostreaming_interface()--------------------------------------

VideoStreaming Interface的自定义描述符:
extra buffer of interface 1:
extra desc 0: 0e 24 01 01 df 00 81 00 02 02 01 01 01 00
VS_INPUT_HEADER bNumFormats
extra desc 1: 1b 24 04 01 05 59 55 59 32 00 00 10 00 80 00 00 aa 00 38 9b 71 10 01 00 00 00 00
VS_FORMAT_UNCOMPRESSED bFormatIndex bNumFrameDescriptors GUID bBitsPerPixel
extra desc 2: 1e 24 05 01 00 80 02 e0 01 00 00 ca 08 00 00 ca 08 00 60 09 00 15 16 05 00 01 15 16 05 00
VS_FRAME_UNCOMPRESSED bFrameIndex bmCapabilities wWidth wHeight
640x480
extra desc 3: 1e 24 05 02 00 60 01 20 01 00 80 e6 02 00 80 e6 02 00 18 03 00 15 16 05 00 01 15 16 05 00
VS_FRAME_UNCOMPRESSED
extra desc 4: 1e 24 05 03 00 40 01 f0 00 00 80 32 02 00 80 32 02 00 58 02 00 15 16 05 00 01 15 16 05 00
extra desc 5: 1e 24 05 04 00 b0 00 90 00 00 a0 b9 00 00 a0 b9 00 00 c6 00 00 15 16 05 00 01 15 16 05 00
extra desc 6: 1e 24 05 05 00 a0 00 78 00 00 a0 8c 00 00 a0 8c 00 00 96 00 00 15 16 05 00 01 15 16 05 00

extra desc 7: 1a 24 03 00 05 80 02 e0 01 60 01 20 01 40 01 f0 00 b0 00 90 00 a0 00 78 00 00
VS_STILL_IMAGE_FRAME
extra desc 8: 06 24 0d 01 01 04

VS_INPUT_HEADER 0x01
VS_STILL_IMAGE_FRAME 0x03
VS_FORMAT_UNCOMPRESSED 0x04
VS_FRAME_UNCOMPRESSED 0x05
VS_COLORFORMAT 0x0D

//参考 lsusb 源码得知如何去实现获取设备描述符:
main
  ->list_devices
   ->dumpdev(libusb_device *dev)
     ->dump_device(udev, &desc);
    ->dump_config(udev, config); //打印出配置描述符
       ->for (i = 0 ; i < config->bNumInterfaces ; i++) //每个设置可能对应多个接口
       dump_interface(dev, &config->interface[i]);
        ->for (i = 0; i < interface->num_altsetting; i++) //每个接口设置描述符
        dump_altsetting(dev, &interface->altsetting[i]);

//lsusb 命令打印出设备ID
Bus 002 Device 006: ID 1b3b:2977

//lsusb -v -d 0x1b3b : 命令打印出设备详细描述符
Bus 002 Device 007: ID 1b3b:2977
Device Descriptor: //设备描述符
bLength 18
bDescriptorType 1
bcdUSB 2.00
bDeviceClass 239 Miscellaneous Device
bDeviceSubClass 2 ?
bDeviceProtocol 1 Interface Association
bMaxPacketSize0 64
idVendor 0x1b3b
idProduct 0x2977
bcdDevice 1.0a
iManufacturer 0
iProduct 0
iSerial 0
bNumConfigurations 1
Configuration Descriptor: //配置描述符
bLength 9
bDescriptorType 2
wTotalLength 492
bNumInterfaces 4
bConfigurationValue 1
iConfiguration 0
bmAttributes 0x80
(Bus Powered)
MaxPower 500mA
Interface Association: //接口
bLength 8
bDescriptorType 11
bFirstInterface 0
bInterfaceCount 2
bFunctionClass 14 Video
bFunctionSubClass 3 Video Interface Collection
bFunctionProtocol 0
iFunction 0
.....................................

/*--------------------------------------------以下代码实现获取通用usb摄像头设备描述符信息-----------------------------------------------------*/

参考:lsusb - 源代码《libusb-1.0.16-rc10》 《usbutils-006》

//注:本份代码仅实现设备描述符的获取和解析
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/videodev2.h>
#include <linux/vmalloc.h>
#include <linux/wait.h>
#include <asm/atomic.h>
#include <asm/unaligned.h> #include <media/v4l2-common.h> //支持的设备类型信息
static struct usb_device_id sheldon_uvc_ids[] = {
/* Generic USB Video Class */
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, , ) },/*1-视频控制接口*/
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, , ) },/*2-视频流控制接口(被1包含)*/
{}
}; static const char *get_guid(const unsigned char *buf)
{
static char guid[]; /* 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[], buf[], buf[], buf[],
buf[], buf[],
buf[], buf[],
buf[], buf[],
buf[], buf[], buf[], buf[], buf[], buf[]);
return guid;
} 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; while (buflen > )
{ if (buf[] != USB_DT_CS_INTERFACE)
printk(" Warning: Invalid descriptor\n");
else if (buf[] < )
printk(" Warning: Descriptor too short\n");
printk(" VideoControl Interface Descriptor:\n"
" bLength %5u\n"
" bDescriptorType %5u\n"
" bDescriptorSubtype %5u ",
buf[], buf[], buf[]);
switch (buf[]) {
case 0x01: /* HEADER */
printk("(HEADER)\n");
n = buf[];
if (buf[] < +n)
printk(" Warning: Descriptor too short\n");
freq = buf[] | (buf[] << ) | (buf[] << ) | (buf[] << );
printk(" bcdUVC %2x.%02x\n"
" wTotalLength %5u\n"
" dwClockFrequency %5u.%06uMHz\n"
" bInCollection %5u\n",
buf[], buf[], buf[] | (buf[] << ), freq / ,
freq % , n);
for (i = ; i < n; i++)
printk(" baInterfaceNr(%2u) %5u\n", i, buf[+i]);
break; case 0x02: /* INPUT_TERMINAL */
printk("(INPUT_TERMINAL)\n");
termt = buf[] | (buf[] << );
n = termt == 0x0201 ? : ;
if (buf[] < + n)
printk(" Warning: Descriptor too short\n");
printk(" bTerminalID %5u\n"
" wTerminalType 0x%04x\n"
" bAssocTerminal %5u\n",
buf[], termt, buf[]);
printk(" iTerminal %5u\n",
buf[]);
if (termt == 0x0201) {
n += buf[];
printk(" wObjectiveFocalLengthMin %5u\n"
" wObjectiveFocalLengthMax %5u\n"
" wOcularFocalLength %5u\n"
" bControlSize %5u\n",
buf[] | (buf[] << ), buf[] | (buf[] << ),
buf[] | (buf[] << ), buf[]);
ctrls = ;
for (i = ; i < && i < buf[]; i++)
ctrls = (ctrls << ) | buf[+n-i-];
printk(" bmControls 0x%08x\n", ctrls);
for (i = ; i < ; i++)
if ((ctrls >> i) & )
printk(" %s\n", camctrlnames[i]);
}
break; case 0x03: /* OUTPUT_TERMINAL */
printk("(OUTPUT_TERMINAL)\n");
termt = buf[] | (buf[] << );
if (buf[] < )
printk(" Warning: Descriptor too short\n");
printk(" bTerminalID %5u\n"
" wTerminalType 0x%04x\n"
" bAssocTerminal %5u\n"
" bSourceID %5u\n"
" iTerminal %5u\n",
buf[], termt, buf[], buf[], buf[]);
break; case 0x04: /* SELECTOR_UNIT */
printk("(SELECTOR_UNIT)\n");
p = buf[];
if (buf[] < +p)
printk(" Warning: Descriptor too short\n"); printk(" bUnitID %5u\n"
" bNrInPins %5u\n",
buf[], p);
for (i = ; i < p; i++)
printk(" baSource(%2u) %5u\n", i, buf[+i]);
printk(" iSelector %5u\n",
buf[+p]);
break; case 0x05: /* PROCESSING_UNIT */
printk("(PROCESSING_UNIT)\n");
n = buf[];
if (buf[] < +n)
printk(" Warning: Descriptor too short\n");
printk(" bUnitID %5u\n"
" bSourceID %5u\n"
" wMaxMultiplier %5u\n"
" bControlSize %5u\n",
buf[], buf[], buf[] | (buf[] << ), n);
ctrls = ;
for (i = ; i < && i < n; i++)
ctrls = (ctrls << ) | buf[+n-i-];
printk(" bmControls 0x%08x\n", ctrls);
for (i = ; i < ; i++)
if ((ctrls >> i) & )
printk(" %s\n", ctrlnames[i]);
stds = buf[+n];
printk(" iProcessing %5u\n"
" bmVideoStandards 0x%2x\n", buf[+n], stds);
for (i = ; i < ; i++)
if ((stds >> i) & )
printk(" %s\n", stdnames[i]);
break; case 0x06: /* EXTENSION_UNIT */
printk("(EXTENSION_UNIT)\n");
p = buf[];
n = buf[+p];
if (buf[] < +p+n)
printk(" Warning: Descriptor too short\n");
printk(" bUnitID %5u\n"
" guidExtensionCode %s\n"
" bNumControl %5u\n"
" bNrPins %5u\n",
buf[], get_guid(&buf[]), buf[], buf[]);
for (i = ; i < p; i++)
printk(" baSourceID(%2u) %5u\n", i, buf[+i]);
printk(" bControlSize %5u\n", buf[+p]);
for (i = ; i < n; i++)
printk(" bmControls(%2u) 0x%02x\n", i, buf[+p+i]);
printk(" iExtension %5u\n",
buf[+p+n]);
break; default:
printk("(unknown)\n"
" Invalid desc subtype:");
break;
} buflen -= buf[];
buf += buf[];
}
} 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; while (buflen > )
{ if (buf[] != USB_DT_CS_INTERFACE)
printk(" Warning: Invalid descriptor\n");
else if (buf[] < )
printk(" Warning: Descriptor too short\n");
printk(" VideoStreaming Interface Descriptor:\n"
" bLength %5u\n"
" bDescriptorType %5u\n"
" bDescriptorSubtype %5u ",
buf[], buf[], buf[]);
switch (buf[]) {
case 0x01: /* INPUT_HEADER */
printk("(INPUT_HEADER)\n");
p = buf[];
n = buf[];
if (buf[] < +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[] | (buf[] << ), buf[], buf[], buf[],
buf[], buf[], buf[], n);
for (i = ; i < p; i++)
printk(
" bmaControls(%2u) %5u\n",
i, buf[+p*n]);
break; case 0x02: /* OUTPUT_HEADER */
printk("(OUTPUT_HEADER)\n");
p = buf[];
n = buf[];
if (buf[] < +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[] | (buf[] << ), buf[], buf[], n);
for (i = ; i < p; i++)
printk(
" bmaControls(%2u) %5u\n",
i, buf[+p*n]);
break; case 0x03: /* STILL_IMAGE_FRAME */
printk("(STILL_IMAGE_FRAME)\n");
n = buf[];
m = buf[+*n];
if (buf[] < +*n+m)
printk(" Warning: Descriptor too short\n");
printk(" bEndpointAddress %5u\n"
" bNumImageSizePatterns %3u\n",
buf[], n);
for (i = ; i < n; i++)
printk(" wWidth(%2u) %5u\n"
" wHeight(%2u) %5u\n",
i, buf[+*i] | (buf[+*i] << ),
i, buf[+*i] | (buf[+*i] << ));
printk(" bNumCompressionPatterns %3u\n", n);
for (i = ; i < m; i++)
printk(" bCompression(%2u) %5u\n",
i, buf[+*n+i]);
break; case 0x04: /* FORMAT_UNCOMPRESSED */
case 0x10: /* FORMAT_FRAME_BASED */
if (buf[] == 0x04) {
printk("(FORMAT_UNCOMPRESSED)\n");
len = ;
} else {
printk("(FORMAT_FRAME_BASED)\n");
len = ;
}
if (buf[] < len)
printk(" Warning: Descriptor too short\n");
flags = buf[];
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[], buf[], get_guid(&buf[]), buf[], buf[],
buf[], buf[], flags);
printk(" Interlaced stream or variable: %s\n",
(flags & ( << )) ? "Yes" : "No");
printk(" Fields per frame: %u fields\n",
(flags & ( << )) ? : );
printk(" Field 1 first: %s\n",
(flags & ( << )) ? "Yes" : "No");
printk(" Field pattern: ");
switch ((flags >> ) & 0x03) {
case :
printk("Field 1 only\n");
break;
case :
printk("Field 2 only\n");
break;
case :
printk("Regular pattern of fields 1 and 2\n");
break;
case :
printk("Random pattern of fields 1 and 2\n");
break;
}
printk(" bCopyProtect %5u\n", buf[]);
if (buf[] == 0x10)
printk(" bVariableSize %5u\n", buf[]);
break; case 0x05: /* FRAME UNCOMPRESSED */
case 0x07: /* FRAME_MJPEG */
case 0x11: /* FRAME_FRAME_BASED */
if (buf[] == 0x05) {
printk("(FRAME_UNCOMPRESSED)\n");
n = ;
} else if (buf[] == 0x07) {
printk("(FRAME_MJPEG)\n");
n = ;
} else {
printk("(FRAME_FRAME_BASED)\n");
n = ;
}
len = (buf[n] != ) ? (+buf[n]*) : ;
if (buf[] < len)
printk(" Warning: Descriptor too short\n");
flags = buf[];
printk(" bFrameIndex %5u\n"
" bmCapabilities 0x%02x\n",
buf[], flags);
printk(" Still image %ssupported\n",
(flags & ( << )) ? "" : "un");
if (flags & ( << ))
printk(" Fixed frame-rate\n");
printk(" wWidth %5u\n"
" wHeight %5u\n"
" dwMinBitRate %9u\n"
" dwMaxBitRate %9u\n",
buf[] | (buf[] << ), buf[] | (buf[] << ),
buf[] | (buf[] << ) | (buf[] << ) | (buf[] << ),
buf[] | (buf[] << ) | (buf[] << ) | (buf[] << ));
if (buf[] == 0x11)
printk(" dwDefaultFrameInterval %9u\n"
" bFrameIntervalType %5u\n"
" dwBytesPerLine %9u\n",
buf[] | (buf[] << ) | (buf[] << ) | (buf[] << ),
buf[],
buf[] | (buf[] << ) | (buf[] << ) | (buf[] << ));
else
printk(" dwMaxVideoFrameBufferSize %9u\n"
" dwDefaultFrameInterval %9u\n"
" bFrameIntervalType %5u\n",
buf[] | (buf[] << ) | (buf[] << ) | (buf[] << ),
buf[] | (buf[] << ) | (buf[] << ) | (buf[] << ),
buf[]);
if (buf[n] == )
printk(" dwMinFrameInterval %9u\n"
" dwMaxFrameInterval %9u\n"
" dwFrameIntervalStep %9u\n",
buf[] | (buf[] << ) | (buf[] << ) | (buf[] << ),
buf[] | (buf[] << ) | (buf[] << ) | (buf[] << ),
buf[] | (buf[] << ) | (buf[] << ) | (buf[] << ));
else
for (i = ; i < buf[n]; i++)
printk(" dwFrameInterval(%2u) %9u\n",
i, buf[+*i] | (buf[+*i] << ) |
(buf[+*i] << ) | (buf[+*i] << ));
break; case 0x06: /* FORMAT_MJPEG */
printk("(FORMAT_MJPEG)\n");
if (buf[] < )
printk(" Warning: Descriptor too short\n");
flags = buf[];
printk(" bFormatIndex %5u\n"
" bNumFrameDescriptors %5u\n"
" bFlags %5u\n",
buf[], buf[], flags);
printk(" Fixed-size samples: %s\n",
(flags & ( << )) ? "Yes" : "No");
flags = buf[];
printk(" bDefaultFrameIndex %5u\n"
" bAspectRatioX %5u\n"
" bAspectRatioY %5u\n"
" bmInterlaceFlags 0x%02x\n",
buf[], buf[], buf[], flags);
printk(" Interlaced stream or variable: %s\n",
(flags & ( << )) ? "Yes" : "No");
printk(" Fields per frame: %u fields\n",
(flags & ( << )) ? : );
printk(" Field 1 first: %s\n",
(flags & ( << )) ? "Yes" : "No");
printk(" Field pattern: ");
switch ((flags >> ) & 0x03) {
case :
printk("Field 1 only\n");
break;
case :
printk("Field 2 only\n");
break;
case :
printk("Regular pattern of fields 1 and 2\n");
break;
case :
printk("Random pattern of fields 1 and 2\n");
break;
}
printk(" bCopyProtect %5u\n", buf[]);
break; case 0x0a: /* FORMAT_MPEG2TS */
printk("(FORMAT_MPEG2TS)\n");
len = buf[] < ? : ;
if (buf[] < len)
printk(" Warning: Descriptor too short\n");
printk(" bFormatIndex %5u\n"
" bDataOffset %5u\n"
" bPacketLength %5u\n"
" bStrideLength %5u\n",
buf[], buf[], buf[], buf[]);
if (len > )
printk(" guidStrideFormat %s\n",
get_guid(&buf[]));
break; case 0x0d: /* COLORFORMAT */
printk("(COLORFORMAT)\n");
if (buf[] < )
printk(" Warning: Descriptor too short\n");
printk(" bColorPrimaries %5u (%s)\n",
buf[], (buf[] <= ) ? colorPrims[buf[]] : "Unknown");
printk(" bTransferCharacteristics %5u (%s)\n",
buf[], (buf[] <= ) ? transferChars[buf[]] : "Unknown");
printk(" bMatrixCoefficients %5u (%s)\n",
buf[], (buf[] <= ) ? matrixCoeffs[buf[]] : "Unknown");
break; default:
printk(" Invalid desc subtype:");
break;
}
buflen -= buf[];
buf += buf[];
}
} //打印端点描述符
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 & ],
syncattr[(endpoint->bmAttributes >> ) & ],
usage[(endpoint->bmAttributes >> ) & ],
wmax, hb[(wmax >> ) & ], wmax & 0x7ff,
endpoint->bInterval);
/* only for audio endpoints */
if (endpoint->bLength == )
printk(" bRefresh %5u\n"
" bSynchAddress %5u\n",
endpoint->bRefresh, endpoint->bSynchAddress); } //probe处理函数,有匹配usb设备时调用
static int sheldon_uvc_probe(struct usb_interface *intf, const struct usb_device_id *id)
{
static int cnt;
static int i, j ,k ,l ,m; unsigned char *buffer;
int buflen; int desc_len;
//int desc_cnt; //根据interface结构体获得usb_device结构体,其中包含了设备描述符
struct usb_device *dev = interface_to_usbdev(intf);
//此处需要定义一个描述符结构体
struct usb_device_descriptor *descriptor = &dev->descriptor; //从usb_device结构体中获得配置描述符相关信息
struct usb_host_config *host_config;
struct usb_config_descriptor *config;
//端点描述符
struct usb_endpoint_descriptor *endpoint; //定义接口联合体描述符结构体,获得 IAD 接口
struct usb_interface_assoc_descriptor *assoc_desc;
//定义接口设置信息结构体
struct usb_interface_descriptor *idesc; printk("----sheldon_uvc_probe : cnt = %d----\n",cnt++); //打印第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++)
{
host_config = &dev->config[i];
config = &host_config->desc;
printk(" Configuration Descriptor Configuration %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 = host_config->intf_assoc[];
printk(" Interface Association: %d\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",
i,
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++)
{
idesc = &intf->altsetting[j].desc;
printk(" Interface Descriptor: %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,
idesc->bLength, idesc->bDescriptorType, idesc->bInterfaceNumber,
idesc->bAlternateSetting, idesc->bNumEndpoints, idesc->bInterfaceClass,
idesc->bInterfaceSubClass, idesc->bInterfaceProtocol,
idesc->iInterface); //打印intf接口里的第i个设置的第m个端点的描述符
for (m = ; m < idesc->bNumEndpoints; m++)
{
endpoint = &intf->altsetting[j].endpoint[m].desc;
dump_endpoint(endpoint);
}
}
//buffer存着设备自定义的描述符(第一个字节描述 长度)
buffer = intf->cur_altsetting->extra;
//自定义描述符长度
buflen = intf->cur_altsetting->extralen; printk("extra buffer of interface %d \n",cnt-); //desc_cnt = 0; //第几个额外的描述符
k = ;
while(k < buflen) //打印描述符
{
desc_len = buffer[k]; //从下一个描述符的第一个字节获得其长度
printk("extra desc %d \n",k);
for(l = ; l < desc_len; l++ ,k++) //保证k指向下一个描述符的第一个字节
{
printk("%02x ", buffer[k]);
}
//desc_cnt++;
printk("\n");
} idesc = &intf->cur_altsetting->desc;
//判断是CS还是VS,
if((buffer[] == USB_DT_CS_INTERFACE) && (idesc->bInterfaceSubClass == ))
{
parse_videocontrol_interface(intf, buffer, buflen);
}
if((buffer[] == USB_DT_CS_INTERFACE) && (idesc->bInterfaceSubClass == ))
{
parse_videostreaming_interface(intf, buffer, buflen);
}
} return ;
} //disconnect函数,设备断开时调用
static void sheldon_uvc_disconnect(struct usb_interface *intf)
{
static int cnt;
printk("sheldon_uvc_disconnect : cnt = %d\n",cnt++);
} //1.分配usb_driver结构体
//2.设置 static struct usb_driver sheldon_uvc_driver = {
.name = "sheldon_uvc",
.id_table = sheldon_uvc_ids,
.probe = sheldon_uvc_probe,
.disconnect = sheldon_uvc_disconnect,
}; static int sheldon_uvc_init(void)
{
//3.注册
printk("sheldon_uvc_init ~\n");
usb_register(&sheldon_uvc_driver);
return ;
} static void sheldon_uvc_exit(void)
{
printk("sheldon_uvc_exit ~\n");
usb_deregister(&sheldon_uvc_driver);
} module_init(sheldon_uvc_init);
module_exit(sheldon_uvc_exit);
MODULE_LICENSE("GPL");

/*-------------附Makefile-----------*/

KERN_DIR = /usr/src/linux-headers-2.6.--generic/

all:
make -C $(KERN_DIR) M=`pwd` modules clean:
make -C $(KERN_DIR) M=`pwd` modules clean
rm -rf modules.order obj-m += sheldon_uvc.o

Linux摄像头驱动学习之:(五)UVC-分析设备描述符的更多相关文章

  1. Linux摄像头驱动学习之:(六)UVC-基本框架代码分析

    仿照内核的自带UVC(usb video class)驱动程序写的一版简化驱动,仅供学习,实际项目开发中应该尽量使用内核自带的驱动,除非内核自带的驱动不支持此款硬件才需要自己写驱动. 下面就直接上代码 ...

  2. Linux摄像头驱动学习之:(一)V4L2_框架分析

    这段时间开始搞安卓camera底层驱动了,把以前的的Linux视频驱动回顾一下,本篇主要概述一下vfl2(video for linux 2). 一. V4L2框架: video for linux ...

  3. Linux摄像头驱动学习之:(四)UVC-摄像头驱动框架分析

    UVC: USB Video ClassUVC驱动:drivers\media\video\uvc\ uvc_driver.c分析:1. usb_register(&uvc_driver.dr ...

  4. Linux摄像头驱动学习之:(二)通过虚拟驱动vivi分析摄像头驱动

    一.通过指令 "strace -o xawtv.log xawtv" 得到以下调用信息:// 1~7都是在v4l2_open里调用1. open2. ioctl(4, VIDIOC ...

  5. Linux摄像头驱动学习之:(三)从零写虚拟驱动(仿照vivi.c)

    本篇仿照vivi.c 写虚拟视频驱动,代码(myvivi.c+fillbuf.c+Makefile)如下: //==========================myvivi.c========== ...

  6. Linux 网卡驱动学习(五)(收发包具体过程)【转】

    转自:https://blog.csdn.net/xy010902100449/article/details/47362787 版权声明:本文为博主原创文章,未经博主允许不得转载. https:// ...

  7. Linux内核驱动学习(五)KThread学习总结

    文章目录 简介 例程 运行结果 参考 简介 使用内核线程需要包含头文件#include <linux/kthread.h>,下面整理了一下常用的api接口,如下表格所示: 函数 功能 st ...

  8. Linux内核驱动学习(八)GPIO驱动模拟输出PWM

    文章目录 前言 原理图 IO模拟输出PWM 设备树 驱动端 调试信息 实验结果 附录 前言 上一篇的学习中介绍了如何在用户空间直接操作GPIO,并写了一个脚本可以产生PWM.本篇的学习会将写一个驱动操 ...

  9. 找回了当年一篇V4L2 linux 摄像头驱动的博客

    从csdn找回 , 无缘无故被封了..当时损失不少啊!!!!!!!!! linux 摄像头驱动 :核心数据结构:    /**     * struct fimc_dev - abstraction ...

随机推荐

  1. CentOS 安装Zookeeper-3.4.6 单节点

    Dubbo 建议使用 Zookeeper 作为服务的注册中心. 注册中心服务器(192.168.3.71)配置,安装 Zookeeper: 1. 修改操作系统的/etc/hosts 文件中添加: #  ...

  2. [问题2014A04] 解答

    [问题2014A04]  解答 (1) 由条件可得 \(AB+BA=0\), 即 \(AB=-BA\), 因此 \[AB=A^2B=A(AB)=A(-BA)=-(AB)A=-(-BA)A=BA^2=B ...

  3. CentOS 6.5搭建PPTP VPN服务器

    VPN是虚拟专用网络(Virtual Private Network)的缩写,VPN有多种分类方式,包括PPTP.L2TP.IPSec等,本文配置的VPN服务器是采用PPTP协议的,PPTP是在PPP ...

  4. 《BI那点儿事》数据流转换——审核

    审核转换允许对数据流添加审核审核数据,以往使用HIPPA和Sarbanes-Oxley (SOX)时,必须跟踪谁在什么时插入数据,审核转换可以实现这种功能.例如要跟踪那一个task向表里插入数据,可以 ...

  5. python 中的[::-1]

    for value in rang(10)涉及的数字倒序输出: for value in rang(10)[::-1]涉及的数字倒序输出: 一.反转 二.详解 这个是python的slice nota ...

  6. python的class的__str__()和__repr__()函数

    repr(object) 返回一个可以用来表示对象的可打印字符串首先,尝试生成这样一个字符串,将其传给 eval()可重新生成同样的对象 否则,生成用尖括号包住的字符串,包含类型名和额外的信息(比如地 ...

  7. remot debug

    哎,首先吐槽一下,尼玛这是什么编辑器居然不能直接复制粘贴我写好的东西,废话不多说.为什么可以远程调试呢?首先JAVA运行依赖JVM,所以你可以把这种 远程debug想象成两个或者多个JVM之间按照约定 ...

  8. Spring + Mybatis 使用 PageHelper 插件分页

    原文:http://www.cnblogs.com/yucongblog/p/5330886.html 先增加maven依赖: <dependency> <groupId>co ...

  9. Makefile-入门与进阶【转】

    from:here 一.入门 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为那些Windows的IDE都为你做了这个工作,但我觉得要作一个好的和professional的 ...

  10. cube定时器延时不准确原因

    昨天晚上测试32cube配置好定时器,以1ms为一次中断,然后在程序中做了一个1s的延时,结果发现实际延时5s左右,百思不得其解,仔细查看cube配置也没问题.最后我打开生成工程文件夹里面的ioc文件 ...