📄 mx27_v4l2_output.c
字号:
}/*! * Shut down the voutera * * @param vout structure vout_data * * * @return status 0 Success */static int mxc_v4l2out_streamoff(vout_data * vout){ int i, retval = 0; unsigned long lock_flag = 0; if (!vout) return -EINVAL; if (vout->state == STATE_STREAM_OFF) { return 0; } spin_lock_irqsave(&g_lock, lock_flag); del_timer(&vout->output_timer); pp_enable(0); /* Disable PP */ if (vout->state == STATE_STREAM_ON) { vout->state = STATE_STREAM_STOPPING; } spin_unlock_irqrestore(&g_lock, lock_flag); vout->ready_q.head = vout->ready_q.tail = 0; vout->done_q.head = vout->done_q.tail = 0; for (i = 0; i < vout->buffer_cnt; i++) { vout->v4l2_bufs[i].flags = 0; vout->v4l2_bufs[i].timestamp.tv_sec = 0; vout->v4l2_bufs[i].timestamp.tv_usec = 0; } vout->state = STATE_STREAM_OFF; if (vout->v4l2_fb.flags == V4L2_FBUF_FLAG_OVERLAY) { struct fb_gwinfo gwinfo; /* Disable graphic window */ gwinfo.enabled = 0; mx2_gw_set(&gwinfo); }#ifdef CONFIG_VIDEO_MXC_OUTPUT_FBSYNC if (vout->tear_protection == TEARING_PROTECTION_ACTIVE) { g_output_fb = -1; g_fb_enabled = 0; g_pp_ready = 0; fb_unregister_client(&fb_event_notifier); mx2fb_unregister_client(&mx2fb_event_notifier); }#endif mxc_free_buffers(vout->display_bufs, vout->display_bufs_vaddr, 2, vout->sdc_fg_buf_size); return retval;}/* * Valid whether the palette is supported * * @param palette V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_BGR24 or V4L2_PIX_FMT_BGR32 * * @return 1 if supported, 0 if failed */static inline int valid_mode(u32 palette){ return (palette == V4L2_PIX_FMT_YUV420);}/* * Returns bits per pixel for given pixel format * * @param pixelformat V4L2_PIX_FMT_RGB565, V4L2_PIX_FMT_BGR24 or V4L2_PIX_FMT_BGR32 * * @return bits per pixel of pixelformat */static u32 fmt_to_bpp(u32 pixelformat){ u32 bpp; switch (pixelformat) { case V4L2_PIX_FMT_RGB565: bpp = 16; break; case V4L2_PIX_FMT_BGR24: case V4L2_PIX_FMT_RGB24: bpp = 24; break; case V4L2_PIX_FMT_BGR32: case V4L2_PIX_FMT_RGB32: bpp = 32; break; default: bpp = 8; break; } return bpp;}/* * V4L2 - Handles VIDIOC_G_FMT Ioctl * * @param vout structure vout_data * * * @param v4l2_format structure v4l2_format * * * @return status 0 success, EINVAL failed */static int mxc_v4l2out_g_fmt(vout_data * vout, struct v4l2_format *f){ if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { return -EINVAL; } *f = vout->v2f; return 0;}/* * V4L2 - Handles VIDIOC_S_FMT Ioctl * * @param vout structure vout_data * * * @param v4l2_format structure v4l2_format * * * @return status 0 success, EINVAL failed */static int mxc_v4l2out_s_fmt(vout_data * vout, struct v4l2_format *f){ int retval = 0; u32 size = 0; u32 bytesperline; if (f->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) { retval = -EINVAL; goto err0; } if (!valid_mode(f->fmt.pix.pixelformat)) { pr_debug("pixel format not supported\n"); retval = -EINVAL; goto err0; } bytesperline = (f->fmt.pix.width * fmt_to_bpp(f->fmt.pix.pixelformat)) / 8; if (f->fmt.pix.bytesperline < bytesperline) { f->fmt.pix.bytesperline = bytesperline; } else { bytesperline = f->fmt.pix.bytesperline; } switch (f->fmt.pix.pixelformat) { case V4L2_PIX_FMT_YUV422P: /* byteperline for YUV planar formats is for Y plane only */ size = bytesperline * f->fmt.pix.height * 2; break; case V4L2_PIX_FMT_YUV420: size = (bytesperline * f->fmt.pix.height * 3) / 2; break; default: size = bytesperline * f->fmt.pix.height; break; } /* Return the actual size of the image to the app */ f->fmt.pix.sizeimage = size; vout->v2f.fmt.pix.sizeimage = size; vout->v2f.fmt.pix.width = f->fmt.pix.width; vout->v2f.fmt.pix.height = f->fmt.pix.height; vout->v2f.fmt.pix.pixelformat = f->fmt.pix.pixelformat; vout->v2f.fmt.pix.bytesperline = f->fmt.pix.bytesperline; retval = 0; err0: return retval;}/* * V4L2 - Handles VIDIOC_G_CTRL Ioctl * * @param vout structure vout_data * * * @param c structure v4l2_control * * * @return status 0 success, EINVAL failed */static int mxc_get_v42lout_control(vout_data * vout, struct v4l2_control *c){ switch (c->id) { case V4L2_CID_HFLIP: return (vout->rotate & IPU_ROTATE_HORIZ_FLIP) ? 1 : 0; case V4L2_CID_VFLIP: return (vout->rotate & IPU_ROTATE_VERT_FLIP) ? 1 : 0; case (V4L2_CID_PRIVATE_BASE + 1): return vout->rotate; case V4L2_CID_MXC_TEAR_PROTECT: c->value = vout->tear_protection; return 0; default: return -EINVAL; }}/* * V4L2 - Handles VIDIOC_S_CTRL Ioctl * * @param vout structure vout_data * * * @param c structure v4l2_control * * * @return status 0 success, EINVAL failed */static int mxc_set_v42lout_control(vout_data * vout, struct v4l2_control *c){ switch (c->id) { case V4L2_CID_HFLIP: case V4L2_CID_VFLIP: case V4L2_CID_MXC_ROT: return 0; case V4L2_CID_MXC_TEAR_PROTECT:#ifdef CONFIG_VIDEO_MXC_OUTPUT_FBSYNC if (c->value == TEARING_PROTECTION_ACTIVE) vout->tear_protection = TEARING_PROTECTION_ACTIVE; else vout->tear_protection = TEARING_PROTECTION_INACTIVE;;#else vout->tear_protection = TEARING_PROTECTION_UNSUPPORTED;#endif return 0; default: return -EINVAL; } return 0;}/*! * V4L2 interface - open function * * @param inode structure inode * * * @param file structure file * * * @return status 0 success, ENODEV invalid device instance, * ENODEV timeout, ERESTARTSYS interrupted by user */static int mxc_v4l2out_open(struct inode *inode, struct file *file){ struct video_device *dev = video_devdata(file); vout_data *vout = video_get_drvdata(dev); int err; dq_intr_cnt = 0; if (!vout) { pr_info("Internal error, vout_data not found!\n"); return -ENODEV; } down(&vout->busy_lock); err = -EINTR; if (signal_pending(current)) goto oops; if (vout->open_count++ == 0) { pp_init(vout); init_waitqueue_head(&vout->v4l_bufq); init_timer(&vout->output_timer); vout->output_timer.function = mxc_v4l2out_timer_handler; vout->output_timer.data = (unsigned long)vout; vout->state = STATE_STREAM_OFF; g_irq_cnt = g_buf_output_cnt = g_buf_q_cnt = g_buf_dq_cnt = 0; }#ifdef CONFIG_VIDEO_MXC_OUTPUT_FBSYNC vout->tear_protection = TEARING_PROTECTION_ACTIVE;#else vout->tear_protection = TEARING_PROTECTION_UNSUPPORTED;#endif file->private_data = dev; up(&vout->busy_lock); return 0; oops: up(&vout->busy_lock); return err;}/*! * V4L2 interface - close function * * @param inode struct inode * * * @param file struct file * * * @return 0 success */static int mxc_v4l2out_close(struct inode *inode, struct file *file){ struct video_device *dev = file->private_data; vout_data *vout = video_get_drvdata(dev); if (--vout->open_count == 0) { pr_debug("release resource\n"); pp_exit(vout); if (vout->state != STATE_STREAM_OFF) mxc_v4l2out_streamoff(vout); file->private_data = NULL; mxc_free_buffers(vout->queue_buf_paddr, vout->queue_buf_vaddr, vout->buffer_cnt, vout->queue_buf_size); vout->buffer_cnt = 0; mxc_free_buffers(vout->display_bufs, vout->display_bufs_vaddr, 2, vout->sdc_fg_buf_size); /* capture off */ wake_up_interruptible(&vout->v4l_bufq); } return 0;}/*! * V4L2 interface - ioctl function * * @param inode struct inode * * * @param file struct file * * * @param ioctlnr unsigned int * * @param arg void * * * @return 0 success, ENODEV for invalid device instance, * -1 for other errors. */static intmxc_v4l2out_do_ioctl(struct inode *inode, struct file *file, unsigned int ioctlnr, void *arg){ struct video_device *dev = file->private_data; vout_data *vout = video_get_drvdata(dev); int retval = 0; int i = 0; if (!vout) return -EBADF; /* make this _really_ smp-safe */ if (down_interruptible(&vout->busy_lock)) return -EBUSY; switch (ioctlnr) { case VIDIOC_QUERYCAP: { struct v4l2_capability *cap = arg; strcpy(cap->driver, "mxc_v4l2_output"); cap->version = 0; cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING; cap->card[0] = '\0'; cap->bus_info[0] = '\0'; retval = 0; break; } case VIDIOC_G_FMT: { struct v4l2_format *gf = arg; retval = mxc_v4l2out_g_fmt(vout, gf); break; } case VIDIOC_S_FMT: { struct v4l2_format *sf = arg; if (vout->state != STATE_STREAM_OFF) { retval = -EBUSY; break; } retval = mxc_v4l2out_s_fmt(vout, sf); break; } case VIDIOC_REQBUFS: { struct v4l2_requestbuffers *req = arg; if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || (req->memory != V4L2_MEMORY_MMAP)) { pr_debug ("VIDIOC_REQBUFS: incorrect buffer type\n"); retval = -EINVAL; break; } if (req->count == 0) mxc_v4l2out_streamoff(vout); if (vout->state == STATE_STREAM_OFF) { if (vout->queue_buf_paddr[0] != 0) { mxc_free_buffers(vout->queue_buf_paddr, vout->queue_buf_vaddr, vout->buffer_cnt, vout->queue_buf_size); pr_debug ("VIDIOC_REQBUFS: freed buffers\n"); } vout->buffer_cnt = 0; } else { pr_debug("VIDIOC_REQBUFS: Buffer is in use\n"); retval = -EBUSY; break; } if (req->count == 0) break; if (req->count < MIN_FRAME_NUM) { req->count = MIN_FRAME_NUM; } else if (req->count > MAX_FRAME_NUM) { req->count = MAX_FRAME_NUM; } vout->buffer_cnt = req->count; vout->queue_buf_size = PAGE_ALIGN(vout->v2f.fmt.pix.sizeimage); retval = mxc_allocate_buffers(vout->queue_buf_paddr, vout->queue_buf_vaddr, vout->buffer_cnt, vout->queue_buf_size); if (retval < 0) break; /* Init buffer queues */ vout->done_q.head = 0; vout->done_q.tail = 0; vout->ready_q.head = 0; vout->ready_q.tail = 0; for (i = 0; i < vout->buffer_cnt; i++) { memset(&(vout->v4l2_bufs[i]), 0, sizeof(vout->v4l2_bufs[i])); vout->v4l2_bufs[i].flags = 0; vout->v4l2_bufs[i].memory = V4L2_MEMORY_MMAP; vout->v4l2_bufs[i].index = i; vout->v4l2_bufs[i].type = V4L2_BUF_TYPE_VIDEO_OUTPUT; vout->v4l2_bufs[i].length = PAGE_ALIGN(vout->v2f.fmt.pix.sizeimage); vout->v4l2_bufs[i].m.offset = (unsigned long)vout->queue_buf_paddr[i]; vout->v4l2_bufs[i].timestamp.tv_sec = 0; vout->v4l2_bufs[i].timestamp.tv_usec = 0; } break; } case VIDIOC_QUERYBUF: { struct v4l2_buffer *buf = arg; u32 type = buf->type; int index = buf->index; if ((type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || (index >= vout->buffer_cnt)) { pr_debug ("VIDIOC_QUERYBUFS: incorrect buffer type\n"); retval = -EINVAL; break; } down(&vout->param_lock); memcpy(buf, &(vout->v4l2_bufs[index]), sizeof(*buf)); up(&vout->param_lock); break; } case VIDIOC_QBUF: { struct v4l2_buffer *buf = arg; int index = buf->index; unsigned long lock_flags; unsigned long timeout;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -