1. 程式人生 > >我對linux理解之v4l2

我對linux理解之v4l2

------------------------------------------ 本文系本站原創,歡迎轉載! ------------------------------------------
我們先看具體sensor slave怎麼註冊到v4l2的:
static struct v4l2_int_ioctl_desc ov5642_ioctl_desc[] = {//ioctl與對應的序號聯絡在一起,在v4l2層將被轉換成固定的名字
    {vidioc_int_dev_init_num, (v4l2_int_ioctl_func *)ioctl_dev_init},
    {vidioc_int_dev_exit_num, ioctl_dev_exit},

    {vidioc_int_s_power_num, (v4l2_int_ioctl_func *)ioctl_s_power},
    {vidioc_int_g_ifparm_num, (v4l2_int_ioctl_func *)ioctl_g_ifparm},
/*    {vidioc_int_g_needs_reset_num,
                (v4l2_int_ioctl_func *)ioctl_g_needs_reset}, */
/*    {vidioc_int_reset_num, (v4l2_int_ioctl_func *)ioctl_reset}, */

    {vidioc_int_init_num, (v4l2_int_ioctl_func *)ioctl_init},
/*    {vidioc_int_enum_fmt_cap_num,
                (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap}, */
/*    {vidioc_int_try_fmt_cap_num,
                (v4l2_int_ioctl_func *)ioctl_try_fmt_cap}, */
    {vidioc_int_g_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_g_fmt_cap},

/*    {vidioc_int_s_fmt_cap_num, (v4l2_int_ioctl_func *)ioctl_s_fmt_cap}, */
    {vidioc_int_g_parm_num, (v4l2_int_ioctl_func *)ioctl_g_parm},
    {vidioc_int_s_parm_num, (v4l2_int_ioctl_func *)ioctl_s_parm},
/*    {vidioc_int_queryctrl_num, (v4l2_int_ioctl_func *)ioctl_queryctrl}, */
    {vidioc_int_g_ctrl_num, (v4l2_int_ioctl_func *)ioctl_g_ctrl},
    {vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func *)ioctl_s_ctrl},
};
static struct v4l2_int_slave ov5642_slave = {//slave
    .ioctls = ov5642_ioctl_desc,
    .num_ioctls = ARRAY_SIZE(ov5642_ioctl_desc),
};

static struct v4l2_int_device ov5642_int_device = {
    .module = THIS_MODULE,
    .name = "ov5642",
    .type = v4l2_int_type_slave,
    .u = {
        .slave = &ov5642_slave,
    },
};
v4l2_int_device_register(&ov5642_int_device);//註冊v4l2_int_device:
int v4l2_int_device_register(struct v4l2_int_device *d)
{
    if (d->type == v4l2_int_type_slave)
        sort(d->u.slave->ioctls, d->u.slave->num_ioctls,//按照序號儲存,加快訪問速度
             sizeof(struct v4l2_int_ioctl_desc),
             &ioctl_sort_cmp, NULL);
    mutex_lock(&mutex);
    list_add(&d->head, &int_list);//無論是slave還是master都會新增到int_list中
    v4l2_int_device_try_attach_all();//都會做匹配動作
    mutex_unlock(&mutex);

    return 0;
}
我們看下v4l2匹配函式v4l2_int_device_try_attach_all():
void v4l2_int_device_try_attach_all(void)
{
    struct v4l2_int_device *m, *s;

    list_for_each_entry(m, &int_list, head) {//對int_list中每個master
        if (m->type != v4l2_int_type_master)
            continue;

        list_for_each_entry(s, &int_list, head) {//對int_list中的每個salve
            if (s->type != v4l2_int_type_slave)
                continue;

            /* Slave is connected? */
            if (s->u.slave->master)//slave中master已經被賦值說明已經連線起來
                continue;

            /* Slave wants to attach to master? */
            if (s->u.slave->attach_to[0] != 0
                && strncmp(m->name, s->u.slave->attach_to,
                       V4L2NAMESIZE))
                continue;

            if (!try_module_get(m->module))
                continue;

            s->u.slave->master = m;//說明slave找到了master
            if (m->u.master->attach(s)) {//執行master的匹配函式
                s->u.slave->master = NULL;
                module_put(m->module);
                continue;
            }
        }
    }
}
上面即是slave註冊到v4l2的過程,也許你會比較的奇怪,開始那些ioctl哪去呢?系統怎麼訪問呢?下面我們就分析這個過程。
我們在v4l2-int-device.h中有這樣的定義:
/* IOCTL command numbers. */
enum v4l2_int_ioctl_num {
    /*
     *
     * "Proper" V4L ioctls, as in struct video_device.
     *
     */
    vidioc_int_enum_fmt_cap_num = 1,
    vidioc_int_g_fmt_cap_num,
    vidioc_int_s_fmt_cap_num,
    vidioc_int_try_fmt_cap_num,
    vidioc_int_queryctrl_num,
    vidioc_int_g_ctrl_num,
    vidioc_int_s_ctrl_num,
    vidioc_int_cropcap_num,
    vidioc_int_g_crop_num,
    vidioc_int_s_crop_num,
    vidioc_int_g_parm_num,
    vidioc_int_s_parm_num,
    vidioc_int_querystd_num,
    vidioc_int_s_std_num,
    vidioc_int_s_video_routing_num,
......
};
V4L2_INT_WRAPPER_1(enum_fmt_cap, struct v4l2_fmtdesc, *);
V4L2_INT_WRAPPER_1(g_fmt_cap, struct v4l2_format, *);
V4L2_INT_WRAPPER_1(s_fmt_cap, struct v4l2_format, *);
V4L2_INT_WRAPPER_1(try_fmt_cap, struct v4l2_format, *);
V4L2_INT_WRAPPER_1(queryctrl, struct v4l2_queryctrl, *);
V4L2_INT_WRAPPER_1(g_ctrl, struct v4l2_control, *);
V4L2_INT_WRAPPER_1(s_ctrl, struct v4l2_control, *);
V4L2_INT_WRAPPER_1(cropcap, struct v4l2_cropcap, *);
V4L2_INT_WRAPPER_1(g_crop, struct v4l2_crop, *);
V4L2_INT_WRAPPER_1(s_crop, struct v4l2_crop, *);
V4L2_INT_WRAPPER_1(g_parm, struct v4l2_streamparm, *);
V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *);
V4L2_INT_WRAPPER_1(querystd, v4l2_std_id, *);
V4L2_INT_WRAPPER_1(s_std, v4l2_std_id, *);
V4L2_INT_WRAPPER_1(s_video_routing, struct v4l2_routing, *);
我們看下V4L2_INT_WRAPPER_1這個巨集定義:
#define V4L2_INT_WRAPPER_1(name, arg_type, asterisk)            \
    static inline int vidioc_int_##name(struct v4l2_int_device *d,    \
                        arg_type asterisk arg)    \
    {                                \
        return v4l2_int_ioctl_1(d, vidioc_int_##name##_num,    \
                    (void *)(unsigned long)arg);    \
    }                                \
                                    \
    static inline struct v4l2_int_ioctl_desc            \
    vidioc_int_##name##_cb(int (*func)                \
                   (struct v4l2_int_device *,        \
                arg_type asterisk))            \
    {                                \
        struct v4l2_int_ioctl_desc desc;            \
                                    \
        desc.num = vidioc_int_##name##_num;            \
        desc.func = (v4l2_int_ioctl_func *)func;        \
                                    \
        return desc;                        \
    }
我們舉例來說,V4L2_INT_WRAPPER_1(s_ctrl, struct v4l2_control, *),那也就是有了這樣的定義:
    static inline int vidioc_int_s_ctrl(struct v4l2_int_device *d,    
                        arg_type asterisk arg)    
    {                                
        return v4l2_int_ioctl_1(d, vidioc_int_s_ctrl_num,    
                    (void *)(unsigned long)arg);    
    }                                

    static inline struct v4l2_int_ioctl_desc            
    vidioc_int_s_ctrl_cb(int (*func)                
                   (struct v4l2_int_device *,        
                arg_type asterisk))            
    {                                
        struct v4l2_int_ioctl_desc desc;            

        desc.num = vidioc_int_s_ctrl_num;            
        desc.func = (v4l2_int_ioctl_func *)func;        

        return desc;                        
    }
也就是定義了這兩個行內函數。我們再看下v4l2_int_ioctl_1(d, vidioc_int_s_ctrl_num, (void *)(unsigned long)arg):
int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg)
{
    return ((v4l2_int_ioctl_func_1 *)
        find_ioctl(d->u.slave, cmd,
               (v4l2_int_ioctl_func *)no_such_ioctl_1))(d, arg);
}
轉到find_ioctl:
static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd,//這裡的slave就上面定義的ov5642_slave
                       v4l2_int_ioctl_func *no_such_ioctl)
{
    const struct v4l2_int_ioctl_desc *first = slave->ioctls;//這裡其實就上面的ov5642_ioctl_desc
    const struct v4l2_int_ioctl_desc *last =
        first + slave->num_ioctls - 1;//slave->num_ioctls=ARRAY_SIZE(ov5642_ioctl_desc)

    while (first <= last) {
        const struct v4l2_int_ioctl_desc *mid;

        mid = (last - first) / 2 + first;//二分法

        if (mid->num < cmd)
            first = mid + 1;
        else if (mid->num > cmd)
            last = mid - 1;
        else
            return mid->func;//找到就返回具體的函式,具體的說這裡的函式就是ov5642_slave定義的ov5642_ioctl_desc中的具體函式!
    }

    return no_such_ioctl;
}
總結這裡的函式對應關係,以ov5642_ioctl_desc中的{vidioc_int_s_ctrl_num, (v4l2_int_ioctl_func *)ioctl_s_ctrl}為例,如果系統有這樣的函式vidioc_int_s_ctrl(...)使用,那也就是對應引用了
ov5642_slave的定義的ioctl_s_ctrl(...)。


下面看下master註冊過程:
static __init int camera_init(void)
{
    u8 err = 0;

    pr_debug("In MVC:camera_init\n");

    /* Register the device driver structure. */
    err = platform_driver_register(&mxc_v4l2_driver);//平臺註冊v4l2驅動
    if (err != 0) {
        pr_err("ERROR: v4l2 capture:camera_init: "
            "platform_driver_register failed.\n");
        return err;
    }

    return err;
}
mxc_v4l2_driver定義:
static struct platform_driver mxc_v4l2_driver = {
    .driver = {
           .name = "mxc_v4l2_capture",
           },
    .probe = mxc_v4l2_probe,
    .remove = mxc_v4l2_remove,
    .suspend = mxc_v4l2_suspend,
    .resume = mxc_v4l2_resume,
    .shutdown = NULL,
};
註冊成功將會執行mxc_v4l2_probe:
static int mxc_v4l2_probe(struct platform_device *pdev)
{
    /* Create g_cam and initialize it. */
    g_cam = kmalloc(sizeof(cam_data), GFP_KERNEL);
    if (g_cam == NULL) {
        pr_err("ERROR: v4l2 capture: failed to register camera\n");
        return -1;
    }
    init_camera_struct(g_cam, pdev);//初始化cam_data結構
    pdev->dev.release = camera_platform_release;

    /* Set up the v4l2 device and register it*/
    mxc_v4l2_int_device.priv = g_cam;//注意這裡的g_cam賦值,後面mattch函式中會用到
    /* This function contains a bug that won't let this be rmmod'd. */
    v4l2_int_device_register(&mxc_v4l2_int_device);//向v4l2註冊int_device

    /* register v4l video device */
    if (video_register_device(g_cam->video_dev, VFL_TYPE_GRABBER, video_nr)//註冊video裝置
        == -1) {
        kfree(g_cam);
        g_cam = NULL;
        pr_err("ERROR: v4l2 capture: video_register_device failed\n");
        return -1;
    }
    pr_debug("   Video device registered: %s #%d\n",
         g_cam->video_dev->name, g_cam->video_dev->minor);

    if (device_create_file(&g_cam->video_dev->dev,
                           &dev_attr_fsl_v4l2_capture_property))//建立fsl_v4l2_capture_property屬性檔案

相關推薦

linux理解v4l2

------------------------------------------ 本文系本站原創,歡迎轉載! ------------------------------------------ 我們先看具體sensor slave怎麼註冊到v4

linux理解alsa一

------------------------------------------ 本文系本站原創,歡迎轉載! ------------------------------------------ 我們以imx51為平臺,去分析alsa的架構。 有兩個檔案跟平臺具體相關的: 一個是跟cpu的音

linux理解spi

------------------------------------------ 本文系本站原創,歡迎轉載! ------------------------------------------ 我們先看spi外設的設備註冊: static struct mc13892_platform_d

Linux自學

記錄學習 作為一只菜鳥,並且沒有任何Linux的經驗,我從網上下載的視頻自學Linux。歡迎各位新手或大師指點,開通博客意在記錄自己學習的點滴。 由於項目在公安行業內,系統的版本無法跟現代的大型網後臺的系統版本相提並論。公安系統的版本大多停留在四五年前,因為是自學,下載的視頻也是四五年前的,所以後

談談Linux系統學習的歷程回顧

linux眾所周知,Windows 和Linux 是目前最流行的2個操作系統。Windows系統適合普通用戶,它的優勢是圖形化界面,簡單易用,使用起來門檻很低,很容易上手,所以,windows占有了大多數普通用戶群體。而Linux 被譽為黑客的操作系統,因其穩定和命令行操作的高效性而廣泛用於開發工作,占有絕大

Linux學習路的感悟

content data 更新 選擇 ati 關系 icp gtk 能夠 首先要跟大家說聲抱歉,這麽久一直沒有更新,有負大家對我的期望。 半年的Linux運維的學習到目前已工作一個月零9天,這一路走來的艱辛和掙紮只有自己最清楚。 首先要感謝

linux學習路-第00天

因此 最終 我們 沒有 之路 成就感 如果 人類 而是 為什麽喜歡linux?為什麽要學linux?我也不清楚,也許因為它可以很小,也許因為它很穩定,也許它的可玩性高?Who knows。 “工作馬馬虎虎,只想在興趣和遊戲中尋覓快活,充其量只能獲得一時的快感,絕不能嘗到從心

Linux學習路(一)

       在大二的開始,還不算太晚的時間點,我決定成為一名網路安全工程師,於是決定先學習Linux,我主要從《Linux就該這麼學》和《鳥哥的Linux私房菜》以及看一些視訊來學習,在這裡會記錄我的學習經歷,學習中的收穫和遇到的困難,也會跟大家分享學習的心得。    

linux學習 V4L2的攝像頭應用

看到一篇比較好的關於V4L2的文章 來自:http://blog.csdn.net/eastmoon502136/article/details/8190262    對於v4l2,上次是在除錯收音機驅動的時候用過,其他也就只是用i2c配置一些暫存器就可以了。那時只是粗

畢業季,Linux求職

開發十年,就只剩下這套架構體系了! >>>   

談談構建法這三章的理解

閱讀 學習者 單元 繼續 挑戰 有時 個人 相關 的人 前言 在第一次作業中我便提過,剛進入大學時,我對未來充滿了憧憬,我的人生有著很好的規劃,也像我所規劃的那樣,我的大一過著學習,技術,學生工作有條不紊運行的狀態,可是後來為了學生工作放棄了工作室,後來又因為一些原因失

貝葉斯分類器的理解

log enter roman 高斯 clas http style 理解 times 我們能夠得到其統計概率密度例如以下: 這樣我們就知道該概率密度曲線大致符合正態分布。例如以下圖所看到的 大概能夠看出它在中心非常集中,邊

Linux進程的理解

linux進程 初始 linux 網上 com 包括 http href title 在本科期間學習過進程,網上也有很多關於進程的知識,但對於進程到底是什麽一直沒有讓我滿意的解答(以下截圖來自網絡,感覺對進程理解有問題,說得也很虛)。 但今天找到這個博文感覺挺符合我的胃口

Lamport Logical Clock的理解

進程 cal 這一 width 排序 之前 能夠 margin 兩個 建議先看論文原文再來看這篇文章,我不會對論文中的各個點都具體說明。僅僅是寫一些我自己的想法,幫助理解。 大家都知道。分布式環境下。確定各個事件發生的順序非常重要,不然就會發生一些麻煩的問題

解構委托、事件--他們本質的理解

remove 類型 實例化 如果 方法 擴展 調用 所有 csharp 一、委托 1、因為委托是一個特殊的類,所以定義委托和定義類一樣,可以在命名空間下定義; namespace _06委托的理解 { public delegate void MyDelege

工廠模式 ioc dom4j 反射的一點理解

nat Coding println hibernate return 控制反轉 加載 light 異常 工廠模式 //工廠模式我的理解 //第一次調用沒有實例化的對象時 會去內存中查找(棧) //如果沒有找到,就去xml配置中查找className和他相同

談談Android View事件分發的理解

event 調用 ack 處理 group ans import ras 運行 寫這篇博客的緣由。近期因為項目中用到相似一個LinearLayout中水平布局中,有一個TextView和Button,然後對該LinearLayout布局設置點擊事件。點擊

線程安全的理解

color ont shared data stat 同學 style 發現 out Wiki的解釋如下 Thread safety is a computer programming concept applicable to multi-threaded code

SAP Business One 項目實施的理解

運行 完整 計劃管理 信息 你們 開發 class netweaver 支持 一、什麽是SAP: 大家都知道ERP是什麽,ERP是企業資源計劃管理系統。是指建立在信息技術基礎上,集信息技術與先進管理思想於一身,以系統化的管理思想,為企業員工及決策層提供決策手段的管理平臺。那

也談談Docker的簡單理解

linux 安全性 看到了 用戶 總結 們的 部分 占用 ont Docker能解決什麽問題呢?一個工具的出現必然需要解決一些問題,Docker也不例外,簡單說說我們常見的2種情況Docker是如何解決的吧。1、程序在我這跑得好好的,在你那怎麽就不行呢?!這是一個典型的應用