我對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、程序在我這跑得好好的,在你那怎麽就不行呢?!這是一個典型的應用