0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

看看Linux為相機提供的驅(qū)動框架

冬至配餃子 ? 來源:嵌入式軟件開發(fā)交流 ? 作者:年輕的 ? 2022-08-07 16:03 ? 次閱讀

前言

前面我們了解了一些相機的基礎(chǔ)知識《相機基礎(chǔ)知識》。下面來看看Linux為相機提供的驅(qū)動框架。

V4L2簡介

V4L2 (Video Linux Two),是為支持Linux內(nèi)核設(shè)計的驅(qū)動框架驅(qū)動框架。為應(yīng)用設(shè)置的操作接口層(ioctl),是在提供更廣泛的時候它的設(shè)備,它們只有在原件上,才是真正的視頻設(shè)備,所以它們才是真正的攝像頭設(shè)計。

V4L2框架

poYBAGLvcXOAU-5_AACaFZ8UYXM697.png

在應(yīng)用層,可以在 /dev 顯示設(shè)備節(jié)點,程序打開設(shè)備設(shè)備進行我們的設(shè)備目錄發(fā)現(xiàn)應(yīng)用程序0、視頻畫面。video1、video2...這些設(shè)備節(jié)點是在核心層注冊。

v4l2-dev.c) 起承上啟下的作用,它會為每一個核心層注冊中的設(shè)備設(shè)置一個統(tǒng)一的 v4l2_fops ,這些統(tǒng)一驅(qū)動的接口最終將調(diào)用到驅(qū)動的 video_device 的 fops 。

重要結(jié)構(gòu)體

視頻設(shè)備

視頻設(shè)備

//表示一個視頻設(shè)備

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; //設(shè)備功能,用于v4l2_capabilities(應(yīng)用層定義的結(jié)構(gòu)體)

struct device dev;

struct cdev *cdev; //字符設(shè)備

struct v4l2_device *v4l2_dev; //V4L2設(shè)備

struct device *dev_parent;

struct v4l2_ctrl_handler *ctrl_handler; //設(shè)備節(jié)點對應(yīng)的控制句柄

struct vb2_queue *queue;

struct v4l2_prio_state *prio;

char name[32]; //Video設(shè)備名稱

enum vfl_devnode_type vfl_type; //V4L設(shè)備類型

enum vfl_devnode_direction vfl_dir; //V4L 接收者/發(fā)送者/m2m

int minor; //子設(shè)備號,主設(shè)備為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()回調(diào)

const struct v4l2_ioctl_ops *ioctl_ops; //IOCTL回調(diào)

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]; //設(shè)備名

void (*notify)(struct v4l2_subdev *sd, unsigned int notification, void *arg);

struct v4l2_ctrl_handler *ctrl_handler; //控制句柄

struct v4l2_prio_state prio; //設(shè)備的優(yōu)先狀態(tài)

struct kref ref; //引用

void (*release)(struct v4l2_device *v4l2_dev);//引用計數(shù)為0后調(diào)用

};

嵌入到video_device中,表示一個v4l2設(shè)備實例。

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操作函數(shù)

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平臺數(shù)據(jù)

};

依附在一個v4l2_device下面,并表示一個v4l2設(shè)備的子設(shè)備,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; //文件句柄的優(yōu)先級

wait_queue_head_t wait;

struct mutex subscribe_lock;

struct list_head subscribed; //訂閱的事件列表

struct list_head available; //可用的事件

unsigned int navailable; //可用的事件數(shù)

u32 sequence;

struct v4l2_m2m_ctx *m2m_ctx;

};

追蹤的文件句柄用于

v4l2_device和v4l2_subdev的關(guān)系:

subdev 的設(shè)計目的是為了多路復(fù)用,就是控制使用一個v4l2_device可以掛接多個v4l2_subdev。這樣的多路復(fù)用就是一個攝像頭來多個攝像頭。手機和后置攝像頭。

在V4L2驅(qū)動中,使用v4l2_device來表示攝像頭攝像頭(ISP)。使用v4l2_subdev來表示具體的某個攝像頭(Sensor)。

v4l2_file_operations

//V4L2設(shè)備操作函數(shù)

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操作函數(shù)

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操作函數(shù)

struct v4l2_subdev_ops {

const struct v4l2_subdev_core_ops *core; //subdev核心操作回調(diào)

const struct v4l2_subdev_tuner_ops *tuner; //radio模式打開v4l設(shè)備時的操作回調(diào)

const struct v4l2_subdev_audio_ops *audio; //音頻相關(guān)設(shè)置回調(diào)

const struct v4l2_subdev_video_ops *video; //video模式打開v4l設(shè)備時的操作回調(diào)

const struct v4l2_subdev_vbi_ops *vbi; //通過vbi設(shè)備節(jié)點以video模式打開v4l設(shè)備時的操作回調(diào)

const struct v4l2_subdev_ir_ops *ir; //IR(紅外)設(shè)備操作函數(shù)

const struct v4l2_subdev_sensor_ops *sensor; //sensor操作函數(shù)

const struct v4l2_subdev_pad_ops *pad; //pad操作函數(shù)

};

v4l22,所以多部分可以輕松地根據(jù)實際設(shè)備的需要實現(xiàn)的設(shè)備。

上面的_ioctl_ops中實現(xiàn)的部分ioctl最終到v4l2_dev_ops中的調(diào)用子函數(shù)。

API函數(shù)

//注冊/注銷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(關(guān)聯(lián)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設(shè)備

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設(shè)備

void v4l2_spi_subdev_init(struct v4l2_subdev *sd, struct spi_device *spi,

const struct v4l2_subdev_ops *ops)



審核編輯:劉清

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • Linux
    +關(guān)注

    關(guān)注

    87

    文章

    11123

    瀏覽量

    207912
  • 攝像頭
    +關(guān)注

    關(guān)注

    59

    文章

    4752

    瀏覽量

    94393
  • LINUX內(nèi)核
    +關(guān)注

    關(guān)注

    1

    文章

    315

    瀏覽量

    21556
收藏 人收藏

    評論

    相關(guān)推薦

    Linux之PWM驅(qū)動

    本文主要講述了Linux的PWM驅(qū)動框架、實現(xiàn)方法、驅(qū)動添加方法和調(diào)試方法。
    發(fā)表于 05-25 09:19 ?583次閱讀
    <b class='flag-5'>Linux</b>之PWM<b class='flag-5'>驅(qū)動</b>

    linux驅(qū)動框架是什么

    編寫linux驅(qū)動先看一下驅(qū)動框架是什么樣子的。驅(qū)動編寫和應(yīng)用層編寫有什么區(qū)別呢?
    發(fā)表于 07-26 08:14

    Linux下的UART驅(qū)動框架詳解

    Linux下的UART驅(qū)動框架
    發(fā)表于 12-22 07:18

    Linux 驅(qū)動 = 軟件框架 + 硬件操作

    ??Linux 驅(qū)動 = 軟件框架 + 硬件操作??驅(qū)動程序依賴于 Linux 內(nèi)核,你開發(fā)板
    發(fā)表于 12-17 07:11

    OpenHarmony相機用戶態(tài)驅(qū)動框架

    Linux采用的開源協(xié)議具有傳染性[1],導(dǎo)致Android HAL[2]成為了手機廠商們競爭的重要戰(zhàn)場。隨著OpenHarmony 3.1[3]的發(fā)布,相機模塊也逐漸完善起來,目前提供了基礎(chǔ)預(yù)覽和拍照的能力
    發(fā)表于 04-20 17:09

    想要駕馭Linux驅(qū)動開發(fā),必須深刻理解Linux總線設(shè)備驅(qū)動框架

    想要駕馭Linux驅(qū)動開發(fā),必須深刻理解Linux總線設(shè)備驅(qū)動框架。之所以會形成這樣的框架,主要
    的頭像 發(fā)表于 03-22 11:08 ?1.1w次閱讀
    想要駕馭<b class='flag-5'>Linux</b><b class='flag-5'>驅(qū)動</b>開發(fā),必須深刻理解<b class='flag-5'>Linux</b>總線設(shè)備<b class='flag-5'>驅(qū)動</b><b class='flag-5'>框架</b>

    Linux DMA Engine框架的介紹

    此會話描述如何從設(shè)備驅(qū)動程序在Linux中使用DMA。 這包括內(nèi)存分配,緩存控制和DMA設(shè)備控制。 詳細介紹了Linux DMA Engine框架。
    的頭像 發(fā)表于 11-23 06:29 ?6122次閱讀

    你對Linux總線設(shè)備驅(qū)動框架是否了解

    Linux的設(shè)備驅(qū)動模型,或者說,Linux的設(shè)備驅(qū)動框架,都是同一個意思。應(yīng)該這樣理解,(Linux
    發(fā)表于 05-05 15:13 ?676次閱讀

    如何使用Linux內(nèi)核實現(xiàn)USB驅(qū)動程序框架

    Linux內(nèi)核提供了完整的USB驅(qū)動程序框架。USB總線采用樹形結(jié)構(gòu),在一條總線上只能有唯一的主機設(shè)備。 Linux內(nèi)核從主機和設(shè)備兩個角度
    發(fā)表于 11-06 17:59 ?19次下載
    如何使用<b class='flag-5'>Linux</b>內(nèi)核實現(xiàn)USB<b class='flag-5'>驅(qū)動</b>程序<b class='flag-5'>框架</b>

    嵌入式Linux驅(qū)動開發(fā)從基礎(chǔ)到框架

    想講好嵌入式Linux驅(qū)動開發(fā)并不容易,各位業(yè)界大神最基礎(chǔ)的字符驅(qū)動到中斷并發(fā)再到驅(qū)動框架、應(yīng)用層調(diào)用。但是總覺得業(yè)界寫的書都是點到為止,
    發(fā)表于 11-01 16:58 ?14次下載
    嵌入式<b class='flag-5'>Linux</b><b class='flag-5'>驅(qū)動</b>開發(fā)從基礎(chǔ)到<b class='flag-5'>框架</b>

    IAR 實現(xiàn)類linux驅(qū)動模塊框架module_init(init_fun)

    其實在單片機上也能使用類linux驅(qū)動模塊框架module_init(init_fun),從而給驅(qū)動管理提供了新的方式。boot.icf文件
    發(fā)表于 12-03 13:36 ?0次下載
    IAR 實現(xiàn)類<b class='flag-5'>linux</b><b class='flag-5'>驅(qū)動</b>模塊<b class='flag-5'>框架</b>module_init(init_fun)

    Linux內(nèi)核中視頻設(shè)備驅(qū)動框架V4L2X詳解

    V4L2(Video for Linux 2):Linux內(nèi)核中關(guān)于視頻設(shè)備驅(qū)動框架,對上向應(yīng)用層提供統(tǒng)一的接口,對下支持各類復(fù)雜硬件的靈
    的頭像 發(fā)表于 05-30 16:18 ?5760次閱讀

    Linux的PWM驅(qū)動框架及實現(xiàn)方法

    本文主要講述了Linux的PWM驅(qū)動框架、實現(xiàn)方法、驅(qū)動添加方法和調(diào)試方法。
    的頭像 發(fā)表于 05-14 15:24 ?1271次閱讀
    <b class='flag-5'>Linux</b>的PWM<b class='flag-5'>驅(qū)動</b><b class='flag-5'>框架</b>及實現(xiàn)方法

    Linux驅(qū)動分析之RTC框架

    Linux內(nèi)核啟動時,它會從RTC中讀取時間與日期,作為基準值。然后通過軟件來維護系統(tǒng)時間和日期。Linux系統(tǒng)中提供了RTC核心層,對于驅(qū)動開發(fā)者而言,操作起來就變得很簡單了。我們
    的頭像 發(fā)表于 05-26 15:12 ?916次閱讀
    <b class='flag-5'>Linux</b><b class='flag-5'>驅(qū)動</b>分析之RTC<b class='flag-5'>框架</b>

    Linux Regmap 驅(qū)動框架

    ,regmap 向驅(qū)動編寫人員提供的 API 接口,驅(qū)動編寫人員使用這些API 接口來操作具體的芯片設(shè)備,也是驅(qū)動編寫人員重點要掌握的。 2、regmap 結(jié)構(gòu)體
    的頭像 發(fā)表于 07-06 17:29 ?959次閱讀
    <b class='flag-5'>Linux</b> Regmap <b class='flag-5'>驅(qū)動</b><b class='flag-5'>框架</b>