• V4L2驱动框架


    V4L2驱动框架

    主设备号: 81

    次设备号:
        0-63
        64-67
        192-223
        224-255

    /dev/videoX    

    应用层
    ————————————
    char驱动
    ————————————
    V4L2
    ————————————
    具体的驱动
    ————————————
    硬件




    应用层的操作都需要有底层V4L2驱动的支持。内核中有一些非常完善的例子。比如:linux-2.6.26内核目录drivers/media/video/vivi.c中的驱动代码实例。


    1、V4L2驱动注册、注销函数
    static int __init videodev_init(void)        //注册256个视频设备
    {
            dev_t dev = MKDEV(VIDEO_MAJOR, 0);
            int ret;

            printk(KERN_INFO "Linux video capture interface: v2.00\n");
            ret = register_chrdev_region(dev, VIDEO_NUM_DEVICES, VIDEO_NAME);
            if (ret < 0) {
                    printk(KERN_WARNING "videodev: unable to get major %d\n", VIDEO_MAJOR);
                    return ret;
            }

            ret = class_register(&video_class);
            if (ret < 0) {
                    unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
                    printk(KERN_WARNING "video_dev: class_register failed\n");
                    return -EIO;
            }

            return 0;
    }

    static void __exit videodev_exit(void)
    {
            dev_t dev = MKDEV(VIDEO_MAJOR, 0);

            class_unregister(&video_class);
            unregister_chrdev_region(dev, VIDEO_NUM_DEVICES);
    }

    module_init(videodev_init)
    module_exit(videodev_exit)


    2、函数实现

    2.1
    Video核心层(drivers/media/video/videodev.c)提供了注册函数供具体的V4L2驱动调用:
    int video_register_device(struct video_device *vfd, int type, int nr)
        —video_device: 要构建的核心数据结构
        —Type: 表示设备类型,此设备号的基地址受此变量的影响
        —Nr: 如果end-base>nr>0 :次设备号=base(基准值,受type影响)+nr;否则:系统自动分配合适的次设备号

    函数内部调用
    static int __video_register_device(struct video_device *vdev, int type, int nr, int warn_if_nr_in_use)
    具体驱动只需要构建video_device结构,然后调用注册函数既可。

    2.2
    Video核心层(drivers/media/video/videodev.c)提供了注销函数
    void video_unregister_device(struct video_device *vdev)

    核心定义设备数组,其中VIDEO_NUM_DEVICES 为 256 是最大设备数
    static struct video_device *video_device[VIDEO_NUM_DEVICES];

    2.3
    V4L2提供了统一的应用层接口

    static const struct file_operations v4l2_fops = {
            .owner = THIS_MODULE,
            .read = v4l2_read,
            .write = v4l2_write,
            .open = v4l2_open,
            .mmap = v4l2_mmap,
            .unlocked_ioctl = v4l2_ioctl,
    #ifdef CONFIG_COMPAT
            .compat_ioctl = v4l2_compat_ioctl32,
    #endif
            .release = v4l2_release,
            .poll = v4l2_poll,
            .llseek = no_llseek,
    };
    v4l2_read定义如下
    static ssize_t v4l2_read(struct file *filp, char __user *buf, size_t sz, loff_t *off)
    {
            struct video_device *vdev = video_devdata(filp);
            int ret = -ENODEV;

            if (!vdev->fops->read)
                    return -EINVAL;
            if (vdev->lock && mutex_lock_interruptible(vdev->lock))
                    return -ERESTARTSYS;
            if (video_is_registered(vdev))
                    ret = vdev->fops->read(filp, buf, sz, off);
            if (vdev->lock)
                    mutex_unlock(vdev->lock);
            return ret;
    }

    函数内部调用的    vdev->fops->read  由具体的V4L2驱动实现


    驱动开发

    定义最重要的数据结构体struct video_device,
    其中,重要的是
    const struct v4l2_file_operations *fops;    //帧缓冲操作

    编写帧缓冲驱动的主要工作就是编写fops各个成员函数

    编写具体驱动方法步骤:
    1、构建具体驱动的struct video_device;
    3、构建具体驱动的struct fops,并定义相关的操作函数;

    4、定义具体驱动的XXX_probe。

    struct video_device
    {
            /* device ops */
            const struct v4l2_file_operations *fops;

            /* sysfs */
            struct device dev;              /* v4l device */
            struct cdev *cdev;              /* character device */

            /* Set either parent or v4l2_dev if your driver uses v4l2_device */
            struct device *parent;          /* device parent */
            struct v4l2_device *v4l2_dev;   /* v4l2_device parent */

            /* Control handler associated with this device node. May be NULL. */
            struct v4l2_ctrl_handler *ctrl_handler;

            /* device info */
            char name[32];
            int vfl_type;
            /* 'minor' is set to -1 if the registration failed */
            int minor;
            u16 num;
            /* use bitops to set/clear/test flags */
            unsigned long flags;
            /* attribute to differentiate multiple indices on one physical device */
            int index;

            /* V4L2 file handles */
            spinlock_t              fh_lock; /* Lock for all v4l2_fhs */
            struct list_head        fh_list; /* List of struct v4l2_fh */

            int debug;                      /* Activates debug level*/

            /* Video standard vars */
            v4l2_std_id tvnorms;            /* Supported tv norms */
            v4l2_std_id current_norm;       /* Current tvnorm */

            /* callbacks */
            void (*release)(struct video_device *vdev);

            /* ioctl callbacks */
            const struct v4l2_ioctl_ops *ioctl_ops;

            /* serialization lock */
            struct mutex *lock;
    };
    ================================================================================
    struct v4l2_file_operations {
            struct module *owner;
            ssize_t (*read) (struct file *, char __user *, size_t, loff_t *);
            ssize_t (*write) (struct file *, const char __user *, size_t, loff_t *);
            unsigned int (*poll) (struct file *, struct poll_table_struct *);
            long (*ioctl) (struct file *, unsigned int, unsigned long);
            long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
            int (*mmap) (struct file *, struct vm_area_struct *);
            int (*open) (struct file *);
            int (*release) (struct file *);
    };
    ================================================================================
    struct device {
            struct device           *parent;
            struct device_private   *p;
            struct kobject kobj;
            const char              *init_name;/* initial name of the device */
            struct device_type      *type;
            struct mutex            mutex;      /* mutex to synchronize calls to its driver. */
            struct bus_type *bus;               /* type of bus device is on */
            struct device_driver     *driver;    /* which driver has allocated this device */
            void                *platform_data; /* Platform specific data, device core doesn't touch it */
            struct dev_pm_info      power;
    #ifdef CONFIG_NUMA
            int                 numa_node;      /* NUMA node this device is close to */
    #endif
            u64                 *dma_mask;      /* dma mask (if dma'able device) */
            u64                 coherent_dma_mask;/* Like dma_mask, but for alloc_coherent mappings as not all hardware supports 64 bit ses for consistent allocations such descriptors. */
            struct device_dma_parameters *dma_parms;
            struct list_head        dma_pools;      /* dma pools (if dma'ble) */
            struct dma_coherent_mem *dma_mem; /* internal for coherent mem override */
            /* arch specific additions */
            struct dev_archdata     archdata;
    #ifdef CONFIG_OF
            struct device_node      *of_node;
    #endif
            dev_t                   devt;   /* dev_t, creates the sysfs "dev" */
            spinlock_t              devres_lock;
            struct list_head        devres_head;
            struct klist_node       knode_class;
            struct class            *class;
            const struct attribute_group **groups;  /* optional groups */
            void    (*release)(struct device *dev);
    };
    ================================================================================
    struct cdev {
            struct kobject kobj;
            struct module *owner;
            const struct file_operations *ops;
            struct list_head list;
            dev_t dev;
            unsigned int count;
    };
    ================================================================================
    struct v4l2_device {
            struct device *dev;    /* dev->driver_data points to this struct. Note: dev might be NULL if there is no parent device as is the case with e.g. ISA devices. */
            struct list_head subdevs;          /* used to keep track of the registered subdevs */
            spinlock_t lock;  /* lock this struct; can be used by the driver as well if this struct is embedded into a larger struct. */
            char name[V4L2_DEVICE_NAME_SIZE];        /* unique device name, by default the driver name + bus ID */
            void (*notify)(struct v4l2_subdev *sd, unsigned int notification, void *arg);        /* notify callback called by some sub-devices. */
            struct v4l2_ctrl_handler *ctrl_handler;        /* The control handler. May be NULL. */
            struct mutex ioctl_lock;        /* BKL replacement mutex. Temporary solution only. */
    };
    ================================================================================
    struct v4l2_ioctl_ops {
            /* ioctl callbacks */
            /* VIDIOC_QUERYCAP handler */
            int (*vidioc_querycap)(struct file *file, void *fh, struct v4l2_capability *cap);
            /* Priority handling */
            int (*vidioc_g_priority)   (struct file *file, void *fh, enum v4l2_priority *p);
            int (*vidioc_s_priority)   (struct file *file, void *fh, enum v4l2_priority p);
            /* VIDIOC_ENUM_FMT handlers */
            int (*vidioc_enum_fmt_vid_cap)     (struct file *file, void *fh, struct v4l2_fmtdesc *f);
            int (*vidioc_enum_fmt_vid_overlay) (struct file *file, void *fh, struct v4l2_fmtdesc *f);
            int (*vidioc_enum_fmt_vid_out)     (struct file *file, void *fh, struct v4l2_fmtdesc *f);
            int (*vidioc_enum_fmt_type_private)(struct file *file, void *fh, struct v4l2_fmtdesc *f);
            /* VIDIOC_G_FMT handlers */
            int (*vidioc_g_fmt_vid_cap)    (struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_g_fmt_vid_overlay)(struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_g_fmt_vid_out)    (struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_g_fmt_vid_out_overlay)(struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_g_fmt_vbi_cap)    (struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_g_fmt_vbi_out)    (struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_g_fmt_sliced_vbi_cap)(struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_g_fmt_sliced_vbi_out)(struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_g_fmt_type_private)(struct file *file, void *fh, struct v4l2_format *f);
            /* VIDIOC_S_FMT handlers */
            int (*vidioc_s_fmt_vid_cap)    (struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_s_fmt_vid_overlay)(struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_s_fmt_vid_out)    (struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_s_fmt_vid_out_overlay)(struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_s_fmt_vbi_cap)    (struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_s_fmt_vbi_out)    (struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_s_fmt_sliced_vbi_cap)(struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_s_fmt_sliced_vbi_out)(struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_s_fmt_type_private)(struct file *file, void *fh, struct v4l2_format *f);
            /* VIDIOC_TRY_FMT handlers */
            int (*vidioc_try_fmt_vid_cap)    (struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_try_fmt_vid_overlay)(struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_try_fmt_vid_out)    (struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_try_fmt_vid_out_overlay)(struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_try_fmt_vbi_cap)    (struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_try_fmt_vbi_out)    (struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_try_fmt_sliced_vbi_cap)(struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_try_fmt_sliced_vbi_out)(struct file *file, void *fh, struct v4l2_format *f);
            int (*vidioc_try_fmt_type_private)(struct file *file, void *fh, struct v4l2_format *f);
            /* Buffer handlers */
            int (*vidioc_reqbufs) (struct file *file, void *fh, struct v4l2_requestbuffers *b);
            int (*vidioc_querybuf)(struct file *file, void *fh, struct v4l2_buffer *b);
            int (*vidioc_qbuf)    (struct file *file, void *fh, struct v4l2_buffer *b);
            int (*vidioc_dqbuf)   (struct file *file, void *fh, struct v4l2_buffer *b);
            int (*vidioc_overlay)    (struct file *file, void *fh, unsigned int i);
            int (*vidioc_g_fbuf)    (struct file *file, void *fh, struct v4l2_framebuffer *a);
            int (*vidioc_s_fbuf)    (struct file *file, void *fh, struct v4l2_framebuffer *a);
            /* Stream on/off */
            int (*vidioc_streamon)    (struct file *file, void *fh, enum v4l2_buf_type i);
            int (*vidioc_streamoff)    (struct file *file, void *fh, enum v4l2_buf_type i);
            /* Standard handling ENUMSTD is handled by videodev.c */
            int (*vidioc_g_std)     (struct file *file, void *fh, v4l2_std_id *norm);
            int (*vidioc_s_std)     (struct file *file, void *fh, v4l2_std_id *norm);
            int (*vidioc_querystd)     (struct file *file, void *fh, v4l2_std_id *a);
            /* Input handling */
            int (*vidioc_enum_input)    (struct file *file, void *fh, struct v4l2_input *inp);
            int (*vidioc_g_input)       (struct file *file, void *fh, unsigned int *i);
            int (*vidioc_s_input)       (struct file *file, void *fh, unsigned int i);
            /* Output handling */
            int (*vidioc_enum_output)    (struct file *file, void *fh, struct v4l2_output *a);
            int (*vidioc_g_output)       (struct file *file, void *fh, unsigned int *i);
            int (*vidioc_s_output)       (struct file *file, void *fh, unsigned int i);
            /* Control handling */
            int (*vidioc_queryctrl)        (struct file *file, void *fh, struct v4l2_queryctrl *a);
            int (*vidioc_g_ctrl)           (struct file *file, void *fh, struct v4l2_control *a);
            int (*vidioc_s_ctrl)           (struct file *file, void *fh, struct v4l2_control *a);
            int (*vidioc_g_ext_ctrls)      (struct file *file, void *fh, struct v4l2_ext_controls *a);
            int (*vidioc_s_ext_ctrls)      (struct file *file, void *fh, struct v4l2_ext_controls *a);
            int (*vidioc_try_ext_ctrls)    (struct file *file, void *fh, struct v4l2_ext_controls *a);
            int (*vidioc_querymenu)        (struct file *file, void *fh, struct v4l2_querymenu *a);
            /* Audio ioctls */
            int (*vidioc_enumaudio)        (struct file *file, void *fh, struct v4l2_audio *a);
            int (*vidioc_g_audio)          (struct file *file, void *fh, struct v4l2_audio *a);
            int (*vidioc_s_audio)          (struct file *file, void *fh, struct v4l2_audio *a);
            /* Audio out ioctls */
            int (*vidioc_enumaudout)       (struct file *file, void *fh, struct v4l2_audioout *a);
            int (*vidioc_g_audout)         (struct file *file, void *fh, struct v4l2_audioout *a);
            int (*vidioc_s_audout)         (struct file *file, void *fh, struct v4l2_audioout *a);
            int (*vidioc_g_modulator)      (struct file *file, void *fh, struct v4l2_modulator *a);
            int (*vidioc_s_modulator)      (struct file *file, void *fh, struct v4l2_modulator *a);
            /* Crop ioctls */
            int (*vidioc_cropcap)          (struct file *file, void *fh, struct v4l2_cropcap *a);
            int (*vidioc_g_crop)           (struct file *file, void *fh, struct v4l2_crop *a);
            int (*vidioc_s_crop)           (struct file *file, void *fh, struct v4l2_crop *a);
            /* Compression ioctls */
            int (*vidioc_g_jpegcomp)       (struct file *file, void *fh, struct v4l2_jpegcompression *a);
            int (*vidioc_s_jpegcomp)       (struct file *file, void *fh, struct v4l2_jpegcompression *a);
            int (*vidioc_g_enc_index)      (struct file *file, void *fh, struct v4l2_enc_idx *a);
            int (*vidioc_encoder_cmd)      (struct file *file, void *fh, struct v4l2_encoder_cmd *a);
            int (*vidioc_try_encoder_cmd)  (struct file *file, void *fh, struct v4l2_encoder_cmd *a);
            /* Stream type-dependent parameter ioctls */
            int (*vidioc_g_parm)           (struct file *file, void *fh, struct v4l2_streamparm *a);
            int (*vidioc_s_parm)           (struct file *file, void *fh, struct v4l2_streamparm *a);
            /* Tuner ioctls */
            int (*vidioc_g_tuner)          (struct file *file, void *fh, struct v4l2_tuner *a);
            int (*vidioc_s_tuner)          (struct file *file, void *fh, struct v4l2_tuner *a);
            int (*vidioc_g_frequency)      (struct file *file, void *fh, struct v4l2_frequency *a);
            int (*vidioc_s_frequency)      (struct file *file, void *fh, struct v4l2_frequency *a);
            /* Sliced VBI cap */
            int (*vidioc_g_sliced_vbi_cap) (struct file *file, void *fh, struct v4l2_sliced_vbi_cap *a);
            /* Log status ioctl */
            int (*vidioc_log_status)       (struct file *file, void *fh);
            int (*vidioc_s_hw_freq_seek)   (struct file *file, void *fh, struct v4l2_hw_freq_seek *a);
            /* Debugging ioctls */
    #ifdef CONFIG_VIDEO_ADV_DEBUG
            int (*vidioc_g_register)       (struct file *file, void *fh, struct v4l2_dbg_register *reg);
            int (*vidioc_s_register)       (struct file *file, void *fh, struct v4l2_dbg_register *reg);
    #endif
            int (*vidioc_g_chip_ident)       (struct file *file, void *fh, struct v4l2_dbg_chip_ident *chip);
            int (*vidioc_enum_framesizes)      (struct file *file, void *fh, struct v4l2_frmsizeenum *fsize);
            int (*vidioc_enum_frameintervals)  (struct file *file, void *fh, struct v4l2_frmivalenum *fival);
            /* DV Timings IOCTLs */
            int (*vidioc_enum_dv_presets)  (struct file *file, void *fh, struct v4l2_dv_enum_preset *preset);
            int (*vidioc_s_dv_preset)      (struct file *file, void *fh, struct v4l2_dv_preset *preset);
            int (*vidioc_g_dv_preset)      (struct file *file, void *fh, struct v4l2_dv_preset *preset);
            int (*vidioc_query_dv_preset)  (struct file *file, void *fh, struct v4l2_dv_preset *qpreset);
            int (*vidioc_s_dv_timings)     (struct file *file, void *fh, struct v4l2_dv_timings *timings);
            int (*vidioc_g_dv_timings)     (struct file *file, void *fh, struct v4l2_dv_timings *timings);
            int (*vidioc_subscribe_event)  (struct v4l2_fh *fh, struct v4l2_event_subscription *sub);
            int (*vidioc_unsubscribe_event)(struct v4l2_fh *fh, struct v4l2_event_subscription *sub);
            /* For other private ioctls */
            long (*vidioc_default)         (struct file *file, void *fh, int cmd, void *arg);
    };

    ================================================================================

    ================================================================================

    ================================================================================

    static struct ov7670_format_struct {
            enum v4l2_mbus_pixelcode mbus_code;
            enum v4l2_colorspace colorspace;
            struct regval_list *regs;
            int cmatrix[CMATRIX_LEN];
        int bpp;
    } ov7670_format_struct ov7670_formats[] = {
        /* "YUYV 4:2:2"     */
            .desc        = "YUYV 4:2:2",
            .pixelformat    = V4L2_PIX_FMT_YUYV,
            .regs         = ov7670_fmt_yuv422,
            .cmatrix    = { 128, -128, 0, -34, -94, 128 },
            .bpp        = 2,
        /* "UYVY 4:2:2"     */
        /* "RGB 444"        */
        /* "RGB 565"        */
        /* "Raw RGB Bayer"  */
    }
    #define N_OV7670_FMTS ARRAY_SIZE(ov7670_formats)

    struct v4l2_fmtdesc {
            __u32               index;             /* Format number      */
            enum v4l2_buf_type  type;              /* buffer type        */
            __u32               flags;
            __u8                description[32];   /* Description string */
            __u32               pixelformat;       /* Format fourcc      */
            __u32               reserved[4];
    };
     
    //每一个subdev驱动程序实例应该创建这个结构,无论是独立或在一个更大的结构之中。
    struct v4l2_subdev {
            struct list_head list;
            struct module *owner;
            u32 flags;
            struct v4l2_device *v4l2_dev;
            const struct v4l2_subdev_ops *ops;
            /* name must be unique */
            char name[V4L2_SUBDEV_NAME_SIZE];
            /* can be used to group similar subdevs, value is driver-specific */
            u32 grp_id; 
            /* pointer to private data */
            void *priv;
    }; 
    struct v4l2_pix_format { 
            __u32                   width;
            __u32                   height;
            __u32                   pixelformat;
            enum v4l2_field         field;
            __u32                   bytesperline;   /* for padding, zero if unused */
            __u32                   sizeimage;
            enum v4l2_colorspace    colorspace;
            __u32                   priv;           /* private data, depends on pixelformat */
    };  

    struct v4l2_format { 
            enum v4l2_buf_type type;
            union { 
                    struct v4l2_pix_format          pix;     /* V4L2_BUF_TYPE_VIDEO_CAPTURE */
                    struct v4l2_window              win;     /* V4L2_BUF_TYPE_VIDEO_OVERLAY */
                    struct v4l2_vbi_format          vbi;     /* V4L2_BUF_TYPE_VBI_CAPTURE */
                    struct v4l2_sliced_vbi_format   sliced;  /* V4L2_BUF_TYPE_SLICED_VBI_CAPTURE */
                    __u8    raw_data[200];                   /* user-defined */
            } fmt;
    };

    static struct ov7670_win_size {
            int     width;
            int     height;
            unsigned char com7_bit;
            int     hstart;         /* Start/stop values for the camera.  Note */
            int     hstop;          /* that they do not always make complete */
            int     vstart;         /* sense to humans, but evidently the sensor */
            int     vstop;          /* will do the right thing... */
            struct regval_list *regs; /* Regs to tweak */
                    /* h/vref stuff */
    } ov7670_win_sizes[] = {
        /* VGA */
        /* CIF */
        /* QVGA */
        /* QCIF */
    }
    #define N_WIN_SIZES (ARRAY_SIZE(ov7670_win_sizes))

    Live together,or Die alone!
  • 相关阅读:
    134. Gas Station
    135. Candy
    137. Single Number II
    136. Single Number
    138. Copy List with Random Pointer
    140. Word Break II(hard)
    139. Word Break
    笔试面试知识点
    OA的一些概念
    实验记录贴 —— 账号同步实验 RTX 和 LDAP(AD域)
  • 原文地址:https://www.cnblogs.com/hzhida/p/2524417.html
Copyright © 2020-2023  润新知