分析阅读的是s3c6410 winCE6.0的摄像头驱动,s5pv210虽然也是6.0,但结构大不相同,暂且不提。
摄像头驱动是个流驱动,提供两类接口CAM_xxx和PIN_xxx。前者供通过注册表装载硬件时使用,在代码中也叫adapter,指的是摄像头硬件;后者在应用层用dshow显示视频图像时调用,是承载数据流stream的工具,分为preview, capture和video三类,每个Pin只能承载一个stream。
根据MSDN,应用层调用摄像头驱动初始化时序如下:1)调用CAM_Init和CAM_Open。2)Dshow调用FindFirstDevice得到设备名,调用CreateFile打开。3)Dshow用CSPROPERTY_PIN_CTYPES 得到驱动支持的pin的数量,用CSPROPERTY_PIN_CATEGORY得到每个pin的种类,用CSPROPERTY_PIN_DEVICENAME得到pin的名字(通常是PIN1:)。4)Dshow调用createFile打开PIN驱动,初始化stream,设置它的properties, data format,并为它分配buffer。5)实例化stream,设置它的种类,并添加一个queue,用于在驱动和Dshow间异步传递数据。
本文以PIN_IOControl中的动作来分析摄像头驱动,主要关注preview动作相关的部分,buffer分配以CSPROPERTY_BUFFER_CLIENT_LIMITED为例(这也是本人开发环境下实际采用的方式)。
PIN_IOControl中的各种命令码可以简单归结为如下框图。除PIN_IOControl外,每个橙色方框中的子命令由CPinDevice类实现,函数名标于方框中。
具体的IOControl配置步骤和分析思路采用http://jazka.blog.51cto.com/809003/719130(感激不尽~),各步骤调用时序如下所述。
0. CAM_Init中初始化CAM,逐层调用到在s3c6410_camera.cpp的cameraInit()可以看到,其中将各寄存器的物理地址映射成虚拟地址,初始化外设模块,设置GPIO,时钟,设置DMA buffer的物理和虚拟地址,初始化中断。
1.实例化各种pin接口
2.设置pin的视频流格式
3.初始化Sensor状态,包括Camera时钟、GPIO、复位等设置,之后设置Capture的状态为PAUSE。可以看出这步需要和camera外设交互,正确设置外设的寄存器数值,使其正常工作。
4.管理Pin的Buffer,本环境中由用户层分配
5.设置still和capture的pin为pause状态。
6.设置preview的pin为run状态。
7.添加buffer到驱动的队列中。CS_ENQUEUE时,在CPinDevice的EnqueueDescriptor()里,把应用层传过来的buffer marshall到PinDevice的m_pStreamDescriptorList里。
8.中断处理。在帧同步的中断中,从buffer中copy image,加入queue中。
摄像头驱动的工作流程大致如上。