USB摄像头描述符参数获取和来源分析(上)

简介: USB摄像头描述符参数获取和来源分析

描述符

USB设备描述符

Interface Descriptor(接口描述符):用于描述USB设备中的一个接口,包括接口号、接口类别、子类别、协议等信息。

VideoControl Interface Descriptor(视频控制接口描述符):描述支持摄像头控制功能的接口,例如调整设置、控制曝光、对焦、白平衡等。

VideoStreaming Interface Descriptor(视频流接口描述符):描述支持视频流传输的接口,指定视频流的设置和参数,如分辨率、帧率、压缩类型等。

Endpoint Descriptor(端点描述符):描述接口中的端点的属性和功能,包括端点号、传输类型、端点方向、最大包大小等。

描述符

USB摄像头参数获取

myuvc.c

#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 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_video_control_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_video_streaming_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 = 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;
    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(j = 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;
            if((buffer[1] == USB_DT_CS_INTERFACE) && (interface->bInterfaceSubClass == 1)){
                parse_video_control_interface(intf,buffer,buflen);
            }
            if((buffer[1] == USB_DT_CS_INTERFACE) && (interface->bInterfaceSubClass == 2)){
                parse_video_streaming_interface(intf,buffer,buflen);
            }
    }
    return 0;
}
void myuvc_disconnect (struct usb_interface *intf){
    static int cnt = 0;
    printk("myuvc_disconnect : cnt = %d\n", cnt++);
}
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 */
    {}
};
/* 1.分配usb_deiver结构体 */
/* 2.设置 */
static struct usb_driver myuvc_driver = {
    .name        = "myuvc", // 驱动名
    .probe        = myuvc_probe, // 探测函数
    .disconnect = myuvc_disconnect, // 断开连接函数    
    .id_table    = myuvc_ids, // 设备 ID 表
};
//入口
static int myuvc_init(void){
    /* 3.注册 */
    usb_register(&myuvc_driver);
    return 0;
}
static void myuvvc_exit(void){
    usb_deregister(&myuvc_driver);
}
module_init(myuvc_init);
module_exit(myuvvc_exit);
MODULE_LICENSE("GPL");

结果

device descriptor设备描述符

在USB摄像头的Device Descriptor(设备描述符)中,中文指的是产品的语言ID。Device Descriptor是USB设备的一部分,它包含有关设备的基本信息,如厂商ID、产品ID、设备类别和子类别等。

configuration descriptor配置描述符

在USB摄像头的Configuration Descriptor(配置描述符)中,中文指的是配置描述符的语言ID。Configuration Descriptor是USB设备的一部分,它描述了设备的一个或多个配置。

interface association接口关联

Interface Association(接口关联)是USB设备描述符中的一个字段,用于关联多个接口,表示它们在逻辑上是相关联的。

inteface desciptor atsetting

videocontrol interface descriptor视频控制接口描述符

在USB摄像头中,VideoControl Interface Descriptor(视频控制接口描述符)是用于描述摄像头控制功能的USB接口描述符。

videostreaming interface descriptor

在USB摄像头中,VideoStreaming Interface Descriptor(视频流接口描述符)用于描述支持视频流传输的USB接口。

与VideoControl Interface Descriptor类似,VideoStreaming Interface Descriptor也不包含中文字段或语言ID。它提供了关于视频流接口的基本属性和功能的描述,如接口号、接口类别、子类别、协议等。

VideoStreaming Interface Descriptor用于指定与视频数据流相关的设置和参数,包括视频格式、分辨率、帧率、压缩类型等。它使得应用程序或操作系统能够了解和配置摄像头的视频流传输功能。

需要注意的是,与语言相关的信息通常在设备描述符或配置描述符中找到,以确定设备支持的语言设置和本地化信息,而不是直接包含在VideoStreaming Interface Descriptor中。

endpoint descriptor端点描述符

在USB摄像头中,Endpoint Descriptor(端点描述符)用于描述USB接口中的端点(endpoint)的属性和功能。

Endpoint Descriptor并不包含中文字段或语言ID。它提供了有关端点的基本信息,包括端点号、传输类型(例如控制、批量、等等)、端点方向(输入或输出)、最大包大小、传输间隔等。

对于USB摄像头,通常会使用两个端点:一个用于视频流的传输,另一个用于控制命令的传输。视频流传输端点负责实时传输图像数据,而控制端点负责传输设置和命令以控制摄像头的行为。

Endpoint Descriptor允许操作系统和应用程序了解端点的特性,例如数据传输方向、传输类型和数据包的大小,以便正确地配置和管理摄像头的数据传输。

目录
相关文章
|
4月前
|
缓存 Linux API
动态DMA映射使用通用设备 【ChatGPT】
动态DMA映射使用通用设备 【ChatGPT】
|
4月前
|
存储 缓存 安全
动态DMA映射指南 【ChatGPT】
动态DMA映射指南 【ChatGPT】
|
内存技术
USB摄像头描述符参数获取和来源分析(下)
USB摄像头描述符参数获取和来源分析(下)
90 0
|
存储 算法 搜索推荐
pacs系统源码,医学图像信息的快速采集、传输、存储、显示和后处理
PACS系统以实现医学影像数字化存储、诊断为核心任务,从医学影像设备(如CT、CR、DR、MR、DSA、RF等)获取影像,集中存储、综合管理医学影像及病人相关信息,建立数字化工作流程。 系统可实现检查预约、病人信息登记、计算机阅片、电子报告书写、胶片打印、数据备份等一系列满足影像科室日常工作的功能,并且由于影像数字化存储,用户可利用影像处理与测量技术辅助诊断、方便快捷地查找资料或利用网络将资料传输至临床科室
|
物联网
STM32:TIM输入捕获硬件部分(内含:1.输入捕获简介+2.频率测量+3.通用/高级定时器的输入捕获电路分析(重点)+4.主从触发模式+5.输入捕获基本结构(重点)+6.PWM基本结构)
STM32:TIM输入捕获硬件部分(内含:1.输入捕获简介+2.频率测量+3.通用/高级定时器的输入捕获电路分析(重点)+4.主从触发模式+5.输入捕获基本结构(重点)+6.PWM基本结构)
564 0
STM32:TIM输入捕获硬件部分(内含:1.输入捕获简介+2.频率测量+3.通用/高级定时器的输入捕获电路分析(重点)+4.主从触发模式+5.输入捕获基本结构(重点)+6.PWM基本结构)
多个音频轨无法在sdi传递解决方案思路
多个音频轨无法在sdi传递解决方案思路
108 0
多个音频轨无法在sdi传递解决方案思路
|
编解码 C++
UVC调用过程部分细节分析
UVC调用过程部分细节分析
632 0
|
传感器 算法 机器人
将执行器「缝」进衣袖,斯坦福无接触设备,远程传递触摸信息
将执行器「缝」进衣袖,斯坦福无接触设备,远程传递触摸信息
UVC 基础学习(6):端点描述符介绍
今天带大家认识一下UVC端点描述符信息。
545 0
|
传感器 数据处理
VM系列振弦采集读取模块激励方法
什么是振弦传感器采集读数模块:指针对振弦传感器的特性而设计的传感器激励、读数模块。具有集成度高、功能模块化、数字接口的一系列特性,能完成振弦 传感器的激励、信号检测、数据处理、质量评估等专用针对性功能,进行传感器频率和温度物理量模数转换,进而通过数字接口实现数据交互。振弦传感器读数模块是振弦传感器与数字化、信息化之间的核心转换单元。
VM系列振弦采集读取模块激励方法