?? s3c2440a_camif.c
字號:
spin_lock_irqsave(&dev->lock, flags); rCIPRSCCTRL &= ~(1<<15); //stop preview scaler. rCICOSCCTRL &= ~(1<<15); //stop codec scaler. rCIIMGCPT &= ~(7<<29); //stop capturing for preview and codec scaler. dev->open_count--; spin_unlock_irqrestore(&dev->lock, flags); camera_power(0); DPRINTK("close(): dev->opencount = %d\n", dev->open_count); MOD_DEC_USE_COUNT;}static int v4l_cam_ioctl(struct video_device *v, unsigned int cmd, void *arg){ int retval = 0; struct s3c2440_camif *dev = (struct s3c2440_camif *)(v->priv); switch (cmd) {/* V4L Standard IOCTL. */ case VIDIOCGCAP: { struct video_capability vc; strcpy (vc.name, "S3C2440A Camera"); vc.maxwidth = CAMIF_MAX_W; vc.maxheight = CAMIF_MAX_H; vc.minwidth = CAMIF_MIN_W; vc.minheight = CAMIF_MIN_H; if (copy_to_user((int __user*)arg, &vc, sizeof(struct video_capability))) return -EFAULT; break; } /* get capture size */ case VIDIOCGWIN: { struct video_window vw; vw.width = s3c2440_camif_cfg.src_x; vw.height = s3c2440_camif_cfg.src_y; if (copy_to_user((int __user*)arg, &vw, sizeof(struct video_window))) retval = -EFAULT; break; } /* set capture size. */ case VIDIOCSWIN: { struct video_window vw; if (copy_from_user(&vw, (int __user*)arg, sizeof(struct video_window))) { retval = -EFAULT; break; } if (vw.width > CAMIF_MAX_W || vw.height > CAMIF_MAX_H || vw.width < CAMIF_MIN_W || vw.height < CAMIF_MIN_H) { retval = -EINVAL; break; } if(down_interruptible(&dev->change)) return -ERESTARTSYS; if(dev->flag&1) retval = -EBUSY; else if(s3c2440_camif_cfg.src_x!=vw.width|| s3c2440_camif_cfg.src_y!=vw.height) { dev->set_chg = 1; s3c2440_camif_cfg.src_x = vw.width; s3c2440_camif_cfg.src_y = vw.height; } up(&dev->change); break; } /* get subcapture */ case VIDIOCGCAPTURE: { struct video_capture vc; vc.x = vc.y = 0; vc.width = s3c2440_camif_cfg.dst_x; vc.height = s3c2440_camif_cfg.dst_y; if (copy_to_user((int __user*)arg, &vc, sizeof(struct video_capture))) retval = -EFAULT; break; } /* set subcapture */ case VIDIOCSCAPTURE: { struct video_capture vc; if (copy_from_user(&vc, (int __user*)arg, sizeof(struct video_capture))) { retval = -EFAULT; break; } if(down_interruptible(&dev->change)) return -ERESTARTSYS; if(dev->flag&1) retval = -EBUSY; else if(vc.width > s3c2440_camif_cfg.src_x || vc.height > s3c2440_camif_cfg.src_y || vc.width < CAMIF_MIN_W || vc.height < CAMIF_MIN_H) retval = -EINVAL; else if(vc.width!=s3c2440_camif_cfg.dst_x || vc.height!=s3c2440_camif_cfg.dst_y) { dev->set_chg = 1; s3c2440_camif_cfg.dst_x = vc.width; s3c2440_camif_cfg.dst_y = vc.height; } up(&dev->change); break; } /* get palette */ case VIDIOCGPICT: { struct video_picture vp; switch (dev->mode) { case 0: vp.palette = VIDEO_PALETTE_RGB565; break; case 1: vp.palette = VIDEO_PALETTE_RGB24; break; case 2: vp.palette = VIDEO_PALETTE_YUV420P; break; case 3: vp.palette = VIDEO_PALETTE_YUV422P; break; default: retval = -EINVAL; break; } if (copy_to_user((int __user*)arg, &vp, sizeof(struct video_picture))) retval = -EFAULT; break; } /* set palette */ case VIDIOCSPICT: { struct video_picture vp; if (copy_from_user(&vp, (int __user*)arg, sizeof(vp))) { retval = -EFAULT; break; } if(down_interruptible(&dev->change)) return -ERESTARTSYS; if(dev->flag&1) retval = -EBUSY; else { int mode = dev->mode; if(vp.palette==VIDEO_PALETTE_RGB565) mode = 0; else if(vp.palette==VIDEO_PALETTE_RGB24) mode = 1; else if(vp.palette==VIDEO_PALETTE_YUV420P) mode = 2; else if(vp.palette==VIDEO_PALETTE_YUV422P) mode = 3; else retval = -EINVAL; if(mode!=dev->mode) { dev->set_chg = 1; dev->mode = mode; } } up(&dev->change); break; } /* set YCbCr order */ case VIDIOCSYCbCr: { if(down_interruptible(&dev->change)) return -ERESTARTSYS; if(dev->flag&1) retval = -EBUSY; else if(s3c2440_camif_cfg.ycbcr!=((int)arg&3)) { dev->set_chg = 1; s3c2440_camif_cfg.ycbcr = (int)arg&3; } up(&dev->change); break; } /* start/stop capture */ case VIDIOCCAPTURE: { int capture_flag = (int)arg; if(down_interruptible(&dev->change)) return -ERESTARTSYS; /* Still Image Capture */ if (capture_flag == STILL_IMAGE) { if(dev->flag&1) retval = -EBUSY; else dev->flag = 1; // one frame capture; } /* Video Capture Start */ else if (capture_flag == VIDEO_START) { if(dev->flag&1) retval = -EBUSY; else dev->flag = 3; // sequential capture; } /* Video Capture Stop */ else if (capture_flag == VIDEO_STOP) { if(dev->flag&1) { init_completion(&dev->stop); dev->flag |= 0x100; wait_for_completion(&dev->stop); // complete with flag = 0 } else retval = -ESRCH; } else retval = -EFAULT; up(&dev->change); if(!retval&&dev->flag) { dev->rdy = 0; if(dev->set_chg) { //now flag.0 is 1 dev->set_chg = 0; dev->size = 0; s3c2440_camif_configure(&s3c2440_camif_cfg); } //enable_irq(); start_capture(dev); #if DEBUG printk(KERN_DEBUG "<0x%08x\n", rCISRCFMT); printk(KERN_DEBUG "0x%08x\n", rCIWDOFST); printk(KERN_DEBUG "0x%08x\n", rCIGCTRL); printk(KERN_DEBUG "0x%08x\n", rCICOYSA1); printk(KERN_DEBUG "0x%08x\n", rCICOCBSA1); printk(KERN_DEBUG "0x%08x\n", rCICOCRSA1); printk(KERN_DEBUG "0x%08x\n", rCICOTRGFMT); printk(KERN_DEBUG "0x%08x\n", rCICOCTRL); printk(KERN_DEBUG "0x%08x\n", rCICOSCPRERATIO); printk(KERN_DEBUG "0x%08x\n", rCICOSCCTRL); printk(KERN_DEBUG "0x%08x\n", rCICOTAREA); printk(KERN_DEBUG "0x%08x\n", rCICOSTATUS); printk(KERN_DEBUG "0x%08x>\n", rCIIMGCPT); printk(KERN_DEBUG "<0x%08x\n", rCIPRCLRSA1); printk(KERN_DEBUG "0x%08x\n", rCIPRTRGFMT); printk(KERN_DEBUG "0x%08x\n", rCIPRCTRL); printk(KERN_DEBUG "0x%08x\n", rCIPRSCPRERATIO); printk(KERN_DEBUG "0x%08x\n", rCIPRSCPREDST); printk(KERN_DEBUG "0x%08x\n", rCIPRSCCTRL); printk(KERN_DEBUG "0x%08x\n", rCIPRTAREA); printk(KERN_DEBUG "0x%08x>\n", rCIPRSTATUS); // printk(KERN_DEBUG "<0x%08x\n", INTMSK); // printk(KERN_DEBUG "0x%08x>\n", INTSUBMSK); #endif } break; } /* mmap interface */ case VIDIOCGMBUF: { struct video_mbuf vm; int i; memset(&vm, 0, sizeof(vm)); vm.size = YUV_IMG_BUF_SIZE; vm.frames = 1; //just support 1 frame for (i = 0; i < vm.frames; i++) vm.offsets[i] = 0; //start at 0 if (copy_to_user((int __user*)arg, (void *)&vm, sizeof(vm))) retval = -EFAULT; break; } default: retval = -ENOIOCTLCMD; } return retval;}static long v4l_cam_read(struct video_device *v, char *buf, unsigned long count, int noblock){ unsigned long flags; int retval = 0; struct s3c2440_camif *dev = (struct s3c2440_camif *)(v->priv); if(noblock) { if(down_trylock(&dev->change)) return -EAGAIN; } else { if(down_interruptible(&dev->change)) return -EINTR; } local_irq_save(flags); if(!dev->rdy) { if(noblock) retval = -EAGAIN; else { interruptible_sleep_on(&dev->wait); if(!dev->rdy) retval = -EINTR; } } local_irq_restore(flags); if(!retval) { //now if retval==0, dev->rdy must be 1 dev->rdy = 0; //clear ready flag retval = min(count, dev->size); if(copy_to_user(buf, (void *)camif_yuv_buf, retval)) //can copy 0 byte retval = -EFAULT; //printk("%d,%d\n", count, dev->size); } up(&dev->change); return retval;}static int v4l_cam_mmap(struct video_device *v, const char *adr, unsigned long size){ //printk("camera mmap address 0x%08x, length %d\n", (int)adr, (int)size); //size = (size + PAGE_SIZE-1) & ~(PAGE_SIZE-1); if(remap_page_range((unsigned long)adr, (unsigned long)camif_yuv_buf_dma, size, PAGE_SHARED)) return -EFAULT; return 0;}#if 0 // needlessstatic long v4l_cam_write(struct video_device *v, const char *buf, unsigned long count, int noblock){ return -EPERM;}#endifstatic unsigned int v4l_cam_poll(struct video_device *v, struct file *file, poll_table *table){ unsigned long flags, rdy; struct s3c2440_camif *dev = (struct s3c2440_camif *)(v->priv); local_irq_save(flags); if(!dev->rdy) poll_wait(file, &dev->wait, table); rdy = dev->rdy; local_irq_restore(flags); return rdy?(POLLIN | POLLRDNORM) : 0;}static int v4l_cam_initdone (struct video_device *v){ return 0;}void inline config_camif_v4l(void){ DPRINTK("%s():\n", __FUNCTION__); sprintf(camif.v.name,"%s","S3C2440_CAMIF"); camif.v.priv = (void*)&camif; camif.v.type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; camif.v.hardware = VID_HARDWARE_S3C2440A; camif.v.open = v4l_cam_open; camif.v.close = v4l_cam_close; camif.v.read = v4l_cam_read; camif.v.ioctl = v4l_cam_ioctl; camif.v.poll = v4l_cam_poll; camif.v.mmap = v4l_cam_mmap;#if 0 // needless camif.v.write = v4l_cam_write;#endif camif.v.initialize = v4l_cam_initdone; //used in video_register_device}int __init s3c2440_camif_initialize(void){ int ret = 0; DPRINTK("%s():\n", __FUNCTION__); s3c2440_camif_init(); spin_lock_init(&camif.lock); init_MUTEX(&camif.change); init_completion(&camif.stop); init_waitqueue_head(&camif.wait); camif_yuv_buf = consistent_alloc(GFP_KERNEL, YUV_IMG_BUF_SIZE, &camif_yuv_buf_dma);#ifdef RGB_YUV_MUTEX camif_rgb_buf = camif_yuv_buf; camif_rgb_buf_dma = camif_yuv_buf_dma;#else camif_rgb_buf = consistent_alloc(GFP_KERNEL, RGB_IMG_BUF_SIZE, &camif_rgb_buf_dma);#endif if (!camif_yuv_buf || !camif_rgb_buf ) { ret = -ENOMEM; goto mem_err; } memset(camif_yuv_buf, 0, YUV_IMG_BUF_SIZE); memset(camif_rgb_buf, 0, RGB_IMG_BUF_SIZE); if ((ret = request_irq(IRQ_CAM_C, s3c2440_camif_isr_c, SA_INTERRUPT, "CAM_C", &camif))) { printk("request_irq(CAM_C) failed.\n"); goto err_irq_s; } if ((ret = request_irq(IRQ_CAM_P, s3c2440_camif_isr_p, SA_INTERRUPT, "CAM_P", &camif))) { free_irq(IRQ_CAM_C, &camif); printk("request_irq(CAM_P) failed.\n"); goto err_irq_s; } config_camif_v4l(); ret = video_register_device (&camif.v, VFL_TYPE_GRABBER, -1); if (ret != 0) { printk("V4L registering failed!\n"); goto error_v4l_register; }#ifdef MODULE /* CPU : FIXME */ flush_scheduled_tasks();#endif return 0;error_v4l_register: free_irq(IRQ_CAM_P, &camif); free_irq(IRQ_CAM_C, &camif);err_irq_s: s3c2440_camif_deinit();mem_err: if (camif_yuv_buf) consistent_free(camif_yuv_buf, YUV_IMG_BUF_SIZE , camif_yuv_buf_dma);#ifndef RGB_YUV_MUTEX if (camif_rgb_buf) consistent_free(camif_rgb_buf, RGB_IMG_BUF_SIZE , camif_rgb_buf_dma);#endif return ret;}void __exit s3c2440_camif_exit(void){ DPRINTK("%s():\n", __FUNCTION__); video_unregister_device(&camif.v); s3c2440_camif_deinit(); free_irq(IRQ_CAM_P, &camif); free_irq(IRQ_CAM_C, &camif); if (camif_yuv_buf) consistent_free(camif_yuv_buf, YUV_IMG_BUF_SIZE , camif_yuv_buf_dma);#ifndef RGB_YUV_MUTEX if (camif_rgb_buf) consistent_free(camif_rgb_buf, RGB_IMG_BUF_SIZE , camif_rgb_buf_dma);#endif}module_exit(s3c2440_camif_exit);module_init(s3c2440_camif_initialize);MODULE_LICENSE("GPL");#ifdef MODULEMODULE_PARM(power_lvl, "h");MODULE_PARM(reset_lvl, "h");#elsestatic int __init pwr_lvl_setup(char *str){ if(simple_strtol(str, NULL, 0)) power_lvl = 1; printk(KERN_DEBUG "Camera power level is %s\n", power_lvl?"high":"low"); return 0;}static int __init rst_lvl_setup(char *str){ if(simple_strtol(str, NULL, 0)) reset_lvl = 1; printk(KERN_DEBUG "Camera reset level is %s\n", reset_lvl?"high":"low"); return 0;}__setup("camera_pwr=", pwr_lvl_setup);__setup("camera_rst=", rst_lvl_setup);#endif
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -