📄 s3c2440camif.c
字号:
*/static int camif_open(struct inode *inode, struct file *file){ int minor; struct s3c2440camif_dev *h,*pdev; struct s3c2440camif_fh *fh; struct list_head *list; int ret; pdev = NULL; minor = iminor(inode); PDEBUG("pid %d[%s] tries to open the camera.\n", current->pid, current->comm); /* find device. */ list_for_each(list,&camif_devlist) { h = list_entry(list, struct s3c2440camif_dev, devlist); if (h->vfd->minor == minor) { pdev = h; break; } } if (NULL == pdev) { PDEBUG("no video device, minor = %d\n", minor); return -ENODEV; } fh = kzalloc(sizeof(*fh),GFP_KERNEL); // alloc memory for filehandle if (NULL == fh) { PDEBUG("kernel memory alloc fail!\n"); return -ENOMEM; } fh->dev = pdev; /* maybe this is a master open, maybe not. */ if (mutex_trylock(&pdev->mfhlock) != 0) { fh->master = 1; PDEBUG("PID[%d:%s], this is a master open!\n", current->pid, current->comm); pdev->state = CAMIF_STATE_READY; PDEBUG("camera state is now READY!\n"); init_camif_config(fh); PDEBUG("camera device is now initialized!\n"); } else { PDEBUG("PID[%d:%s], this is a slave open!\n", current->pid, current->comm); fh->master = 0; } /* maybe this is the first open, maybe not. */ mutex_lock(&pdev->rcmutex); pdev->rc++; if (pdev->rc == 1) // if this the first open.... { ret = init_image_buffer(); // init image buffer. if (ret < 0) { PDEBUG("init image buffer fail!\n"); goto error1; } PDEBUG("image buffer init successfully!\n"); request_irq(IRQ_S3C2440_CAM_C, on_camif_irq_c, IRQF_DISABLED, "CAM_C", pdev); // setup ISRs if (ret < 0) { PDEBUG("init image buffer fail!\n"); goto error2; } PDEBUG("IRQ_S3C2440_CAM_C setup successfully!\n"); request_irq(IRQ_S3C2440_CAM_P, on_camif_irq_p, IRQF_DISABLED, "CAM_P", pdev); if (ret < 0) { PDEBUG("init image buffer fail!\n"); goto error3; } PDEBUG("IRQ_S3C2440_CAM_P setup successfully!\n"); clk_enable(pdev->clk); // and enable camif clock. PDEBUG("camera interface clock enabled!\n"); soft_reset_camif(); PDEBUG("soft reset camif done!!\n"); } mutex_unlock(&pdev->rcmutex); file->private_data = fh; fh->dev = pdev; PDEBUG("pid %d[%s] open the camera sucessfully.\n", current->pid, current->comm); return 0;error3: free_irq(IRQ_S3C2440_CAM_C, pdev);error2: free_image_buffer();error1: kfree(fh); return ret;}/* * camif_read() */static ssize_t camif_read(struct file *file, char __user *data, size_t count, loff_t *ppos){ int i; struct s3c2440camif_fh * fh; struct s3c2440camif_dev * pdev; ssize_t size; struct v4l2_format fmt; fh = file->private_data; pdev = fh->dev; PDEBUG("pid %d[%s] is trying to read frame data from camif..\n", current->pid, current->comm); fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; vidioc_g_fmt_cap(file, fh, &fmt); size = fmt.fmt.pix.sizeimage; PDEBUG("each frame size is %dKBytes.\n", size/1024); if (start_capture(pdev, 0) != 0) { PDEBUG("read action wakeuped by a asynchronous signal!\n"); return -ERESTARTSYS; } disable_irq(IRQ_S3C2440_CAM_C); disable_irq(IRQ_S3C2440_CAM_P); for (i = 0; i < 4; i++) { if (img_buff[i].state != CAMIF_BUFF_INVALID) { copy_to_user(data, (void *)img_buff[i].virt_base, (count<size)?count:size); img_buff[i].state = CAMIF_BUFF_INVALID; } } enable_irq(IRQ_S3C2440_CAM_P); enable_irq(IRQ_S3C2440_CAM_C);#if 0 for (i = 0; i < 240 * 100; i++) { ((unsigned short *)img_buff[0].base)[i] = 0xF800; } for (i = 240*100; i < 2* 240 * 100; i+=1) { ((unsigned short *)img_buff[0].base)[i] = 0x07E0; } for (i = 240*100*2; i < 240 * 320; i+=1) { ((unsigned short *)img_buff[0].base)[i] = 0x001F; } copy_to_user(data, (void *)img_buff[0].base, size);#endif PDEBUG("pid %d[%s] read %d bytes from camera\n", current->pid, current->comm, (count<size)?count:size); return size;}/* * camif_poll() */static unsigned int camif_poll(struct file *file, struct poll_table_struct *wait){ struct s3c2440camif_fh * fh; fh = file->private_data; PDEBUG("%s(): not implement now!\n", __FUNCTION__); BUG(); return -ENOENT;}/* * camif_release() */static int camif_release(struct inode *inode, struct file *file){ int minor; struct s3c2440camif_fh * fh; struct s3c2440camif_dev * pdev; minor = iminor(inode); fh = file->private_data; pdev = fh->dev; PDEBUG("pid %d[%s] tries to close camera.\n", current->pid, current->comm); if (fh->master != 0) { PDEBUG("master file handle close, release the device master file handle lock!\n"); mutex_unlock(&pdev->mfhlock); } /* maybe this is the latest close, maybe not. */ mutex_lock(&pdev->rcmutex); pdev->rc--; if (pdev->rc == 0) // latest close, {// stop_capture(pdev); // stop capturing... PDEBUG("capturing stopped!\n"); clk_disable(pdev->clk); // stop camif clock PDEBUG("camif clock stopped!\n"); free_irq(IRQ_S3C2440_CAM_P, pdev); // free camif IRQs PDEBUG("IRQ_S3C2440_CAM_P freed!\n"); free_irq(IRQ_S3C2440_CAM_C, pdev); PDEBUG("IRQ_S3C2440_CAM_C freed!\n"); free_image_buffer(); // and free image buffer PDEBUG("image buffer freed.\n"); } mutex_unlock(&pdev->rcmutex); PDEBUG("pid %d[%s] close camera successfully.\n", current->pid, current->comm); return 0;}/* * camif_mmap() */static int camif_mmap(struct file *file, struct vm_area_struct * vma){ int ret; struct s3c2440camif_fh * fh; fh = file->private_data; (void)ret; PDEBUG("now in %s(), vma=0x%08lx\n",__FUNCTION__, (unsigned long)vma); PDEBUG("%s(): not implement now!\n", __FUNCTION__); BUG(); return -ENOENT;}/* * the key methods/attributes for this video device. */static struct file_operations camif_fops ={ .owner = THIS_MODULE, .open = camif_open, .release = camif_release, .read = camif_read, .poll = camif_poll, .ioctl = video_ioctl2, /* V4L2 ioctl handler */ .mmap = camif_mmap, .llseek = no_llseek,};/* * camif_dev_release() */static void camif_dev_release (struct video_device *vfd){ PDEBUG("now in %s()!\n", __FUNCTION__);}/* * the inner structure to register to videodev layer. */static struct video_device camif_dev ={ .name = "s3c2440 camif", .type = VID_TYPE_CAPTURE|VID_TYPE_SCALES|VID_TYPE_SUBCAPTURE, .hardware = 0, .fops = &camif_fops, .minor = -1, .release = camif_dev_release, .vidioc_querycap = vidioc_querycap, .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap, .vidioc_g_fmt_cap = vidioc_g_fmt_cap, .vidioc_s_fmt_cap = vidioc_s_fmt_cap, .vidioc_queryctrl = vidioc_queryctrl, .vidioc_g_ctrl = vidioc_g_ctrl, .vidioc_s_ctrl = vidioc_s_ctrl,#ifdef CONFIG_VIDEO_V4L1_COMPAT .vidiocgmbuf = vidiocgmbuf,#endif};static struct s3c2440camif_dev camera;#if 1int __init sccb_init(void);void __exit sccb_cleanup(void);int __init ov9650_init(void);void __exit ov9650_cleanup(void);#endif/* * camif_init() */static int __init camif_init(void){ int ret; struct s3c2440camif_dev * pdev; struct clk * camif_upll_clk; printk(KERN_ALERT"initializing s3c2440 camera interface......\n"); pdev = &camera; pdev->vfd = &camif_dev; /* set gpio-j to camera mode. */ PDEBUG("set GPIO-J to camera mode.\n"); PDEBUG("GPJCON=0x%08x\n", __raw_readl(S3C24XX_GPIO_BASE(S3C2440_GPJ0))); s3c2410_gpio_cfgpin(S3C2440_GPJ0, S3C2440_GPJ0_CAMDATA0); s3c2410_gpio_cfgpin(S3C2440_GPJ1, S3C2440_GPJ1_CAMDATA1); s3c2410_gpio_cfgpin(S3C2440_GPJ2, S3C2440_GPJ2_CAMDATA2); s3c2410_gpio_cfgpin(S3C2440_GPJ3, S3C2440_GPJ3_CAMDATA3); s3c2410_gpio_cfgpin(S3C2440_GPJ4, S3C2440_GPJ4_CAMDATA4); s3c2410_gpio_cfgpin(S3C2440_GPJ5, S3C2440_GPJ5_CAMDATA5); s3c2410_gpio_cfgpin(S3C2440_GPJ6, S3C2440_GPJ6_CAMDATA6); s3c2410_gpio_cfgpin(S3C2440_GPJ7, S3C2440_GPJ7_CAMDATA7); s3c2410_gpio_cfgpin(S3C2440_GPJ8, S3C2440_GPJ8_CAMPCLK); s3c2410_gpio_cfgpin(S3C2440_GPJ9, S3C2440_GPJ9_CAMVSYNC); s3c2410_gpio_cfgpin(S3C2440_GPJ10, S3C2440_GPJ10_CAMHREF); s3c2410_gpio_cfgpin(S3C2440_GPJ11, S3C2440_GPJ11_CAMCLKOUT); s3c2410_gpio_cfgpin(S3C2440_GPJ12, S3C2440_GPJ12_CAMRESET); PDEBUG("GPJCON=0x%08x\n", __raw_readl(S3C24XX_GPIO_BASE(S3C2440_GPJ0))); /* init camera's virtual memory. */ PDEBUG("request camera virtual memory region.\n"); if (!request_mem_region((unsigned long)S3C2440_PA_CAMIF, S3C2440_SZ_CAMIF, DRIVER_NAME)) { PDEBUG("can't request virtual memory region for camera!\n"); ret = -EBUSY; goto error1; } /* remap the virtual memory. */ PDEBUG("remap camera virtual memory region.\n"); camif_base_addr = (unsigned long)ioremap_nocache((unsigned long)S3C2440_PA_CAMIF, S3C2440_SZ_CAMIF); if (camif_base_addr == (unsigned long)NULL) { PDEBUG("can't remap virtual memory region for camera!\n"); ret = -EBUSY; goto error2; } PDEBUG("camif_base_addr = 0x%08x\n", (unsigned)camif_base_addr); /* init camera clock. */ PDEBUG("initialize camera clock.\n"); pdev->clk = clk_get(NULL, "camif"); if (IS_ERR(pdev->clk)) { PDEBUG("can't get system clock for camera!\n"); ret = -ENOENT; goto error3; } clk_enable(pdev->clk); camif_upll_clk = clk_get(NULL, "camif-upll"); if (IS_ERR(camif_upll_clk)) { PDEBUG("can't get UPLL clock for camera!\n"); } clk_set_rate(camif_upll_clk, 24000000); mdelay(100); /* init reference counter and its mutex. */ mutex_init(&pdev->rcmutex); pdev->rc = 0; /* init master file handle mutex. */ mutex_init(&pdev->mfhlock); /* init image input source. */ pdev->input = 0; /* init camif state and its lock. */ pdev->state = CAMIF_STATE_FREE; spin_lock_init(&pdev->statelock); /* init command code, command lock and the command wait queue. */ pdev->cmdcode = CAMIF_CMD_NONE; spin_lock_init(&pdev->cmdlock); init_waitqueue_head(&pdev->cmdqueue); /* add to device chain. */ list_add_tail(&pdev->devlist, &camif_devlist); /* register to videodev layer. */ camif_dev.minor = video_nr; if (video_register_device(&camif_dev, VFL_TYPE_GRABBER, camif_dev.minor) != 0) { PDEBUG("register video device to videodev layer fail!\n"); ret = -EBUSY; goto error4; } PDEBUG("register video device to videodev layer successfully!\n"); printk(KERN_ALERT"s3c2440 camif init done!\n"); sccb_init(); ov9650_init(); return 0;error4: mutex_destroy(&pdev->mfhlock); mutex_destroy(&pdev->rcmutex); clk_put(pdev->clk);error3: iounmap((void *)camif_base_addr);error2: release_mem_region((unsigned long)S3C2440_PA_CAMIF, S3C2440_SZ_CAMIF); error1: return ret;}/* * camif_cleanup() */static void __exit camif_cleanup(void){ struct s3c2440camif_dev *pdev; ov9650_cleanup(); sccb_cleanup(); pdev = &camera; PDEBUG("removing s3c2440 camera interface......\n"); video_unregister_device(pdev->vfd); PDEBUG("unregister camif device successfully!\n"); mutex_destroy(&pdev->mfhlock); mutex_destroy(&pdev->rcmutex); clk_put(pdev->clk); iounmap((void *)camif_base_addr); release_mem_region((unsigned long)S3C2440_PA_CAMIF, S3C2440_SZ_CAMIF); printk(KERN_ALERT"s3c2440camif: module removed!\n");}static LIST_HEAD(input_devlist);int s3c2440_camif_register_camhw (struct s3c2440camif_hw * camifhw){ if (camifhw == NULL) { PDEBUG("bug here.\n"); BUG(); } list_add_tail(&camifhw->devlist, &input_devlist); hw_reset_camif(); if (camifhw->init != NULL) { camifhw->init(); } return 0;}EXPORT_SYMBOL(s3c2440_camif_register_camhw);void s3c2440_camif_unregister_camhw (struct s3c2440camif_hw * camifhw){ if (camifhw == NULL) { PDEBUG("bug here.\n"); BUG(); } if (camifhw->cleanup != NULL) { camifhw->cleanup(); } list_del(&camifhw->devlist);}EXPORT_SYMBOL(s3c2440_camif_unregister_camhw);#if 0static void print_regs(void){ PDEBUG("S3C244X_CISRCFMT = 0x%08x\n", ioread32(S3C244X_CISRCFMT)); PDEBUG("S3C244X_CIWDOFST = 0x%08x\n", ioread32(S3C244X_CIWDOFST)); PDEBUG("S3C244X_CIGCTRL = 0x%08x\n", ioread32(S3C244X_CIGCTRL)); PDEBUG("S3C244X_CICOYSA1 = 0x%08x\n", ioread32(S3C244X_CICOYSA1)); PDEBUG("S3C244X_CICOYSA2 = 0x%08x\n", ioread32(S3C244X_CICOYSA2)); PDEBUG("S3C244X_CICOYSA3 = 0x%08x\n", ioread32(S3C244X_CICOYSA3)); PDEBUG("S3C244X_CICOYSA4 = 0x%08x\n", ioread32(S3C244X_CICOYSA4)); PDEBUG("S3C244X_CICOCBSA1 = 0x%08x\n", ioread32(S3C244X_CICOCBSA1)); PDEBUG("S3C244X_CICOCBSA2 = 0x%08x\n", ioread32(S3C244X_CICOCBSA2)); PDEBUG("S3C244X_CICOCBSA3 = 0x%08x\n", ioread32(S3C244X_CICOCBSA3)); PDEBUG("S3C244X_CICOCBSA4 = 0x%08x\n", ioread32(S3C244X_CICOCBSA4)); PDEBUG("S3C244X_CICOCRSA1 = 0x%08x\n", ioread32(S3C244X_CICOCRSA1)); PDEBUG("S3C244X_CICOCRSA2 = 0x%08x\n", ioread32(S3C244X_CICOCRSA2)); PDEBUG("S3C244X_CICOCRSA3 = 0x%08x\n", ioread32(S3C244X_CICOCRSA3)); PDEBUG("S3C244X_CICOCRSA4 = 0x%08x\n", ioread32(S3C244X_CICOCRSA4)); PDEBUG("S3C244X_CICOTRGFMT = 0x%08x\n", ioread32(S3C244X_CICOTRGFMT)); PDEBUG("S3C244X_CICOCTRL = 0x%08x\n", ioread32(S3C244X_CICOCTRL)); PDEBUG("S3C244X_CICOSCPRERATIO = 0x%08x\n", ioread32(S3C244X_CICOSCPRERATIO)); PDEBUG("S3C244X_CICOSCPREDST = 0x%08x\n", ioread32(S3C244X_CICOSCPREDST)); PDEBUG("S3C244X_CICOSCCTRL = 0x%08x\n", ioread32(S3C244X_CICOSCCTRL)); PDEBUG("S3C244X_CICOTAREA = 0x%08x\n", ioread32(S3C244X_CICOTAREA)); PDEBUG("S3C244X_CICOSTATUS = 0x%08x\n", ioread32(S3C244X_CICOSTATUS)); PDEBUG("S3C244X_CIPRCLRSA1 = 0x%08x\n", ioread32(S3C244X_CIPRCLRSA1)); PDEBUG("S3C244X_CIPRCLRSA2 = 0x%08x\n", ioread32(S3C244X_CIPRCLRSA2)); PDEBUG("S3C244X_CIPRCLRSA3 = 0x%08x\n", ioread32(S3C244X_CIPRCLRSA3)); PDEBUG("S3C244X_CIPRCLRSA4 = 0x%08x\n", ioread32(S3C244X_CIPRCLRSA4)); PDEBUG("S3C244X_CIPRTRGFMT = 0x%08x\n", ioread32(S3C244X_CIPRTRGFMT)); PDEBUG("S3C244X_CIPRCTRL = 0x%08x\n", ioread32(S3C244X_CIPRCTRL)); PDEBUG("S3C244X_CIPRSCPRERATIO = 0x%08x\n", ioread32(S3C244X_CIPRSCPRERATIO)); PDEBUG("S3C244X_CIPRSCPREDST = 0x%08x\n", ioread32(S3C244X_CIPRSCPREDST)); PDEBUG("S3C244X_CIPRSCCTRL = 0x%08x\n", ioread32(S3C244X_CIPRSCCTRL)); PDEBUG("S3C244X_CIPRTAREA = 0x%08x\n", ioread32(S3C244X_CIPRTAREA)); PDEBUG("S3C244X_CIPRSTATUS = 0x%08x\n", ioread32(S3C244X_CIPRSTATUS)); PDEBUG("S3C244X_CIIMGCPT = 0x%08x\n", ioread32(S3C244X_CIIMGCPT));}#endifMODULE_DESCRIPTION("v4l2 driver module for s3c2440 camera interface");MODULE_AUTHOR("sunxq [baobaoba520@yahoo.com.cn]");MODULE_LICENSE("GPL");module_init(camif_init);module_exit(camif_cleanup);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -