diff options
Diffstat (limited to 'drivers/media/pci/cx18/cx18-ioctl.c')
-rw-r--r-- | drivers/media/pci/cx18/cx18-ioctl.c | 391 |
1 files changed, 159 insertions, 232 deletions
diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c index c8ba7841c720..1817b9ed042c 100644 --- a/drivers/media/pci/cx18/cx18-ioctl.c +++ b/drivers/media/pci/cx18/cx18-ioctl.c @@ -27,6 +27,133 @@ #include <media/tveeprom.h> #include <media/v4l2-event.h> +static const struct v4l2_fmtdesc cx18_formats_yuv[] = { + { + .index = 0, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .pixelformat = V4L2_PIX_FMT_NV12_16L16, + }, + { + .index = 1, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .pixelformat = V4L2_PIX_FMT_UYVY, + }, +}; + +static const struct v4l2_fmtdesc cx18_formats_mpeg[] = { + { + .index = 0, + .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, + .flags = V4L2_FMT_FLAG_COMPRESSED, + .pixelformat = V4L2_PIX_FMT_MPEG, + }, +}; + +static int cx18_g_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + struct cx18_open_id *id = fh2id(fh); + struct cx18 *cx = id->cx; + struct cx18_stream *s = &cx->streams[id->type]; + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + + pixfmt->width = cx->cxhdl.width; + pixfmt->height = cx->cxhdl.height; + pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + pixfmt->field = V4L2_FIELD_INTERLACED; + if (id->type == CX18_ENC_STREAM_TYPE_YUV) { + pixfmt->pixelformat = s->pixelformat; + pixfmt->sizeimage = s->vb_bytes_per_frame; + pixfmt->bytesperline = s->vb_bytes_per_line; + } else { + pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; + pixfmt->sizeimage = 128 * 1024; + pixfmt->bytesperline = 0; + } + return 0; +} + +static int cx18_try_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + struct cx18_open_id *id = fh2id(fh); + struct cx18 *cx = id->cx; + struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; + int w = pixfmt->width; + int h = pixfmt->height; + + w = min(w, 720); + w = max(w, 720 / 16); + + h = min(h, cx->is_50hz ? 576 : 480); + h = max(h, (cx->is_50hz ? 576 : 480) / 8); + + if (id->type == CX18_ENC_STREAM_TYPE_YUV) { + if (pixfmt->pixelformat != V4L2_PIX_FMT_NV12_16L16 && + pixfmt->pixelformat != V4L2_PIX_FMT_UYVY) + pixfmt->pixelformat = V4L2_PIX_FMT_UYVY; + /* YUV height must be a multiple of 32 */ + h = round_up(h, 32); + /* + * HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) + * UYUV YUV size is (Y=(h*720) + UV=(h*(720))) + */ + if (pixfmt->pixelformat == V4L2_PIX_FMT_NV12_16L16) { + pixfmt->sizeimage = h * 720 * 3 / 2; + pixfmt->bytesperline = 720; /* First plane */ + } else { + pixfmt->sizeimage = h * 720 * 2; + pixfmt->bytesperline = 1440; /* Packed */ + } + } else { + pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; + pixfmt->sizeimage = 128 * 1024; + pixfmt->bytesperline = 0; + } + + pixfmt->width = w; + pixfmt->height = h; + pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; + pixfmt->field = V4L2_FIELD_INTERLACED; + return 0; +} + +static int cx18_s_fmt_vid_cap(struct file *file, void *fh, + struct v4l2_format *fmt) +{ + struct cx18_open_id *id = fh2id(fh); + struct cx18 *cx = id->cx; + struct v4l2_subdev_format format = { + .which = V4L2_SUBDEV_FORMAT_ACTIVE, + }; + struct cx18_stream *s = &cx->streams[id->type]; + int ret; + int w, h; + + ret = cx18_try_fmt_vid_cap(file, fh, fmt); + if (ret) + return ret; + w = fmt->fmt.pix.width; + h = fmt->fmt.pix.height; + + if (cx->cxhdl.width == w && cx->cxhdl.height == h && + s->pixelformat == fmt->fmt.pix.pixelformat) + return 0; + + if (atomic_read(&cx->ana_capturing) > 0) + return -EBUSY; + + s->pixelformat = fmt->fmt.pix.pixelformat; + s->vb_bytes_per_frame = fmt->fmt.pix.sizeimage; + s->vb_bytes_per_line = fmt->fmt.pix.bytesperline; + + format.format.width = cx->cxhdl.width = w; + format.format.height = cx->cxhdl.height = h; + format.format.code = MEDIA_BUS_FMT_FIXED; + v4l2_subdev_call(cx->sd_av, pad, set_fmt, NULL, &format); + return cx18_g_fmt_vid_cap(file, fh, fmt); +} + u16 cx18_service2vbi(int type) { switch (type) { @@ -131,30 +258,6 @@ u16 cx18_get_service_set(struct v4l2_sliced_vbi_format *fmt) return set; } -static int cx18_g_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - struct v4l2_pix_format *pixfmt = &fmt->fmt.pix; - - pixfmt->width = cx->cxhdl.width; - pixfmt->height = cx->cxhdl.height; - pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M; - pixfmt->field = V4L2_FIELD_INTERLACED; - if (id->type == CX18_ENC_STREAM_TYPE_YUV) { - pixfmt->pixelformat = s->pixelformat; - pixfmt->sizeimage = s->vb_bytes_per_frame; - pixfmt->bytesperline = s->vb_bytes_per_line; - } else { - pixfmt->pixelformat = V4L2_PIX_FMT_MPEG; - pixfmt->sizeimage = 128 * 1024; - pixfmt->bytesperline = 0; - } - return 0; -} - static int cx18_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { @@ -199,30 +302,6 @@ static int cx18_g_fmt_sliced_vbi_cap(struct file *file, void *fh, return 0; } -static int cx18_try_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - int w = fmt->fmt.pix.width; - int h = fmt->fmt.pix.height; - int min_h = 2; - - w = min(w, 720); - w = max(w, 2); - if (id->type == CX18_ENC_STREAM_TYPE_YUV) { - /* YUV height must be a multiple of 32 */ - h &= ~0x1f; - min_h = 32; - } - h = min(h, cx->is_50hz ? 576 : 480); - h = max(h, min_h); - - fmt->fmt.pix.width = w; - fmt->fmt.pix.height = h; - return 0; -} - static int cx18_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { @@ -248,49 +327,6 @@ static int cx18_try_fmt_sliced_vbi_cap(struct file *file, void *fh, return 0; } -static int cx18_s_fmt_vid_cap(struct file *file, void *fh, - struct v4l2_format *fmt) -{ - struct cx18_open_id *id = fh2id(fh); - struct cx18 *cx = id->cx; - struct v4l2_subdev_format format = { - .which = V4L2_SUBDEV_FORMAT_ACTIVE, - }; - struct cx18_stream *s = &cx->streams[id->type]; - int ret; - int w, h; - - ret = cx18_try_fmt_vid_cap(file, fh, fmt); - if (ret) - return ret; - w = fmt->fmt.pix.width; - h = fmt->fmt.pix.height; - - if (cx->cxhdl.width == w && cx->cxhdl.height == h && - s->pixelformat == fmt->fmt.pix.pixelformat) - return 0; - - if (atomic_read(&cx->ana_capturing) > 0) - return -EBUSY; - - s->pixelformat = fmt->fmt.pix.pixelformat; - /* HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) - UYUV YUV size is (Y=(h*720) + UV=(h*(720))) */ - if (s->pixelformat == V4L2_PIX_FMT_NV12_16L16) { - s->vb_bytes_per_frame = h * 720 * 3 / 2; - s->vb_bytes_per_line = 720; /* First plane */ - } else { - s->vb_bytes_per_frame = h * 720 * 2; - s->vb_bytes_per_line = 1440; /* Packed */ - } - - format.format.width = cx->cxhdl.width = w; - format.format.height = cx->cxhdl.height = h; - format.format.code = MEDIA_BUS_FMT_FIXED; - v4l2_subdev_call(cx->sd_av, pad, set_fmt, NULL, &format); - return cx18_g_fmt_vid_cap(file, fh, fmt); -} - static int cx18_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt) { @@ -463,31 +499,17 @@ static int cx18_g_selection(struct file *file, void *fh, static int cx18_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt) { - static const struct v4l2_fmtdesc formats[] = { - { - .index = 0, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "HM12 (YUV 4:1:1)", - .pixelformat = V4L2_PIX_FMT_NV12_16L16, - }, - { - .index = 1, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .flags = V4L2_FMT_FLAG_COMPRESSED, - .description = "MPEG", - .pixelformat = V4L2_PIX_FMT_MPEG, - }, - { - .index = 2, - .type = V4L2_BUF_TYPE_VIDEO_CAPTURE, - .description = "UYVY 4:2:2", - .pixelformat = V4L2_PIX_FMT_UYVY, - }, - }; + struct cx18_open_id *id = fh2id(fh); - if (fmt->index > ARRAY_SIZE(formats) - 1) + if (id->type == CX18_ENC_STREAM_TYPE_YUV) { + if (fmt->index >= ARRAY_SIZE(cx18_formats_yuv)) + return -EINVAL; + *fmt = cx18_formats_yuv[fmt->index]; + return 0; + } + if (fmt->index) return -EINVAL; - *fmt = formats[fmt->index]; + *fmt = cx18_formats_mpeg[0]; return 0; } @@ -596,6 +618,19 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id std) cx2341x_handler_set_50hz(&cx->cxhdl, cx->is_50hz); cx->cxhdl.width = 720; cx->cxhdl.height = cx->is_50hz ? 576 : 480; + /* + * HM12 YUV size is (Y=(h*720) + UV=(h*(720/2))) + * UYUV YUV size is (Y=(h*720) + UV=(h*(720))) + */ + if (cx->streams[CX18_ENC_STREAM_TYPE_YUV].pixelformat == V4L2_PIX_FMT_NV12_16L16) { + cx->streams[CX18_ENC_STREAM_TYPE_YUV].vb_bytes_per_frame = + cx->cxhdl.height * 720 * 3 / 2; + cx->streams[CX18_ENC_STREAM_TYPE_YUV].vb_bytes_per_line = 720; + } else { + cx->streams[CX18_ENC_STREAM_TYPE_YUV].vb_bytes_per_frame = + cx->cxhdl.height * 720 * 2; + cx->streams[CX18_ENC_STREAM_TYPE_YUV].vb_bytes_per_line = 1440; + } cx->vbi.count = cx->is_50hz ? 18 : 12; cx->vbi.start[0] = cx->is_50hz ? 6 : 10; cx->vbi.start[1] = cx->is_50hz ? 318 : 273; @@ -803,117 +838,6 @@ static int cx18_g_enc_index(struct file *file, void *fh, return 0; } -static struct videobuf_queue *cx18_vb_queue(struct cx18_open_id *id) -{ - struct videobuf_queue *q = NULL; - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - - switch (s->vb_type) { - case V4L2_BUF_TYPE_VIDEO_CAPTURE: - q = &s->vbuf_q; - break; - case V4L2_BUF_TYPE_VBI_CAPTURE: - break; - default: - break; - } - return q; -} - -static int cx18_streamon(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct cx18_open_id *id = file->private_data; - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - - /* Start the hardware only if we're the video device */ - if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) - return -EINVAL; - - if (id->type != CX18_ENC_STREAM_TYPE_YUV) - return -EINVAL; - - /* Establish a buffer timeout */ - mod_timer(&s->vb_timeout, msecs_to_jiffies(2000) + jiffies); - - return videobuf_streamon(cx18_vb_queue(id)); -} - -static int cx18_streamoff(struct file *file, void *priv, - enum v4l2_buf_type type) -{ - struct cx18_open_id *id = file->private_data; - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - - /* Start the hardware only if we're the video device */ - if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) - return -EINVAL; - - if (id->type != CX18_ENC_STREAM_TYPE_YUV) - return -EINVAL; - - return videobuf_streamoff(cx18_vb_queue(id)); -} - -static int cx18_reqbufs(struct file *file, void *priv, - struct v4l2_requestbuffers *rb) -{ - struct cx18_open_id *id = file->private_data; - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - - if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) - return -EINVAL; - - return videobuf_reqbufs(cx18_vb_queue(id), rb); -} - -static int cx18_querybuf(struct file *file, void *priv, - struct v4l2_buffer *b) -{ - struct cx18_open_id *id = file->private_data; - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - - if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) - return -EINVAL; - - return videobuf_querybuf(cx18_vb_queue(id), b); -} - -static int cx18_qbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct cx18_open_id *id = file->private_data; - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - - if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) - return -EINVAL; - - return videobuf_qbuf(cx18_vb_queue(id), b); -} - -static int cx18_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b) -{ - struct cx18_open_id *id = file->private_data; - struct cx18 *cx = id->cx; - struct cx18_stream *s = &cx->streams[id->type]; - - if ((s->vb_type != V4L2_BUF_TYPE_VIDEO_CAPTURE) && - (s->vb_type != V4L2_BUF_TYPE_VBI_CAPTURE)) - return -EINVAL; - - return videobuf_dqbuf(cx18_vb_queue(id), b, file->f_flags & O_NONBLOCK); -} - static int cx18_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc) { @@ -930,7 +854,7 @@ static int cx18_encoder_cmd(struct file *file, void *fh, case V4L2_ENC_CMD_STOP: CX18_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n"); enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END; - cx18_stop_capture(id, + cx18_stop_capture(&cx->streams[id->type], enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END); break; @@ -1106,12 +1030,15 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = { .vidioc_s_register = cx18_s_register, #endif .vidioc_default = cx18_default, - .vidioc_streamon = cx18_streamon, - .vidioc_streamoff = cx18_streamoff, - .vidioc_reqbufs = cx18_reqbufs, - .vidioc_querybuf = cx18_querybuf, - .vidioc_qbuf = cx18_qbuf, - .vidioc_dqbuf = cx18_dqbuf, + + .vidioc_reqbufs = vb2_ioctl_reqbufs, + .vidioc_querybuf = vb2_ioctl_querybuf, + .vidioc_qbuf = vb2_ioctl_qbuf, + .vidioc_dqbuf = vb2_ioctl_dqbuf, + .vidioc_create_bufs = vb2_ioctl_create_bufs, + .vidioc_streamon = vb2_ioctl_streamon, + .vidioc_streamoff = vb2_ioctl_streamoff, + .vidioc_prepare_buf = vb2_ioctl_prepare_buf, .vidioc_subscribe_event = v4l2_ctrl_subscribe_event, .vidioc_unsubscribe_event = v4l2_event_unsubscribe, }; |