1.Shark camera driver架构
l HAL层调用camera_init_internal()对sensor,v4l2,preview,capture等初始化,初始化时创建各自的处理线程。
int (uint32_t camera_id)
{
struct camera_ctrl *ctrl = &g_cxt->control;
int ret = CAMERA_SUCCESS;
CMR_PRINT_TIME;
ret = camera_sensor_init(camera_id);
if (ret) {
CMR_LOGE("Failed to init sensor %d", ret);
goto exit;
}
CMR_PRINT_TIME;
ret = camera_v4l2_init();
if (ret) {
CMR_LOGE("Failed to init V4L2 manager %d", ret);
goto sensor_deinit;
}
…
ret = camera_cap_thread_init();
if (ret) {
CMR_LOGE("Failed to init capture manager %d", ret);
goto cb_deinit;
}
…
ret = camera_prev_thread_init();
if (ret) {
CMR_LOGE("Failed to init preview manager %d", ret);
goto cap_sub_deinit;
}
…
}
2. V4L2
1)Intro
在Linux中,摄像头方面的标准化程度比较高,这个标准就是V4L2驱动程序,这也是业界比较公认的方式。
V4L全称是Video for Linux,是Linux内核中标准的关于视频驱动程序,目前使用比较多的版本是Video for Linux 2,简称V4L2。它为Linux下的视频驱动提供了统一的接口,使得应用程序可以使用统一的API操作不同的视频设备。从内核空间到用户空间,主要的数据流和控制类均由V4L2驱动程序的框架来定义。
V4L2驱动程序一般只提供Video数据的获得,而如何实现视频预览,如何向上层发送数据,如何把纯视频流和取景器、视频录制等实际业务组织起来,都是camera的硬件抽象层需要负责的工作。
V4L2驱动核心实现为如下文件:drivers/media/video/v4l2-dev.c。
V4l2-dev.h中定义的video_device是V4L2驱动程序的核心数据结构,它为具体的摄像头sensor驱动提供了接口调用。
V4l2的采集过程(应用程序):
1)打开设备,获得文件描述符
2)检查和设置设备属性
3)设置帧格式
4)设置一种输入输出方法(缓冲区管理)
5)循环获取数据
6)停止采集,关闭设备
针对上图的流程:
1. 由v4l2驱动框架注册底层字符设备驱动程序/dev/videoX
2. 用户层通过设备接口/dev/videoX打开v4l2设备
3. 通过设备接口/dev/videoX控制camera设备
l 调用v4l2驱动核心
l V4l2驱动核心调用具体V4l2驱动(DCAM设备驱动)
l DCAM设备驱动通过硬件操作控制camera硬件接口控制器DCAM
2)数据结构
V4L2的主要数据结构是video_device,定义在v4l2_dev.h中:
struct video_device
{
#if defined(CONFIG_MEDIA_CONTROLLER)
struct media_entity entity;
#endif
/* device ops */
const struct v4l2_file_operations *fops;
/* sysfs */
struct device dev; /* v4l device */
struct cdev *cdev; /* character device */
/* Set either parent or v4l2_dev if your driver uses v4l2_device */
struct device *parent; /* device parent */
struct v4l2_device *v4l2_dev; /* v4l2_device parent */
/* Control handler associated with this device node. May be NULL. */
struct v4l2_ctrl_handler *ctrl_handler;
/* Priority state. If NULL, then v4l2_dev->prio will be used. */
struct v4l2_prio_state *prio;
/* device info */
char name[32];
int vfl_type;
/* 'minor' is set to -1 if the registration failed */
int minor;
u16 num;
/* use bitops to set/clear/test flags */
unsigned long flags;
/* attribute to differentiate multiple indices on one physical device */
int index;
/* V4L2 file handles */
spinlock_t fh_lock; /* Lock for all v4l2_fhs */
struct list_head fh_list; /* List of struct v4l2_fh */
int debug; /* Activates debug level*/
/* Video standard vars */
v4l2_std_id tvnorms; /* Supported tv norms */
v4l2_std_id current_norm; /* Current tvnorm */
/* callbacks */
void (*release)(struct video_device *vdev);
/* ioctl callbacks */
const struct v4l2_ioctl_ops *ioctl_ops;
/* serialization lock */
struct mutex *lock;
};
3)主要接口函数
int video_register_device(struct video_device *vdev, int type, int nr);
注册字符设备/dev/videoX
static int v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
v4l2的控制接口,最终调用dcam实现的回调
3. DCAM
1)Intro
DCAM模块是SHARK中的camera硬件控制接口,主要关心以下几个方面:
1. 对从sensor采集的数据进行处理、转换以及输出
2. 支持CCIR和MIPI接口
3. 代码实现上,DCAM和V4L2紧密相关,由DCAM实现V4L2框架中的各个接口,而上层代码利用V4L2提供的接口来控制和处理数据,实际上最终是由DCAM来控制和处理。
2)接口方式:
1.Shark前置摄像头使用的ccir并行接口:
2.Shark后置摄像头使用的MIPI-CSI2接口连接sensor:
3)DCAM驱动的代码关系:
DCAM的驱动实现了v4l2所有的接口,dcam_v4l2.c里面注册了很多的回调函数,都是用于实现v4l2的标准接口的.
DCAM的驱动在内核中的位置:drivers/media/video/sprd_dcam/sc8830它包含下边的文件:
dcam_drv_sc8830.c
dcam的具体实现
dcam_v4l2.c
dcam的v4l2的接口
csi2目录
mipi接口驱动
上层进行preview时,HAL,V4L2,DCAM以及Sensor各层代码,它们之间的调用关系如下:
4) DCAM驱动初始化
1. 在SHARK中,DCAM作为平台设备进行管理,初始设置代码在 kernel\arch\arm\mach-sc\devices-sc8830.c,其中定义了平台设备:
struct platform_device sprd_dcam_device = {
.name = "sprd_dcam",
.id = 0,
.num_resources = ARRAY_SIZE(sprd_dcam_resources),
.resource = sprd_dcam_resources,
};
2. 并在kernel\arch\arm\mach-sc\board-sp8830ssd.c中注册平台设备sprd_dcam_device。
3. 最后DCAM module加载时在dcam_v4l2.c中由platform_driver_register()注册dcam驱动,驱动和设备进行绑定到内核。
int __init dcam_v4l2_init(void)
{
int ret = 0, i;
if (platform_driver_register(&dcam_driver) != 0) {
printk("platform device register Failed \n");
return -1;
}
printk(KERN_INFO "Video Technology Magazine Virtual Video "
"Capture Board ver %u.%u.%u successfully loaded.\n",
(DCAM_VERSION >> 16) & 0xFF, (DCAM_VERSION >> 8) & 0xFF,
DCAM_VERSION & 0xFF);
return ret;
}
5) 数据结构
DCAM的主要数据结构dcam_dev:
struct dcam_dev {
struct list_head dcam_devlist;
struct v4l2_device v4l2_dev;
spinlock_t slock;
struct mutex lock;
atomic_t users;
/* various device info */
struct video_device *vfd;
struct dcam_dmaqueue vidq;
/* Several counters */
int h, m, s, ms;
unsigned long jiffies;
char timestr[13];
int mv_count; /* Controls bars movement */
/* Input Number */
int input;
/* Control 'registers' */
int qctl_regs[ARRAY_SIZE(dcam_qctrl)];
struct v4l2_streamparm streamparm;
};
DCAM控制器在驱动里使用了下面结构来描述:
LOCAL struct video_device sprd_v4l2_template = {
.name = "dcam",
.fops = &sprd_v4l2_fops,
.ioctl_ops = &sprd_v4l2_ioctl_ops,
.minor = -1,
.release = video_device_release,
.tvnorms = V4L2_STD_525_60,
.current_norm = V4L2_STD_NTSC_M,
};
fops结构体是针对v4l2设备的基本操作,定义如下:
LOCAL const struct v4l2_file_operations sprd_v4l2_fops = {
.owner = THIS_MODULE,
.open = sprd_v4l2_open,
.read = sprd_v4l2_read,
.release = sprd_v4l2_close,
.write = sprd_v4l2_write,
.ioctl = video_ioctl2, /* V4L2 ioctl handler */
};
cmr_v4l2_init()中打开v4l2设备:
fd = open(“/dev/video0”, O_RDWR, 0)-> sprd_v4l2_open()
6)接口函数
DCAM的主要回调函数如下,在dcam_v4l2.c中实现v4l2框架中的各个接口函数:
LOCAL const struct v4l2_ioctl_ops sprd_v4l2_ioctl_ops = {
.vidioc_g_parm = v4l2_g_parm,
.vidioc_s_parm = v4l2_s_parm,
.vidioc_querycap = v4l2_querycap,
.vidioc_cropcap = v4l2_cropcap,
.vidioc_s_crop = v4l2_s_crop,
.vidioc_enum_fmt_vid_cap = v4l2_enum_fmt_vid_cap,
.vidioc_enum_fmt_type_private = v4l2_enum_fmt_vid_cap,
.vidioc_g_fmt_vid_cap = v4l2_g_fmt_vid_cap,
.vidioc_g_fmt_type_private = v4l2_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = v4l2_try_fmt_vid_cap,
.vidioc_try_fmt_type_private = v4l2_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = v4l2_s_fmt_vid_cap,
.vidioc_qbuf = v4l2_qbuf,
.vidioc_dqbuf = v4l2_dqbuf,
.vidioc_streamon = v4l2_streamon,
.vidioc_streamoff = v4l2_streamoff,
.vidioc_g_crop = v4l2_g_crop,
.vidioc_g_output = v4l2_g_output,
.vidioc_s_ctrl = v4l2_s_ctrl,
.vidioc_g_fmt_vid_out = v4l2_g_fmt_vid_out,
.vidioc_enum_fmt_vid_out = v4l2_enum_fmt_vid_cap,
.vidioc_try_fmt_vid_out = v4l2_try_fmt_vid_cap
};
HAL层cmr_v4l2.c中的控制接口ioctl()根据不同参数通过v4l2-ioctl.c的控制,最终调用上面对应的回调函数,以完成对dcam的控制。
4. Sensor驱动
1) 驱动三大步
l 摄像头的上电、时钟这些基本条件;
l I2C保证摄像头的初始化;
l 摄像头工作后传回数据到Camera控制器DCAM。
2) 主要涉及文件
sensor_drv_u.c
用户层的sensor接口,封装sensor_srv_k.c,提供对上接口
sensor_s5k4ecgx_mipi.c
l 具体摄像头驱动-后置
l 用户层驱动,分离于内核层sensor_srv_k.c内核驱动,便于开发和调试
l Sensor寄存器的读写以实现具体camera功能
sensor_hi702_ccir.c
同上,前置摄像头
sensor_drv_k.c
l sensor的内核驱动模块,作为platform驱动管理
l 初始化、控制sensor,具体功能包括:
n 上下电
n 设置时钟
n 配置I2C,I2C读写
n 控制闪光灯
l 通过/dev/sprd_sensor提供用户层访问接口
3) 调用关系