USB摄像头驱动---UVC驱动的文件描述符分析

文件描述符

在linux的眼里,everything is file!每一个设备也是一个文件。打开一个文件,这个文件对应一个唯一的正整数,直至文件关闭,内核回收文件描述符。内核(kernel)利用文件描述符(file descriptor)来访问文件。 文件描述符是非负整数。 打开现存文件或新建文件时,内核会返回一个文件描述符。 读写文件也需要使用文件描述符来指定待读写的文件。

标准设备描述符

在这里插入图片描述
每个设备对应一个设备描述符,设备有多个配置(对应多个配置描述符),配置中有多个接口,接口下面又有多个端点。

USB视频描述符层次结构

在这里插入图片描述
首先,阐明一个观点,一个USB视频设备只会暴露一个VC(video control)interface,而VS (Video control)interface是属于VC interface或者说可以从VC(video control)interface找到VS interface。
ps:
IAD:Interface Association Descriptor 接口联合描述符。这个描述符告诉使用者有一个VC、多少个VS、第一个是谁!
途中白框表示标准设备描述符所提供的的信息,灰色的框表示UVC自定义的特殊描述符信息(类似一些亮度,白平衡,锐化等信息都在灰色框中定义)

描述符的提取以及分析

#include <linux/atomic.h>
#include <linux/kernel.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/videodev2.h>
#include <linux/vmalloc.h>
#include <linux/wait.h>
#include <linux/version.h>
#include <asm/unaligned.h>

#include <media/v4l2-common.h>

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;
}

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 > 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 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 > 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 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);

}
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 >> 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);
		
		/*打印的是接口联合体运算符*/
		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);



		/*打印接口描述符*/
		/*打印该接口下面的多个设置*/
		/*这里的设置就是描述符的信息*/
		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;	/*UVC类所定义的描述符都在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");
		}

		/*分析UVC自定义的描述符*/
		interface = &intf->cur_altsetting->desc;
		if ((buffer[1] == USB_DT_CS_INTERFACE) && (interface->bInterfaceSubClass == 1))
		{
			/*解析VC的数据*/
			parse_videocontrol_interface(intf, buffer, buflen);
		}
		if ((buffer[1] == USB_DT_CS_INTERFACE) && (interface->bInterfaceSubClass == 2))
		{
			/*分析VS interface的信息*/
			parse_videostreaming_interface(intf, buffer, buflen);
		}
			
	}
	return 0;
}
static void myuvc_disconnect(struct usb_interface *intf)
{
	static int cnt;
	printk("myuvc_disconnect : cnt = %d\n", cnt++);
}
/*myuvc_ids里面可以填充某个厂家特定的设备,也可以填充通用的设备*/
/*内核比对id成功一次调用一次probe函数,拔除设备时一样会比对id调用myuvc_disconnect函数*/
/*这是是两个通用设备,所以会调用两次*/
static struct usb_device_id myuvc_ids[] = {
	/* Generic USB Video Class */
	/*这个设备属于USB_CLASS_VIDEO类,子类是1(VIDEOControl视频控制接口),协议是0*/
	/*流接口属于控制接口,可以通过控制接口找到流接口*/
	{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },	/*VdieoControl Interface*/
	{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 2, 0) },	/*VdieoStreaming Interface*/
	{}
};
/*1.分配一个usb_driver结构体*/
/*2.设置*/
/*id_table表示支持哪些设备*/
/*probe表示接上支持的设备时,probe函数就会被调用*/
/*disconnect表示拔除设备后会调用该函数进行销毁的工作*/
static struct usb_driver myuvc_driver = {
	.name = "myuvc",
	.probe = myuvc_probe,
	.disconnect = myuvc_disconnect,
	.id_table = myuvc_ids,
};

static int myuvc_init(void)
{
	/*注册*/
	usb_register(&myuvc_driver);
	return 0;
}

static void myuvc_exit(void)
{
	usb_deregister(&myuvc_driver);
}

module_init(myuvc_init);
module_exit(myuvc_exit);

MODULE_LICENSE("GPL");



对于设备的成功调用与否,需要比对id_table中的信息,里面可以是特定厂家提供的设备,也可以是通用设备。

自定义描述符的内容

VideoControl Interface的自定义描述符:
extra buffer of interface 0:
extra desc 0: 0d 24 01 00 01 4d 00 80 c3 c9 01 01 01
在这里插入图片描述
在这里插入图片描述
第一个字节表示该描述符的长度,第二个字节标书CS(class special)类型,第三个字节表示子类型,一次按着TABLE 3-3比对解析。

VC_INPUT_TERMINAL (IT) :
extra desc 1: 12 24 02 01 01 02 00 00 00 00 00 00 00 00 03 0e 00 00
在这里插入图片描述
VC_OUTPUT_TERMINAL (OT):
extra desc 2: 09 24 03 02 01 01 00 04 00
在这里插入图片描述
VC_PROCESSING_UNIT (PU):
extra desc 3: 0b 24 05 03 01 00 00 02 7f 14 00
在这里插入图片描述在这里插入图片描述
VC_EXTENSION_UNIT (EU):
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 interface中内部的结构:
IT(01) ===> PU(03) ===> EU(04) ===> OT(02)

VideoStreaming Interface的自定义描述符:

VS_INPUT_HEADER :
extra desc 0: 0e 24 01 01 df 00 81 00 02 02 01 01 01 00
在这里插入图片描述
在这里插入图片描述
VS_FORMAT_UNCOMPRESSED :
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
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
General UVC摄像头驱动是一种通用视频类设备驱动程序,用于支持各种品牌和型号的UVCUSB Video Class)摄像头在计算机上的正常工作。UVC是一个通用的摄像头驱动标准,它可以使摄像头设备在不同的操作系统和平台上使用相同的驱动程序,并且无需另行安装驱动程序。 General UVC摄像头驱动具有以下几个重要特点: 1. 通用性:该驱动适用于大多数UVC兼容的摄像头设备,因此用户无需为每个品牌和型号的摄像头安装不同的驱动程序。这使得使用和管理摄像头设备变得更加简便。 2. 兼容性:该驱动可以与多种操作系统和平台兼容,包括Windows、Mac和Linux等。这意味着用户可以在不同的平台上使用同一款摄像头,而无需为每个平台安装单独的驱动程序。 3. 稳定性:这种驱动经过精心设计和测试,具有较高的稳定性和可靠性。它能够确保摄像头设备在各种操作环境下都可以正常工作,并提供稳定的视频和音频传输。 4. 简易安装:安装General UVC摄像头驱动非常简单,通常只需将驱动程序插入计算机的USB接口并按照驱动安装向导的指示进行操作即可。这使得用户能够快速地将摄像头设备连接到计算机上并投入使用。 综上所述,General UVC摄像头驱动是一种通用、兼容、稳定且易于安装的摄像头设备驱动程序,使用户能够方便地使用各种品牌和型号的UVC摄像头设备。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值