📄 pxa_ov_camera.c
字号:
wake_up_interruptible (&ovcamera_wait_q);
task_waiting = 0;
}
return;
}
void pxa_ci_dma_irq_u(int channel, void *data, struct pt_regs *regs)
{
return;
}
void pxa_ci_dma_irq_v(int channel, void *data, struct pt_regs *regs)
{
return;
}
void pxa_ovcamera_irq(int irq, void* dev_id, struct pt_regs *regs)
{
int cisr;
static int dma_started=0;
ovcamera_context_t *ovcam_ctx = g_ovcamera_context;
disable_irq(IRQ_CAMERA);
cisr = CISR;
if (cisr & CI_CISR_SOF) //start of frame
{
if(still_image_mode)
{
if( ovcam_ctx->ui_capture_status & CAMERA_STATUS_STILLIMAGE_CAPTURE_IN_PROCESS )
{
if( ovcam_ctx->cf.in == CAMERA_IMAGE_FORMAT_JPEG )
{
if( dma_started)
{
ovcamprint("pxa_ovcamera_irq( ) JPEG END\n");
dma_transfer_stop(ovcam_ctx);
if (task_waiting == 1)
{
ovcamprint("pxa_ovcamera_irq( +1 ) \n");
wake_up_interruptible (&ovcamera_wait_q);
task_waiting = 0;
}
else
{
ovcamprint("pxa_ci_dma_irq_y( +2 ) \n");
still_image_ready = 1;
}
ovcam_ctx->ui_capture_status &=~ CAMERA_STATUS_STILLIMAGE_CAPTURE_IN_PROCESS;
still_image_mode=0;
dma_started = 0;
}
else if(dma_started ==0)
{
dma_started = 1;
ovcamprint("pxa_ovcamera_irq( ) JPEG STAT\n");
}
}
}
}
CISR |= CI_CISR_SOF;
}
if (cisr & CI_CISR_EOF) //end of frame
{
CISR |= CI_CISR_EOF;
dma_started=0;
}
ci_clear_int_status(0xffffffff);
enable_irq(IRQ_CAMERA);
}
/*########################################################################################
/
/ API: Open
/
/########################################################################################*/
static int pxa_ovcamera_open(struct inode *inode, struct file *file)
{
int ret;
ovcamera_context_t *ovcam_ctx;
ovcamprint("pxa_ovcamera_open( + ) \n");
init_waitqueue_head(&ovcamera_wait_q);
ovcam_ctx=g_ovcamera_context;
if(atomic_read(&ovcam_ctx->count))
{
ovcamprint("pxa_ovcamera_open( -1 ) \n");
return -EBUSY;
}
atomic_inc(&ovcam_ctx->count);
ovcam_ctx->vw.width = WIDTH_DEFAULT;
ovcam_ctx->vw.height = HEIGHT_DEFAULT;
ovcam_ctx->cf.in = CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR;
ovcam_ctx->cf.out = CAMERA_IMAGE_FORMAT_YCBCR422_PLANAR;
ovcam_ctx->frame_rate = FRAMERATE_DEFAULT;
ovcam_ctx->camera_functions = &camerachip_func;
ovcam_ctx->ui_ost_reg_base =0;
ovcam_ctx->ui_gpio_reg_base=0;
ovcam_ctx->ui_ci_reg_base=0;
ovcam_ctx->ui_board_reg_base=0;
ovcam_ctx->p_dmadest_virtual=dma_alloc_writecombine(NULL,MAX_DESCRIPTORS_NUM * sizeof(pxa_dma_desc),
(void*)&ovcam_ctx->p_dmadest_physical,GFP_KERNEL);
if (NULL == ovcam_ctx->p_dmadest_virtual)
{
ovcamprint("can't alloc mem\n");
ovcamprint("pxa_ovcamera_open( -1 ) \n");
goto open_error_0;
}
ovcam_ctx->ui_dmadest_size = MAX_DESC_NUM;
#if 0
ovcam_ctx->ui_buffer_size = BUFFER_SIZE_DEFAULT;
ovcam_ctx->p_buffer_virtual = dma_alloc_writecombine(NULL,ovcam_ctx->ui_buffer_size,
(void*)&ovcam_ctx->p_buffer_physical,GFP_KERNEL);
if( NULL == ovcam_ctx->p_buffer_virtual )
{
ovcamprint("pxa_ovcamera_open( -2 ) \n");
goto open_error_0;
}
#endif
ret = ovcamera_init(ovcam_ctx);
PM_INC_DEV_USER(PM_DEV_CS);
ovcamprint("pxa_ovcamera_open( - ) \n");
return ret;
open_error_0:
return -1;
}
static void pxa_ovcamera_close(struct inode *inode, struct file *file)
{
ovcamera_context_t *ovcam_ctx = g_ovcamera_context;
ovcamprint("pxa_ovcamera_close ( )\n");
atomic_dec(&ovcam_ctx->count);
ovcamera_deinit(ovcam_ctx);
if (ovcam_ctx->p_dmadest_virtual)
dma_free_writecombine (NULL, MAX_DESCRIPTORS_NUM * sizeof (pxa_dma_desc),
ovcam_ctx->p_dmadest_virtual,
(int)ovcam_ctx->p_dmadest_physical);
#if 0
if (ovcam_ctx->p_buffer_virtual)
dma_free_writecombine (NULL,ovcam_ctx->ui_buffer_size,
ovcam_ctx->p_buffer_virtual,
(int)ovcam_ctx->p_buffer_physical);
#endif
PM_DEC_DEV_USER(PM_DEV_CS);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
//API - Read
//
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
static long pxa_ovcamera_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
ovcamera_context_t *ovcam_ctx = g_ovcamera_context;
int offset = 0;
if ((still_image_mode == 1) && (still_image_ready == 1))
{
if (copy_to_user(buf, ovcam_ctx->p_buffer_virtual + offset, ovcam_ctx->block_size))
return -EFAULT;
still_image_ready = 0;
still_image_mode = 0;
ovcamprint("pxa_ovcamera_read( - 0 ) \n");
return ovcam_ctx->block_size;
}
if (first_video_frame == 1)
{
first_video_frame = 0;
}
else if (still_image_mode == 0)
{
ovcam_ctx->block_tail = (ovcam_ctx->block_tail + 1) % ovcam_ctx->block_number;
}
offset = ovcam_ctx->block_tail * ovcam_ctx->block_size;
if (ovcam_ctx->block_header == ovcam_ctx->block_tail)
{
task_waiting = 1;
interruptible_sleep_on (&ovcamera_wait_q);
}
if (copy_to_user(buf, ovcam_ctx->p_buffer_virtual + offset, ovcam_ctx->block_size))
{
ovcamprint("pxa_ovcamera_read( - 2) \n");
return -EFAULT;
}
return ovcam_ctx->block_size;
}
static unsigned int pxa_ovcamera_poll(struct file *file, poll_table *wait)
{
return POLLIN|POLLRDNORM;
}
static int pxa_ovcamera_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long param)
{
switch (cmd) {
case VIDIOCGCAP:
{
return pxa_ovcamera_VIDIOCGCAP(g_ovcamera_context,param);
}
case VIDIOCGWIN:
{
return pxa_ovcamera_VIDIOCGWIN(g_ovcamera_context,param);
}
case VIDIOCSWIN:
{
return pxa_ovcamera_VIDIOCSWIN(g_ovcamera_context,param);
}
case VIDIOCSPICT:
{
return pxa_ovcamera_VIDIOCSPICT(g_ovcamera_context,param);
}
case VIDIOCGPICT:
{
return pxa_ovcamera_VIDIOCGPICT(g_ovcamera_context,param);
}
case VIDIOCCAPTURE:
{
return pxa_ovcamera_VIDIOCCAPTURE(g_ovcamera_context,param);
}
case VIDIOCGMBUF:
{
return pxa_ovcamera_VIDIOCGMBUF(g_ovcamera_context,param);
}
case WCAM_VIDIOCSCAMREG:
{
return pxa_ovcamera_WCAM_VIDIOCSCAMREG(g_ovcamera_context,param);
}
case WCAM_VIDIOCGCAMREG:
{
return pxa_ovcamera_WCAM_VIDIOCGCAMREG(g_ovcamera_context,param);
}
case WCAM_VIDIOCSINFOR:
{
return pxa_ovcamera_WCAM_VIDIOCSINFOR(g_ovcamera_context,param);
}
case WCAM_VIDIOCGINFOR:
{
return pxa_ovcamera_WCAM_VIDIOCGINFOR(g_ovcamera_context,param);
}
case WCAM_VIDIOCCAMERACHIP:
{
return pxa_ovcamera_WCAM_VIDIOCCAMERACHIP(g_ovcamera_context,param);
}
default:
{
return 0;
}
}
return 0;
}
static inline unsigned long uvirt_to_kva(pgd_t *pgd, unsigned long adr)
{
unsigned long ret = 0UL;
pmd_t *pmd;
pte_t *ptep, pte;
if (!pgd_none(*pgd))
{
pmd = pmd_offset(pgd, adr);
if (!pmd_none(*pmd))
{
ptep = pte_offset(pmd, adr);
pte = *ptep;
if (pte_present(pte))
{
ret = (unsigned long) page_address(pte_page(pte));
ret |= (adr & (PAGE_SIZE-1));
}
}
}
return ret;
}
static inline unsigned long kvirt_to_pa(unsigned long adr)
{
unsigned long va, kva, ret;
va = VMALLOC_VMADDR(adr);
kva = uvirt_to_kva(pgd_offset_k(va), va);
ret = __pa(kva);
return ret;
}
static int pxa_ovcamera_mmap(struct file* file, struct vm_area_struct *vma)
{
unsigned long start = (unsigned long)vma->vm_start;
unsigned long end = (unsigned long)vma->vm_end;
unsigned long size = end-start;
unsigned long page, pos;
ovcamera_context_t *ovcam_ctx = g_ovcamera_context;
pos = (unsigned long)ovcam_ctx->p_buffer_virtual;
page = (unsigned long)(ovcam_ctx->p_buffer_physical) >> 12;
if (remap_pfn_range(vma,start, page, size,vma->vm_page_prot ))
{
return -EFAULT;
}
return 0;
}
static int pxa_ovcamera_video_init(struct video_device *dev)
{
int ret=-1;
ovcamprint("pxa_ovcamera_video_init() ......\n");
g_ovcamera_context=kmalloc(sizeof(struct ovcamera_context_s),GFP_KERNEL);
if ( !g_ovcamera_context)
{
ovcamprint("allocate buffer for camera context \n");
}
else
{
memset(g_ovcamera_context, 0, sizeof(struct ovcamera_context_s));
ret = 0;
}
#if 1
g_ovcamera_context->ui_buffer_size = BUFFER_SIZE_DEFAULT;
g_ovcamera_context->p_buffer_virtual = dma_alloc_writecombine(NULL,g_ovcamera_context->ui_buffer_size,
(void*)&g_ovcamera_context->p_buffer_physical,GFP_KERNEL);
if( NULL == g_ovcamera_context->p_buffer_virtual ) {
ovcamprint("video_init( -2 ) mem not enough \n");
ret = -ENOMEM;
}
#endif
atomic_set(&g_ovcamera_context->count,0);
return ret;
}
static void pxa_camera_release(struct video_device *dev)
{
}
static int pxa_camera_suspend()
{
return 0;
}
static int pxa_camera_resume()
{
DRCMR68 = ci_dma_y | DRCMR_MAPVLD;
DRCMR69 = ci_dma_u | DRCMR_MAPVLD;
DRCMR70 = ci_dma_v | DRCMR_MAPVLD;
return 0;
}
int pxa_camera_pm_switch(unsigned int flag)
{
if(flag==0){
pxa_camera_suspend();
}else{
pxa_camera_resume();
}
return PM_SW_READY;
}
static pm_reg_dev_t pm_dev={"CAMERA PM DEV",PM_DEV_CS,0, pxa_camera_pm_switch};
static struct file_operations fops= {
owner: THIS_MODULE,
open: pxa_ovcamera_open,
release:pxa_ovcamera_close,
read: pxa_ovcamera_read,
poll: pxa_ovcamera_poll,
ioctl: pxa_ovcamera_ioctl,
mmap: pxa_ovcamera_mmap,
};
static struct video_device ovcam = {
.owner = THIS_MODULE,
.name = "PXA Camera",
.type = VID_TYPE_CAPTURE,
.hardware = VID_HARDWARE_OVCAMERA, /* FIXME */
.fops = &fops,
.release = pxa_camera_release,
//initialize: pxa_camera_video_init,
.minor = -1,
};
static int __init pxa_ovcamera_init(void)
{
ovcamprint("pxa_ovcamer_init() ......\n");
if(request_irq(IRQ_CAMERA,pxa_ovcamera_irq,0,"OmniVsion Camera",&ovcam))
{
ovcamprint("Register camera irq failed\n");
goto init_error_0;
}
ci_dma_y = -1;
ci_dma_u = -1;
ci_dma_v = -1;
ci_dma_y = pxa_request_dma("CI_Y",DMA_PRIO_MEDIUM,pxa_ci_dma_irq_y,&ovcam) ;
if(ci_dma_y < 0) {
ovcamprint("Register DMA for Y channel failed\n");
goto init_error_1;
}
ci_dma_u = pxa_request_dma("CI_Cb",DMA_PRIO_MEDIUM,pxa_ci_dma_irq_u,&ovcam) ;
if(ci_dma_u < 0) {
ovcamprint("Register DMA for U channel failed\n");
goto init_error_1;
}
ci_dma_v = pxa_request_dma("CI_Cr",DMA_PRIO_MEDIUM,pxa_ci_dma_irq_v,&ovcam) ;
if(ci_dma_v < 0) {
ovcamprint("Register DMA for V channel failed\n");
goto init_error_1;
}
DRCMR68 = ci_dma_y | DRCMR_MAPVLD;
DRCMR69 = ci_dma_u | DRCMR_MAPVLD;
DRCMR70 = ci_dma_v | DRCMR_MAPVLD;
if(video_register_device(&ovcam,VFL_TYPE_GRABBER,-1)<0) //jhy minor
{
ovcamprint("ov camera device register failed\n");
goto init_error_1;
}
else
{
PM_REGISTER_DEVICE(&pm_dev);
ovcamprint("ov camera driver initialization is ok \n");
}
if(pxa_ovcamera_video_init(&ovcam)<0){
goto init_error_1;
}
return 0;
init_error_1:
if (0 <= ci_dma_y)
pxa_free_dma(ci_dma_y);
if (0 <= ci_dma_u)
pxa_free_dma(ci_dma_u);
if (0 <= ci_dma_v)
pxa_free_dma(ci_dma_v);
free_irq(IRQ_CAMERA, &ovcam);
init_error_0:
return -EIO;
}
static void __exit pxa_ovcamera_exit(void)
{
ovcamera_context_t *ovcam_ctx;
ovcam_ctx = g_ovcamera_context;
#if 1
if (ovcam_ctx->p_buffer_virtual)
dma_free_writecombine (NULL,ovcam_ctx->ui_buffer_size,
ovcam_ctx->p_buffer_virtual,
(int)ovcam_ctx->p_buffer_physical);
#endif
if(ovcam_ctx->dma_channels[0])
{
pxa_free_dma(ovcam_ctx->dma_channels[0]);
ovcam_ctx->dma_channels[0] = 0;
}
if(ovcam_ctx->dma_channels[1])
{
pxa_free_dma(ovcam_ctx->dma_channels[1]);
ovcam_ctx->dma_channels[1] = 0;
}
if(ovcam_ctx->dma_channels[2])
{
pxa_free_dma(ovcam_ctx->dma_channels[2]);
ovcam_ctx->dma_channels[2] = 0;
}
free_irq(IRQ_CAMERA,&ovcam);
kfree(g_ovcamera_context);
video_unregister_device(&ovcam);
PM_UNREGISTER_DEVICE(&pm_dev);
ovcamprint("camera driver exit\n");
return;
}
module_init(pxa_ovcamera_init);
module_exit(pxa_ovcamera_exit);
MODULE_DESCRIPTION("Bulverde Camera Interface driver");
MODULE_LICENSE("GPL");
EXPORT_NO_SYMBOLS;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -