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