linux csi驱动添加,CSI接口Camera驱动学习
sam_code@hotmail.com
在Android4.0升級(jí)后,突然發(fā)現(xiàn)大量平臺(tái)對(duì)Camera的支持均非常不好。要么Camera使用不穩(wěn)定,要么各類ioctl設(shè)置不能使用,更有甚者,連Camera
Device都不能創(chuàng)建。
而我們的產(chǎn)品,基于Camera的正常工作,必須解決此類問題。選擇了其中一款使用CSI接口Camera的平臺(tái):全志A20來做研究和解決。
0. 基礎(chǔ)知識(shí)
:
0.0. 目錄結(jié)構(gòu):
除了常見的,在linux-3.3/drivers/media/video/
目錄下有v4l2一些文件外,全志還在另一個(gè)目錄下放置了csi以及做支持模組芯片的代碼:linux-3.3/drivers/media/video/sunxi_csi/
其中,csi部分在csi0或者csi1中。 模組對(duì)應(yīng)代碼在device中。
這些代碼,基本組成了全志CSI 接口 Camera的全部驅(qū)動(dòng)代碼。
0.1. CSI:
COMS Sensor Interface:
CSI接口通常從COMS Sensor,Video Encoder和其它視頻輸出設(shè)備收集數(shù)據(jù)。
0.2. 模組芯片:
手頭這塊板子上自帶GT2005模組。所以需要看linux-3.3/drivers/media/video/sunxi_csi/device/gt2005.c
1. 驅(qū)動(dòng)結(jié)構(gòu):
CSI 模組Driver的基本思路其實(shí)挺簡(jiǎn)單,就是需要?jiǎng)?chuàng)建主設(shè)備號(hào)為81的device.
/dev/videoX。并將其open,close,ioctl 與Driver聯(lián)系起來,最終反應(yīng)到Sensor
(gt2005)層面。
我們首先從linux-3.3/drivers/media/video/sunxi_csi/csi0部分開始著手,這個(gè)文件夾內(nèi)的三個(gè)文件:sunxi_csi_reg.c
,sunxi_drv_csi.c, sunxi_csi_reg.h 最終會(huì)生成sunxi_csi0.ko。
會(huì)被以modules形式insmod 進(jìn)系統(tǒng)。
1.1:CSI0 modules學(xué)習(xí):
當(dāng)sunxi_csi0.ko被insmod時(shí),sunxi_drv_csi.c中的csi_init()被調(diào)用。
csi_init() 中注冊(cè)了一個(gè)driver--csi_driver.
platform_driver_register(&csi_driver);
csi_driver中有偵測(cè)函數(shù):.probe = csi_probe,
Sam的理解是:因?yàn)镃SI接口一直連接著,所以當(dāng)此Driver剛被注冊(cè)時(shí),csi_probe就被調(diào)用。
請(qǐng)注意:csi_probe中作了相當(dāng)多事情,是sunxi_csi0.ko的重點(diǎn)。
它做了很多準(zhǔn)備工作.并通過video_register_device()創(chuàng)建了Device. /dev/videoX.
并將此device的操作與v4l2_fops聯(lián)系起來。
所以,對(duì)此Device的open,close, ioctl等, 都使用v4l2_fops中提供的函數(shù)指證。
而我們看v4l2_fops中的ioctl. 它最終是
video_device?->fops->ioctl()。
其實(shí)就是:csi_template 中的:.fops ?= &csi_fops, 的ioctl.
即:video_ioctl2
video_ioctl2,在v4l2-ioctl.c中定義:其實(shí)就是:
static long __video_do_ioctl(struct
file *file,unsigned int cmd, void *arg)
所以,經(jīng)過CSI程序的鏈接。最終,對(duì)Device /dev/videoX的操作,最終都被歸結(jié)到__video_do_ioctl
同時(shí),csi_ioctl_ops也被鏈接到ioctl_ops。請(qǐng)注意,未來要用到這里。
看到這里,大家都會(huì)疑惑。 這怎么和Sensor操作練習(xí)起來了。這部分只將CSI和V4L2 連起來了。
這就是下一部要說的gt2005.ko了。
1.2: GT2005模塊學(xué)習(xí):
同樣道理,insmod gt2005.ko時(shí),gt2005.c中的init_sensor()會(huì)被啟動(dòng)。
在init_sensor()中,只執(zhí)行了:i2c_add_driver(&sensor_driver);
其中,sensor_driver 同樣會(huì)在驅(qū)動(dòng)安裝后立刻啟動(dòng)。
static int sensor_probe(struct
i2c_client *client,const struct i2c_device_id *id)
v4l2_i2c_subdev_init(sd, client, &sensor_ops);
這一句代碼是關(guān)鍵。
它將sensor_ops加入v4l2_subdev->ops中去了。而v4l2_subdev類型的sd被加入list.未來會(huì)用。(關(guān)鍵3)
分析下:sensor_ops.
static const struct v4l2_subdev_ops sensor_ops = {
.core = &sensor_core_ops,
.video = &sensor_video_ops,
};
也就是有:core和video 兩個(gè)。一定要注意了,這里和未來很有關(guān)系。(關(guān)鍵4)
__video_do_ioctl()最終會(huì)通過vfd->ioctl_ops
來做實(shí)際動(dòng)作。而ioctl_ops是誰呢?就是在在sunxi_drv_csi.c中的csi_ioctl_ops
2. ioctl的完整流程:
當(dāng)用戶open /dev/videoX后,使用ioctl()時(shí),
例1:得到能力集:
rel = ioctl(Handle, VIDIOC_QUERYCAP, &cap);
通過上面的分析, 它通過?__video_do_ioctl?最終調(diào)用到:vfd->ioctl_ops->vidioc_querycap.
也就是?csi_ioctl_ops
的?.vidioc_querycap ?= vidioc_querycap,
也就是說: 調(diào)用ioctl(VIDIOC_QUERYCAP). 會(huì)通過__vidoe_do_ioctl()
最終調(diào)用到sunxi_drv_sic.c中的vidioc_querycap()
為什么沒有進(jìn)Sensor呢? 是因?yàn)槟芰诖a層面維護(hù)。不需要去問Sensor。
例2:得到像素格式
ioctl(Handle, VIDIOC_G_FMT, &Format)
它最終被調(diào)用sunxi_drv_csi.c中的vidioc_g_fmt_vid_cap()
因?yàn)楦袷揭彩怯沙绦蚓S護(hù),所以沒有訪問Sensor。
例3:設(shè)置像素格式
ioctl(Handle, VIDIOC_S_FMT, &Format);
最終被調(diào)用sunxi_drv_csi.c中的vidioc_s_fmt_vid_cap()
注意: 設(shè)置像素格式,需要通知Sensor。
所以會(huì)被調(diào)用:
v4l2_subdev_call(dev->sd,video,s_mbus_fmt,&ccm_fmt);
這里的video. 就是表明調(diào)用的是關(guān)鍵4 那個(gè)的sensor_video_ops。
這里的sd,其實(shí)就是關(guān)鍵3 那里的v4l2_subdev類型sd.
所以,又被調(diào)用到gt2005.c中的sensor_s_fmt()
此時(shí)會(huì)向Sensor中寫入數(shù)據(jù)。sensor_write
例4:
ioctl(Handle, VIDIOC_G_PARM, &Stream_Parm)
會(huì)通過__vidoe_do_ioctl()
調(diào)用到sunxi_drv_csi.c中vidioc_g_parm()
這里會(huì):v4l2_subdev_call(dev->sd,video,g_parm,parms);
在gt2005.c中寫死的。 如果格式大于 800x600. 則15幀。 小于800x600. 則30幀。
例5:
ioctl(Handle, VIDIOC_G_PARM, &Stream_Parm)
會(huì)通過__vidoe_do_ioctl()
調(diào)用到sunxi_drv_csi.c中vidioc_s_parm()
這里會(huì):v4l2_subdev_call(dev->sd,video,s_parm,parms);
在gt2005.c 中。這里打空。所以其實(shí)不能調(diào)。
例6:
ioctl(Handle, VIDIOC_G_CTRL, &ctrl)
會(huì)通過__vidoe_do_ioctl()
調(diào)用到sunxi_drv_csi.c中vidioc_g_ctrl()
這里會(huì):v4l2_subdev_call(dev->sd,core,g_ctrl,ctrl);
注意:這里是core.
所以調(diào)用gt2005.c中的sensor_g_ctrl()
例7:
ioctl(Handle, VIDIOC_S_CTRL,
&ctrl)
會(huì)通過__vidoe_do_ioctl()
調(diào)用到sunxi_drv_csi.c中vidioc_s_ctrl()
這里會(huì):v4l2_subdev_call(dev->sd,core,s_ctrl,ctrl);
注意:這里是core.
所以調(diào)用gt2005.c中的sensor_s_ctrl()
但有一點(diǎn)需要注意:在A20平臺(tái)編程中,大家會(huì)發(fā)現(xiàn)所有VIDIOC_G_CTRL,VIDIOC_S_CTRL全不可用。Sam查了一下代碼。發(fā)現(xiàn)是全志修改Kernel時(shí)弄錯(cuò)了。
錯(cuò)誤如下:
struct v4l2_control {
__u32 ?id;
__s32 ?value;
__u32 user_pt;
};
看起來,是全志一位叫Raymon的工程師非常隨意的修改了v4l2_control結(jié)構(gòu)體。添加了4個(gè)字節(jié)的user_pt;
但這會(huì)造成嚴(yán)重后果,首先,大量使用v4l2_control的接口會(huì)出現(xiàn)未知問題。
更嚴(yán)重的是:ioctl的cmd這一項(xiàng)是計(jì)算出來的。v4l2_control的大小會(huì)影響到cmd的值。
所以,在A20平臺(tái)上,應(yīng)用程序使用VIDIOC_G_CTRL,VIDIOC_S_CTRL時(shí),
__video_do_ioctl(struct file *file,unsigned int cmd, void
*arg)
參數(shù)2:cmd這一項(xiàng)和Kernel中算出的cmd值對(duì)不上。所以無法進(jìn)入:
case VIDIOC_G_CTRL:
case VIDIOC_S_CTRL:
如果有全志工程師偶爾看到這篇Blog。 請(qǐng)通知Driver部門。修改這個(gè)明顯錯(cuò)誤。
總結(jié)
以上是生活随笔為你收集整理的linux csi驱动添加,CSI接口Camera驱动学习的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: PHP笔记-使用PHPStorm断点调试
- 下一篇: linux vps 可视化监控,Cent