Skip to content

Commit

Permalink
V4L/DVB: ivtv: convert to the new control framework
Browse files Browse the repository at this point in the history
Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
  • Loading branch information
Hans Verkuil authored and Mauro Carvalho Chehab committed Aug 9, 2010
1 parent 2fd7814 commit f7b80e6
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 301 deletions.
276 changes: 32 additions & 244 deletions drivers/media/video/ivtv/ivtv-controls.c
Original file line number Diff line number Diff line change
Expand Up @@ -17,163 +17,14 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <linux/kernel.h>
#include <linux/slab.h>

#include "ivtv-driver.h"
#include "ivtv-cards.h"
#include "ivtv-ioctl.h"
#include "ivtv-routing.h"
#include "ivtv-i2c.h"
#include "ivtv-mailbox.h"
#include "ivtv-controls.h"

/* Must be sorted from low to high control ID! */
static const u32 user_ctrls[] = {
V4L2_CID_USER_CLASS,
V4L2_CID_BRIGHTNESS,
V4L2_CID_CONTRAST,
V4L2_CID_SATURATION,
V4L2_CID_HUE,
V4L2_CID_AUDIO_VOLUME,
V4L2_CID_AUDIO_BALANCE,
V4L2_CID_AUDIO_BASS,
V4L2_CID_AUDIO_TREBLE,
V4L2_CID_AUDIO_MUTE,
V4L2_CID_AUDIO_LOUDNESS,
0
};

static const u32 *ctrl_classes[] = {
user_ctrls,
cx2341x_mpeg_ctrls,
NULL
};


int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
const char *name;

qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
if (qctrl->id == 0)
return -EINVAL;

switch (qctrl->id) {
/* Standard V4L2 controls */
case V4L2_CID_USER_CLASS:
return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
case V4L2_CID_BRIGHTNESS:
case V4L2_CID_HUE:
case V4L2_CID_SATURATION:
case V4L2_CID_CONTRAST:
if (v4l2_subdev_call(itv->sd_video, core, queryctrl, qctrl))
qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
return 0;

case V4L2_CID_AUDIO_VOLUME:
case V4L2_CID_AUDIO_MUTE:
case V4L2_CID_AUDIO_BALANCE:
case V4L2_CID_AUDIO_BASS:
case V4L2_CID_AUDIO_TREBLE:
case V4L2_CID_AUDIO_LOUDNESS:
if (v4l2_subdev_call(itv->sd_audio, core, queryctrl, qctrl))
qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
return 0;

default:
if (cx2341x_ctrl_query(&itv->params, qctrl))
qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
return 0;
}
strncpy(qctrl->name, name, sizeof(qctrl->name) - 1);
qctrl->name[sizeof(qctrl->name) - 1] = 0;
return 0;
}

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;

qctrl.id = qmenu->id;
ivtv_queryctrl(file, fh, &qctrl);
return v4l2_ctrl_query_menu(qmenu, &qctrl,
cx2341x_ctrl_get_menu(&itv->params, qmenu->id));
}

static int ivtv_try_ctrl(struct file *file, void *fh,
struct v4l2_ext_control *vctrl)
{
struct v4l2_queryctrl qctrl;
const char **menu_items = NULL;
int err;

qctrl.id = vctrl->id;
err = ivtv_queryctrl(file, fh, &qctrl);
if (err)
return err;
if (qctrl.type == V4L2_CTRL_TYPE_MENU)
menu_items = v4l2_ctrl_get_menu(qctrl.id);
return v4l2_ctrl_check(vctrl, &qctrl, menu_items);
}

static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
{
switch (vctrl->id) {
/* Standard V4L2 controls */
case V4L2_CID_BRIGHTNESS:
case V4L2_CID_HUE:
case V4L2_CID_SATURATION:
case V4L2_CID_CONTRAST:
return v4l2_subdev_call(itv->sd_video, core, s_ctrl, vctrl);

case V4L2_CID_AUDIO_VOLUME:
case V4L2_CID_AUDIO_MUTE:
case V4L2_CID_AUDIO_BALANCE:
case V4L2_CID_AUDIO_BASS:
case V4L2_CID_AUDIO_TREBLE:
case V4L2_CID_AUDIO_LOUDNESS:
return v4l2_subdev_call(itv->sd_audio, core, s_ctrl, vctrl);

default:
IVTV_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
return -EINVAL;
}
return 0;
}

static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
static int ivtv_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt)
{
switch (vctrl->id) {
/* Standard V4L2 controls */
case V4L2_CID_BRIGHTNESS:
case V4L2_CID_HUE:
case V4L2_CID_SATURATION:
case V4L2_CID_CONTRAST:
return v4l2_subdev_call(itv->sd_video, core, g_ctrl, vctrl);

case V4L2_CID_AUDIO_VOLUME:
case V4L2_CID_AUDIO_MUTE:
case V4L2_CID_AUDIO_BALANCE:
case V4L2_CID_AUDIO_BASS:
case V4L2_CID_AUDIO_TREBLE:
case V4L2_CID_AUDIO_LOUDNESS:
return v4l2_subdev_call(itv->sd_audio, core, g_ctrl, vctrl);
default:
IVTV_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
return -EINVAL;
}
return 0;
}

static int ivtv_setup_vbi_fmt(struct ivtv *itv, enum v4l2_mpeg_stream_vbi_fmt fmt)
{
if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE))
return -EINVAL;
if (atomic_read(&itv->capturing) > 0)
return -EBUSY;
struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl);

/* First try to allocate sliced VBI buffers if needed. */
if (fmt && itv->vbi.sliced_mpeg_data[0] == NULL) {
Expand Down Expand Up @@ -208,106 +59,43 @@ static int ivtv_setup_vbi_fmt(struct ivtv *itv, enum v4l2_mpeg_stream_vbi_fmt fm
return 0;
}

int ivtv_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
static int ivtv_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val)
{
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_g_ctrl(itv, &ctrl);
c->controls[i].value = ctrl.value;
if (err) {
c->error_idx = i;
break;
}
}
return err;
}
if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
return cx2341x_ext_ctrls(&itv->params, 0, c, VIDIOC_G_EXT_CTRLS);
return -EINVAL;
struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl);
int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
struct v4l2_mbus_framefmt fmt;

/* fix videodecoder resolution */
fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1);
fmt.height = cxhdl->height;
fmt.code = V4L2_MBUS_FMT_FIXED;
v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &fmt);
return 0;
}

int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
static int ivtv_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx)
{
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(itv, &ctrl);
c->controls[i].value = ctrl.value;
if (err) {
c->error_idx = i;
break;
}
}
return err;
}
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;
static const u32 freqs[3] = { 44100, 48000, 32000 };
struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl);

if (p.video_encoding != itv->params.video_encoding) {
int is_mpeg1 = p.video_encoding ==
V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
struct v4l2_mbus_framefmt fmt;

/* fix videodecoder resolution */
fmt.width = itv->params.width / (is_mpeg1 ? 2 : 1);
fmt.height = itv->params.height;
fmt.code = V4L2_MBUS_FMT_FIXED;
v4l2_subdev_call(itv->sd_video, video, s_mbus_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 < ARRAY_SIZE(freqs))
ivtv_call_all(itv, audio, s_clock_freq, freqs[idx]);
return err;
}
return -EINVAL;
/* The audio clock of the digitizer must match the codec sample
rate otherwise you get some very strange effects. */
if (idx < ARRAY_SIZE(freqs))
ivtv_call_all(itv, audio, s_clock_freq, freqs[idx]);
return 0;
}

int ivtv_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
static int ivtv_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val)
{
struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl);

if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
int i;
int err = 0;

for (i = 0; i < c->count; i++) {
err = ivtv_try_ctrl(file, fh, &c->controls[i]);
if (err) {
c->error_idx = i;
break;
}
}
return err;
}
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;
itv->dualwatch_stereo_mode = val;
return 0;
}

struct cx2341x_handler_ops ivtv_cxhdl_ops = {
.s_audio_mode = ivtv_s_audio_mode,
.s_audio_sampling_freq = ivtv_s_audio_sampling_freq,
.s_video_encoding = ivtv_s_video_encoding,
.s_stream_vbi_fmt = ivtv_s_stream_vbi_fmt,
};
6 changes: 1 addition & 5 deletions drivers/media/video/ivtv/ivtv-controls.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,6 @@
#ifndef IVTV_CONTROLS_H
#define IVTV_CONTROLS_H

int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *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);
extern struct cx2341x_handler_ops ivtv_cxhdl_ops;

#endif
18 changes: 13 additions & 5 deletions drivers/media/video/ivtv/ivtv-driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include "ivtv-cards.h"
#include "ivtv-vbi.h"
#include "ivtv-routing.h"
#include "ivtv-controls.h"
#include "ivtv-gpio.h"

#include <media/tveeprom.h>
Expand Down Expand Up @@ -734,9 +735,8 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
itv->open_id = 1;

/* Initial settings */
cx2341x_fill_defaults(&itv->params);
itv->params.port = CX2341X_PORT_MEMORY;
itv->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI;
itv->cxhdl.port = CX2341X_PORT_MEMORY;
itv->cxhdl.capabilities = CX2341X_CAP_HAS_SLICED_VBI;
init_waitqueue_head(&itv->eos_waitq);
init_waitqueue_head(&itv->event_waitq);
init_waitqueue_head(&itv->vsync_waitq);
Expand Down Expand Up @@ -1006,6 +1006,13 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
retval = -ENOMEM;
goto err;
}
retval = cx2341x_handler_init(&itv->cxhdl, 50);
if (retval)
goto err;
itv->v4l2_dev.ctrl_handler = &itv->cxhdl.hdl;
itv->cxhdl.ops = &ivtv_cxhdl_ops;
itv->cxhdl.priv = itv;
itv->cxhdl.func = ivtv_api_func;

IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr);

Expand Down Expand Up @@ -1127,7 +1134,7 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
itv->yuv_info.v4l2_src_w = itv->yuv_info.osd_full_w;
itv->yuv_info.v4l2_src_h = itv->yuv_info.osd_full_h;

itv->params.video_gop_size = itv->is_60hz ? 15 : 12;
cx2341x_handler_set_50hz(&itv->cxhdl, itv->is_50hz);

itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_MPG] = 0x08000;
itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_PCM] = 0x01200;
Expand Down Expand Up @@ -1322,6 +1329,8 @@ int ivtv_init_on_first_open(struct ivtv *itv)
/* For cards with video out, this call needs interrupts enabled */
ivtv_s_std(NULL, &fh, &itv->tuner_std);

/* Setup initial controls */
cx2341x_handler_setup(&itv->cxhdl);
return 0;
}

Expand Down Expand Up @@ -1386,7 +1395,6 @@ static void ivtv_remove(struct pci_dev *pdev)
printk(KERN_INFO "ivtv: Removed %s\n", itv->card_name);

v4l2_device_unregister(&itv->v4l2_dev);
v4l2_ctrl_handler_free(&itv->hdl_gpio);
kfree(itv);
}

Expand Down
Loading

0 comments on commit f7b80e6

Please sign in to comment.