Commit 3f038d80 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

V4L/DVB (8079): ivtv: Convert to video_ioctl2.

Based on an initial conversion patch from Douglas Landgraf.
Signed-off-by: default avatarDouglas Schilling Landgraf <dougsland@gmail.com>
Signed-off-by: default avatarHans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@infradead.org>
parent 539a7555
......@@ -47,8 +47,10 @@ static const u32 *ctrl_classes[] = {
NULL
};
static int ivtv_queryctrl(struct ivtv *itv, struct v4l2_queryctrl *qctrl)
int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
const char *name;
IVTV_DEBUG_IOCTL("VIDIOC_QUERYCTRL(%08x)\n", qctrl->id);
......@@ -87,17 +89,20 @@ static int ivtv_queryctrl(struct ivtv *itv, struct v4l2_queryctrl *qctrl)
return 0;
}
static int ivtv_querymenu(struct ivtv *itv, struct v4l2_querymenu *qmenu)
int ivtv_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qmenu)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
struct v4l2_queryctrl qctrl;
IVTV_DEBUG_IOCTL("VIDIOC_QUERYMENU\n");
qctrl.id = qmenu->id;
ivtv_queryctrl(itv, &qctrl);
ivtv_queryctrl(file, fh, &qctrl);
return v4l2_ctrl_query_menu(qmenu, &qctrl, cx2341x_ctrl_get_menu(qmenu->id));
}
static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
int ivtv_s_ctrl(struct file *file, void *fh, struct v4l2_control *vctrl)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
s32 v = vctrl->value;
IVTV_DEBUG_IOCTL("VIDIOC_S_CTRL(%08x, %x)\n", vctrl->id, v);
......@@ -125,8 +130,10 @@ static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
return 0;
}
static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
int ivtv_g_ctrl(struct file *file, void *fh, struct v4l2_control *vctrl)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
IVTV_DEBUG_IOCTL("VIDIOC_G_CTRL(%08x)\n", vctrl->id);
switch (vctrl->id) {
......@@ -191,119 +198,96 @@ static int ivtv_setup_vbi_fmt(struct ivtv *itv, enum v4l2_mpeg_stream_vbi_fmt fm
return 0;
}
int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg)
int ivtv_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
struct v4l2_control ctrl;
switch (cmd) {
case VIDIOC_QUERYMENU:
IVTV_DEBUG_IOCTL("VIDIOC_QUERYMENU\n");
return ivtv_querymenu(itv, arg);
case VIDIOC_QUERYCTRL:
return ivtv_queryctrl(itv, arg);
case VIDIOC_S_CTRL:
return ivtv_s_ctrl(itv, arg);
case VIDIOC_G_CTRL:
return ivtv_g_ctrl(itv, arg);
case VIDIOC_S_EXT_CTRLS:
{
struct v4l2_ext_controls *c = arg;
if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
int i;
int err = 0;
for (i = 0; i < c->count; i++) {
ctrl.id = c->controls[i].id;
ctrl.value = c->controls[i].value;
err = ivtv_s_ctrl(itv, &ctrl);
c->controls[i].value = ctrl.value;
if (err) {
c->error_idx = i;
break;
}
}
return err;
}
IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
static u32 freqs[3] = { 44100, 48000, 32000 };
struct cx2341x_mpeg_params p = itv->params;
int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), arg, cmd);
unsigned idx;
if (err)
return err;
if (p.video_encoding != itv->params.video_encoding) {
int is_mpeg1 = p.video_encoding ==
V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
struct v4l2_format fmt;
/* fix videodecoder resolution */
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1);
fmt.fmt.pix.height = itv->params.height;
itv->video_dec_func(itv, VIDIOC_S_FMT, &fmt);
}
err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p);
if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt) {
err = ivtv_setup_vbi_fmt(itv, p.stream_vbi_fmt);
if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
int i;
int err = 0;
for (i = 0; i < c->count; i++) {
ctrl.id = c->controls[i].id;
ctrl.value = c->controls[i].value;
err = ivtv_g_ctrl(file, fh, &ctrl);
c->controls[i].value = ctrl.value;
if (err) {
c->error_idx = i;
break;
}
itv->params = p;
itv->dualwatch_stereo_mode = p.audio_properties & 0x0300;
idx = p.audio_properties & 0x03;
/* The audio clock of the digitizer must match the codec sample
rate otherwise you get some very strange effects. */
if (idx < sizeof(freqs))
ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[idx]);
return err;
}
return -EINVAL;
return err;
}
IVTV_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n");
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
return cx2341x_ext_ctrls(&itv->params, 0, c, VIDIOC_G_EXT_CTRLS);
return -EINVAL;
}
case VIDIOC_G_EXT_CTRLS:
{
struct v4l2_ext_controls *c = arg;
if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
int i;
int err = 0;
for (i = 0; i < c->count; i++) {
ctrl.id = c->controls[i].id;
ctrl.value = c->controls[i].value;
err = ivtv_g_ctrl(itv, &ctrl);
c->controls[i].value = ctrl.value;
if (err) {
c->error_idx = i;
break;
}
int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
struct v4l2_control ctrl;
if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
int i;
int err = 0;
for (i = 0; i < c->count; i++) {
ctrl.id = c->controls[i].id;
ctrl.value = c->controls[i].value;
err = ivtv_s_ctrl(file, fh, &ctrl);
c->controls[i].value = ctrl.value;
if (err) {
c->error_idx = i;
break;
}
return err;
}
IVTV_DEBUG_IOCTL("VIDIOC_G_EXT_CTRLS\n");
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
return cx2341x_ext_ctrls(&itv->params, 0, arg, cmd);
return -EINVAL;
return err;
}
IVTV_DEBUG_IOCTL("VIDIOC_S_EXT_CTRLS\n");
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
static u32 freqs[3] = { 44100, 48000, 32000 };
struct cx2341x_mpeg_params p = itv->params;
int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), c, VIDIOC_S_EXT_CTRLS);
unsigned idx;
if (err)
return err;
case VIDIOC_TRY_EXT_CTRLS:
{
struct v4l2_ext_controls *c = arg;
if (p.video_encoding != itv->params.video_encoding) {
int is_mpeg1 = p.video_encoding ==
V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
struct v4l2_format fmt;
IVTV_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
return cx2341x_ext_ctrls(&itv->params, atomic_read(&itv->capturing), arg, cmd);
return -EINVAL;
/* fix videodecoder resolution */
fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
fmt.fmt.pix.width = itv->params.width / (is_mpeg1 ? 2 : 1);
fmt.fmt.pix.height = itv->params.height;
itv->video_dec_func(itv, VIDIOC_S_FMT, &fmt);
}
err = cx2341x_update(itv, ivtv_api_func, &itv->params, &p);
if (!err && itv->params.stream_vbi_fmt != p.stream_vbi_fmt)
err = ivtv_setup_vbi_fmt(itv, p.stream_vbi_fmt);
itv->params = p;
itv->dualwatch_stereo_mode = p.audio_properties & 0x0300;
idx = p.audio_properties & 0x03;
/* The audio clock of the digitizer must match the codec sample
rate otherwise you get some very strange effects. */
if (idx < sizeof(freqs))
ivtv_call_i2c_clients(itv, VIDIOC_INT_AUDIO_CLOCK_FREQ, &freqs[idx]);
return err;
}
return -EINVAL;
}
default:
return -EINVAL;
}
return 0;
int ivtv_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
IVTV_DEBUG_IOCTL("VIDIOC_TRY_EXT_CTRLS\n");
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
return cx2341x_ext_ctrls(&itv->params, atomic_read(&itv->capturing), c, VIDIOC_TRY_EXT_CTRLS);
return -EINVAL;
}
......@@ -21,6 +21,12 @@
#ifndef IVTV_CONTROLS_H
#define IVTV_CONTROLS_H
int ivtv_control_ioctls(struct ivtv *itv, unsigned int cmd, void *arg);
int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a);
int ivtv_g_ctrl(struct file *file, void *fh, struct v4l2_control *a);
int ivtv_s_ctrl(struct file *file, void *fh, struct v4l2_control *a);
int ivtv_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
int ivtv_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
int ivtv_querymenu(struct file *file, void *fh, struct v4l2_querymenu *a);
#endif
......@@ -1262,9 +1262,13 @@ static int __devinit ivtv_probe(struct pci_dev *dev,
int ivtv_init_on_first_open(struct ivtv *itv)
{
struct v4l2_frequency vf;
/* Needed to call ioctls later */
struct ivtv_open_id fh;
int fw_retry_count = 3;
int video_input;
fh.itv = itv;
if (test_bit(IVTV_F_I_FAILED, &itv->i_flags))
return -ENXIO;
......@@ -1312,18 +1316,18 @@ int ivtv_init_on_first_open(struct ivtv *itv)
video_input = itv->active_input;
itv->active_input++; /* Force update of input */
ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_INPUT, &video_input);
ivtv_s_input(NULL, &fh, video_input);
/* Let the VIDIOC_S_STD ioctl do all the work, keeps the code
in one place. */
itv->std++; /* Force full standard initialization */
itv->std_out = itv->std;
ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_FREQUENCY, &vf);
ivtv_s_frequency(NULL, &fh, &vf);
if (itv->card->v4l2_capabilities & V4L2_CAP_VIDEO_OUTPUT) {
ivtv_init_mpeg_decoder(itv);
}
ivtv_v4l2_ioctls(itv, NULL, VIDIOC_S_STD, &itv->tuner_std);
ivtv_s_std(NULL, &fh, &itv->tuner_std);
/* On a cx23416 this seems to be able to enable DMA to the chip? */
if (!itv->has_cx23415)
......
......@@ -373,267 +373,172 @@ static int ivtv_itvc(struct ivtv *itv, unsigned int cmd, void *arg)
return 0;
}
static int ivtv_get_fmt(struct ivtv *itv, int streamtype, struct v4l2_format *fmt)
static int ivtv_g_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
{
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
fmt->fmt.pix.width = itv->main_rect.width;
fmt->fmt.pix.height = itv->main_rect.height;
fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) {
case IVTV_YUV_MODE_INTERLACED:
fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ?
V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB;
break;
case IVTV_YUV_MODE_PROGRESSIVE:
fmt->fmt.pix.field = V4L2_FIELD_NONE;
break;
default:
fmt->fmt.pix.field = V4L2_FIELD_ANY;
break;
}
fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
fmt->fmt.pix.bytesperline = 720;
fmt->fmt.pix.width = itv->yuv_info.v4l2_src_w;
fmt->fmt.pix.height = itv->yuv_info.v4l2_src_h;
/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
fmt->fmt.pix.sizeimage =
1080 * ((fmt->fmt.pix.height + 31) & ~31);
} else if (streamtype == IVTV_ENC_STREAM_TYPE_YUV) {
fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
fmt->fmt.pix.sizeimage =
fmt->fmt.pix.height * fmt->fmt.pix.width +
fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
} else {
fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
fmt->fmt.pix.sizeimage = 128 * 1024;
}
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
fmt->fmt.pix.width = itv->params.width;
fmt->fmt.pix.height = itv->params.height;
fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
if (streamtype == IVTV_ENC_STREAM_TYPE_YUV ||
streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
fmt->fmt.pix.sizeimage =
fmt->fmt.pix.height * fmt->fmt.pix.width +
fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
} else {
fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
fmt->fmt.pix.sizeimage = 128 * 1024;
}
break;
case V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY:
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
fmt->fmt.win.chromakey = itv->osd_chroma_key;
fmt->fmt.win.global_alpha = itv->osd_global_alpha;
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
fmt->fmt.vbi.sampling_rate = 27000000;
fmt->fmt.vbi.offset = 248;
fmt->fmt.vbi.samples_per_line = itv->vbi.raw_decoder_line_size - 4;
fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
fmt->fmt.vbi.start[0] = itv->vbi.start[0];
fmt->fmt.vbi.start[1] = itv->vbi.start[1];
fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = itv->vbi.count;
break;
case V4L2_BUF_TYPE_SLICED_VBI_OUTPUT:
{
struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
return -EINVAL;
vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
if (itv->is_60hz) {
vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
} else {
vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625;
vbifmt->service_lines[0][16] = V4L2_SLICED_VPS;
}
vbifmt->service_set = ivtv_get_service_set(vbifmt);
break;
if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
return -EINVAL;
vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
if (itv->is_60hz) {
vbifmt->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
vbifmt->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
} else {
vbifmt->service_lines[0][23] = V4L2_SLICED_WSS_625;
vbifmt->service_lines[0][16] = V4L2_SLICED_VPS;
}
vbifmt->service_set = ivtv_get_service_set(vbifmt);
return 0;
}
case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
{
struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
memset(vbifmt->reserved, 0, sizeof(vbifmt->reserved));
memset(vbifmt->service_lines, 0, sizeof(vbifmt->service_lines));
if (streamtype == IVTV_DEC_STREAM_TYPE_VBI) {
vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 :
V4L2_SLICED_VBI_525;
ivtv_expand_service_set(vbifmt, itv->is_50hz);
break;
}
static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct ivtv_open_id *id = fh;
struct ivtv *itv = id->itv;
itv->video_dec_func(itv, VIDIOC_G_FMT, fmt);
vbifmt->service_set = ivtv_get_service_set(vbifmt);
break;
}
case V4L2_BUF_TYPE_VBI_OUTPUT:
case V4L2_BUF_TYPE_VIDEO_OVERLAY:
default:
return -EINVAL;
fmt->fmt.pix.width = itv->params.width;
fmt->fmt.pix.height = itv->params.height;
fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
if (id->type == IVTV_ENC_STREAM_TYPE_YUV ||
id->type == IVTV_DEC_STREAM_TYPE_YUV) {
fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
fmt->fmt.pix.sizeimage =
fmt->fmt.pix.height * fmt->fmt.pix.width +
fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
} else {
fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
fmt->fmt.pix.sizeimage = 128 * 1024;
}
return 0;
}
static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
struct v4l2_format *fmt, int set_fmt)
static int ivtv_g_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct yuv_playback_info *yi = &itv->yuv_info;
struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
u16 set;
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
fmt->fmt.vbi.sampling_rate = 27000000;
fmt->fmt.vbi.offset = 248;
fmt->fmt.vbi.samples_per_line = itv->vbi.raw_decoder_line_size - 4;
fmt->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
fmt->fmt.vbi.start[0] = itv->vbi.start[0];
fmt->fmt.vbi.start[1] = itv->vbi.start[1];
fmt->fmt.vbi.count[0] = fmt->fmt.vbi.count[1] = itv->vbi.count;
return 0;
}
if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
struct v4l2_rect r;
int field;
static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
struct ivtv_open_id *id = fh;
struct ivtv *itv = id->itv;
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
field = fmt->fmt.pix.field;
r.top = 0;
r.left = 0;
r.width = fmt->fmt.pix.width;
r.height = fmt->fmt.pix.height;
ivtv_get_fmt(itv, streamtype, fmt);
fmt->fmt.pix.width = r.width;
fmt->fmt.pix.height = r.height;
if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
fmt->fmt.pix.field = field;
if (fmt->fmt.pix.width < 2)
fmt->fmt.pix.width = 2;
if (fmt->fmt.pix.width > 720)
fmt->fmt.pix.width = 720;
if (fmt->fmt.pix.height < 2)
fmt->fmt.pix.height = 2;
if (fmt->fmt.pix.height > 576)
fmt->fmt.pix.height = 576;
}
if (set_fmt && streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
/* Return now if we already have some frame data */
if (yi->stream_size)
return -EBUSY;
vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
yi->v4l2_src_w = r.width;
yi->v4l2_src_h = r.height;
if (id->type == IVTV_DEC_STREAM_TYPE_VBI) {
vbifmt->service_set = itv->is_50hz ? V4L2_SLICED_VBI_625 :
V4L2_SLICED_VBI_525;
ivtv_expand_service_set(vbifmt, itv->is_50hz);
return 0;
}
switch (field) {
case V4L2_FIELD_NONE:
yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
break;
case V4L2_FIELD_ANY:
yi->lace_mode = IVTV_YUV_MODE_AUTO;
break;
case V4L2_FIELD_INTERLACED_BT:
yi->lace_mode =
IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
break;
case V4L2_FIELD_INTERLACED_TB:
default:
yi->lace_mode = IVTV_YUV_MODE_INTERLACED;
break;
}
yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
itv->video_dec_func(itv, VIDIOC_G_FMT, fmt);
vbifmt->service_set = ivtv_get_service_set(vbifmt);
return 0;
}
if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
itv->dma_data_req_size =
1080 * ((yi->v4l2_src_h + 31) & ~31);
static int ivtv_g_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct ivtv_open_id *id = fh;
struct ivtv *itv = id->itv;
/* Force update of yuv registers */
yi->yuv_forced_update = 1;
return 0;
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
fmt->fmt.pix.width = itv->main_rect.width;
fmt->fmt.pix.height = itv->main_rect.height;
fmt->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
fmt->fmt.pix.field = V4L2_FIELD_INTERLACED;
if (id->type == IVTV_DEC_STREAM_TYPE_YUV) {
switch (itv->yuv_info.lace_mode & IVTV_YUV_MODE_MASK) {
case IVTV_YUV_MODE_INTERLACED:
fmt->fmt.pix.field = (itv->yuv_info.lace_mode & IVTV_YUV_SYNC_MASK) ?
V4L2_FIELD_INTERLACED_BT : V4L2_FIELD_INTERLACED_TB;
break;
case IVTV_YUV_MODE_PROGRESSIVE:
fmt->fmt.pix.field = V4L2_FIELD_NONE;
break;
default:
fmt->fmt.pix.field = V4L2_FIELD_ANY;
break;
}
return 0;
fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
fmt->fmt.pix.bytesperline = 720;
fmt->fmt.pix.width = itv->yuv_info.v4l2_src_w;
fmt->fmt.pix.height = itv->yuv_info.v4l2_src_h;
/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
fmt->fmt.pix.sizeimage =
1080 * ((fmt->fmt.pix.height + 31) & ~31);
} else if (id->type == IVTV_ENC_STREAM_TYPE_YUV) {
fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_HM12;
/* YUV size is (Y=(h*w) + UV=(h*(w/2))) */
fmt->fmt.pix.sizeimage =
fmt->fmt.pix.height * fmt->fmt.pix.width +
fmt->fmt.pix.height * (fmt->fmt.pix.width / 2);
} else {
fmt->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
fmt->fmt.pix.sizeimage = 128 * 1024;
}
return 0;
}
if (fmt->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_OVERLAY) {
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
if (set_fmt) {
itv->osd_chroma_key = fmt->fmt.win.chromakey;
itv->osd_global_alpha = fmt->fmt.win.global_alpha;
ivtv_set_osd_alpha(itv);
}
return 0;
}
static int ivtv_g_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
/* set window size */
if (fmt->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
struct cx2341x_mpeg_params *p = &itv->params;
int w = fmt->fmt.pix.width;
int h = fmt->fmt.pix.height;
if (w > 720) w = 720;
else if (w < 1) w = 1;
if (h > (itv->is_50hz ? 576 : 480)) h = (itv->is_50hz ? 576 : 480);
else if (h < 2) h = 2;
ivtv_get_fmt(itv, streamtype, fmt);
fmt->fmt.pix.width = w;
fmt->fmt.pix.height = h;
if (!set_fmt || (p->width == w && p->height == h))
return 0;
if (atomic_read(&itv->capturing) > 0)
return -EBUSY;
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
fmt->fmt.win.chromakey = itv->osd_chroma_key;
fmt->fmt.win.global_alpha = itv->osd_global_alpha;
return 0;
}
p->width = w;
p->height = h;
if (w != 720 || h != (itv->is_50hz ? 576 : 480))
p->video_temporal_filter = 0;
else
p->video_temporal_filter = 8;
if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
fmt->fmt.pix.width /= 2;
itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
return ivtv_get_fmt(itv, streamtype, fmt);
}
static int ivtv_try_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
{
return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt);
}
/* set raw VBI format */
if (fmt->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
if (set_fmt && atomic_read(&itv->capturing) > 0) {
return -EBUSY;
}
if (set_fmt) {
itv->vbi.sliced_in->service_set = 0;
itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in);
}
return ivtv_get_fmt(itv, streamtype, fmt);
}
static int ivtv_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct ivtv_open_id *id = fh;
struct ivtv *itv = id->itv;
int w = fmt->fmt.pix.width;
int h = fmt->fmt.pix.height;
w = min(w, 720);
w = max(w, 1);
h = min(h, itv->is_50hz ? 576 : 480);
h = max(h, 2);
ivtv_g_fmt_vid_cap(file, fh, fmt);
fmt->fmt.pix.width = w;
fmt->fmt.pix.height = h;
return 0;
}
/* set sliced VBI output
In principle the user could request that only certain
VBI types are output and that the others are ignored.
I.e., suppress CC in the even fields or only output
WSS and no VPS. Currently though there is no choice. */
if (fmt->type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT)
return ivtv_get_fmt(itv, streamtype, fmt);
static int ivtv_try_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
{
return ivtv_g_fmt_vbi_cap(file, fh, fmt);
}
/* any else but sliced VBI capture is an error */
if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
return -EINVAL;
static int ivtv_try_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
struct ivtv_open_id *id = fh;
struct ivtv *itv = id->itv;
if (streamtype == IVTV_DEC_STREAM_TYPE_VBI)
return ivtv_get_fmt(itv, streamtype, fmt);
if (id->type == IVTV_DEC_STREAM_TYPE_VBI)
return ivtv_g_fmt_sliced_vbi_cap(file, fh, fmt);
/* set sliced VBI capture format */
vbifmt->io_size = sizeof(struct v4l2_sliced_vbi_data) * 36;
......@@ -641,777 +546,997 @@ static int ivtv_try_or_set_fmt(struct ivtv *itv, int streamtype,
if (vbifmt->service_set)
ivtv_expand_service_set(vbifmt, itv->is_50hz);
set = check_service_set(vbifmt, itv->is_50hz);
check_service_set(vbifmt, itv->is_50hz);
vbifmt->service_set = ivtv_get_service_set(vbifmt);
return 0;
}
static int ivtv_try_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct ivtv_open_id *id = fh;
s32 w, h;
int field;
int ret;
w = fmt->fmt.pix.width;
h = fmt->fmt.pix.height;
field = fmt->fmt.pix.field;
ret = ivtv_g_fmt_vid_out(file, fh, fmt);
fmt->fmt.pix.width = w;
fmt->fmt.pix.height = h;
if (!ret && id->type == IVTV_DEC_STREAM_TYPE_YUV) {
fmt->fmt.pix.field = field;
if (fmt->fmt.pix.width < 2)
fmt->fmt.pix.width = 2;
if (fmt->fmt.pix.width > 720)
fmt->fmt.pix.width = 720;
if (fmt->fmt.pix.height < 2)
fmt->fmt.pix.height = 2;
if (fmt->fmt.pix.height > 576)
fmt->fmt.pix.height = 576;
}
return ret;
}
static int ivtv_try_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
if (!set_fmt)
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
return 0;
}
static int ivtv_s_fmt_sliced_vbi_out(struct file *file, void *fh, struct v4l2_format *fmt)
{
return ivtv_g_fmt_sliced_vbi_out(file, fh, fmt);
}
static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct ivtv_open_id *id = fh;
struct ivtv *itv = id->itv;
struct cx2341x_mpeg_params *p = &itv->params;
int w = fmt->fmt.pix.width;
int h = fmt->fmt.pix.height;
int ret = ivtv_try_fmt_vid_cap(file, fh, fmt);
if (ret)
return ret;
if (p->width == w && p->height == h)
return 0;
if (set == 0)
if (atomic_read(&itv->capturing) > 0)
return -EBUSY;
p->width = w;
p->height = h;
if (w != 720 || h != (itv->is_50hz ? 576 : 480))
p->video_temporal_filter = 0;
else
p->video_temporal_filter = 8;
if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
fmt->fmt.pix.width /= 2;
itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
return ivtv_g_fmt_vid_cap(file, fh, fmt);
}
static int ivtv_s_fmt_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
itv->vbi.sliced_in->service_set = 0;
itv->video_dec_func(itv, VIDIOC_S_FMT, &itv->vbi.in);
return ivtv_g_fmt_vbi_cap(file, fh, fmt);
}
static int ivtv_s_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct v4l2_sliced_vbi_format *vbifmt = &fmt->fmt.sliced;
struct ivtv_open_id *id = fh;
struct ivtv *itv = id->itv;
int ret = ivtv_try_fmt_sliced_vbi_cap(file, fh, fmt);
if (ret || id->type == IVTV_DEC_STREAM_TYPE_VBI)
return ret;
if (check_service_set(vbifmt, itv->is_50hz) == 0)
return -EINVAL;
if (atomic_read(&itv->capturing) > 0) {
if (atomic_read(&itv->capturing) > 0)
return -EBUSY;
}
itv->video_dec_func(itv, VIDIOC_S_FMT, fmt);
memcpy(itv->vbi.sliced_in, vbifmt, sizeof(*itv->vbi.sliced_in));
return 0;
}
static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
static int ivtv_s_fmt_vid_out(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
struct ivtv_open_id *id = fh;
struct ivtv *itv = id->itv;
struct v4l2_register *reg = arg;
struct yuv_playback_info *yi = &itv->yuv_info;
int ret = ivtv_try_fmt_vid_out(file, fh, fmt);
switch (cmd) {
/* ioctls to allow direct access to the encoder registers for testing */
case VIDIOC_DBG_G_REGISTER:
if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
return ivtv_itvc(itv, cmd, arg);
if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
return ivtv_i2c_id(itv, reg->match_chip, cmd, arg);
return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg);
case VIDIOC_DBG_S_REGISTER:
if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
return ivtv_itvc(itv, cmd, arg);
if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
return ivtv_i2c_id(itv, reg->match_chip, cmd, arg);
return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg);
case VIDIOC_G_CHIP_IDENT: {
struct v4l2_chip_ident *chip = arg;
chip->ident = V4L2_IDENT_NONE;
chip->revision = 0;
if (reg->match_type == V4L2_CHIP_MATCH_HOST) {
if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416;
return 0;
}
if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
return ivtv_i2c_id(itv, reg->match_chip, cmd, arg);
if (reg->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
return ivtv_call_i2c_client(itv, reg->match_chip, cmd, arg);
return -EINVAL;
}
if (ret)
return ret;
case VIDIOC_INT_S_AUDIO_ROUTING: {
struct v4l2_routing *route = arg;
if (id->type != IVTV_DEC_STREAM_TYPE_YUV)
return 0;
ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route);
break;
}
/* Return now if we already have some frame data */
if (yi->stream_size)
return -EBUSY;
case VIDIOC_INT_RESET: {
u32 val = *(u32 *)arg;
yi->v4l2_src_w = fmt->fmt.pix.width;
yi->v4l2_src_h = fmt->fmt.pix.height;
if ((val == 0 && itv->options.newi2c) || (val & 0x01)) {
ivtv_reset_ir_gpio(itv);
}
if (val & 0x02) {
itv->video_dec_func(itv, cmd, NULL);
}
switch (fmt->fmt.pix.field) {
case V4L2_FIELD_NONE:
yi->lace_mode = IVTV_YUV_MODE_PROGRESSIVE;
break;
}
case V4L2_FIELD_ANY:
yi->lace_mode = IVTV_YUV_MODE_AUTO;
break;
case V4L2_FIELD_INTERLACED_BT:
yi->lace_mode =
IVTV_YUV_MODE_INTERLACED|IVTV_YUV_SYNC_ODD;
break;
case V4L2_FIELD_INTERLACED_TB:
default:
return -EINVAL;
yi->lace_mode = IVTV_YUV_MODE_INTERLACED;
break;
}
yi->lace_sync_field = (yi->lace_mode & IVTV_YUV_SYNC_MASK) == IVTV_YUV_SYNC_EVEN ? 0 : 1;
if (test_bit(IVTV_F_I_DEC_YUV, &itv->i_flags))
itv->dma_data_req_size =
1080 * ((yi->v4l2_src_h + 31) & ~31);
/* Force update of yuv registers */
yi->yuv_forced_update = 1;
return 0;
}
int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg)
static int ivtv_s_fmt_vid_out_overlay(struct file *file, void *fh, struct v4l2_format *fmt)
{
struct ivtv_open_id *id = NULL;
struct yuv_playback_info *yi = &itv->yuv_info;
u32 data[CX2341X_MBOX_MAX_DATA];
int streamtype = 0;
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
int ret = ivtv_try_fmt_vid_out_overlay(file, fh, fmt);
if (filp) {
id = (struct ivtv_open_id *)filp->private_data;
streamtype = id->type;
if (ret == 0) {
itv->osd_chroma_key = fmt->fmt.win.chromakey;
itv->osd_global_alpha = fmt->fmt.win.global_alpha;
ivtv_set_osd_alpha(itv);
}
return ret;
}
switch (cmd) {
case VIDIOC_G_PRIORITY:
{
enum v4l2_priority *p = arg;
static int ivtv_g_chip_ident(struct file *file, void *fh, struct v4l2_chip_ident *chip)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
*p = v4l2_prio_max(&itv->prio);
break;
chip->ident = V4L2_IDENT_NONE;
chip->revision = 0;
if (chip->match_type == V4L2_CHIP_MATCH_HOST) {
if (v4l2_chip_match_host(chip->match_type, chip->match_chip))
chip->ident = itv->has_cx23415 ? V4L2_IDENT_CX23415 : V4L2_IDENT_CX23416;
return 0;
}
if (chip->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
return ivtv_i2c_id(itv, chip->match_chip, VIDIOC_G_CHIP_IDENT, chip);
if (chip->match_type == V4L2_CHIP_MATCH_I2C_ADDR)
return ivtv_call_i2c_client(itv, chip->match_chip, VIDIOC_G_CHIP_IDENT, chip);
return -EINVAL;
}
case VIDIOC_S_PRIORITY:
{
enum v4l2_priority *prio = arg;
static int ivtv_g_register(struct file *file, void *fh, struct v4l2_register *reg)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
return v4l2_prio_change(&itv->prio, &id->prio, *prio);
}
if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
return ivtv_itvc(itv, VIDIOC_DBG_G_REGISTER, reg);
if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
return ivtv_i2c_id(itv, reg->match_chip, VIDIOC_DBG_G_REGISTER, reg);
return ivtv_call_i2c_client(itv, reg->match_chip, VIDIOC_DBG_G_REGISTER, reg);
}
static int ivtv_s_register(struct file *file, void *fh, struct v4l2_register *reg)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
case VIDIOC_QUERYCAP:{
struct v4l2_capability *vcap = arg;
if (v4l2_chip_match_host(reg->match_type, reg->match_chip))
return ivtv_itvc(itv, VIDIOC_DBG_S_REGISTER, reg);
if (reg->match_type == V4L2_CHIP_MATCH_I2C_DRIVER)
return ivtv_i2c_id(itv, reg->match_chip, VIDIOC_DBG_S_REGISTER, reg);
return ivtv_call_i2c_client(itv, reg->match_chip, VIDIOC_DBG_S_REGISTER, reg);
}
memset(vcap, 0, sizeof(*vcap));
strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
strlcpy(vcap->bus_info, pci_name(itv->dev), sizeof(vcap->bus_info));
vcap->version = IVTV_DRIVER_VERSION; /* version */
vcap->capabilities = itv->v4l2_cap; /* capabilities */
static int ivtv_g_priority(struct file *file, void *fh, enum v4l2_priority *p)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
/* reserved.. must set to 0! */
vcap->reserved[0] = vcap->reserved[1] =
vcap->reserved[2] = vcap->reserved[3] = 0;
break;
}
*p = v4l2_prio_max(&itv->prio);
case VIDIOC_ENUMAUDIO:{
struct v4l2_audio *vin = arg;
return 0;
}
return ivtv_get_audio_input(itv, vin->index, vin);
}
static int ivtv_s_priority(struct file *file, void *fh, enum v4l2_priority prio)
{
struct ivtv_open_id *id = fh;
struct ivtv *itv = id->itv;
case VIDIOC_G_AUDIO:{
struct v4l2_audio *vin = arg;
return v4l2_prio_change(&itv->prio, &id->prio, prio);
}
vin->index = itv->audio_input;
return ivtv_get_audio_input(itv, vin->index, vin);
}
static int ivtv_querycap(struct file *file, void *fh, struct v4l2_capability *vcap)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
memset(vcap, 0, sizeof(*vcap));
strlcpy(vcap->driver, IVTV_DRIVER_NAME, sizeof(vcap->driver));
strlcpy(vcap->card, itv->card_name, sizeof(vcap->card));
strlcpy(vcap->bus_info, pci_name(itv->dev), sizeof(vcap->bus_info));
vcap->version = IVTV_DRIVER_VERSION; /* version */
vcap->capabilities = itv->v4l2_cap; /* capabilities */
/* reserved.. must set to 0! */
vcap->reserved[0] = vcap->reserved[1] =
vcap->reserved[2] = vcap->reserved[3] = 0;
return 0;
}
case VIDIOC_S_AUDIO:{
struct v4l2_audio *vout = arg;
static int ivtv_enumaudio(struct file *file, void *fh, struct v4l2_audio *vin)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
if (vout->index >= itv->nof_audio_inputs)
return -EINVAL;
itv->audio_input = vout->index;
ivtv_audio_set_io(itv);
break;
}
return ivtv_get_audio_input(itv, vin->index, vin);
}
static int ivtv_g_audio(struct file *file, void *fh, struct v4l2_audio *vin)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
case VIDIOC_ENUMAUDOUT:{
struct v4l2_audioout *vin = arg;
vin->index = itv->audio_input;
return ivtv_get_audio_input(itv, vin->index, vin);
}
/* set it to defaults from our table */
return ivtv_get_audio_output(itv, vin->index, vin);
}
static int ivtv_s_audio(struct file *file, void *fh, struct v4l2_audio *vout)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
case VIDIOC_G_AUDOUT:{
struct v4l2_audioout *vin = arg;
if (vout->index >= itv->nof_audio_inputs)
return -EINVAL;
vin->index = 0;
return ivtv_get_audio_output(itv, vin->index, vin);
}
itv->audio_input = vout->index;
ivtv_audio_set_io(itv);
case VIDIOC_S_AUDOUT:{
struct v4l2_audioout *vout = arg;
return 0;
}
return ivtv_get_audio_output(itv, vout->index, vout);
}
static int ivtv_enumaudout(struct file *file, void *fh, struct v4l2_audioout *vin)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
case VIDIOC_ENUMINPUT:{
struct v4l2_input *vin = arg;
/* set it to defaults from our table */
return ivtv_get_audio_output(itv, vin->index, vin);
}
/* set it to defaults from our table */
return ivtv_get_input(itv, vin->index, vin);
}
static int ivtv_g_audout(struct file *file, void *fh, struct v4l2_audioout *vin)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
case VIDIOC_ENUMOUTPUT:{
struct v4l2_output *vout = arg;
vin->index = 0;
return ivtv_get_audio_output(itv, vin->index, vin);
}
return ivtv_get_output(itv, vout->index, vout);
}
static int ivtv_s_audout(struct file *file, void *fh, struct v4l2_audioout *vout)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
case VIDIOC_TRY_FMT:
case VIDIOC_S_FMT: {
struct v4l2_format *fmt = arg;
return ivtv_get_audio_output(itv, vout->index, vout);
}
return ivtv_try_or_set_fmt(itv, id->type, fmt, cmd == VIDIOC_S_FMT);
}
static int ivtv_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
case VIDIOC_G_FMT: {
struct v4l2_format *fmt = arg;
int type = fmt->type;
/* set it to defaults from our table */
return ivtv_get_input(itv, vin->index, vin);
}
memset(fmt, 0, sizeof(*fmt));
fmt->type = type;
return ivtv_get_fmt(itv, id->type, fmt);
}
static int ivtv_enum_output(struct file *file, void *fh, struct v4l2_output *vout)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
case VIDIOC_CROPCAP: {
struct v4l2_cropcap *cropcap = arg;
return ivtv_get_output(itv, vout->index, vout);
}
if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
return -EINVAL;
cropcap->bounds.top = cropcap->bounds.left = 0;
cropcap->bounds.width = 720;
if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
cropcap->bounds.height = itv->is_50hz ? 576 : 480;
cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
} else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
if (yi->track_osd) {
cropcap->bounds.width = yi->osd_full_w;
cropcap->bounds.height = yi->osd_full_h;
} else {
cropcap->bounds.width = 720;
cropcap->bounds.height =
itv->is_out_50hz ? 576 : 480;
}
cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
static int ivtv_cropcap(struct file *file, void *fh, struct v4l2_cropcap *cropcap)
{
struct ivtv_open_id *id = fh;
struct ivtv *itv = id->itv;
struct yuv_playback_info *yi = &itv->yuv_info;
int streamtype;
streamtype = id->type;
if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
return -EINVAL;
cropcap->bounds.top = cropcap->bounds.left = 0;
cropcap->bounds.width = 720;
if (cropcap->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
cropcap->bounds.height = itv->is_50hz ? 576 : 480;
cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
} else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
if (yi->track_osd) {
cropcap->bounds.width = yi->osd_full_w;
cropcap->bounds.height = yi->osd_full_h;
} else {
cropcap->bounds.height = itv->is_out_50hz ? 576 : 480;
cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
cropcap->bounds.width = 720;
cropcap->bounds.height =
itv->is_out_50hz ? 576 : 480;
}
cropcap->defrect = cropcap->bounds;
return 0;
cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
} else {
cropcap->bounds.height = itv->is_out_50hz ? 576 : 480;
cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
}
cropcap->defrect = cropcap->bounds;
return 0;
}
static int ivtv_s_crop(struct file *file, void *fh, struct v4l2_crop *crop)
{
struct ivtv_open_id *id = fh;
struct ivtv *itv = id->itv;
struct yuv_playback_info *yi = &itv->yuv_info;
int streamtype;
case VIDIOC_S_CROP: {
struct v4l2_crop *crop = arg;
streamtype = id->type;
if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
yi->main_rect = crop->c;
if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
/* Should be replaced */
/* v4l_printk_ioctl(VIDIOC_S_CROP); */
}
if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
yi->main_rect = crop->c;
return 0;
} else {
if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
itv->main_rect = crop->c;
return 0;
} else {
if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
crop->c.width, crop->c.height, crop->c.left, crop->c.top)) {
itv->main_rect = crop->c;
return 0;
}
}
return -EINVAL;
}
return -EINVAL;
}
return -EINVAL;
}
case VIDIOC_G_CROP: {
struct v4l2_crop *crop = arg;
static int ivtv_g_crop(struct file *file, void *fh, struct v4l2_crop *crop)
{
struct ivtv_open_id *id = fh;
struct ivtv *itv = id->itv;
struct yuv_playback_info *yi = &itv->yuv_info;
int streamtype;
if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
if (streamtype == IVTV_DEC_STREAM_TYPE_YUV)
crop->c = yi->main_rect;
else
crop->c = itv->main_rect;
return 0;
streamtype = id->type;
if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
if (streamtype == IVTV_DEC_STREAM_TYPE_YUV)
crop->c = yi->main_rect;
else
crop->c = itv->main_rect;
return 0;
}
return -EINVAL;
}
static int ivtv_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
{
static struct v4l2_fmtdesc formats[] = {
{ 0, 0, 0,
"HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12,
{ 0, 0, 0, 0 }
},
{ 1, 0, V4L2_FMT_FLAG_COMPRESSED,
"MPEG", V4L2_PIX_FMT_MPEG,
{ 0, 0, 0, 0 }
}
};
enum v4l2_buf_type type = fmt->type;
if (fmt->index > 1)
return -EINVAL;
}
case VIDIOC_ENUM_FMT: {
static struct v4l2_fmtdesc formats[] = {
{ 0, 0, 0,
"HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12,
{ 0, 0, 0, 0 }
},
{ 1, 0, V4L2_FMT_FLAG_COMPRESSED,
"MPEG", V4L2_PIX_FMT_MPEG,
{ 0, 0, 0, 0 }
}
};
struct v4l2_fmtdesc *fmt = arg;
enum v4l2_buf_type type = fmt->type;
*fmt = formats[fmt->index];
fmt->type = type;
return 0;
}
switch (type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
break;
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
break;
default:
return -EINVAL;
static int ivtv_enum_fmt_vid_out(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
static struct v4l2_fmtdesc formats[] = {
{ 0, 0, 0,
"HM12 (YUV 4:2:0)", V4L2_PIX_FMT_HM12,
{ 0, 0, 0, 0 }
},
{ 1, 0, V4L2_FMT_FLAG_COMPRESSED,
"MPEG", V4L2_PIX_FMT_MPEG,
{ 0, 0, 0, 0 }
}
if (fmt->index > 1)
return -EINVAL;
*fmt = formats[fmt->index];
fmt->type = type;
};
enum v4l2_buf_type type = fmt->type;
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
if (fmt->index > 1)
return -EINVAL;
*fmt = formats[fmt->index];
fmt->type = type;
return 0;
}
static int ivtv_g_input(struct file *file, void *fh, unsigned int *i)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
*i = itv->active_input;
return 0;
}
int ivtv_s_input(struct file *file, void *fh, unsigned int inp)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
if (inp < 0 || inp >= itv->nof_inputs)
return -EINVAL;
if (inp == itv->active_input) {
IVTV_DEBUG_INFO("Input unchanged\n");
return 0;
}
case VIDIOC_G_INPUT:{
*(int *)arg = itv->active_input;
break;
if (atomic_read(&itv->capturing) > 0) {
return -EBUSY;
}
case VIDIOC_S_INPUT:{
int inp = *(int *)arg;
IVTV_DEBUG_INFO("Changing input from %d to %d\n",
itv->active_input, inp);
if (inp < 0 || inp >= itv->nof_inputs)
return -EINVAL;
itv->active_input = inp;
/* Set the audio input to whatever is appropriate for the
input type. */
itv->audio_input = itv->card->video_inputs[inp].audio_index;
if (inp == itv->active_input) {
IVTV_DEBUG_INFO("Input unchanged\n");
break;
}
if (atomic_read(&itv->capturing) > 0) {
return -EBUSY;
}
IVTV_DEBUG_INFO("Changing input from %d to %d\n",
itv->active_input, inp);
/* prevent others from messing with the streams until
we're finished changing inputs. */
ivtv_mute(itv);
ivtv_video_set_io(itv);
ivtv_audio_set_io(itv);
ivtv_unmute(itv);
return 0;
}
itv->active_input = inp;
/* Set the audio input to whatever is appropriate for the
input type. */
itv->audio_input = itv->card->video_inputs[inp].audio_index;
static int ivtv_g_output(struct file *file, void *fh, unsigned int *i)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
/* prevent others from messing with the streams until
we're finished changing inputs. */
ivtv_mute(itv);
ivtv_video_set_io(itv);
ivtv_audio_set_io(itv);
ivtv_unmute(itv);
break;
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
*i = itv->active_output;
return 0;
}
static int ivtv_s_output(struct file *file, void *fh, unsigned int outp)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
struct v4l2_routing route;
if (outp >= itv->card->nof_outputs)
return -EINVAL;
if (outp == itv->active_output) {
IVTV_DEBUG_INFO("Output unchanged\n");
return 0;
}
IVTV_DEBUG_INFO("Changing output from %d to %d\n",
itv->active_output, outp);
case VIDIOC_G_OUTPUT:{
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT))
return -EINVAL;
*(int *)arg = itv->active_output;
break;
itv->active_output = outp;
route.input = SAA7127_INPUT_TYPE_NORMAL;
route.output = itv->card->video_outputs[outp].video_output;
ivtv_saa7127(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
return 0;
}
static int ivtv_g_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
if (vf->tuner != 0)
return -EINVAL;
ivtv_call_i2c_clients(itv, VIDIOC_G_FREQUENCY, vf);
return 0;
}
int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
if (vf->tuner != 0)
return -EINVAL;
ivtv_mute(itv);
IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf->frequency);
ivtv_call_i2c_clients(itv, VIDIOC_S_FREQUENCY, vf);
ivtv_unmute(itv);
return 0;
}
static int ivtv_g_std(struct file *file, void *fh, v4l2_std_id *std)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
*std = itv->std;
return 0;
}
int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
struct yuv_playback_info *yi = &itv->yuv_info;
if ((*std & V4L2_STD_ALL) == 0)
return -EINVAL;
if (*std == itv->std)
return 0;
if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ||
atomic_read(&itv->capturing) > 0 ||
atomic_read(&itv->decoding) > 0) {
/* Switching standard would turn off the radio or mess
with already running streams, prevent that by
returning EBUSY. */
return -EBUSY;
}
itv->std = *std;
itv->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
itv->params.is_50hz = itv->is_50hz = !itv->is_60hz;
itv->params.width = 720;
itv->params.height = itv->is_50hz ? 576 : 480;
itv->vbi.count = itv->is_50hz ? 18 : 12;
itv->vbi.start[0] = itv->is_50hz ? 6 : 10;
itv->vbi.start[1] = itv->is_50hz ? 318 : 273;
if (itv->hw_flags & IVTV_HW_CX25840)
itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284;
IVTV_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)itv->std);
/* Tuner */
ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std);
if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
/* set display standard */
itv->std_out = *std;
itv->is_out_60hz = itv->is_60hz;
itv->is_out_50hz = itv->is_50hz;
ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std_out);
ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz);
itv->main_rect.left = itv->main_rect.top = 0;
itv->main_rect.width = 720;
itv->main_rect.height = itv->params.height;
ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
720, itv->main_rect.height, 0, 0);
yi->main_rect = itv->main_rect;
if (!itv->osd_info) {
yi->osd_full_w = 720;
yi->osd_full_h = itv->is_out_50hz ? 576 : 480;
}
}
return 0;
}
static int ivtv_s_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
{
struct ivtv_open_id *id = fh;
struct ivtv *itv = id->itv;
if (vt->index != 0)
return -EINVAL;
ivtv_call_i2c_clients(itv, VIDIOC_S_TUNER, vt);
return 0;
}
static int ivtv_g_tuner(struct file *file, void *fh, struct v4l2_tuner *vt)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
if (vt->index != 0)
return -EINVAL;
memset(vt, 0, sizeof(*vt));
ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt);
if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name));
vt->type = V4L2_TUNER_RADIO;
} else {
strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name));
vt->type = V4L2_TUNER_ANALOG_TV;
}
case VIDIOC_S_OUTPUT:{
int outp = *(int *)arg;
struct v4l2_routing route;
return 0;
}
if (outp >= itv->card->nof_outputs)
static int ivtv_g_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_sliced_vbi_cap *cap)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
int f, l;
enum v4l2_buf_type type = cap->type;
memset(cap, 0, sizeof(*cap));
cap->type = type;
if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
for (f = 0; f < 2; f++) {
for (l = 0; l < 24; l++) {
if (valid_service_line(f, l, itv->is_50hz))
cap->service_lines[f][l] = set;
}
}
return 0;
}
if (type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {
if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
return -EINVAL;
if (outp == itv->active_output) {
IVTV_DEBUG_INFO("Output unchanged\n");
break;
if (itv->is_60hz) {
cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
} else {
cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
cap->service_lines[0][16] = V4L2_SLICED_VPS;
}
IVTV_DEBUG_INFO("Changing output from %d to %d\n",
itv->active_output, outp);
itv->active_output = outp;
route.input = SAA7127_INPUT_TYPE_NORMAL;
route.output = itv->card->video_outputs[outp].video_output;
ivtv_saa7127(itv, VIDIOC_INT_S_VIDEO_ROUTING, &route);
break;
return 0;
}
return -EINVAL;
}
case VIDIOC_G_FREQUENCY:{
struct v4l2_frequency *vf = arg;
static int ivtv_g_enc_index(struct file *file, void *fh, struct v4l2_enc_idx *idx)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
struct v4l2_enc_idx_entry *e = idx->entry;
int entries;
int i;
if (vf->tuner != 0)
return -EINVAL;
ivtv_call_i2c_clients(itv, cmd, arg);
break;
entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) %
IVTV_MAX_PGM_INDEX;
if (entries > V4L2_ENC_IDX_ENTRIES)
entries = V4L2_ENC_IDX_ENTRIES;
idx->entries = 0;
for (i = 0; i < entries; i++) {
*e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX];
if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) {
idx->entries++;
e++;
}
}
itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX;
return 0;
}
case VIDIOC_S_FREQUENCY:{
struct v4l2_frequency vf = *(struct v4l2_frequency *)arg;
static int ivtv_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc)
{
struct ivtv_open_id *id = fh;
struct ivtv *itv = id->itv;
if (vf.tuner != 0)
return -EINVAL;
memset(&enc->raw, 0, sizeof(enc->raw));
ivtv_mute(itv);
IVTV_DEBUG_INFO("v4l2 ioctl: set frequency %d\n", vf.frequency);
ivtv_call_i2c_clients(itv, cmd, &vf);
ivtv_unmute(itv);
break;
}
switch (enc->cmd) {
case V4L2_ENC_CMD_START:
IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
enc->flags = 0;
return ivtv_start_capture(id);
case VIDIOC_ENUMSTD:{
struct v4l2_standard *vs = arg;
int idx = vs->index;
case V4L2_ENC_CMD_STOP:
IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
return 0;
if (idx < 0 || idx >= ARRAY_SIZE(enum_stds))
return -EINVAL;
case V4L2_ENC_CMD_PAUSE:
IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
enc->flags = 0;
*vs = (enum_stds[idx].std & V4L2_STD_525_60) ?
ivtv_std_60hz : ivtv_std_50hz;
vs->index = idx;
vs->id = enum_stds[idx].std;
strlcpy(vs->name, enum_stds[idx].name, sizeof(vs->name));
break;
}
if (!atomic_read(&itv->capturing))
return -EPERM;
if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
return 0;
case VIDIOC_G_STD:{
*(v4l2_std_id *) arg = itv->std;
ivtv_mute(itv);
ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0);
break;
}
case VIDIOC_S_STD: {
v4l2_std_id std = *(v4l2_std_id *) arg;
if ((std & V4L2_STD_ALL) == 0)
return -EINVAL;
case V4L2_ENC_CMD_RESUME:
IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
enc->flags = 0;
if (std == itv->std)
break;
if (!atomic_read(&itv->capturing))
return -EPERM;
if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ||
atomic_read(&itv->capturing) > 0 ||
atomic_read(&itv->decoding) > 0) {
/* Switching standard would turn off the radio or mess
with already running streams, prevent that by
returning EBUSY. */
return -EBUSY;
}
if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
return 0;
itv->std = std;
itv->is_60hz = (std & V4L2_STD_525_60) ? 1 : 0;
itv->params.is_50hz = itv->is_50hz = !itv->is_60hz;
itv->params.width = 720;
itv->params.height = itv->is_50hz ? 576 : 480;
itv->vbi.count = itv->is_50hz ? 18 : 12;
itv->vbi.start[0] = itv->is_50hz ? 6 : 10;
itv->vbi.start[1] = itv->is_50hz ? 318 : 273;
if (itv->hw_flags & IVTV_HW_CX25840) {
itv->vbi.sliced_decoder_line_size = itv->is_60hz ? 272 : 284;
}
IVTV_DEBUG_INFO("Switching standard to %llx.\n", (unsigned long long)itv->std);
/* Tuner */
ivtv_call_i2c_clients(itv, VIDIOC_S_STD, &itv->std);
if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
/* set display standard */
itv->std_out = std;
itv->is_out_60hz = itv->is_60hz;
itv->is_out_50hz = itv->is_50hz;
ivtv_call_i2c_clients(itv, VIDIOC_INT_S_STD_OUTPUT, &itv->std_out);
ivtv_vapi(itv, CX2341X_DEC_SET_STANDARD, 1, itv->is_out_50hz);
itv->main_rect.left = itv->main_rect.top = 0;
itv->main_rect.width = 720;
itv->main_rect.height = itv->params.height;
ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
720, itv->main_rect.height, 0, 0);
yi->main_rect = itv->main_rect;
if (!itv->osd_info) {
yi->osd_full_w = 720;
yi->osd_full_h = itv->is_out_50hz ? 576 : 480;
}
}
ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1);
ivtv_unmute(itv);
break;
default:
IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
return -EINVAL;
}
case VIDIOC_S_TUNER: { /* Setting tuner can only set audio mode */
struct v4l2_tuner *vt = arg;
return 0;
}
if (vt->index != 0)
return -EINVAL;
static int ivtv_try_encoder_cmd(struct file *file, void *fh, struct v4l2_encoder_cmd *enc)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
ivtv_call_i2c_clients(itv, VIDIOC_S_TUNER, vt);
break;
}
memset(&enc->raw, 0, sizeof(enc->raw));
case VIDIOC_G_TUNER: {
struct v4l2_tuner *vt = arg;
switch (enc->cmd) {
case V4L2_ENC_CMD_START:
IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
enc->flags = 0;
return 0;
if (vt->index != 0)
return -EINVAL;
case V4L2_ENC_CMD_STOP:
IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
return 0;
memset(vt, 0, sizeof(*vt));
ivtv_call_i2c_clients(itv, VIDIOC_G_TUNER, vt);
case V4L2_ENC_CMD_PAUSE:
IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
enc->flags = 0;
return 0;
if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags)) {
strlcpy(vt->name, "ivtv Radio Tuner", sizeof(vt->name));
vt->type = V4L2_TUNER_RADIO;
} else {
strlcpy(vt->name, "ivtv TV Tuner", sizeof(vt->name));
vt->type = V4L2_TUNER_ANALOG_TV;
}
break;
case V4L2_ENC_CMD_RESUME:
IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
enc->flags = 0;
return 0;
default:
IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
return -EINVAL;
}
}
case VIDIOC_G_SLICED_VBI_CAP: {
struct v4l2_sliced_vbi_cap *cap = arg;
int set = itv->is_50hz ? V4L2_SLICED_VBI_625 : V4L2_SLICED_VBI_525;
int f, l;
enum v4l2_buf_type type = cap->type;
memset(cap, 0, sizeof(*cap));
cap->type = type;
if (type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
for (f = 0; f < 2; f++) {
for (l = 0; l < 24; l++) {
if (valid_service_line(f, l, itv->is_50hz)) {
cap->service_lines[f][l] = set;
}
}
}
return 0;
}
if (type == V4L2_BUF_TYPE_SLICED_VBI_OUTPUT) {
if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_OUTPUT))
return -EINVAL;
if (itv->is_60hz) {
cap->service_lines[0][21] = V4L2_SLICED_CAPTION_525;
cap->service_lines[1][21] = V4L2_SLICED_CAPTION_525;
} else {
cap->service_lines[0][23] = V4L2_SLICED_WSS_625;
cap->service_lines[0][16] = V4L2_SLICED_VPS;
}
return 0;
}
static int ivtv_g_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
u32 data[CX2341X_MBOX_MAX_DATA];
struct yuv_playback_info *yi = &itv->yuv_info;
int pixfmt;
static u32 pixel_format[16] = {
V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */
V4L2_PIX_FMT_RGB565,
V4L2_PIX_FMT_RGB555,
V4L2_PIX_FMT_RGB444,
V4L2_PIX_FMT_RGB32,
0,
0,
0,
V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */
V4L2_PIX_FMT_YUV565,
V4L2_PIX_FMT_YUV555,
V4L2_PIX_FMT_YUV444,
V4L2_PIX_FMT_YUV32,
0,
0,
0,
};
memset(fb, 0, sizeof(*fb));
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
return -EINVAL;
}
case VIDIOC_G_ENC_INDEX: {
struct v4l2_enc_idx *idx = arg;
struct v4l2_enc_idx_entry *e = idx->entry;
int entries;
int i;
entries = (itv->pgm_info_write_idx + IVTV_MAX_PGM_INDEX - itv->pgm_info_read_idx) %
IVTV_MAX_PGM_INDEX;
if (entries > V4L2_ENC_IDX_ENTRIES)
entries = V4L2_ENC_IDX_ENTRIES;
idx->entries = 0;
for (i = 0; i < entries; i++) {
*e = itv->pgm_info[(itv->pgm_info_read_idx + i) % IVTV_MAX_PGM_INDEX];
if ((e->flags & V4L2_ENC_IDX_FRAME_MASK) <= V4L2_ENC_IDX_FRAME_B) {
idx->entries++;
e++;
}
}
itv->pgm_info_read_idx = (itv->pgm_info_read_idx + idx->entries) % IVTV_MAX_PGM_INDEX;
break;
}
fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY |
V4L2_FBUF_CAP_GLOBAL_ALPHA;
case VIDIOC_ENCODER_CMD:
case VIDIOC_TRY_ENCODER_CMD: {
struct v4l2_encoder_cmd *enc = arg;
int try = cmd == VIDIOC_TRY_ENCODER_CMD;
memset(&enc->raw, 0, sizeof(enc->raw));
switch (enc->cmd) {
case V4L2_ENC_CMD_START:
IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_START\n");
enc->flags = 0;
if (try)
return 0;
return ivtv_start_capture(id);
ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
pixfmt = (data[0] >> 3) & 0xf;
case V4L2_ENC_CMD_STOP:
IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_STOP\n");
enc->flags &= V4L2_ENC_CMD_STOP_AT_GOP_END;
if (try)
return 0;
ivtv_stop_capture(id, enc->flags & V4L2_ENC_CMD_STOP_AT_GOP_END);
return 0;
fb->fmt.pixelformat = pixel_format[pixfmt];
fb->fmt.width = itv->osd_rect.width;
fb->fmt.height = itv->osd_rect.height;
fb->base = (void *)itv->osd_video_pbase;
case V4L2_ENC_CMD_PAUSE:
IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_PAUSE\n");
enc->flags = 0;
if (try)
return 0;
if (!atomic_read(&itv->capturing))
return -EPERM;
if (test_and_set_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
return 0;
ivtv_mute(itv);
ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 0);
break;
if (itv->osd_chroma_key_state)
fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
case V4L2_ENC_CMD_RESUME:
IVTV_DEBUG_IOCTL("V4L2_ENC_CMD_RESUME\n");
enc->flags = 0;
if (try)
return 0;
if (!atomic_read(&itv->capturing))
return -EPERM;
if (!test_and_clear_bit(IVTV_F_I_ENC_PAUSED, &itv->i_flags))
return 0;
ivtv_vapi(itv, CX2341X_ENC_PAUSE_ENCODER, 1, 1);
ivtv_unmute(itv);
break;
default:
IVTV_DEBUG_IOCTL("Unknown cmd %d\n", enc->cmd);
return -EINVAL;
}
break;
}
if (itv->osd_global_alpha_state)
fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
case VIDIOC_G_FBUF: {
struct v4l2_framebuffer *fb = arg;
int pixfmt;
static u32 pixel_format[16] = {
V4L2_PIX_FMT_PAL8, /* Uses a 256-entry RGB colormap */
V4L2_PIX_FMT_RGB565,
V4L2_PIX_FMT_RGB555,
V4L2_PIX_FMT_RGB444,
V4L2_PIX_FMT_RGB32,
0,
0,
0,
V4L2_PIX_FMT_PAL8, /* Uses a 256-entry YUV colormap */
V4L2_PIX_FMT_YUV565,
V4L2_PIX_FMT_YUV555,
V4L2_PIX_FMT_YUV444,
V4L2_PIX_FMT_YUV32,
0,
0,
0,
};
pixfmt &= 7;
memset(fb, 0, sizeof(*fb));
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
return -EINVAL;
fb->capability = V4L2_FBUF_CAP_EXTERNOVERLAY | V4L2_FBUF_CAP_CHROMAKEY |
V4L2_FBUF_CAP_GLOBAL_ALPHA;
ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
pixfmt = (data[0] >> 3) & 0xf;
fb->fmt.pixelformat = pixel_format[pixfmt];
fb->fmt.width = itv->osd_rect.width;
fb->fmt.height = itv->osd_rect.height;
fb->base = (void *)itv->osd_video_pbase;
if (itv->osd_chroma_key_state)
fb->flags |= V4L2_FBUF_FLAG_CHROMAKEY;
if (itv->osd_global_alpha_state)
fb->flags |= V4L2_FBUF_FLAG_GLOBAL_ALPHA;
pixfmt &= 7;
/* no local alpha for RGB565 or unknown formats */
if (pixfmt == 1 || pixfmt > 4)
break;
/* no local alpha for RGB565 or unknown formats */
if (pixfmt == 1 || pixfmt > 4)
return 0;
/* 16-bit formats have inverted local alpha */
if (pixfmt == 2 || pixfmt == 3)
fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA;
else
fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA;
if (itv->osd_local_alpha_state) {
/* 16-bit formats have inverted local alpha */
if (pixfmt == 2 || pixfmt == 3)
fb->capability |= V4L2_FBUF_CAP_LOCAL_INV_ALPHA;
fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA;
else
fb->capability |= V4L2_FBUF_CAP_LOCAL_ALPHA;
if (itv->osd_local_alpha_state) {
/* 16-bit formats have inverted local alpha */
if (pixfmt == 2 || pixfmt == 3)
fb->flags |= V4L2_FBUF_FLAG_LOCAL_INV_ALPHA;
else
fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
}
if (yi->track_osd)
fb->flags |= V4L2_FBUF_FLAG_OVERLAY;
break;
fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
}
if (yi->track_osd)
fb->flags |= V4L2_FBUF_FLAG_OVERLAY;
return 0;
}
case VIDIOC_S_FBUF: {
struct v4l2_framebuffer *fb = arg;
static int ivtv_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *fb)
{
struct ivtv_open_id *id = fh;
struct ivtv *itv = id->itv;
struct yuv_playback_info *yi = &itv->yuv_info;
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
return -EINVAL;
itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
itv->osd_local_alpha_state =
(fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0;
itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
ivtv_set_osd_alpha(itv);
yi->track_osd = (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0;
break;
}
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
return -EINVAL;
case VIDIOC_OVERLAY: {
int *on = arg;
itv->osd_global_alpha_state = (fb->flags & V4L2_FBUF_FLAG_GLOBAL_ALPHA) != 0;
itv->osd_local_alpha_state =
(fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0;
itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
ivtv_set_osd_alpha(itv);
yi->track_osd = (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0;
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
return -EINVAL;
ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, *on != 0);
break;
}
return 0;
}
static int ivtv_overlay(struct file *file, void *fh, unsigned int on)
{
struct ivtv_open_id *id = fh;
struct ivtv *itv = id->itv;
case VIDIOC_LOG_STATUS:
{
int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT;
struct v4l2_input vidin;
struct v4l2_audio audin;
int i;
if (!(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT_OVERLAY))
return -EINVAL;
IVTV_INFO("================= START STATUS CARD #%d =================\n", itv->num);
IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name);
if (itv->hw_flags & IVTV_HW_TVEEPROM) {
struct tveeprom tv;
ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, on != 0);
ivtv_read_eeprom(itv, &tv);
}
ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL);
ivtv_get_input(itv, itv->active_input, &vidin);
ivtv_get_audio_input(itv, itv->audio_input, &audin);
IVTV_INFO("Video Input: %s\n", vidin.name);
IVTV_INFO("Audio Input: %s%s\n", audin.name,
(itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : "");
if (has_output) {
struct v4l2_output vidout;
struct v4l2_audioout audout;
int mode = itv->output_mode;
static const char * const output_modes[5] = {
"None",
"MPEG Streaming",
"YUV Streaming",
"YUV Frames",
"Passthrough",
};
static const char * const audio_modes[5] = {
"Stereo",
"Left",
"Right",
"Mono",
"Swapped"
};
static const char * const alpha_mode[4] = {
"None",
"Global",
"Local",
"Global and Local"
};
static const char * const pixel_format[16] = {
"ARGB Indexed",
"RGB 5:6:5",
"ARGB 1:5:5:5",
"ARGB 1:4:4:4",
"ARGB 8:8:8:8",
"5",
"6",
"7",
"AYUV Indexed",
"YUV 5:6:5",
"AYUV 1:5:5:5",
"AYUV 1:4:4:4",
"AYUV 8:8:8:8",
"13",
"14",
"15",
};
ivtv_get_output(itv, itv->active_output, &vidout);
ivtv_get_audio_output(itv, 0, &audout);
IVTV_INFO("Video Output: %s\n", vidout.name);
IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name,
audio_modes[itv->audio_stereo_mode],
audio_modes[itv->audio_bilingual_mode]);
if (mode < 0 || mode > OUT_PASSTHROUGH)
mode = OUT_NONE;
IVTV_INFO("Output Mode: %s\n", output_modes[mode]);
ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n",
data[0] & 1 ? "On" : "Off",
alpha_mode[(data[0] >> 1) & 0x3],
pixel_format[(data[0] >> 3) & 0xf]);
}
IVTV_INFO("Tuner: %s\n",
test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
cx2341x_log_status(&itv->params, itv->name);
IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags);
for (i = 0; i < IVTV_MAX_STREAMS; i++) {
struct ivtv_stream *s = &itv->streams[i];
if (s->v4l2dev == NULL || s->buffers == 0)
continue;
IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags,
(s->buffers - s->q_free.buffers) * 100 / s->buffers,
(s->buffers * s->buf_size) / 1024, s->buffers);
}
IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted);
IVTV_INFO("================== END STATUS CARD #%d ==================\n", itv->num);
break;
return 0;
}
static int ivtv_log_status(struct file *file, void *fh)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
u32 data[CX2341X_MBOX_MAX_DATA];
int has_output = itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT;
struct v4l2_input vidin;
struct v4l2_audio audin;
int i;
IVTV_INFO("================= START STATUS CARD #%d =================\n", itv->num);
IVTV_INFO("Version: %s Card: %s\n", IVTV_VERSION, itv->card_name);
if (itv->hw_flags & IVTV_HW_TVEEPROM) {
struct tveeprom tv;
ivtv_read_eeprom(itv, &tv);
}
ivtv_call_i2c_clients(itv, VIDIOC_LOG_STATUS, NULL);
ivtv_get_input(itv, itv->active_input, &vidin);
ivtv_get_audio_input(itv, itv->audio_input, &audin);
IVTV_INFO("Video Input: %s\n", vidin.name);
IVTV_INFO("Audio Input: %s%s\n", audin.name,
(itv->dualwatch_stereo_mode & ~0x300) == 0x200 ? " (Bilingual)" : "");
if (has_output) {
struct v4l2_output vidout;
struct v4l2_audioout audout;
int mode = itv->output_mode;
static const char * const output_modes[5] = {
"None",
"MPEG Streaming",
"YUV Streaming",
"YUV Frames",
"Passthrough",
};
static const char * const audio_modes[5] = {
"Stereo",
"Left",
"Right",
"Mono",
"Swapped"
};
static const char * const alpha_mode[4] = {
"None",
"Global",
"Local",
"Global and Local"
};
static const char * const pixel_format[16] = {
"ARGB Indexed",
"RGB 5:6:5",
"ARGB 1:5:5:5",
"ARGB 1:4:4:4",
"ARGB 8:8:8:8",
"5",
"6",
"7",
"AYUV Indexed",
"YUV 5:6:5",
"AYUV 1:5:5:5",
"AYUV 1:4:4:4",
"AYUV 8:8:8:8",
"13",
"14",
"15",
};
ivtv_get_output(itv, itv->active_output, &vidout);
ivtv_get_audio_output(itv, 0, &audout);
IVTV_INFO("Video Output: %s\n", vidout.name);
IVTV_INFO("Audio Output: %s (Stereo/Bilingual: %s/%s)\n", audout.name,
audio_modes[itv->audio_stereo_mode],
audio_modes[itv->audio_bilingual_mode]);
if (mode < 0 || mode > OUT_PASSTHROUGH)
mode = OUT_NONE;
IVTV_INFO("Output Mode: %s\n", output_modes[mode]);
ivtv_vapi_result(itv, data, CX2341X_OSD_GET_STATE, 0);
data[0] |= (read_reg(0x2a00) >> 7) & 0x40;
IVTV_INFO("Overlay: %s, Alpha: %s, Pixel Format: %s\n",
data[0] & 1 ? "On" : "Off",
alpha_mode[(data[0] >> 1) & 0x3],
pixel_format[(data[0] >> 3) & 0xf]);
}
IVTV_INFO("Tuner: %s\n",
test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags) ? "Radio" : "TV");
cx2341x_log_status(&itv->params, itv->name);
IVTV_INFO("Status flags: 0x%08lx\n", itv->i_flags);
for (i = 0; i < IVTV_MAX_STREAMS; i++) {
struct ivtv_stream *s = &itv->streams[i];
default:
return -EINVAL;
if (s->v4l2dev == NULL || s->buffers == 0)
continue;
IVTV_INFO("Stream %s: status 0x%04lx, %d%% of %d KiB (%d buffers) in use\n", s->name, s->s_flags,
(s->buffers - s->q_free.buffers) * 100 / s->buffers,
(s->buffers * s->buf_size) / 1024, s->buffers);
}
IVTV_INFO("Read MPG/VBI: %lld/%lld bytes\n", (long long)itv->mpg_data_received, (long long)itv->vbi_data_inserted);
IVTV_INFO("================== END STATUS CARD #%d ==================\n", itv->num);
return 0;
}
......@@ -1607,121 +1732,30 @@ static int ivtv_decoder_ioctls(struct file *filp, unsigned int cmd, void *arg)
return 0;
}
static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
unsigned int cmd, void *arg)
static int ivtv_default(struct file *file, void *fh, int cmd, void *arg)
{
struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
struct ivtv *itv = id->itv;
int ret;
/* check priority */
switch (cmd) {
case VIDIOC_S_CTRL:
case VIDIOC_S_STD:
case VIDIOC_S_INPUT:
case VIDIOC_S_OUTPUT:
case VIDIOC_S_TUNER:
case VIDIOC_S_FREQUENCY:
case VIDIOC_S_FMT:
case VIDIOC_S_CROP:
case VIDIOC_S_AUDIO:
case VIDIOC_S_AUDOUT:
case VIDIOC_S_EXT_CTRLS:
case VIDIOC_S_FBUF:
case VIDIOC_OVERLAY:
ret = v4l2_prio_check(&itv->prio, &id->prio);
if (ret)
return ret;
}
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
switch (cmd) {
case VIDIOC_DBG_G_REGISTER:
case VIDIOC_DBG_S_REGISTER:
case VIDIOC_G_CHIP_IDENT:
case VIDIOC_INT_S_AUDIO_ROUTING:
case VIDIOC_INT_RESET:
if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
v4l_printk_ioctl(cmd);
printk("\n");
}
return ivtv_debug_ioctls(filp, cmd, arg);
case VIDIOC_INT_S_AUDIO_ROUTING: {
struct v4l2_routing *route = arg;
case VIDIOC_G_PRIORITY:
case VIDIOC_S_PRIORITY:
case VIDIOC_QUERYCAP:
case VIDIOC_ENUMINPUT:
case VIDIOC_G_INPUT:
case VIDIOC_S_INPUT:
case VIDIOC_ENUMOUTPUT:
case VIDIOC_G_OUTPUT:
case VIDIOC_S_OUTPUT:
case VIDIOC_G_FMT:
case VIDIOC_S_FMT:
case VIDIOC_TRY_FMT:
case VIDIOC_ENUM_FMT:
case VIDIOC_CROPCAP:
case VIDIOC_G_CROP:
case VIDIOC_S_CROP:
case VIDIOC_G_FREQUENCY:
case VIDIOC_S_FREQUENCY:
case VIDIOC_ENUMSTD:
case VIDIOC_G_STD:
case VIDIOC_S_STD:
case VIDIOC_S_TUNER:
case VIDIOC_G_TUNER:
case VIDIOC_ENUMAUDIO:
case VIDIOC_S_AUDIO:
case VIDIOC_G_AUDIO:
case VIDIOC_ENUMAUDOUT:
case VIDIOC_S_AUDOUT:
case VIDIOC_G_AUDOUT:
case VIDIOC_G_SLICED_VBI_CAP:
case VIDIOC_LOG_STATUS:
case VIDIOC_G_ENC_INDEX:
case VIDIOC_ENCODER_CMD:
case VIDIOC_TRY_ENCODER_CMD:
case VIDIOC_G_FBUF:
case VIDIOC_S_FBUF:
case VIDIOC_OVERLAY:
if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
v4l_printk_ioctl(cmd);
printk("\n");
}
return ivtv_v4l2_ioctls(itv, filp, cmd, arg);
ivtv_i2c_hw(itv, itv->card->hw_audio, VIDIOC_INT_S_AUDIO_ROUTING, route);
break;
}
case VIDIOC_QUERYMENU:
case VIDIOC_QUERYCTRL:
case VIDIOC_S_CTRL:
case VIDIOC_G_CTRL:
case VIDIOC_S_EXT_CTRLS:
case VIDIOC_G_EXT_CTRLS:
case VIDIOC_TRY_EXT_CTRLS:
if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
v4l_printk_ioctl(cmd);
printk("\n");
}
return ivtv_control_ioctls(itv, cmd, arg);
case VIDIOC_INT_RESET: {
u32 val = *(u32 *)arg;
case IVTV_IOC_DMA_FRAME:
case VIDEO_GET_PTS:
case VIDEO_GET_FRAME_COUNT:
case VIDEO_GET_EVENT:
case VIDEO_PLAY:
case VIDEO_STOP:
case VIDEO_FREEZE:
case VIDEO_CONTINUE:
case VIDEO_COMMAND:
case VIDEO_TRY_COMMAND:
return ivtv_decoder_ioctls(filp, cmd, arg);
if ((val == 0 && itv->options.newi2c) || (val & 0x01))
ivtv_reset_ir_gpio(itv);
if (val & 0x02)
itv->video_dec_func(itv, cmd, NULL);
break;
}
case 0x00005401: /* Handle isatty() calls */
return -EINVAL;
default:
return v4l_compat_translate_ioctl(inode, filp, cmd, arg,
ivtv_v4l2_do_ioctl);
return -EINVAL;
}
return 0;
}
......@@ -1729,7 +1763,10 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct file *filp,
unsigned int cmd, unsigned long arg)
{
/* Filter dvb ioctls that cannot be handled by video_usercopy */
struct ivtv_open_id *id = (struct ivtv_open_id *)filp->private_data;
int ret;
/* Filter dvb ioctls that cannot be handled by the v4l ioctl framework */
switch (cmd) {
case VIDEO_SELECT_SOURCE:
IVTV_DEBUG_IOCTL("VIDEO_SELECT_SOURCE\n");
......@@ -1758,10 +1795,49 @@ static int ivtv_serialized_ioctl(struct ivtv *itv, struct inode *inode, struct f
ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
return 0;
case IVTV_IOC_DMA_FRAME:
case VIDEO_GET_PTS:
case VIDEO_GET_FRAME_COUNT:
case VIDEO_GET_EVENT:
case VIDEO_PLAY:
case VIDEO_STOP:
case VIDEO_FREEZE:
case VIDEO_CONTINUE:
case VIDEO_COMMAND:
case VIDEO_TRY_COMMAND:
return ivtv_decoder_ioctls(filp, cmd, (void *)arg);
default:
break;
}
return video_usercopy(inode, filp, cmd, arg, ivtv_v4l2_do_ioctl);
/* check priority */
switch (cmd) {
case VIDIOC_S_CTRL:
case VIDIOC_S_STD:
case VIDIOC_S_INPUT:
case VIDIOC_S_OUTPUT:
case VIDIOC_S_TUNER:
case VIDIOC_S_FREQUENCY:
case VIDIOC_S_FMT:
case VIDIOC_S_CROP:
case VIDIOC_S_AUDIO:
case VIDIOC_S_AUDOUT:
case VIDIOC_S_EXT_CTRLS:
case VIDIOC_S_FBUF:
case VIDIOC_OVERLAY:
ret = v4l2_prio_check(&itv->prio, &id->prio);
if (ret)
return ret;
}
if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
v4l_printk_ioctl(cmd);
printk("\n");
}
return video_ioctl2(inode, filp, cmd, arg);
}
int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
......@@ -1776,3 +1852,70 @@ int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
mutex_unlock(&itv->serialize_lock);
return res;
}
void ivtv_set_funcs(struct video_device *vdev)
{
vdev->vidioc_querycap = ivtv_querycap;
vdev->vidioc_g_priority = ivtv_g_priority;
vdev->vidioc_s_priority = ivtv_s_priority;
vdev->vidioc_s_audio = ivtv_s_audio;
vdev->vidioc_g_audio = ivtv_g_audio;
vdev->vidioc_enumaudio = ivtv_enumaudio;
vdev->vidioc_s_audout = ivtv_s_audout;
vdev->vidioc_g_audout = ivtv_g_audout;
vdev->vidioc_enum_input = ivtv_enum_input;
vdev->vidioc_enum_output = ivtv_enum_output;
vdev->vidioc_enumaudout = ivtv_enumaudout;
vdev->vidioc_cropcap = ivtv_cropcap;
vdev->vidioc_s_crop = ivtv_s_crop;
vdev->vidioc_g_crop = ivtv_g_crop;
vdev->vidioc_g_input = ivtv_g_input;
vdev->vidioc_s_input = ivtv_s_input;
vdev->vidioc_g_output = ivtv_g_output;
vdev->vidioc_s_output = ivtv_s_output;
vdev->vidioc_g_frequency = ivtv_g_frequency;
vdev->vidioc_s_frequency = ivtv_s_frequency;
vdev->vidioc_s_tuner = ivtv_s_tuner;
vdev->vidioc_g_tuner = ivtv_g_tuner;
vdev->vidioc_g_enc_index = ivtv_g_enc_index;
vdev->vidioc_g_fbuf = ivtv_g_fbuf;
vdev->vidioc_s_fbuf = ivtv_s_fbuf;
vdev->vidioc_g_std = ivtv_g_std;
vdev->vidioc_s_std = ivtv_s_std;
vdev->vidioc_overlay = ivtv_overlay;
vdev->vidioc_log_status = ivtv_log_status;
vdev->vidioc_enum_fmt_vid_cap = ivtv_enum_fmt_vid_cap;
vdev->vidioc_encoder_cmd = ivtv_encoder_cmd;
vdev->vidioc_try_encoder_cmd = ivtv_try_encoder_cmd;
vdev->vidioc_enum_fmt_vid_out = ivtv_enum_fmt_vid_out;
vdev->vidioc_g_fmt_vid_cap = ivtv_g_fmt_vid_cap;
vdev->vidioc_g_fmt_vbi_cap = ivtv_g_fmt_vbi_cap;
vdev->vidioc_g_fmt_sliced_vbi_cap = ivtv_g_fmt_sliced_vbi_cap;
vdev->vidioc_g_fmt_vid_out = ivtv_g_fmt_vid_out;
vdev->vidioc_g_fmt_vid_out_overlay = ivtv_g_fmt_vid_out_overlay;
vdev->vidioc_g_fmt_sliced_vbi_out = ivtv_g_fmt_sliced_vbi_out;
vdev->vidioc_s_fmt_vid_cap = ivtv_s_fmt_vid_cap;
vdev->vidioc_s_fmt_vbi_cap = ivtv_s_fmt_vbi_cap;
vdev->vidioc_s_fmt_sliced_vbi_cap = ivtv_s_fmt_sliced_vbi_cap;
vdev->vidioc_s_fmt_vid_out = ivtv_s_fmt_vid_out;
vdev->vidioc_s_fmt_vid_out_overlay = ivtv_s_fmt_vid_out_overlay;
vdev->vidioc_s_fmt_sliced_vbi_out = ivtv_s_fmt_sliced_vbi_out;
vdev->vidioc_try_fmt_vid_cap = ivtv_try_fmt_vid_cap;
vdev->vidioc_try_fmt_vbi_cap = ivtv_try_fmt_vbi_cap;
vdev->vidioc_try_fmt_sliced_vbi_cap = ivtv_try_fmt_sliced_vbi_cap;
vdev->vidioc_try_fmt_vid_out = ivtv_try_fmt_vid_out;
vdev->vidioc_try_fmt_vid_out_overlay = ivtv_try_fmt_vid_out_overlay;
vdev->vidioc_try_fmt_sliced_vbi_out = ivtv_try_fmt_sliced_vbi_out;
vdev->vidioc_g_sliced_vbi_cap = ivtv_g_sliced_vbi_cap;
vdev->vidioc_g_chip_ident = ivtv_g_chip_ident;
vdev->vidioc_g_register = ivtv_g_register;
vdev->vidioc_s_register = ivtv_s_register;
vdev->vidioc_default = ivtv_default;
vdev->vidioc_queryctrl = ivtv_queryctrl;
vdev->vidioc_querymenu = ivtv_querymenu;
vdev->vidioc_g_ctrl = ivtv_g_ctrl;
vdev->vidioc_s_ctrl = ivtv_s_ctrl;
vdev->vidioc_g_ext_ctrls = ivtv_g_ext_ctrls;
vdev->vidioc_s_ext_ctrls = ivtv_s_ext_ctrls;
vdev->vidioc_try_ext_ctrls = ivtv_try_ext_ctrls;
}
......@@ -24,10 +24,13 @@
u16 ivtv_service2vbi(int type);
void ivtv_expand_service_set(struct v4l2_sliced_vbi_format *fmt, int is_pal);
u16 ivtv_get_service_set(struct v4l2_sliced_vbi_format *fmt);
int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg);
int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg);
void ivtv_set_osd_alpha(struct ivtv *itv);
int ivtv_set_speed(struct ivtv *itv, int speed);
void ivtv_set_funcs(struct video_device *vdev);
int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std);
int ivtv_s_frequency(struct file *file, void *fh, struct v4l2_frequency *vf);
int ivtv_s_input(struct file *file, void *fh, unsigned int inp);
int ivtv_v4l2_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
unsigned long arg);
#endif
......@@ -220,7 +220,8 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
s->v4l2dev->dev = &itv->dev->dev;
s->v4l2dev->fops = ivtv_stream_info[type].fops;
s->v4l2dev->release = video_device_release;
s->v4l2dev->tvnorms = V4L2_STD_ALL;
ivtv_set_funcs(s->v4l2dev);
return 0;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment