V4L2 driver(一). 整体框架
1.1 從字符設備說起
熟悉v4l2用戶空間編程的都知道, v4l2編程主要是調用一系列的ioctl函數去對v4l2設備進行打開, 關閉, 查詢, 設置等操作. v4l2設備是一個字符設備, 而且其驅動的主要工作就是實現各種各樣的ioctl.?
v4l2的整體框架如下圖所示
V4L2的整體框架圖?
上圖中, 淡綠色背景為用戶空間, 淡藍色背景為內核空間. 橢圓表示相關的結構體, 子系統或實例. 方框表示相關的接口. 藍色的橢圓表示這部分屬于v4l2-core的內容. 從圖中可以看出用戶空間通過file_operations接口與內核空間進行交互, 因此驅動必須實現file_operations中的相關的內容, 其中比較重要的幾個函數是open,?release,?ioctl,?mmap,?poll.?read和write是可以不需要實現的. 因為為了效率v4l2基本都是使用流io的方式來進行數據傳輸的. 在v4l2的核心中對這個file_operations的實現如下:
static const struct file_operations v4l2_fops = {.owner = THIS_MODULE,.read = v4l2_read,.write = v4l2_write,.open = v4l2_open,.get_unmapped_area = v4l2_get_unmapped_area,.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, };- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
這個v4l2_fops函數最終綁定在一個cdev上, 并注冊到系統中. 之后對該v4l2設備的調用都是通過這個cdev的設備節點進行調用的. 這個cdev的指針被一個video_device結構體引用, 從而將cdev封裝到了v4l2的框架中.
1.2 v4l2_fops的封裝
這里以這個fops的mmap為例:
static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm) {struct video_device *vdev = video_devdata(filp);int ret = -ENODEV;if (!vdev->fops->mmap)return -ENODEV;if (video_is_registered(vdev))ret = vdev->fops->mmap(filp, vm);if (vdev->debug)printk(KERN_DEBUG "%s: mmap (%d)\n",video_device_node_name(vdev), ret);return ret; }- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
可以看出這個mmap函數最終仍用了vdev->fops->mmap, 這里的vdev->fops結構體就是struct v4l2_file_operations, 其定義如下:
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); #ifdef CONFIG_COMPATlong (*compat_ioctl32) (struct file *, unsigned int, unsigned long); #endifunsigned long (*get_unmapped_area) (struct file *, unsigned long,unsigned long, unsigned long, unsigned long);int (*mmap) (struct file *, struct vm_area_struct *);int (*open) (struct file *);int (*release) (struct file *); };- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
可以看出這個結構體和struct file_operations是十分的相似, 每個函數指針都對應的struct file_operations的一個函數指針, 區別是這些函數指針都不再有ionode參數.
1.3 v4l2_file_operations的分拆
看到這里我們來看一下struct video_device的定義
struct video_device { #if defined(CONFIG_MEDIA_CONTROLLER)struct media_entity entity; #endif/* 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;/* vb2_queue associated with this device node. May be NULL. */struct vb2_queue *queue;/* Priority state. If NULL, then v4l2_dev->prio will be used. */struct v4l2_prio_state *prio;/* device info */char name[32];int vfl_type; /* device type */int vfl_dir; /* receiver, transmitter or m2m *//* '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;DECLARE_BITMAP(valid_ioctls, BASE_VIDIOC_PRIVATE);/* serialization lock */DECLARE_BITMAP(disable_locking, BASE_VIDIOC_PRIVATE);struct mutex *lock; };- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
注意到這里除了v4l2_file_operations的ops參數外, 還有一個struct v4l2_ioctl_ops參數, 這個參數又是什么操作函數呢? 這個參數也是一系列的參數集, 其作用是將struct v4l2_file_operations中的ioctl函數的每一個IOCTL CMD分解為一個函數. 然后將這些函數全部收集起來封裝到這個結構體中. 其具體的回調過程, 我們后面再講. 因為v4l2驅動主要是各種ioctl, ioctl太多, 全部都用swich case寫在一個函數里面, 那必然是又臭又長. 這樣可以提升代碼的可讀性和可維護性.?
這表示v4l2-core將v4l2_file_operations這個接口分解為兩個, 一個是ioctl, 另一個v4l2_file_operations的其他成員.?
到這里我們知道, 如果要實現一個v4l2驅動, 那么我們必須要實現的是:
- v4l2_ioctl_ops
- v4l2_file_operations的其他成員
1.4 soc_camera的銜接
在圖中有一條虛線, 其中虛線上面表示的是v4l2-core所實現的內容, 而虛線下面則是建立在v4l2-core上實現的soc_camera子系統. 這個子系統主要用來實現圖像采集設備的驅動程序. 圖中可以看出, soc_camera子系統實現了上面所說的必須實現的兩個接口, 然后向下繼續暴露出一個soc_camera_host_ops接口, 這個接口主要是soc_camera host相關的一些操作函數接口, 這樣如果需要實現一個soc_camera host只需要實現這些接口就可以了. 這樣驅動開發者只需要是關注與camera host密切相關的操作函數的設計就可以啦.?
(此處暫時略去subdev的說明, 回頭在加上)
1.5 最后總結一下
file_operations是用來實現用戶空間請求的一個接口, v4l2-core中的v4l2_fops實現了這個接口, 并向下層暴露了v4l2_file_operations接口, 這個接口的ioctl函數又被v4l2-core中的video_ioctl2函數實現, 然后向下層暴露了v4l2_ioctl_ops接口, soc_camera子系統實現了v4l2_ioctl_ops接口和v4l2_file_operations'除了ioctl以外的接口, 然后向下層暴露了soc_camera_host接口. 最終soc_camera_host`的driver實現了這個接口. 從而完成了整個v4l2框架注冊.
總結
以上是生活随笔為你收集整理的V4L2 driver(一). 整体框架的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: V4L2驱动框架
- 下一篇: 深入理解l内核v4l2框架之video