前言
前面我們了解了一些相機的基礎知識《相機基礎知識》。下面來看看Linux為相機提供的驅動框架。
V4L2簡介
V4L2 (Video Linux Two),是為支持Linux內核設計的驅動框架驅動框架。為應用設置的操作接口層(ioctl),是在提供更廣泛的時候它的設備,它們只有在原件上,才是真正的視頻設備,所以它們才是真正的攝像頭設計。
V4L2框架
在應用層,可以在 /dev 顯示設備節點,程序打開設備設備進行我們的設備目錄發現應用程序0、視頻畫面。video1、video2...這些設備節點是在核心層注冊。
v4l2-dev.c) 起承上啟下的作用,它會為每一個核心層注冊中的設備設置一個統一的 v4l2_fops ,這些統一驅動的接口最終將調用到驅動的 video_device 的 fops 。
重要結構體
視頻設備
視頻設備
//表示一個視頻設備
struct video_device {
#if defined(CONFIG_MEDIA_CONTROLLER);
struct media_entity entity;
struct media_intf_devnode *intf_devnode;
struct media_pipeline pipe;
#endif;
const struct v4l2_file_operations *fops; //文件操作接口(dev/videoX)
u32 device_caps; //設備功能,用于v4l2_capabilities(應用層定義的結構體)
struct device dev;
struct cdev *cdev; //字符設備
struct v4l2_device *v4l2_dev; //V4L2設備
struct device *dev_parent;
struct v4l2_ctrl_handler *ctrl_handler; //設備節點對應的控制句柄
struct vb2_queue *queue;
struct v4l2_prio_state *prio;
char name[32]; //Video設備名稱
enum vfl_devnode_type vfl_type; //V4L設備類型
enum vfl_devnode_direction vfl_dir; //V4L 接收者/發送者/m2m
int minor; //子設備號,主設備為81
u16 num;
unsigned long flags;
int index;
spinlock_t fh_lock;
struct list_head fh_list;
int dev_debug;
v4l2_std_id tvnorms;
void (*release)(struct video_device *vdev); //video_device release()回調
const struct v4l2_ioctl_ops *ioctl_ops; //IOCTL回調
unsigned long valid_ioctls[BITS_TO_LONGS(BASE_VIDIOC_PRIVATE)];
struct mutex *lock;
};
v4l2_device
struct v4l2_device {
struct device *dev;
struct media_device *mdev;
struct list_head subdevs; //用于追蹤已注冊的subdev
spinlock_t lock;
char name[V4L2_DEVICE_NAME_SIZE]; //設備名
void (*notify)(struct v4l2_subdev *sd, unsigned int notification, void *arg);
struct v4l2_ctrl_handler *ctrl_handler; //控制句柄
struct v4l2_prio_state prio; //設備的優先狀態
struct kref ref; //引用
void (*release)(struct v4l2_device *v4l2_dev);//引用計數為0后調用
};
嵌入到video_device中,表示一個v4l2設備實例。
v4l2_subdev
struct v4l2_subdev {
#if defined(CONFIG_MEDIA_CONTROLLER);
struct media_entity entity;
#endif;
struct list_head list; //subdev列表
struct module *owner;
bool owner_v4l2_dev;
u32 flags;
struct v4l2_device *v4l2_dev; //依附的v4l2_device
const struct v4l2_subdev_ops *ops; //subdev操作函數
const struct v4l2_subdev_internal_ops *internal_ops;
struct v4l2_ctrl_handler *ctrl_handler; //控制句柄
char name[V4L2_SUBDEV_NAME_SIZE]; //subdev名稱
u32 grp_id;
void *dev_priv;
void *host_priv;
struct video_device *devnode;
struct device *dev;
struct fwnode_handle *fwnode;
struct list_head async_list;
struct v4l2_async_subdev *asd;
struct v4l2_async_notifier *notifier;
struct v4l2_async_notifier *subdev_notifier;
struct v4l2_subdev_platform_data *pdata;//subdev平臺數據
};
依附在一個v4l2_device下面,并表示一個v4l2設備的子設備,v4l2_device下可以有多個sub_device。
v4l2_fh
struct v4l2_fh {
struct list_head list; //文件句柄列表
struct video_device *vdev; //依附的video_device
struct v4l2_ctrl_handler *ctrl_handler;
enum v4l2_priority prio; //文件句柄的優先級
wait_queue_head_t wait;
struct mutex subscribe_lock;
struct list_head subscribed; //訂閱的事件列表
struct list_head available; //可用的事件
unsigned int navailable; //可用的事件數
u32 sequence;
struct v4l2_m2m_ctx *m2m_ctx;
};
追蹤的文件句柄用于
v4l2_device和v4l2_subdev的關系:
subdev 的設計目的是為了多路復用,就是控制使用一個v4l2_device可以掛接多個v4l2_subdev。這樣的多路復用就是一個攝像頭來多個攝像頭。手機和后置攝像頭。
在V4L2驅動中,使用v4l2_device來表示攝像頭攝像頭(ISP)。使用v4l2_subdev來表示具體的某個攝像頭(Sensor)。
v4l2_file_operations
//V4L2設備操作函數
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 *);
__poll_t (*poll) (struct file *, struct poll_table_struct *);
long (*unlocked_ioctl) (struct file *, unsigned int, unsigned long);
#ifdef CONFIG_COMPAT;
long (*compat_ioctl32) (struct file *, unsigned int, unsigned long);
#endif;
unsigned 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 *);
};
v4l2_ioctl_ops
//IOCTL操作函數
struct v4l2_ioctl_ops {
......
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, const struct v4l2_framebuffer *a);
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);
......
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);
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_query_dv_timings)(struct file *file, void *fh, struct v4l2_dv_timings *timings);
int (*vidioc_enum_dv_timings)(struct file *file, void *fh, struct v4l2_enum_dv_timings *timings);
int (*vidioc_dv_timings_cap)(struct file *file, void *fh, struct v4l2_dv_timings_cap *cap);
int (*vidioc_g_edid)(struct file *file, void *fh, struct v4l2_edid *edid);
int (*vidioc_s_edid)(struct file *file, void *fh, struct v4l2_edid *edid);
int (*vidioc_subscribe_event)(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub);
int (*vidioc_unsubscribe_event)(struct v4l2_fh *fh, const struct v4l2_event_subscription *sub);
long (*vidioc_default)(struct file *file, void *fh, bool valid_prio, unsigned int cmd, void *arg);
};
v4l2_subdev_ops
//subdev操作函數
struct v4l2_subdev_ops {
const struct v4l2_subdev_core_ops *core; //subdev核心操作回調
const struct v4l2_subdev_tuner_ops *tuner; //radio模式打開v4l設備時的操作回調
const struct v4l2_subdev_audio_ops *audio; //音頻相關設置回調
const struct v4l2_subdev_video_ops *video; //video模式打開v4l設備時的操作回調
const struct v4l2_subdev_vbi_ops *vbi; //通過vbi設備節點以video模式打開v4l設備時的操作回調
const struct v4l2_subdev_ir_ops *ir; //IR(紅外)設備操作函數
const struct v4l2_subdev_sensor_ops *sensor; //sensor操作函數
const struct v4l2_subdev_pad_ops *pad; //pad操作函數
};
v4l22,所以多部分可以輕松地根據實際設備的需要實現的設備。
上面的_ioctl_ops中實現的部分ioctl最終到v4l2_dev_ops中的調用子函數。
API函數
//注冊/注銷video_device
int video_register_device(struct video_device *vdev, enum vfl_devnode_type type, int nr)
void video_unregister_device(struct video_device *vdev)
//分配/釋放video_device
struct video_device * __must_check video_device_alloc(void);
void video_device_release(struct video_device *vdev)
//注冊/注銷v4l2_device
int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
//注冊/注銷v4l2_subdev(關聯v4l2_device和v4l2_subdev)
int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev, struct v4l2_subdev *sd)
void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
//初始化v4l2_subdev
void v4l2_subdev_init(struct v4l2_subdev *sd, const struct v4l2_subdev_ops *ops);
/********************************I2C subdev*************************************/
//初始化v4l2_subdev, 該subdev是I2C設備
void v4l2_i2c_subdev_init(struct v4l2_subdev *sd, struct i2c_client *client,
const struct v4l2_subdev_ops *ops)
/*******************************SPI subdev************************************************/
//初始化v4l2_subdev, 該subdev是SPI設備
void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,
const struct v4l2_subdev_ops *ops)
審核編輯:劉清
-
Linux
+關注
關注
87文章
11292瀏覽量
209332 -
攝像頭
+關注
關注
59文章
4836瀏覽量
95599 -
LINUX內核
+關注
關注
1文章
316瀏覽量
21644
發布評論請先 登錄
相關推薦
評論