前面的博客已经分析了USB摄像头驱动程序的框架,我们知道了USB摄像头驱动程序的重点在于1)描述符的分析;2)属性的控制(通过VC来设置);3)格式的选择(通过VS来设置);4)数据的获得(通过VS的URB来获得)。后面的博客就会从这4个方面进行深入的分析,本篇博客首先来看一下UVC驱动程序的描述符分析。

回顾之前的内容https://www.cnblogs.com/-glb/p/11568992.html,每一个USB设备都有一个设备描述符,设备描述符中有配置描述符,配置描述符中有接口描述符,接口描述符中有端点描述符。

在进行分析之前,首先来看一张USB摄像头的描述符的布局

USB摄像头驱动之描述符分析(上)

 

 白色的描述符是每个usb设备都要支持的,灰色的部分是UVC规范自己定义的。本篇博客将围绕这张图进行讲解,将图中的描述符打印出来,来个直观的感受

1.史上最简单的USB摄像头驱动程序

Myuvc.c

#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 int myuvc_probe(struct usb_interface *intf,
             const struct usb_device_id *id)
{
    static int cnt = 0;
    printk("myuvc_probe : cnt \n", cnt++);

    return 0;
    
}

static void myuvc_disconnect(struct usb_interface *intf)
{
    static int cnt = 0;
    printk("myuvc_probe : cnt \n", cnt++);

}

static struct usb_device_id myuvc_ids[] = {

    /* Generic USB Video Class */
    { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
    {}
};

/*1.分配一个usb driver结构体*/
static struct usb_driver myuvc_driver = {
    .name = "myuvc",
    .probe = myuvc_probe,
    .disconnect = myuvc_disconnect,
    .id_table = myuvc_ids,

};


/*2.设置*/

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

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

module_init(myuvc_init);
module_exit(myuvc_exit);
MODULE_LICENSE("GPL v2");

1.1分析USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) 

USB_INTERFACE_INFO是一个宏,首先看一下该宏是如何定义的:

#define USB_INTERFACE_INFO(cl, sc, pr) \
    .match_flags = USB_DEVICE_ID_MATCH_INT_INFO, \
    .bInterfaceClass = (cl), \
    .bInterfaceSubClass = (sc), \
    .bInterfaceProtocol = (pr)
    

第一个参数cl:表示Video interface class 

第二个参数sc:表示Video interface subclass

第三个参数pr:表示Video interface protocol

#define USB_CLASS_VIDEO  0x0e

USB摄像头驱动之描述符分析(上)

USB摄像头驱动之描述符分析(上)

USB摄像头驱动之描述符分析(上)

任意一个USB摄像头,它都有一个视频控制接口,在这个地方为什么不把视频流接口也放上去呢?
因为只要硬件上有视频控制接口,就可以根据视频控制接口找到从属于此视频控制接口的视频流接口。

上面这个驱动程序没有实际的意义,只是当我们插上USB摄像头的时候,会将USB摄像头的接口个数进行打印。在程序中,我们只有一个视频控制接口,所有cnt的值为1.

注意:在进行试验的时候,首先将ubuntu中自带的USB摄像头驱动程序去掉,然后安装上我们自己编写的USB摄像头驱动程序。

2. 打印设备描述符

lsusb
Bus 001 Device 007: ID 1e4e: 0102
Bus 001 Device 007: ID 1d6b: 0002 Linux Foundation 2.0 root hub
Bus 001 Device 007: ID 1e4e: 0001 Linux Foundation 1.1 root hub
lsusb.c:
main
    dumpdev
        dump_device
        dump_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]);
#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 int myuvc_probe(struct usb_interface *intf,
             const struct usb_device_id *id)
{
    static int cnt = 0;
    struct usb_device *udev = interface_to_usbdev(intf);
    struct usb_device_descriptor *descriptor = &dev->descriptor;
    printk("myuvc_probe : cnt \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);

    return 0;
    
}

static void myuvc_disconnect(struct usb_interface *intf)
{
    static int cnt = 0;
    printk("myuvc_probe : cnt \n", cnt++);

}

static struct usb_device_id myuvc_ids[] = {

    /* Generic USB Video Class */
    { USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
    {}
};

/*1.分配一个usb driver结构体*/
static struct usb_driver myuvc_driver = {
    .name = "myuvc",
    .probe = myuvc_probe,
    .disconnect = myuvc_disconnect,
    .id_table = myuvc_ids,

};


/*2.设置*/

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

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

module_init(myuvc_init);
module_exit(myuvc_exit);
MODULE_LICENSE("GPL v2");
View Code

相关文章:

  • 2022-01-01
  • 2021-09-11
  • 2022-01-12
  • 2022-12-23
  • 2022-01-01
  • 2021-09-21
  • 2021-06-26
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-01-01
  • 2021-10-28
  • 2021-12-11
  • 2021-06-07
相关资源
相似解决方案