📄 s3c2440a_camif.c
字号:
return 0;}static void v4l_cam_release(struct inode *inode, struct file *file){ unsigned long flags; struct s3c2440_camif *dev = file->private_data; DPRINTK("%s():\n", __FUNCTION__); if(camif.open_count) { spin_lock_irqsave(&dev->lock, flags); __raw_writel(__raw_readl(rCIPRSCCTRL) & ~(1<<15),rCIPRSCCTRL); __raw_writel(__raw_readl(rCICOSCCTRL) & ~(1<<15),rCICOSCCTRL); __raw_writel(__raw_readl(rCIIMGCPT) & ~(7<<29),rCIIMGCPT); dev->open_count--; spin_unlock_irqrestore(&dev->lock, flags); camera_power(0); DPRINTK("release(): dev->opencount = %d\n", dev->open_count); }}static int v4l_cam_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg){ int retval = 0; struct s3c2440_camif *dev = file->private_data; DPRINTK("%s():\n", __FUNCTION__); 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&0x1)) { 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 0//DEBUG printk( "<0x%08x\n", __raw_readl(rCISRCFMT)); printk( "0x%08x\n", __raw_readl(rCIWDOFST)); printk( "0x%08x\n", __raw_readl(rCIGCTRL)); printk( "0x%08x\n", __raw_readl(rCICOYSA1)); printk( "0x%08x\n", __raw_readl(rCICOCBSA1)); printk( "0x%08x\n", __raw_readl(rCICOCRSA1)); printk( "0x%08x\n", __raw_readl(rCICOTRGFMT)); printk( "0x%08x\n", __raw_readl(rCICOCTRL)); printk( "0x%08x\n", __raw_readl(rCICOSCPRERATIO)); printk( "0x%08x\n", __raw_readl(rCICOSCCTRL)); printk( "0x%08x\n", __raw_readl(rCICOTAREA)); printk( "0x%08x\n", __raw_readl(rCICOSTATUS)); printk( "0x%08x>\n", __raw_readl(rCIIMGCPT)); printk( "<0x%08x\n", __raw_readl(rCIPRCLRSA1)); printk( "0x%08x\n", __raw_readl(rCIPRTRGFMT)); printk( "0x%08x\n", __raw_readl(rCIPRCTRL)); printk( "0x%08x\n", __raw_readl(rCIPRSCPRERATIO)); printk( "0x%08x\n", __raw_readl(rCIPRSCPREDST)); printk( "0x%08x\n", __raw_readl(rCIPRSCCTRL)); printk( "0x%08x\n", __raw_readl(rCIPRTAREA)); printk( "0x%08x>\n", __raw_readl(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 ssize_t v4l_cam_read(struct file *file, char *buf, size_t count, loff_t *ppos){ unsigned long flags; int retval = 0; struct s3c2440_camif *dev = file->private_data; DPRINTK("%s():\n", __FUNCTION__); if(file->f_flags&O_NONBLOCK) { if(down_trylock(&dev->change)) return -EAGAIN; } else { if(down_interruptible(&dev->change)) return -EINTR; } local_irq_save(flags); if(!dev->rdy) { if(file->f_flags&O_NONBLOCK) retval = -EAGAIN; else { if(wait_event_interruptible(dev->wait,dev->rdy)) retval= -ERESTARTSYS; /*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; } up(&dev->change); return retval;}void cam_vma_open(struct vm_area_struct *vma){ DPRINTK("vma open, virt %lx, pys %lx \n",vma->vm_start, vma->vm_pgoff<<PAGE_SHIFT);}void cam_vma_close(struct vm_area_struct *vma){ DPRINTK("vma close\n");}static struct vm_operations_struct cam_remap_vm_ops ={ .open = cam_vma_open, .close = cam_vma_close,};static int v4l_cam_mmap(struct file *v, struct vm_area_struct *vma){ DPRINTK("%s():\n", __FUNCTION__); if(remap_pfn_range(vma, vma->vm_start, camif_yuv_buf_dma>>PAGE_SHIFT/*vma->vm_pgoff*/, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EFAULT; vma->vm_ops = &cam_remap_vm_ops;
cam_vma_open(vma);
return 0;}static unsigned int v4l_cam_poll(struct file *file, struct poll_table_struct *table){ unsigned long flags, rdy; struct s3c2440_camif *dev = file->private_data; 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;}void inline config_camif_v4l(void){ DPRINTK("%s():\n", __FUNCTION__); sprintf(camif.v.name,"%s","S3C2440_CAMIF"); camif.v.owner = THIS_MODULE; camif.v.priv = (void*)&camif; camif.v.type = VID_TYPE_CAPTURE | VID_TYPE_SCALES; camif.v.fops = (struct file_operations *)&cam_ops; camif.v.release = v4l_cam_release; camif.open_count = 0; }int __init s3c2440_camif_initialize(void){ int i,ret = 0; char *feiling1="|w.iehcmc|"; char *feiling2="wwwtc.o.n"; printk("+-----------------+\n"); for(i=1;i<20;i++){ if(i%2){ printk("%c",*feiling1); feiling1++; }else{ printk("%c",*feiling2); feiling2++; } } printk("\n+-----------------+\n"); 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 = dma_alloc_coherent(NULL, YUV_IMG_BUF_SIZE, &camif_yuv_buf_dma,GFP_KERNEL);#ifdef RGB_YUV_MUTEX camif_rgb_buf = camif_yuv_buf; camif_rgb_buf_dma = camif_yuv_buf_dma;#else camif_rgb_buf = dma_alloc_coherent(NULL, RGB_IMG_BUF_SIZE, &camif_rgb_buf_dma,GFP_KERNEL);#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_S3C2440_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_S3C2440_CAM_P, s3c2440_camif_isr_p, SA_INTERRUPT, "CAM_P", &camif))) { free_irq(IRQ_S3C2440_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; } return 0;error_v4l_register: free_irq(IRQ_S3C2440_CAM_P, &camif); free_irq(IRQ_S3C2440_CAM_C, &camif);err_irq_s: s3c2440_camif_deinit();mem_err: if (camif_yuv_buf) dma_free_coherent(camif.v.dev , YUV_IMG_BUF_SIZE , camif_yuv_buf , camif_yuv_buf_dma);#ifndef RGB_YUV_MUTEX if (camif_rgb_buf) dma_free_coherent(camif.v.dev , RGB_IMG_BUF_SIZE , camif_rgb_buf , 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_S3C2440_CAM_P, &camif); free_irq(IRQ_S3C2440_CAM_C, &camif); if (camif_yuv_buf) dma_free_coherent(camif.v.dev , YUV_IMG_BUF_SIZE , camif_yuv_buf , camif_yuv_buf_dma);#ifndef RGB_YUV_MUTEX if (camif_rgb_buf) dma_free_coherent(camif.v.dev , RGB_IMG_BUF_SIZE , camif_rgb_buf , 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 + -