?? mxc_v4l2_output.c
字號:
} if (ipu_init_channel_buffer(MEM_ROT_PP_MEM, IPU_INPUT_BUFFER, params.mem_pp_mem. out_pixel_fmt, out_width, out_height, out_width, vout->rotate, vout->rot_pp_bufs[0], vout->rot_pp_bufs[1], 0, 0) != 0) { dev_err(dev, "Error initializing PP ROT input buffer\n"); return -EINVAL; } /* swap width and height */ out_width = vout->crop_current.width; out_height = vout->crop_current.height; if (ipu_init_channel_buffer(MEM_ROT_PP_MEM, IPU_OUTPUT_BUFFER, params.mem_pp_mem. out_pixel_fmt, out_width, out_height, out_width, IPU_ROTATE_NONE, vout->display_bufs[0], vout->display_bufs[1], 0, 0) != 0) { dev_err(dev, "Error initializing PP output buffer\n"); return -EINVAL; } if (ipu_link_channels(vout->post_proc_ch, MEM_ROT_PP_MEM) < 0) { return -EINVAL; } ipu_select_buffer(MEM_ROT_PP_MEM, IPU_OUTPUT_BUFFER, 0); ipu_select_buffer(MEM_ROT_PP_MEM, IPU_OUTPUT_BUFFER, 1); ipu_enable_channel(MEM_ROT_PP_MEM); display_input_ch = MEM_ROT_PP_MEM; } else { if (ipu_init_channel_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, params.mem_pp_mem. out_pixel_fmt, out_width, out_height, out_width, vout->rotate, vout->display_bufs[0], vout->display_bufs[1], 0, 0) != 0) { dev_err(dev, "Error initializing PP output buffer\n"); return -EINVAL; } } if (ipu_link_channels(display_input_ch, vout->display_ch) < 0) { dev_err(dev, "Error linking ipu channels\n"); return -EINVAL; } } vout->state = STATE_STREAM_PAUSED; ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 0); ipu_select_buffer(vout->post_proc_ch, IPU_INPUT_BUFFER, 1); if (use_direct_adc == false) { ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 0); ipu_select_buffer(vout->post_proc_ch, IPU_OUTPUT_BUFFER, 1); ipu_enable_channel(vout->post_proc_ch); ipu_enable_channel(vout->display_ch); } else { ipu_enable_channel(vout->post_proc_ch); } vout->start_jiffies = jiffies; dev_dbg(dev, "streamon: start time = %lu jiffies\n", vout->start_jiffies); return 0;}/*! * 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; u32 lockflag = 0; if (!vout) return -EINVAL; if (vout->state == STATE_STREAM_OFF) { return 0; } spin_lock_irqsave(&g_lock, lockflag); del_timer(&vout->output_timer); if (vout->state == STATE_STREAM_ON) { vout->state = STATE_STREAM_STOPPING; } ipu_disable_irq(IPU_IRQ_PP_IN_EOF); spin_unlock_irqrestore(&g_lock, lockflag); if (vout->post_proc_ch == MEM_PP_MEM) { /* SDC or ADC with Rotation */ ipu_disable_channel(MEM_PP_MEM, true); if (vout->rotate >= IPU_ROTATE_90_RIGHT) { ipu_disable_channel(MEM_ROT_PP_MEM, true); ipu_unlink_channels(MEM_PP_MEM, MEM_ROT_PP_MEM); ipu_unlink_channels(MEM_ROT_PP_MEM, vout->display_ch); } else { ipu_unlink_channels(MEM_PP_MEM, vout->display_ch); } ipu_disable_channel(vout->display_ch, true); ipu_uninit_channel(vout->display_ch); ipu_uninit_channel(MEM_PP_MEM); ipu_uninit_channel(MEM_ROT_PP_MEM); } else { /* ADC Direct */ ipu_disable_channel(MEM_PP_ADC, true); ipu_uninit_channel(MEM_PP_ADC); } 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;#ifdef CONFIG_FB_MXC_ASYNC_PANEL if (vout->cur_disp_output != DISP3) { mxcfb_set_refresh_mode(registered_fb [vout-> output_fb_num[vout->cur_disp_output]], MXCFB_REFRESH_PARTIAL, 0); }#endif 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_RGB565) || (palette == V4L2_PIX_FMT_BGR24) || (palette == V4L2_PIX_FMT_RGB24) || (palette == V4L2_PIX_FMT_BGR32) || (palette == V4L2_PIX_FMT_RGB32) || (palette == V4L2_PIX_FMT_YUV422P) || (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)) { dev_err(vout->video_dev->dev, "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 */ if (f->fmt.pix.sizeimage < size) { f->fmt.pix.sizeimage = size; } else { size = f->fmt.pix.sizeimage; } vout->v2f.fmt.pix = f->fmt.pix; copy_from_user(&vout->offset, (void *)vout->v2f.fmt.pix.priv, sizeof(vout->offset)); 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; 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: vout->rotate |= c->value ? IPU_ROTATE_HORIZ_FLIP : IPU_ROTATE_NONE; break; case V4L2_CID_VFLIP: vout->rotate |= c->value ? IPU_ROTATE_VERT_FLIP : IPU_ROTATE_NONE; break; case V4L2_CID_MXC_ROT: vout->rotate = c->value; break; 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; dq_timeout_cnt = 0; if (!vout) { return -ENODEV; } down(&vout->busy_lock); err = -EINTR; if (signal_pending(current)) goto oops; if (vout->open_count++ == 0) { ipu_request_irq(IPU_IRQ_PP_IN_EOF, mxc_v4l2out_pp_in_irq_handler, 0, dev->name, 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; } 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) { if (vout->state != STATE_STREAM_OFF) mxc_v4l2out_streamoff(vout); ipu_free_irq(IPU_IRQ_PP_IN_EOF, 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); mxc_free_buffers(vout->rot_pp_bufs, vout->rot_pp_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 *vdev = file->private_data; vout_data *vout = video_get_drvdata(vdev); 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)) { dev_dbg(vdev->dev, "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); dev_dbg(vdev->dev, "VIDIOC_REQBUFS: freed buffers\n"); } vout->buffer_cnt = 0; } else { dev_dbg(vdev->dev, "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 =
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -