Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a75b9be1 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab
Browse files

[media] cx18: Use the control framework

parent 34a078da
Loading
Loading
Loading
Loading
+12 −80
Original line number Original line Diff line number Diff line
@@ -342,17 +342,6 @@ void cx18_av_audio_set_path(struct cx18 *cx)
	}
	}
}
}


static int get_volume(struct cx18 *cx)
{
	/* Volume runs +18dB to -96dB in 1/2dB steps
	 * change to fit the msp3400 -114dB to +12dB range */

	/* check PATH1_VOLUME */
	int vol = 228 - cx18_av_read(cx, 0x8d4);
	vol = (vol / 2) + 23;
	return vol << 9;
}

static void set_volume(struct cx18 *cx, int volume)
static void set_volume(struct cx18 *cx, int volume)
{
{
	/* First convert the volume to msp3400 values (0-127) */
	/* First convert the volume to msp3400 values (0-127) */
@@ -369,52 +358,18 @@ static void set_volume(struct cx18 *cx, int volume)
	cx18_av_write(cx, 0x8d4, 228 - (vol * 2));
	cx18_av_write(cx, 0x8d4, 228 - (vol * 2));
}
}


static int get_bass(struct cx18 *cx)
{
	/* bass is 49 steps +12dB to -12dB */

	/* check PATH1_EQ_BASS_VOL */
	int bass = cx18_av_read(cx, 0x8d9) & 0x3f;
	bass = (((48 - bass) * 0xffff) + 47) / 48;
	return bass;
}

static void set_bass(struct cx18 *cx, int bass)
static void set_bass(struct cx18 *cx, int bass)
{
{
	/* PATH1_EQ_BASS_VOL */
	/* PATH1_EQ_BASS_VOL */
	cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
	cx18_av_and_or(cx, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
}
}


static int get_treble(struct cx18 *cx)
{
	/* treble is 49 steps +12dB to -12dB */

	/* check PATH1_EQ_TREBLE_VOL */
	int treble = cx18_av_read(cx, 0x8db) & 0x3f;
	treble = (((48 - treble) * 0xffff) + 47) / 48;
	return treble;
}

static void set_treble(struct cx18 *cx, int treble)
static void set_treble(struct cx18 *cx, int treble)
{
{
	/* PATH1_EQ_TREBLE_VOL */
	/* PATH1_EQ_TREBLE_VOL */
	cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
	cx18_av_and_or(cx, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
}
}


static int get_balance(struct cx18 *cx)
{
	/* balance is 7 bit, 0 to -96dB */

	/* check PATH1_BAL_LEVEL */
	int balance = cx18_av_read(cx, 0x8d5) & 0x7f;
	/* check PATH1_BAL_LEFT */
	if ((cx18_av_read(cx, 0x8d5) & 0x80) == 0)
		balance = 0x80 - balance;
	else
		balance = 0x80 + balance;
	return balance << 8;
}

static void set_balance(struct cx18 *cx, int balance)
static void set_balance(struct cx18 *cx, int balance)
{
{
	int bal = balance >> 8;
	int bal = balance >> 8;
@@ -431,12 +386,6 @@ static void set_balance(struct cx18 *cx, int balance)
	}
	}
}
}


static int get_mute(struct cx18 *cx)
{
	/* check SRC1_MUTE_EN */
	return cx18_av_read(cx, 0x8d3) & 0x2 ? 1 : 0;
}

static void set_mute(struct cx18 *cx, int mute)
static void set_mute(struct cx18 *cx, int mute)
{
{
	struct cx18_av_state *state = &cx->av_state;
	struct cx18_av_state *state = &cx->av_state;
@@ -490,50 +439,33 @@ int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
	return retval;
	return retval;
}
}


int cx18_av_audio_g_ctrl(struct cx18 *cx, struct v4l2_control *ctrl)
static int cx18_av_audio_s_ctrl(struct v4l2_ctrl *ctrl)
{
{
	switch (ctrl->id) {
	struct v4l2_subdev *sd = to_sd(ctrl);
	case V4L2_CID_AUDIO_VOLUME:
	struct cx18 *cx = v4l2_get_subdevdata(sd);
		ctrl->value = get_volume(cx);
		break;
	case V4L2_CID_AUDIO_BASS:
		ctrl->value = get_bass(cx);
		break;
	case V4L2_CID_AUDIO_TREBLE:
		ctrl->value = get_treble(cx);
		break;
	case V4L2_CID_AUDIO_BALANCE:
		ctrl->value = get_balance(cx);
		break;
	case V4L2_CID_AUDIO_MUTE:
		ctrl->value = get_mute(cx);
		break;
	default:
		return -EINVAL;
	}
	return 0;
}


int cx18_av_audio_s_ctrl(struct cx18 *cx, struct v4l2_control *ctrl)
{
	switch (ctrl->id) {
	switch (ctrl->id) {
	case V4L2_CID_AUDIO_VOLUME:
	case V4L2_CID_AUDIO_VOLUME:
		set_volume(cx, ctrl->value);
		set_volume(cx, ctrl->val);
		break;
		break;
	case V4L2_CID_AUDIO_BASS:
	case V4L2_CID_AUDIO_BASS:
		set_bass(cx, ctrl->value);
		set_bass(cx, ctrl->val);
		break;
		break;
	case V4L2_CID_AUDIO_TREBLE:
	case V4L2_CID_AUDIO_TREBLE:
		set_treble(cx, ctrl->value);
		set_treble(cx, ctrl->val);
		break;
		break;
	case V4L2_CID_AUDIO_BALANCE:
	case V4L2_CID_AUDIO_BALANCE:
		set_balance(cx, ctrl->value);
		set_balance(cx, ctrl->val);
		break;
		break;
	case V4L2_CID_AUDIO_MUTE:
	case V4L2_CID_AUDIO_MUTE:
		set_mute(cx, ctrl->value);
		set_mute(cx, ctrl->val);
		break;
		break;
	default:
	default:
		return -EINVAL;
		return -EINVAL;
	}
	}
	return 0;
	return 0;
}
}

const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops = {
	.s_ctrl = cx18_av_audio_s_ctrl,
};
+71 −104
Original line number Original line Diff line number Diff line
@@ -129,6 +129,7 @@ static void cx18_av_initialize(struct v4l2_subdev *sd)
{
{
	struct cx18_av_state *state = to_cx18_av_state(sd);
	struct cx18_av_state *state = to_cx18_av_state(sd);
	struct cx18 *cx = v4l2_get_subdevdata(sd);
	struct cx18 *cx = v4l2_get_subdevdata(sd);
	int default_volume;
	u32 v;
	u32 v;


	cx18_av_loadfw(cx);
	cx18_av_loadfw(cx);
@@ -247,8 +248,23 @@ static void cx18_av_initialize(struct v4l2_subdev *sd)
/*      	CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */
/*      	CxDevWrReg(CXADEC_SRC_COMB_CFG, 0x6628021F); */
/*    } */
/*    } */
	cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F);
	cx18_av_write4(cx, CXADEC_SRC_COMB_CFG, 0x6628021F);
	state->default_volume = 228 - cx18_av_read(cx, 0x8d4);
	default_volume = cx18_av_read(cx, 0x8d4);
	state->default_volume = ((state->default_volume / 2) + 23) << 9;
	/*
	 * Enforce the legacy volume scale mapping limits to avoid
	 * -ERANGE errors when initializing the volume control
	 */
	if (default_volume > 228) {
		/* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */
		default_volume = 228;
		cx18_av_write(cx, 0x8d4, 228);
	} else if (default_volume < 20) {
		/* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */
		default_volume = 20;
		cx18_av_write(cx, 0x8d4, 20);
	}
	default_volume = (((228 - default_volume) >> 1) + 23) << 9;
	state->volume->cur.val = state->volume->default_value = default_volume;
	v4l2_ctrl_handler_setup(&state->hdl);
}
}


static int cx18_av_reset(struct v4l2_subdev *sd, u32 val)
static int cx18_av_reset(struct v4l2_subdev *sd, u32 val)
@@ -901,126 +917,35 @@ static int cx18_av_s_radio(struct v4l2_subdev *sd)
	return 0;
	return 0;
}
}


static int cx18_av_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int cx18_av_s_ctrl(struct v4l2_ctrl *ctrl)
{
{
	struct v4l2_subdev *sd = to_sd(ctrl);
	struct cx18 *cx = v4l2_get_subdevdata(sd);
	struct cx18 *cx = v4l2_get_subdevdata(sd);


	switch (ctrl->id) {
	switch (ctrl->id) {
	case V4L2_CID_BRIGHTNESS:
	case V4L2_CID_BRIGHTNESS:
		if (ctrl->value < 0 || ctrl->value > 255) {
		cx18_av_write(cx, 0x414, ctrl->val - 128);
			CX18_ERR_DEV(sd, "invalid brightness setting %d\n",
				     ctrl->value);
			return -ERANGE;
		}

		cx18_av_write(cx, 0x414, ctrl->value - 128);
		break;
		break;


	case V4L2_CID_CONTRAST:
	case V4L2_CID_CONTRAST:
		if (ctrl->value < 0 || ctrl->value > 127) {
		cx18_av_write(cx, 0x415, ctrl->val << 1);
			CX18_ERR_DEV(sd, "invalid contrast setting %d\n",
				     ctrl->value);
			return -ERANGE;
		}

		cx18_av_write(cx, 0x415, ctrl->value << 1);
		break;
		break;


	case V4L2_CID_SATURATION:
	case V4L2_CID_SATURATION:
		if (ctrl->value < 0 || ctrl->value > 127) {
		cx18_av_write(cx, 0x420, ctrl->val << 1);
			CX18_ERR_DEV(sd, "invalid saturation setting %d\n",
		cx18_av_write(cx, 0x421, ctrl->val << 1);
				     ctrl->value);
			return -ERANGE;
		}

		cx18_av_write(cx, 0x420, ctrl->value << 1);
		cx18_av_write(cx, 0x421, ctrl->value << 1);
		break;
		break;


	case V4L2_CID_HUE:
	case V4L2_CID_HUE:
		if (ctrl->value < -128 || ctrl->value > 127) {
		cx18_av_write(cx, 0x422, ctrl->val);
			CX18_ERR_DEV(sd, "invalid hue setting %d\n",
				     ctrl->value);
			return -ERANGE;
		}

		cx18_av_write(cx, 0x422, ctrl->value);
		break;
		break;


	case V4L2_CID_AUDIO_VOLUME:
	case V4L2_CID_AUDIO_BASS:
	case V4L2_CID_AUDIO_TREBLE:
	case V4L2_CID_AUDIO_BALANCE:
	case V4L2_CID_AUDIO_MUTE:
		return cx18_av_audio_s_ctrl(cx, ctrl);

	default:
		return -EINVAL;
	}
	return 0;
}

static int cx18_av_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
	struct cx18 *cx = v4l2_get_subdevdata(sd);

	switch (ctrl->id) {
	case V4L2_CID_BRIGHTNESS:
		ctrl->value = (s8)cx18_av_read(cx, 0x414) + 128;
		break;
	case V4L2_CID_CONTRAST:
		ctrl->value = cx18_av_read(cx, 0x415) >> 1;
		break;
	case V4L2_CID_SATURATION:
		ctrl->value = cx18_av_read(cx, 0x420) >> 1;
		break;
	case V4L2_CID_HUE:
		ctrl->value = (s8)cx18_av_read(cx, 0x422);
		break;
	case V4L2_CID_AUDIO_VOLUME:
	case V4L2_CID_AUDIO_BASS:
	case V4L2_CID_AUDIO_TREBLE:
	case V4L2_CID_AUDIO_BALANCE:
	case V4L2_CID_AUDIO_MUTE:
		return cx18_av_audio_g_ctrl(cx, ctrl);
	default:
	default:
		return -EINVAL;
		return -EINVAL;
	}
	}
	return 0;
	return 0;
}
}


static int cx18_av_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
{
	struct cx18_av_state *state = to_cx18_av_state(sd);

	switch (qc->id) {
	case V4L2_CID_BRIGHTNESS:
		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
	case V4L2_CID_CONTRAST:
	case V4L2_CID_SATURATION:
		return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
	case V4L2_CID_HUE:
		return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
	default:
		break;
	}

	switch (qc->id) {
	case V4L2_CID_AUDIO_VOLUME:
		return v4l2_ctrl_query_fill(qc, 0, 65535,
			65535 / 100, state->default_volume);
	case V4L2_CID_AUDIO_MUTE:
		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
	case V4L2_CID_AUDIO_BALANCE:
	case V4L2_CID_AUDIO_BASS:
	case V4L2_CID_AUDIO_TREBLE:
		return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
	default:
		return -EINVAL;
	}
	return -EINVAL;
}

static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
{
{
	struct cx18_av_state *state = to_cx18_av_state(sd);
	struct cx18_av_state *state = to_cx18_av_state(sd);
@@ -1356,14 +1281,22 @@ static int cx18_av_s_register(struct v4l2_subdev *sd,
}
}
#endif
#endif


static const struct v4l2_ctrl_ops cx18_av_ctrl_ops = {
	.s_ctrl = cx18_av_s_ctrl,
};

static const struct v4l2_subdev_core_ops cx18_av_general_ops = {
static const struct v4l2_subdev_core_ops cx18_av_general_ops = {
	.g_chip_ident = cx18_av_g_chip_ident,
	.g_chip_ident = cx18_av_g_chip_ident,
	.log_status = cx18_av_log_status,
	.log_status = cx18_av_log_status,
	.load_fw = cx18_av_load_fw,
	.load_fw = cx18_av_load_fw,
	.reset = cx18_av_reset,
	.reset = cx18_av_reset,
	.queryctrl = cx18_av_queryctrl,
	.g_ctrl = v4l2_subdev_g_ctrl,
	.g_ctrl = cx18_av_g_ctrl,
	.s_ctrl = v4l2_subdev_s_ctrl,
	.s_ctrl = cx18_av_s_ctrl,
	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
	.queryctrl = v4l2_subdev_queryctrl,
	.querymenu = v4l2_subdev_querymenu,
	.s_std = cx18_av_s_std,
	.s_std = cx18_av_s_std,
#ifdef CONFIG_VIDEO_ADV_DEBUG
#ifdef CONFIG_VIDEO_ADV_DEBUG
	.g_register = cx18_av_g_register,
	.g_register = cx18_av_g_register,
@@ -1427,8 +1360,42 @@ int cx18_av_probe(struct cx18 *cx)
	snprintf(sd->name, sizeof(sd->name),
	snprintf(sd->name, sizeof(sd->name),
		 "%s %03x", cx->v4l2_dev.name, (state->rev >> 4));
		 "%s %03x", cx->v4l2_dev.name, (state->rev >> 4));
	sd->grp_id = CX18_HW_418_AV;
	sd->grp_id = CX18_HW_418_AV;
	v4l2_ctrl_handler_init(&state->hdl, 9);
	v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops,
			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
	v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops,
			V4L2_CID_CONTRAST, 0, 127, 1, 64);
	v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops,
			V4L2_CID_SATURATION, 0, 127, 1, 64);
	v4l2_ctrl_new_std(&state->hdl, &cx18_av_ctrl_ops,
			V4L2_CID_HUE, -128, 127, 1, 0);

	state->volume = v4l2_ctrl_new_std(&state->hdl,
			&cx18_av_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME,
			0, 65535, 65535 / 100, 0);
	v4l2_ctrl_new_std(&state->hdl,
			&cx18_av_audio_ctrl_ops, V4L2_CID_AUDIO_MUTE,
			0, 1, 1, 0);
	v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops,
			V4L2_CID_AUDIO_BALANCE,
			0, 65535, 65535 / 100, 32768);
	v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops,
			V4L2_CID_AUDIO_BASS,
			0, 65535, 65535 / 100, 32768);
	v4l2_ctrl_new_std(&state->hdl, &cx18_av_audio_ctrl_ops,
			V4L2_CID_AUDIO_TREBLE,
			0, 65535, 65535 / 100, 32768);
	sd->ctrl_handler = &state->hdl;
	if (state->hdl.error) {
		int err = state->hdl.error;

		v4l2_ctrl_handler_free(&state->hdl);
		return err;
	}
	err = v4l2_device_register_subdev(&cx->v4l2_dev, sd);
	err = v4l2_device_register_subdev(&cx->v4l2_dev, sd);
	if (!err)
	if (err)
		v4l2_ctrl_handler_free(&state->hdl);
	else
		cx18_av_init(cx);
		cx18_av_init(cx);
	return err;
	return err;
}
}
+9 −3
Original line number Original line Diff line number Diff line
@@ -26,6 +26,7 @@
#define _CX18_AV_CORE_H_
#define _CX18_AV_CORE_H_


#include <media/v4l2-device.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ctrls.h>


struct cx18;
struct cx18;


@@ -95,13 +96,14 @@ enum cx18_av_audio_input {


struct cx18_av_state {
struct cx18_av_state {
	struct v4l2_subdev sd;
	struct v4l2_subdev sd;
	struct v4l2_ctrl_handler hdl;
	struct v4l2_ctrl *volume;
	int radio;
	int radio;
	v4l2_std_id std;
	v4l2_std_id std;
	enum cx18_av_video_input vid_input;
	enum cx18_av_video_input vid_input;
	enum cx18_av_audio_input aud_input;
	enum cx18_av_audio_input aud_input;
	u32 audclk_freq;
	u32 audclk_freq;
	int audmode;
	int audmode;
	int default_volume;
	u32 id;
	u32 id;
	u32 rev;
	u32 rev;
	int is_initialized;
	int is_initialized;
@@ -347,6 +349,11 @@ static inline struct cx18_av_state *to_cx18_av_state(struct v4l2_subdev *sd)
	return container_of(sd, struct cx18_av_state, sd);
	return container_of(sd, struct cx18_av_state, sd);
}
}


static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
{
	return &container_of(ctrl->handler, struct cx18_av_state, hdl)->sd;
}

/* ----------------------------------------------------------------------- */
/* ----------------------------------------------------------------------- */
/* cx18_av-core.c 							   */
/* cx18_av-core.c 							   */
int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
int cx18_av_write(struct cx18 *cx, u16 addr, u8 value);
@@ -369,10 +376,9 @@ int cx18_av_loadfw(struct cx18 *cx);


/* ----------------------------------------------------------------------- */
/* ----------------------------------------------------------------------- */
/* cx18_av-audio.c                                                         */
/* cx18_av-audio.c                                                         */
int cx18_av_audio_g_ctrl(struct cx18 *cx, struct v4l2_control *ctrl);
int cx18_av_audio_s_ctrl(struct cx18 *cx, struct v4l2_control *ctrl);
int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq);
int cx18_av_s_clock_freq(struct v4l2_subdev *sd, u32 freq);
void cx18_av_audio_set_path(struct cx18 *cx);
void cx18_av_audio_set_path(struct cx18 *cx);
extern const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops;


/* ----------------------------------------------------------------------- */
/* ----------------------------------------------------------------------- */
/* cx18_av-vbi.c                                                           */
/* cx18_av-vbi.c                                                           */
+33 −252
Original line number Original line Diff line number Diff line
@@ -30,152 +30,11 @@
#include "cx18-mailbox.h"
#include "cx18-mailbox.h"
#include "cx18-controls.h"
#include "cx18-controls.h"


/* Must be sorted from low to high control ID! */
static int cx18_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt)
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 cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
	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(cx->sd_av, 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(cx->sd_av, core, queryctrl, qctrl))
			qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
		return 0;

	default:
		if (cx2341x_ctrl_query(&cx->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 cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qmenu)
{
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
	struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);
	struct v4l2_queryctrl qctrl;
	int type = cxhdl->stream_type->val;

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


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

	qctrl.id = vctrl->id;
	err = cx18_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 cx18_s_ctrl(struct cx18 *cx, 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(cx->sd_av, 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(cx->sd_av, core, s_ctrl, vctrl);

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

static int cx18_g_ctrl(struct cx18 *cx, 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(cx->sd_av, 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(cx->sd_av, core, g_ctrl, vctrl);

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

static int cx18_setup_vbi_fmt(struct cx18 *cx,
			      enum v4l2_mpeg_stream_vbi_fmt fmt,
			      enum v4l2_mpeg_stream_type type)
{
	if (!(cx->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE))
		return -EINVAL;
	if (atomic_read(&cx->ana_capturing) > 0)
	if (atomic_read(&cx->ana_capturing) > 0)
		return -EBUSY;
		return -EBUSY;


@@ -230,121 +89,43 @@ static int cx18_setup_vbi_fmt(struct cx18 *cx,
	return 0;
	return 0;
}
}


int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
static int cx18_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val)
{
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
	struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);
	struct v4l2_control ctrl;
	int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;

	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 = cx18_g_ctrl(cx, &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(&cx->params, 0, c, VIDIOC_G_EXT_CTRLS);
	return -EINVAL;
}

int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
{
	struct cx18_open_id *id = fh;
	struct cx18 *cx = id->cx;
	int ret;
	struct v4l2_control ctrl;

	ret = v4l2_prio_check(&cx->prio, id->prio);
	if (ret)
		return ret;

	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 = cx18_s_ctrl(cx, &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 cx18_api_func_private priv;
		struct cx2341x_mpeg_params p = cx->params;
		int err = cx2341x_ext_ctrls(&p, atomic_read(&cx->ana_capturing),
						c, VIDIOC_S_EXT_CTRLS);
		unsigned int idx;

		if (err)
			return err;

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


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

		priv.s = &cx->streams[id->type];
static int cx18_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx)
		err = cx2341x_update(&priv, cx18_api_func, &cx->params, &p);
{
		if (!err &&
	static const u32 freqs[3] = { 44100, 48000, 32000 };
		    (cx->params.stream_vbi_fmt != p.stream_vbi_fmt ||
	struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);
		     cx->params.stream_type != p.stream_type))

			err = cx18_setup_vbi_fmt(cx, p.stream_vbi_fmt,
						 p.stream_type);
		cx->params = p;
		cx->dualwatch_stereo_mode = p.audio_properties & 0x0300;
		idx = p.audio_properties & 0x03;
	/* The audio clock of the digitizer must match the codec sample
	/* The audio clock of the digitizer must match the codec sample
	   rate otherwise you get some very strange effects. */
	   rate otherwise you get some very strange effects. */
	if (idx < ARRAY_SIZE(freqs))
	if (idx < ARRAY_SIZE(freqs))
		cx18_call_all(cx, audio, s_clock_freq, freqs[idx]);
		cx18_call_all(cx, audio, s_clock_freq, freqs[idx]);
		return err;
	return 0;
	}
	return -EINVAL;
}
}


int cx18_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
static int cx18_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val)
{
{
	struct cx18 *cx = ((struct cx18_open_id *)fh)->cx;
	struct cx18 *cx = container_of(cxhdl, struct cx18, cxhdl);


	if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
	cx->dualwatch_stereo_mode = val;
		int i;
	return 0;
		int err = 0;

		for (i = 0; i < c->count; i++) {
			err = cx18_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(&cx->params,
						atomic_read(&cx->ana_capturing),
						c, VIDIOC_TRY_EXT_CTRLS);
	return -EINVAL;
}
}

struct cx2341x_handler_ops cx18_cxhdl_ops = {
	.s_audio_mode = cx18_s_audio_mode,
	.s_audio_sampling_freq = cx18_s_audio_sampling_freq,
	.s_video_encoding = cx18_s_video_encoding,
	.s_stream_vbi_fmt = cx18_s_stream_vbi_fmt,
};
+1 −6
Original line number Original line Diff line number Diff line
@@ -21,9 +21,4 @@
 *  02111-1307  USA
 *  02111-1307  USA
 */
 */


int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a);
extern struct cx2341x_handler_ops cx18_cxhdl_ops;
int cx18_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
int cx18_try_ext_ctrls(struct file *file, void *fh,
			struct v4l2_ext_controls *a);
int cx18_querymenu(struct file *file, void *fh, struct v4l2_querymenu *a);
Loading