📄 pxa_ov_camera.c
字号:
// set capture format
ret = ovcamera_set_capture_format(p_ovcam_ctx);
if (ret)
{
ovcamprint("ovcamera_init ( -8 ) \n");
goto camera_init_err;
}
// set frame rate
ci_set_frame_rate(p_ovcam_ctx->frame_rate);
return 0;
camera_init_err:
ovcamera_deinit(p_ovcam_ctx);
return -1;
}
static int ovcamera_deinit ( p_ovcamera_context_t p_ovcam_ctx )
{
int ret;
// deinit sensor
ret = p_ovcam_ctx->camera_functions->deinit(p_ovcam_ctx);
// capture interface deinit
ci_deinit();
return ret;
}
///////////////////////////////////////////////////////////////////////////////////////////
//Configure Quick Capture Interface accoding to current setting
///////////////////////////////////////////////////////////////////////////////////////////
static int ovcamera_set_capture_format(p_ovcamera_context_t p_ovcam_ctx)
{
int ret;
unsigned int frame_size;
unsigned int block_number = 0;
CI_IMAGE_FORMAT ci_input_format, ci_output_format;
CI_MP_TIMING timing;
ovcamprint("ovcamera_set_capture_format( + ) \n");
if (p_ovcam_ctx->cf.in > CAMERA_IMAGE_FORMAT_MAX ||
p_ovcam_ctx->cf.out > CAMERA_IMAGE_FORMAT_MAX )
{
ovcamprint("ovcamera_set_capture_format( -0 ) \n");
return STATUS_WRONG_PARAMETER;
}
ci_input_format = FORMAT_MAPPINGS[p_ovcam_ctx->cf.in];
ci_output_format = FORMAT_MAPPINGS[p_ovcam_ctx->cf.out];
if (ci_input_format == CI_INVALID_FORMAT || ci_output_format == CI_INVALID_FORMAT)
{
ovcamprint("ovcamera_set_capture_format( -1 ) \n");
return STATUS_WRONG_PARAMETER;
}
ci_set_image_format(ci_input_format, ci_output_format);
if(ci_input_format == CI_JPEG)
{
ovcamprint("ovcamera_set_capture_format( +JPEG ) \n");
timing.BFW = timing.BLW = 0;
ci_configure_mp(1023,2047, &timing);
}
else
{
timing.BFW = timing.BLW = 0;
ci_configure_mp(p_ovcam_ctx->vw.width-1, p_ovcam_ctx->vw.height-1, &timing);
}
ret = p_ovcam_ctx->camera_functions->capture_set_format(p_ovcam_ctx);
if (ret)
{
ovcamprint("ovcamera_set_capture_format( -2 ) \n");
return ret;
}
switch(p_ovcam_ctx->cf.out)
{
case CAMERA_IMAGE_FORMAT_RGB565:
frame_size = p_ovcam_ctx->vw.width * p_ovcam_ctx->vw.height * 2;
p_ovcam_ctx->fifo0_transfer_size = frame_size;
p_ovcam_ctx->fifo1_transfer_size = 0;
p_ovcam_ctx->fifo2_transfer_size = 0;
break;
case CAMERA_IMAGE_FORMAT_YCBCR422_PACKED:
frame_size = p_ovcam_ctx->vw.width * p_ovcam_ctx->vw.height * 2;
p_ovcam_ctx->fifo0_transfer_size = frame_size;
p_ovcam_ctx->fifo1_transfer_size = 0;
p_ovcam_ctx->fifo2_transfer_size = 0;
break;
case CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR:
frame_size = p_ovcam_ctx->vw.width * p_ovcam_ctx->vw.height * 2;
p_ovcam_ctx->fifo0_transfer_size = frame_size / 2;
p_ovcam_ctx->fifo1_transfer_size = frame_size / 4;
p_ovcam_ctx->fifo2_transfer_size = frame_size / 4;
break;
case CAMERA_IMAGE_FORMAT_RGB666_PLANAR:
frame_size = p_ovcam_ctx->vw.width * p_ovcam_ctx->vw.height * 4;
p_ovcam_ctx->fifo0_transfer_size = frame_size;
p_ovcam_ctx->fifo1_transfer_size = 0;
p_ovcam_ctx->fifo2_transfer_size = 0;
break;
case CAMERA_IMAGE_FORMAT_RGB666_PACKED:
frame_size = p_ovcam_ctx->vw.width * p_ovcam_ctx->vw.height * 3;
p_ovcam_ctx->fifo0_transfer_size = frame_size;
p_ovcam_ctx->fifo1_transfer_size = 0;
p_ovcam_ctx->fifo2_transfer_size = 0;
break;
case CAMERA_IMAGE_FORMAT_RGB888_PLANAR:
frame_size = p_ovcam_ctx->vw.width * p_ovcam_ctx->vw.height * 4;
p_ovcam_ctx->fifo0_transfer_size = frame_size;
p_ovcam_ctx->fifo1_transfer_size = 0;
p_ovcam_ctx->fifo2_transfer_size = 0;
break;
case CAMERA_IMAGE_FORMAT_JPEG:
frame_size = p_ovcam_ctx->vw.width * p_ovcam_ctx->vw.height ; //compression ration > 2:1
p_ovcam_ctx->fifo0_transfer_size = frame_size;
p_ovcam_ctx->fifo1_transfer_size = 0;
p_ovcam_ctx->fifo2_transfer_size = 0;
break;
default:
return STATUS_WRONG_PARAMETER;
break;
}
p_ovcam_ctx->block_size = frame_size;
block_number = p_ovcam_ctx->ui_buffer_size / frame_size;
p_ovcam_ctx->block_number = block_number > MAX_BLOCK_NUM ? MAX_BLOCK_NUM : block_number;
p_ovcam_ctx->block_header = p_ovcam_ctx->block_tail = 0;
// generate dma descriptor chain
ret = update_dma_chain(p_ovcam_ctx);
if (ret)
{
ovcamprint("ovcamera_set_capture_format( -3 ) \n");
return -1;
}
ovcamprint("ovcamera_set_capture_format( - ) \n");
return 0;
}
static int ovcamera_video_capture_start(p_ovcamera_context_t p_ovcam_ctx, unsigned int block_id)
{
int ret;
ovcamprint("ovcamera_video_capture_start( + ) \n");
// init buffer status & capture
p_ovcam_ctx->block_header = p_ovcam_ctx->block_tail = block_id;
p_ovcam_ctx->ui_capture_status = CAMERA_STATUS_VIDEO_CAPTURE_IN_PROCESS;
ret = capture_start( p_ovcam_ctx, block_id, 0 );
ovcamprint("ovcamera_video_capture_start( - ) \n");
return ret;
}
static int ovcamera_video_capture_stop(p_ovcamera_context_t p_ovcam_ctx)
{
int ret;
ovcamprint("ovcamera_video_capture_stop( ) \n");
ret = p_ovcam_ctx->camera_functions->capture_stop( p_ovcam_ctx);
dma_transfer_stop( p_ovcam_ctx);
if ( !( p_ovcam_ctx->ui_capture_status & CAMERA_STATUS_RING_BUFFER_FULL) )
p_ovcam_ctx->ui_capture_status &= ~CAMERA_STATUS_VIDEO_CAPTURE_IN_PROCESS;
return ret;
}
static int ovcamera_stillimage_capture(p_ovcamera_context_t p_ovcam_ctx, unsigned int block_id)
{
int ret;
ovcamprint("ovcamera_video_capture_start( + ) \n");
// init buffer status & capture
p_ovcam_ctx->block_header = p_ovcam_ctx->block_tail = block_id;
p_ovcam_ctx->ui_capture_status = CAMERA_STATUS_STILLIMAGE_CAPTURE_IN_PROCESS;
ret = capture_start( p_ovcam_ctx, block_id, 1 );
ovcamprint("ovcamera_video_capture_start( - ) \n");
return ret;
}
static int pxa_ovcamera_VIDIOCGCAP(p_ovcamera_context_t p_ovcam_ctx,void* param)
{
struct video_capability vc;
strcpy(vc.name,"OmniVsion Camera Driver for OV2640");
vc.maxwidth= 1600;
vc.maxheight= 1200;
vc.minwidth =8;
vc.minheight =8;
if(copy_to_user(param,&vc,sizeof(struct video_capability)))
return -EFAULT;
return 0;
}
static int pxa_ovcamera_VIDIOCGWIN(p_ovcamera_context_t p_ovcam_ctx,void* param)
{
struct video_window vw;
vw.width= p_ovcam_ctx->vw.width;
vw.height= p_ovcam_ctx->vw.height;
if(copy_to_user(param,&vw,sizeof(struct video_window)))
return -EFAULT;
return 0;
}
static int pxa_ovcamera_VIDIOCSWIN(p_ovcamera_context_t p_ovcam_ctx,void* param)
{
struct video_window vw;
if(copy_from_user(&vw,param,sizeof(struct video_window)))
{
ovcamprint("parameter error 0 ");
return -EFAULT;
}
if(vw.width > 1600 || vw.height > 1200 || vw.width < 8 || vw.height < 8)
{
ovcamprint("parameter error 1");
return -EFAULT;
}
p_ovcam_ctx->vw.width = (vw.width + 7) / 8;
p_ovcam_ctx->vw.width *=8;
p_ovcam_ctx->vw.height = (vw.height + 7) / 8;
p_ovcam_ctx->vw.height *=8;
return ovcamera_set_capture_format(p_ovcam_ctx);
}
static int pxa_ovcamera_VIDIOCSPICT(p_ovcamera_context_t p_ovcam_ctx,void* param)
{
struct video_picture vp;
if(copy_to_user(&vp,param,sizeof(struct video_picture)))
return -EFAULT;
return 0;
}
static int pxa_ovcamera_VIDIOCGPICT(p_ovcamera_context_t p_ovcam_ctx,void* param)
{
struct video_picture vp;
if(copy_from_user(&vp,param,sizeof(struct video_picture)))
return -EFAULT;
return 0;
}
static int pxa_ovcamera_VIDIOCCAPTURE(p_ovcamera_context_t p_ovcam_ctx,void* param)
{
int stream_flag=(int)param;
ovcamprint("pxa_ovcamera_VIDIOCCAPTURE ( + ) ");
if( 0 < stream_flag ) // Still image mode
{
ovcamprint("pxa_ovcamera_VIDIOCCAPTURE ( +1 ) ");
ovcamera_set_int_mask( p_ovcam_ctx,0x3f9 | 0x0400 );
p_ovcam_ctx->block_header = 0;
p_ovcam_ctx->block_tail = 0;
still_image_mode = 1;
ovcamera_stillimage_capture ( p_ovcam_ctx,0 );
}
else if(0 == stream_flag ) //start video mode
{
ovcamprint("pxa_ovcamera_VIDIOCCAPTURE ( +2 ) ");
ovcamera_set_int_mask ( p_ovcam_ctx,0x3f9 | 0x0400 );
p_ovcam_ctx->block_header = 0;
p_ovcam_ctx->block_tail = 0;
still_image_mode = 0;
first_video_frame = 1;
ovcamera_video_capture_start ( p_ovcam_ctx,0 );
}
else if( -1 == stream_flag ) //stop video mode
{
ovcamprint("pxa_ovcamera_VIDIOCCAPTURE ( +3 ) ");
ovcamera_video_capture_stop ( p_ovcam_ctx );
}
else
{
ovcamprint("pxa_ovcamera_VIDIOCCAPTURE ( +0 ) ");
}
ovcamprint("pxa_ovcamera_VIDIOCCAPTURE ( - ) ");
return 0;
}
static int pxa_ovcamera_VIDIOCGMBUF(p_ovcamera_context_t p_ovcam_ctx,void* param)
{
struct video_mbuf vm;
int i;
memset(&vm,0,sizeof(vm));
vm.size = 256;
vm.frames = 3;
for(i = 0; i < vm.frames; i++)
vm.offsets[i] = p_ovcam_ctx->page_aligned_block_size*i;
if(copy_to_user((void*)param,(void*)&vm,sizeof(struct video_mbuf)))
return -EFAULT;
return 0;
}
static int pxa_ovcamera_WCAM_VIDIOCSCAMREG(p_ovcamera_context_t p_ovcam_ctx,void* param)
{
int ret;
camerachip_protocol_t cp;
if(copy_from_user(&cp,param,sizeof(camerachip_protocol_t)))
{
ovcamprint("parameter error 0 ");
return -EFAULT;
}
cp.cmd = OVCAMCHIP_CMD_REG_SET;
ret = p_ovcam_ctx->camera_functions->command(p_ovcam_ctx, cp.cmd, (void*)&cp);
if(copy_to_user((void*)param,(void*)&cp,sizeof(camerachip_protocol_t)))
{
return -EFAULT;
}
return ret;
}
static int pxa_ovcamera_WCAM_VIDIOCGCAMREG(p_ovcamera_context_t p_ovcam_ctx,void* param)
{
int ret;
camerachip_protocol_t cp;
if(copy_from_user(&cp,param,sizeof(camerachip_protocol_t)))
{
ovcamprint("parameter error 0 ");
return -EFAULT;
}
cp.cmd = OVCAMCHIP_CMD_REG_GET;
ret = p_ovcam_ctx->camera_functions->command(p_ovcam_ctx, cp.cmd, (void*)&cp);
if(copy_to_user((void*)param,(void*)&cp,sizeof(camerachip_protocol_t)))
{
return -EFAULT;
}
return ret;
}
static int pxa_ovcamera_WCAM_VIDIOCSINFOR(p_ovcamera_context_t p_ovcam_ctx,void* param)
{
int ret;
struct capture_format cf;
if (copy_from_user(&cf, param, sizeof(struct capture_format)))
{
return -EFAULT;
}
p_ovcam_ctx->cf = cf;
ret = ovcamera_set_capture_format ( p_ovcam_ctx );
return ret;
}
static int pxa_ovcamera_WCAM_VIDIOCGINFOR(p_ovcamera_context_t p_ovcam_ctx,void* param)
{
struct capture_format cf;
if (copy_from_user(&cf, param, sizeof(int) * 2))
{
return -EFAULT;
}
cf.out = ci_get_reg_value (cf.in);
if (copy_to_user(param, &cf, sizeof(int) * 2))
{
return -EFAULT;
}
return 0;
}
static int pxa_ovcamera_WCAM_VIDIOCCAMERACHIP(p_ovcamera_context_t p_ovcam_ctx,void* param)
{
int ret;
camerachip_protocol_t cp;
if (copy_from_user(&cp, param, sizeof(camerachip_protocol_t)))
{
return -EFAULT;
}
ret = p_ovcam_ctx->camera_functions->command(p_ovcam_ctx,cp.cmd, (void*)&cp);
if(copy_to_user((void*)param,(void*)&cp,sizeof(camerachip_protocol_t)))
{
return -EFAULT;
}
return ret;
}
void pxa_dma_repeat(ovcamera_context_t *ovcam_ctx)
{
pxa_dma_desc *cnt_head, *cnt_tail;
int cnt_block;
cnt_block = (ovcam_ctx->block_header + 1) % ovcam_ctx->block_number;
// FIFO0
(pxa_dma_desc *)cnt_head = (pxa_dma_desc *)ovcam_ctx->fifo0_descriptors_virtual + cnt_block * ovcam_ctx->fifo0_num_descriptors;
cnt_tail = cnt_head + ovcam_ctx->fifo0_num_descriptors - 1;
cnt_tail->ddadr = cnt_head->ddadr - sizeof(pxa_dma_desc);
// FIFO1
if (ovcam_ctx->fifo1_transfer_size)
{
cnt_head = (pxa_dma_desc *)ovcam_ctx->fifo1_descriptors_virtual + cnt_block * ovcam_ctx->fifo1_num_descriptors;
cnt_tail = cnt_head + ovcam_ctx->fifo1_num_descriptors - 1;
cnt_tail->ddadr = cnt_head->ddadr - sizeof(pxa_dma_desc);
}
// FIFO2
if (ovcam_ctx->fifo2_transfer_size)
{
cnt_head = (pxa_dma_desc *)ovcam_ctx->fifo2_descriptors_virtual + cnt_block * ovcam_ctx->fifo2_num_descriptors;
cnt_tail = cnt_head + ovcam_ctx->fifo2_num_descriptors - 1;
cnt_tail->ddadr = cnt_head->ddadr - sizeof(pxa_dma_desc);
}
return;
}
void pxa_dma_continue(ovcamera_context_t *ovcam_ctx)
{
pxa_dma_desc *cnt_head, *cnt_tail;
pxa_dma_desc *next_head;
int cnt_block, next_block;
cnt_block = ovcam_ctx->block_header;
next_block = (cnt_block + 1) % ovcam_ctx->block_number;
// FIFO0
cnt_head = (pxa_dma_desc *)ovcam_ctx->fifo0_descriptors_virtual + cnt_block * ovcam_ctx->fifo0_num_descriptors;
cnt_tail = cnt_head + ovcam_ctx->fifo0_num_descriptors - 1;
next_head = (pxa_dma_desc *)ovcam_ctx->fifo0_descriptors_virtual + next_block * ovcam_ctx->fifo0_num_descriptors;
cnt_tail->ddadr = next_head->ddadr - sizeof(pxa_dma_desc);
// FIFO1
if (ovcam_ctx->fifo1_transfer_size)
{
cnt_head = (pxa_dma_desc *)ovcam_ctx->fifo1_descriptors_virtual + cnt_block * ovcam_ctx->fifo1_num_descriptors;
cnt_tail = cnt_head + ovcam_ctx->fifo1_num_descriptors - 1;
next_head = (pxa_dma_desc *)ovcam_ctx->fifo1_descriptors_virtual + next_block * ovcam_ctx->fifo1_num_descriptors;
cnt_tail->ddadr = next_head->ddadr - sizeof(pxa_dma_desc);
}
// FIFO2
if (ovcam_ctx->fifo2_transfer_size)
{
cnt_head = (pxa_dma_desc *)ovcam_ctx->fifo2_descriptors_virtual + cnt_block * ovcam_ctx->fifo2_num_descriptors;
cnt_tail = cnt_head + ovcam_ctx->fifo2_num_descriptors - 1;
next_head = (pxa_dma_desc *)ovcam_ctx->fifo2_descriptors_virtual + next_block * ovcam_ctx->fifo2_num_descriptors;
cnt_tail->ddadr = next_head->ddadr - sizeof(pxa_dma_desc);
}
return;
}
void pxa_ci_dma_irq_y(int channel, void *data, struct pt_regs *regs)
{
int dcsr;
static int dma_repeated=0;
ovcamera_context_t *ovcam_ctx = g_ovcamera_context;
dcsr = DCSR(channel);
DCSR(channel) = dcsr & ~DCSR_STOPIRQEN;
if (still_image_mode == 1)
{
if (task_waiting == 1)
{
wake_up_interruptible (&ovcamera_wait_q);
task_waiting = 0;
}
else
{
still_image_ready = 1;
}
}
else if (dma_repeated == 0
&& (ovcam_ctx->block_tail == ((ovcam_ctx->block_header + 2) % ovcam_ctx->block_number)))
{
dma_repeated = 1;
pxa_dma_repeat(ovcam_ctx);
ovcam_ctx->block_header = (ovcam_ctx->block_header + 1) % ovcam_ctx->block_number;
}
else if (dma_repeated == 1 &&
(ovcam_ctx->block_tail != ((ovcam_ctx->block_header + 1) % ovcam_ctx->block_number))
&& (ovcam_ctx->block_tail != ((ovcam_ctx->block_header + 2) % ovcam_ctx->block_number)))
{
pxa_dma_continue(ovcam_ctx);
dma_repeated = 0;
}
else if (dma_repeated == 0)
{
ovcam_ctx->block_header = (ovcam_ctx->block_header + 1) % ovcam_ctx->block_number;
}
if (task_waiting == 1 && !(ovcam_ctx->block_header == ovcam_ctx->block_tail))
{
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -