📄 pxa_camera.c
字号:
pos = (unsigned long)(cam_ctx->buffer_virtual); //page = kvirt_to_pa(pos); //commented by hzh page = (unsigned long)cam_ctx->buffer_physical; //modified by hzh//printk(KERN_DEBUG "start %x, end %x, size %d, page %x\n", start, end, size, page);//hzh if (remap_page_range(vma, start, page, size, PAGE_SHARED)) { return -EFAULT; } return 0;}unsigned int pxa_camera_poll(struct file *file, poll_table *wait){ camera_context_t *cam_ctx = g_camera_context; static int waited = 0; poll_wait(file, &camera_wait_q, wait); if (still_image_mode == 1 && still_image_rdy == 1) { //still_image_rdy = 0; //masked by hzh, don't clear rdy return POLLIN | POLLRDNORM; } if (first_video_frame == 1) first_video_frame = 0; else if (still_image_mode == 0 && waited != 1) cam_ctx->block_tail = (cam_ctx->block_tail + 1) % cam_ctx->block_number; if (cam_ctx->block_header == cam_ctx->block_tail) { task_waiting = 1; waited = 1; return 0; } else waited = 0; return POLLIN | POLLRDNORM;}/* * Suspend the Camera Module. */static int pxa_camera_suspend(struct device * dev, u32 state, u32 level){ switch(level){ case SUSPEND_POWER_DOWN: printk(KERN_INFO "pxa_camera: camera suspend\n"); disable_irq(IRQ_CAMERA); } return 0;}/* * Resume the Camera Module. */static int pxa_camera_resume(struct device * dev, u32 level){ switch(level){ case RESUME_POWER_ON: printk(KERN_INFO "pxa_camera: camera resume\n"); enable_irq(IRQ_CAMERA); DRCMR68 = ci_dma_y | DRCMR_MAPVLD; DRCMR69 = ci_dma_cb | DRCMR_MAPVLD; DRCMR70 = ci_dma_cr | DRCMR_MAPVLD; } return 0;}int pxa_camera_video_init(struct video_device *vdev){ int status = -1; if (! (g_camera_context = kmalloc (sizeof(struct camera_context_s), GFP_KERNEL) ) ) printk( "PXA_CAMERA: Cann't allocate buffer for camera control structure \n"); else status = 0; memset(g_camera_context, 0, sizeof(*g_camera_context)); //hzh!!! g_camera_context->dma_channels[0] = ci_dma_y; g_camera_context->dma_channels[1] = ci_dma_cb; g_camera_context->dma_channels[2] = ci_dma_cr; return status;}static void pxa_camera_release(struct video_device *dev){#if 0 /*FIXME: add specific release function here*/ printk(KERN_WARNING "videodev: has no release callback. " "Please fix your driver for proper sysfs support, see " "http://lwn.net/Articles/36850/\n");#endif}static struct file_operations pxa_camera_fops ={ .owner = THIS_MODULE, .open = pxa_camera_open, .release = pxa_camera_close, .ioctl = pxa_camera_ioctl, .read = pxa_camera_read, .mmap = pxa_camera_mmap, .poll = pxa_camera_poll, .llseek = no_llseek, };static struct video_device vd ={ .name = "PXA Camera", .type = VID_TYPE_CAPTURE, .hardware = VID_HARDWARE_PXA_CAMERA, /* FIXME */ .fops = &pxa_camera_fops, .release = pxa_camera_release, .minor = -1,};static int pxa_camera_probe(struct device *dev){ /* 1. mapping CI registers, so that we can access the CI */ if (request_irq(IRQ_CAMERA, pxa_camera_irq, 0, "PXA Camera", &vd)) { printk ("Camera interrupt register failed \n"); goto init_error_1; } ci_dma_y = -1; ci_dma_cb = -1; ci_dma_cr = -1; ci_dma_y = pxa_request_dma("CI_Y",DMA_PRIO_HIGH, pxa_ci_dma_irq_y, &vd); if (ci_dma_y < 0) { printk( "PXA_CAMERA: Cann't request DMA for Y\n"); goto init_error_2; } ci_dma_cb = pxa_request_dma("CI_Cb",DMA_PRIO_HIGH, pxa_ci_dma_irq_cb, &vd); if (ci_dma_cb < 0) { printk( "PXA_CAMERA: Cann't request DMA for Cb\n"); goto init_error_2; } ci_dma_cr = pxa_request_dma("CI_Cr",DMA_PRIO_HIGH, pxa_ci_dma_irq_cr, &vd); if (ci_dma_cr < 0) { printk( "PXA_CAMERA: Cann't request DMA for Cr\n"); goto init_error_2; } DRCMR68 = ci_dma_y | DRCMR_MAPVLD; DRCMR69 = ci_dma_cb | DRCMR_MAPVLD; DRCMR70 = ci_dma_cr | DRCMR_MAPVLD; if (video_register_device(&vd, VFL_TYPE_GRABBER, minor) < 0) { printk("PXA_CAMERA: video_register_device failed\n"); goto init_error_2; } else { printk("PXA_CAMERA: PXA Camera driver loaded for: /dev/video%d \n",minor); } if(pxa_camera_video_init(&vd)<0){ goto init_error_2; } return 0;init_error_2: if (ci_dma_y >= 0) pxa_free_dma(ci_dma_y); if (ci_dma_cb >= 0) pxa_free_dma(ci_dma_cb); if (ci_dma_cr >= 0) pxa_free_dma(ci_dma_cr); if (g_camera_context) kfree(g_camera_context); free_irq (IRQ_CAMERA, &vd);init_error_1: return -EIO;}static int pxa_camera_remove(struct device *dev){ camera_context_t *cam_ctx = g_camera_context; if (cam_ctx->dma_channels[0]) { pxa_free_dma(cam_ctx->dma_channels[0]); cam_ctx->dma_channels[0] = 0; } if (cam_ctx->dma_channels[1]) { pxa_free_dma(cam_ctx->dma_channels[1]); cam_ctx->dma_channels[1] = 0; } if (cam_ctx->dma_channels[2]) { pxa_free_dma(cam_ctx->dma_channels[2]); cam_ctx->dma_channels[2] = 0; } free_irq(IRQ_CAMERA, &vd); kfree(g_camera_context); video_unregister_device(&vd); printk("PXA_CAMERA: PXA Camera driver unloaded.\n"); return 0;}static struct device_driver pxa_camera_driver = { .name = "pxa2xx-camera", .bus = &platform_bus_type, .probe = pxa_camera_probe, .remove = pxa_camera_remove, .suspend = pxa_camera_suspend, .resume = pxa_camera_resume,};static int __devinit pxa_camera_init(void){ return driver_register(&pxa_camera_driver);}static void __exit pxa_camera_exit(void){ return driver_unregister(&pxa_camera_driver);}//-------------------------------------------------------------------------------------------------------// Configuration APIs//-------------------------------------------------------------------------------------------------------void ci_set_frame_rate(CI_FRAME_CAPTURE_RATE frate){ unsigned int value; // write cicr4 value = CICR4; value &= ~(CI_CICR4_FR_RATE_SMASK << CI_CICR4_FR_RATE_SHIFT); value |= (unsigned)frate << CI_CICR4_FR_RATE_SHIFT; CICR4 = value;}CI_FRAME_CAPTURE_RATE ci_get_frame_rate(void){ unsigned int value; value = CICR4; return (CI_FRAME_CAPTURE_RATE)((value >> CI_CICR4_FR_RATE_SHIFT) & CI_CICR4_FR_RATE_SMASK);}void ci_set_image_format(CI_IMAGE_FORMAT input_format, CI_IMAGE_FORMAT output_format){ unsigned int value, tbit, rgbt_conv, rgb_conv, rgb_f, ycbcr_f, rgb_bpp, raw_bpp, cspace; // write cicr1: preserve ppl value and data width value value = CICR1; value &= ( (CI_CICR1_PPL_SMASK << CI_CICR1_PPL_SHIFT) | ((CI_CICR1_DW_SMASK) << CI_CICR1_DW_SHIFT)); tbit = rgbt_conv = rgb_conv = rgb_f = ycbcr_f = rgb_bpp = raw_bpp = cspace = 0; switch(input_format) { case CI_RAW8: cspace = 0; raw_bpp = 0; break; case CI_RAW9: cspace = 0; raw_bpp = 1; break; case CI_RAW10: cspace = 0; raw_bpp = 2; break; case CI_YCBCR422: case CI_YCBCR422_PLANAR: cspace = 2; if (output_format == CI_YCBCR422_PLANAR) { ycbcr_f = 1; } break; case CI_RGB444: cspace = 1; rgb_bpp = 0; break; case CI_RGB555: cspace = 1; rgb_bpp = 1; if (output_format == CI_RGBT555_0) { rgbt_conv = 2; tbit = 0; } else if (output_format == CI_RGBT555_1) { rgbt_conv = 2; tbit = 1; } break; case CI_RGB565: cspace = 1; rgb_bpp = 2; rgb_f = 1; break; case CI_RGB666: cspace = 1; rgb_bpp = 3; if (output_format == CI_RGB666_PACKED) { rgb_f = 1; } break; case CI_RGB888: case CI_RGB888_PACKED: cspace = 1; rgb_bpp = 4; switch(output_format) { case CI_RGB888_PACKED: rgb_f = 1; break; case CI_RGBT888_0: rgbt_conv = 1; tbit = 0; break; case CI_RGBT888_1: rgbt_conv = 1; tbit = 1; break; case CI_RGB666: rgb_conv = 1; break; case CI_RGB666_PACKED: rgb_conv = 1; rgb_f = 1; break; case CI_RGB565: rgb_conv = 2; break; case CI_RGB555: rgb_conv = 3; break; case CI_RGB444: rgb_conv = 4; break; default: break; } break; default: break; } value |= (tbit==1) ? CI_CICR1_TBIT : 0; value |= rgbt_conv << CI_CICR1_RGBT_CONV_SHIFT; value |= rgb_conv << CI_CICR1_RGB_CONV_SHIFT; value |= (rgb_f==1) ? CI_CICR1_RBG_F : 0; value |= (ycbcr_f==1) ? CI_CICR1_YCBCR_F : 0; value |= rgb_bpp << CI_CICR1_RGB_BPP_SHIFT; value |= raw_bpp << CI_CICR1_RAW_BPP_SHIFT; value |= cspace << CI_CICR1_COLOR_SP_SHIFT; CICR1 = value; return; }void ci_set_mode(CI_MODE mode, CI_DATA_WIDTH data_width){ unsigned int value; // write mode field in cicr0 value = CICR0; value &= ~(CI_CICR0_SIM_SMASK << CI_CICR0_SIM_SHIFT); value |= (unsigned int)mode << CI_CICR0_SIM_SHIFT; CICR0 = value; // write data width cicr1 value = CICR1; value &= ~(CI_CICR1_DW_SMASK << CI_CICR1_DW_SHIFT); value |= ((unsigned)data_width) << CI_CICR1_DW_SHIFT; CICR1 = value; return; }void ci_configure_mp(unsigned int ppl, unsigned int lpf, CI_MP_TIMING* timing){ unsigned int value; // write ppl field in cicr1 value = CICR1; value &= ~(CI_CICR1_PPL_SMASK << CI_CICR1_PPL_SHIFT); value |= (ppl & CI_CICR1_PPL_SMASK) << CI_CICR1_PPL_SHIFT; CICR1 = value; // write BLW, ELW in cicr2 value = CICR2; value &= ~(CI_CICR2_BLW_SMASK << CI_CICR2_BLW_SHIFT | CI_CICR2_ELW_SMASK << CI_CICR2_ELW_SHIFT ); value |= (timing->BLW & CI_CICR2_BLW_SMASK) << CI_CICR2_BLW_SHIFT; CICR2 = value; // write BFW, LPF in cicr3 value = CICR3; value &= ~(CI_CICR3_BFW_SMASK << CI_CICR3_BFW_SHIFT | CI_CICR3_LPF_SMASK << CI_CICR3_LPF_SHIFT ); value |= (timing->BFW & CI_CICR3_BFW_SMASK) << CI_CICR3_BFW_SHIFT; value |= (lpf & CI_CICR3_LPF_SMASK) << CI_CICR3_LPF_SHIFT; CICR3 = value; return;}void ci_configure_sp(unsigned int ppl, unsigned int lpf, CI_SP_TIMING* timing){ unsigned int value; // write ppl field in cicr1 value = CICR1; value &= ~(CI_CICR1_PPL_SMASK << CI_CICR1_PPL_SHIFT); value |= (ppl & CI_CICR1_PPL_SMASK) << CI_CICR1_PPL_SHIFT; CICR1 = value; // write cicr2 value = CICR2; value |= (timing->BLW & CI_CICR2_BLW_SMASK) << CI_CICR2_BLW_SHIFT; value |= (timing->ELW & CI_CICR2_ELW_SMASK) << CI_CICR2_ELW_SHIFT; value |= (timing->HSW & CI_CICR2_HSW_SMASK) << CI_CICR2_HSW_SHIFT; value |= (timing->BFPW & CI_CICR2_BFPW_SMASK) << CI_CICR2_BFPW_SHIFT; value |= (timing->FSW & CI_CICR2_FSW_SMASK) << CI_CICR2_FSW_SHIFT; CICR2 = value; // write cicr3 value = CICR3; value |= (timing->BFW & CI_CICR3_BFW_SMASK) << CI_CICR3_BFW_SHIFT; value |= (timing->EFW & CI_CICR3_EFW_SMASK) << CI_CICR3_EFW_SHIFT; value |= (timing->VSW & CI_CICR3_VSW_SMASK) << CI_CICR3_VSW_SHIFT; value |= (lpf & CI_CICR3_LPF_SMASK) << CI_CICR3_LPF_SHIFT; CICR3 = value; return;}void ci_configure_ms(unsigned int ppl, unsigned int lpf, CI_MS_TIMING* timing){ // the operation is same as Master-Parallel ci_configure_mp(ppl, lpf, (CI_MP_TIMING*)timing);}void ci_configure_ep(int parity_check)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -