📄 s3c2440camif.c
字号:
return 0;error3: PDEBUG("free img_buff[2] pages.\n"); free_pages(img_buff[2].virt_base, order); img_buff[2].phy_base = (unsigned long)NULL;error2: PDEBUG("free img_buff[1] pages.\n"); free_pages(img_buff[1].virt_base, order); img_buff[1].phy_base = (unsigned long)NULL;error1: PDEBUG("free img_buff[0] pages.\n"); free_pages(img_buff[0].virt_base, order); img_buff[0].phy_base = (unsigned long)NULL;error0: return -ENOMEM;}/* free image buffers (only when the camif is latest close). */static void __inline__ free_image_buffer(void){ if ((img_buff[0].virt_base == (unsigned long)NULL) ||(img_buff[1].virt_base == (unsigned long)NULL) ||(img_buff[2].virt_base == (unsigned long)NULL) ||(img_buff[3].virt_base == (unsigned long)NULL)) { PDEBUG("bug here."); BUG(); } free_pages(img_buff[0].virt_base, img_buff[0].order); free_pages(img_buff[1].virt_base, img_buff[1].order); free_pages(img_buff[2].virt_base, img_buff[2].order); free_pages(img_buff[3].virt_base, img_buff[3].order); img_buff[0].order = 0; img_buff[0].virt_base = (unsigned long)NULL; img_buff[0].phy_base = (unsigned long)NULL; img_buff[1].order = 0; img_buff[1].virt_base = (unsigned long)NULL; img_buff[1].phy_base = (unsigned long)NULL; img_buff[2].order = 0; img_buff[2].virt_base = (unsigned long)NULL; img_buff[2].phy_base = (unsigned long)NULL; img_buff[3].order = 0; img_buff[3].virt_base = (unsigned long)NULL; img_buff[3].phy_base = (unsigned long)NULL; PDEBUG("free pages for img_buff[0..3] done.\n");}/* * vidioc_querycap(), * * IOCTL method for cmd 'VIDIOC_QUERYCAP' */static int vidioc_querycap (struct file *file, void *priv, struct v4l2_capability *cap){ PDEBUG("now in %s().\n", __FUNCTION__); memset(cap, 0, sizeof(struct v4l2_capability)); strcpy(cap->driver, DRIVER_NAME); strcpy(cap->card, CARD_NAME); cap->version = DRIVER_VERSION; cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE; return 0;}/* * vidioc_enum_fmt_cap () * * IOCTL method for cmd 'VIDIOC_ENUM_FMT' */static int vidioc_enum_fmt_cap (struct file *file, void *priv, struct v4l2_fmtdesc *f){ int index; int ret; PDEBUG("now in %s().\n", __FUNCTION__); switch (f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: index = f->index; if (index < ARRAY_SIZE(formats)) { memset (f, 0, sizeof (struct v4l2_fmtdesc)); f->index = index; f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE; f->flags = 0; f->pixelformat = formats[index].pixelformat; memcpy (&f->description[0], &formats[index].description[0], sizeof(formats[index].description)); ret = 0; PDEBUG("%s() successfully!\n", __FUNCTION__); } else { PDEBUG("%s() fail, f->index = %d.\n", __FUNCTION__, f->index); ret = -EINVAL; } break; default: PDEBUG("%s() failed with unknown buffer type %d.\n", __FUNCTION__, f->type); ret = -EINVAL; break; } return ret;}/* * vidioc_g_fmt_cap () * * IOCTL method for cmd 'VIDIOC_G_FMT' */static int vidioc_g_fmt_cap (struct file *file, void * priv, struct v4l2_format * f){ int ret; struct s3c2440camif_fh * fh; struct s3c2440camif_dev * pdev; fh = priv; pdev = fh->dev; PDEBUG("now in %s().\n", __FUNCTION__); if (pdev->format >= ARRAY_SIZE(formats)) BUG(); switch(f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: switch (formats[pdev->format].pixelformat) { case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB24: f->fmt.pix.width = pdev->preTargetHsize; f->fmt.pix.height = pdev->preTargetVsize; f->fmt.pix.field = V4L2_FIELD_ANY; f->fmt.pix.pixelformat = formats[pdev->format].pixelformat; f->fmt.pix.bytesperline = (pdev->preTargetHsize * formats[pdev->format].depth) / 8; f->fmt.pix.sizeimage = pdev->preTargetVsize * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.priv = 0; PDEBUG("%s() successfully.\n", __FUNCTION__); break; case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YUYV: f->fmt.pix.width = pdev->coTargetHsize; f->fmt.pix.height = pdev->coTargetVsize; f->fmt.pix.field = V4L2_FIELD_ANY; f->fmt.pix.pixelformat = formats[pdev->format].pixelformat; f->fmt.pix.bytesperline = (pdev->coTargetHsize * formats[pdev->format].depth) / 8; f->fmt.pix.sizeimage = pdev->coTargetVsize * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.priv = 0; PDEBUG("%s() successfully.\n", __FUNCTION__); break; default: PDEBUG("bug here."); BUG(); break; } ret = 0; break; default: PDEBUG("%s() failed with unknown buffer type %d.\n", __FUNCTION__, f->type); ret = -EINVAL; break; } return ret;}/* * vidioc_s_fmt_cap () * * IOCTL method for cmd 'VIDIOC_S_FMT' */static int vidioc_s_fmt_cap (struct file *file, void *priv, struct v4l2_format * f){ int i; int ret; struct v4l2_pix_format * pfmt; struct s3c2440camif_fh * fh; struct s3c2440camif_dev * pdev; u32 cmdcode; fh = priv; pdev = fh->dev; cmdcode = CAMIF_CMD_NONE; PDEBUG("now in %s().\n", __FUNCTION__); if (fh->master != 1) { if (mutex_trylock(&pdev->mfhlock) != 0) { fh->master = 1; PDEBUG("pid %d[%s] is now the master file handle.\n", current->pid, current->comm); } else { PDEBUG("%s(), not a master file handle!\n", __FUNCTION__); return -EBUSY; } } ret = 0; switch(f->type) { case V4L2_BUF_TYPE_VIDEO_CAPTURE: pfmt = &f->fmt.pix; for (i = 0; i < ARRAY_SIZE(formats); i++) { if (formats[i].pixelformat == pfmt->pixelformat) { PDEBUG("%s() find, the new format is %s!\n", __FUNCTION__, &formats[i].description[0]); break; } } if (i >= ARRAY_SIZE(formats)) { /* unsupport image format, just return current image format. */ PDEBUG("unsupported pixel format, 0x%08x\n", pfmt->pixelformat); vidioc_g_fmt_cap(file, priv, f); } else { switch (formats[i].pixelformat) { case V4L2_PIX_FMT_RGB565: case V4L2_PIX_FMT_RGB24: /* change P-path setting. */ if (pfmt->width >= MAX_P_WIDTH) pdev->preTargetHsize = MAX_P_WIDTH; else pdev->preTargetHsize = pfmt->width & 0xFFFFFFF8; if (pfmt->height >= MAX_P_HEIGHT) pdev->preTargetVsize = MAX_P_HEIGHT; else pdev->preTargetVsize = pfmt->height & 0xFFFFFFF8; f->fmt.pix.width = pdev->preTargetHsize; f->fmt.pix.height = pdev->preTargetVsize; f->fmt.pix.pixelformat = formats[i].pixelformat; f->fmt.pix.bytesperline = (pdev->preTargetHsize * formats[i].depth) / 8; f->fmt.pix.sizeimage = pdev->preTargetVsize * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.priv = 0; pdev->format = i; pdev->p_format = i; PDEBUG("P-path default output format changed.\n"); break; case V4L2_PIX_FMT_YUV420: case V4L2_PIX_FMT_YUYV: /* change C-path setting. */ if (pfmt->width >= MAX_C_WIDTH) pdev->coTargetHsize = MAX_C_WIDTH; else pdev->coTargetHsize = pfmt->width & 0xFFFFFFF8; if (pfmt->height >= MAX_C_HEIGHT) pdev->coTargetVsize = MAX_C_HEIGHT; else pdev->coTargetVsize = pfmt->height & 0xFFFFFFF8; f->fmt.pix.width = pdev->coTargetHsize; f->fmt.pix.height = pdev->coTargetVsize; f->fmt.pix.pixelformat = formats[i].pixelformat; f->fmt.pix.bytesperline = (pdev->coTargetHsize * formats[i].depth) / 8; f->fmt.pix.sizeimage = pdev->coTargetVsize * f->fmt.pix.bytesperline; f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M; f->fmt.pix.priv = 0; pdev->format = i; pdev->c_format = i; PDEBUG("C-path default output format changed.\n"); break; default: BUG(); break; } } update_camif_config(fh, cmdcode); // ok, updates the camif regs. break; default: PDEBUG("%s() unknown buffer type %d.\n", __FUNCTION__, f->type); ret = -EINVAL; break; } return ret;}static int vidioc_queryctrl (struct file *file, void *priv, struct v4l2_queryctrl * arg){ int ret; PDEBUG("now in %s().\n", __FUNCTION__); if (arg->id < ARRAY_SIZE(g_ctrls)) { memcpy (arg, &g_ctrls[arg->id], sizeof(struct v4l2_queryctrl)); ret = 0; } else { ret = -EINVAL; } return ret;}static int vidioc_g_ctrl (struct file *file, void *priv, struct v4l2_control * arg){ int ret; struct s3c2440camif_fh * fh; struct s3c2440camif_dev * pdev; PDEBUG("now in %s().\n", __FUNCTION__); fh = priv; pdev = fh->dev; switch (arg->id) { case 0: arg->value = (pdev->srcHsize - pdev->wndHsize) / 2; PDEBUG("horizontal window offset: %d\n", arg->value); ret = 0; break; case 1: arg->value = (pdev->srcVsize - pdev->wndVsize) / 2; PDEBUG("vertical window offset: %d\n", arg->value); ret = 0; break; default: PDEBUG("unknown control id: [%d]\n", arg->id); ret = -EINVAL; break; } return ret;}static int vidioc_s_ctrl (struct file *file, void *priv, struct v4l2_control * arg){ int ret; struct s3c2440camif_fh * fh; struct s3c2440camif_dev * pdev; PDEBUG("now in %s().\n", __FUNCTION__); fh = priv; pdev = fh->dev; switch (arg->id) { case 0: BUG_ON((arg->value%8)!=0); pdev->wndHsize = (pdev->srcHsize - arg->value) / 2; PDEBUG("horizontal window size changed to: %d\n", pdev->wndHsize); ret = 0; break; case 1: BUG_ON((arg->value%8)!=0); pdev->wndVsize = (pdev->srcVsize - arg->value) / 2; PDEBUG("vertical window offset: %d\n", pdev->wndVsize); ret = 0; break; default: PDEBUG("unknown control id: [%d]\n", arg->id); ret = -EINVAL; break; } return ret;}/* * ISR: service for C-path interrupt. */static irqreturn_t on_camif_irq_c(int irq, void * dev){ u32 cicostatus; u32 frame; struct s3c2440camif_dev * pdev; cicostatus = ioread32(S3C244X_CICOSTATUS); PDEBUG("Now in CAM_C ISR, CICOSTATUS=0x%08x!!\n", cicostatus); if ((cicostatus & (1<<21))== 0) { return IRQ_RETVAL(IRQ_NONE); } pdev = (struct s3c2440camif_dev *)dev; /* valid img_buff[x] just DMAed. */ frame = (cicostatus&(3<<26))>>26; frame = (frame+4-1)%4; PDEBUG("frame=%d\n", frame); if (formats[pdev->format].pixelformat == V4L2_PIX_FMT_YUV420) { img_buff[frame].state = CAMIF_BUFF_YCbCr420; } else { img_buff[frame].state = CAMIF_BUFF_YCbCr422; } if (pdev->cmdcode & CAMIF_CMD_STOP) { stop_capture(pdev); pdev->state = CAMIF_STATE_READY; } else { if (pdev->cmdcode & CAMIF_CMD_C2P) { camif_c2p(pdev); } if (pdev->cmdcode & CAMIF_CMD_WND) { update_target_wnd_regs(pdev); } if (pdev->cmdcode & CAMIF_CMD_TFMT) { update_target_fmt_regs(pdev); } if (pdev->cmdcode & CAMIF_CMD_ZOOM) { update_target_zoom_regs(pdev); } invalid_image_buffer(); } pdev->cmdcode = CAMIF_CMD_NONE; wake_up(&pdev->cmdqueue); PDEBUG("wake up some process from camif command queue!\n"); return IRQ_RETVAL(IRQ_HANDLED);}/* * ISR: service for P-path interrupt. */static irqreturn_t on_camif_irq_p(int irq, void * dev){ u32 ciprstatus; u32 frame; struct s3c2440camif_dev * pdev; ciprstatus = ioread32(S3C244X_CIPRSTATUS); PDEBUG("Now in CAM_P ISR, CIPRSTATUS=0x%08x!!\n", ciprstatus); if ((ciprstatus & (1<<21))== 0) { return IRQ_RETVAL(IRQ_NONE); } pdev = (struct s3c2440camif_dev *)dev; /* valid img_buff[x] just DMAed. */ frame = (ciprstatus&(3<<26))>>26; frame = (frame+4-1)%4; PDEBUG("frame=%d\n", frame); if (formats[pdev->format].pixelformat == V4L2_PIX_FMT_RGB565) { img_buff[frame].state = CAMIF_BUFF_RGB565; } else { img_buff[frame].state = CAMIF_BUFF_RGB24; } if (pdev->cmdcode & CAMIF_CMD_STOP) { stop_capture(pdev); pdev->state = CAMIF_STATE_READY; } else { if (pdev->cmdcode & CAMIF_CMD_P2C) { camif_c2p(pdev); } if (pdev->cmdcode & CAMIF_CMD_WND) { update_target_wnd_regs(pdev); } if (pdev->cmdcode & CAMIF_CMD_TFMT) { update_target_fmt_regs(pdev); } if (pdev->cmdcode & CAMIF_CMD_ZOOM) { update_target_zoom_regs(pdev); } invalid_image_buffer(); } pdev->cmdcode = CAMIF_CMD_NONE; wake_up(&pdev->cmdqueue); PDEBUG("wake up some process from camif command queue!\n"); return IRQ_RETVAL(IRQ_HANDLED);}/* * camif_open()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -