Skip to contentSkip to conversation

Convert subdevs to the control fw and related fixes

PATCH New Hans Verkuil 1 participant 20 messages Dec 12, 2010

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover Convert subdevs to the control fw and related fixes

This patch series converts a number of subdev drivers to use the control framework. In addition, it also converts the cx18 and vivi drivers to the control framework.

This has been tested with the vivi, cx18 and em28xx drivers.

As a result of these tests bugs relating to ENUM_INPUT/OUTPUT and some incorrect checks in em28xx and the control framework were fixed.

It would be great if someone can check the tvaudio and tda drivers in particular.

Regards,

Hans

Hans Verkuil (19):
cs5345: use the control framework
tvaudio: use the control framework, fix vol/balance bugs
cx18: Use the control framework.
adv7343: use control framework
bt819: use control framework
ov7670: use the control framework
saa7110: use control framework
tda7432: use control framework
tda9875: use control framework
tlv320aic23b: use control framework
tvp514x: use the control framework
tvp5150: use the control framework
vpx3220: use control framework
tvp7002: use control framework
v4l2-ctrls: use const char * const * for the menu arrays
vivi: convert to the control framework and add test controls.
v4l: fix handling of v4l2_input.capabilities
em28xx: fix incorrect s_ctrl error code and wrong call to res_free
v4l2-ctrls: only check def for menu, integer and boolean controls

 drivers/media/dvb/ttpci/av7110_v4l.c               |    4 +
 drivers/media/dvb/ttpci/budget-av.c                |    6 +-
 drivers/media/video/adv7343.c                      |  167 ++++-------
 drivers/media/video/adv7343_regs.h                 |    8 +-
 drivers/media/video/bt819.c                        |  129 ++++------
 drivers/media/video/cs5345.c                       |   87 ++++--
 drivers/media/video/cx18/cx18-av-audio.c           |   92 +------
 drivers/media/video/cx18/cx18-av-core.c            |  162 ++++-------
 drivers/media/video/cx18/cx18-av-core.h            |   12 +-
 drivers/media/video/cx18/cx18-cards.c              |    1 -
 drivers/media/video/cx18/cx18-controls.c           |  285 +++-----------------
 drivers/media/video/cx18/cx18-controls.h           |    7 +-
 drivers/media/video/cx18/cx18-driver.c             |   30 ++-
 drivers/media/video/cx18/cx18-driver.h             |    2 +-
 drivers/media/video/cx18/cx18-fileops.c            |   32 +--
 drivers/media/video/cx18/cx18-ioctl.c              |   24 +-
 drivers/media/video/cx18/cx18-mailbox.c            |    5 +-
 drivers/media/video/cx18/cx18-mailbox.h            |    5 -
 drivers/media/video/cx18/cx18-streams.c            |   16 +-
 drivers/media/video/cx2341x.c                      |    8 +-
 drivers/media/video/cx23885/cx23885-video.c        |    1 -
 drivers/media/video/em28xx/em28xx-video.c          |   14 +-
 drivers/media/video/et61x251/et61x251_core.c       |    1 +
 drivers/media/video/hexium_gemini.c                |   18 +-
 drivers/media/video/hexium_orion.c                 |   18 +-
 drivers/media/video/ivtv/ivtv-cards.c              |    2 -
 drivers/media/video/mxb.c                          |    8 +-
 drivers/media/video/ov7670.c                       |  296 ++++++++------------
 drivers/media/video/pvrusb2/pvrusb2-ctrl.c         |    6 +-
 drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h |    2 +-
 drivers/media/video/saa7110.c                      |  115 +++-----
 drivers/media/video/saa7134/saa7134-video.c        |    1 -
 drivers/media/video/sn9c102/sn9c102_core.c         |    1 +
 drivers/media/video/tda7432.c                      |  277 +++++++-----------
 drivers/media/video/tda9875.c                      |  192 ++++---------
 drivers/media/video/timblogiw.c                    |    1 -
 drivers/media/video/tlv320aic23b.c                 |   74 +++--
 drivers/media/video/tvaudio.c                      |  221 +++++----------
 drivers/media/video/tvp514x.c                      |  236 ++++------------
 drivers/media/video/tvp5150.c                      |  157 +++--------
 drivers/media/video/tvp7002.c                      |  117 +++-----
 drivers/media/video/v4l2-common.c                  |    6 +-
 drivers/media/video/v4l2-ctrls.c                   |   55 ++--
 drivers/media/video/vino.c                         |    3 -
 drivers/media/video/vivi.c                         |  228 +++++++++------
 drivers/media/video/vpx3220.c                      |  137 ++++------
 drivers/media/video/zoran/zoran_driver.c           |    6 -
 drivers/staging/cx25821/cx25821-video.c            |    2 -
 include/media/cx2341x.h                            |    2 +-
 include/media/v4l2-common.h                        |    6 +-
 include/media/v4l2-ctrls.h                         |    4 +-
 51 files changed, 1203 insertions(+), 2086 deletions(-)
#1 lore raw

PATCH 1/19 cs5345: use the control framework

---
 drivers/media/video/cs5345.c |   87 ++++++++++++++++++++++++++++-------------
 1 files changed, 59 insertions(+), 28 deletions(-)
drivers/media/video/cs5345.c +59 -28
index 9358fe7..5909f25 100644
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
 
 MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC");
 MODULE_AUTHOR("Hans Verkuil");
@@ -36,6 +37,20 @@ module_param(debug, bool, 0644);
 
 MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On");
 
+struct cs5345_state {
+	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+};
+
+static inline struct cs5345_state *to_state(struct v4l2_subdev *sd)
+{
+	return container_of(sd, struct cs5345_state, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct cs5345_state, hdl)->sd;
+}
 
 /* ----------------------------------------------------------------------- */
 
@@ -65,33 +80,20 @@ static int cs5345_s_routing(struct v4l2_subdev *sd,
 	return 0;
 }
 
-static int cs5345_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int cs5345_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
-		ctrl->value = (cs5345_read(sd, 0x04) & 0x08) != 0;
-		return 0;
-	}
-	if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
-		return -EINVAL;
-	ctrl->value = cs5345_read(sd, 0x07) & 0x3f;
-	if (ctrl->value >= 32)
-		ctrl->value = ctrl->value - 64;
-	return 0;
-}
+	struct v4l2_subdev *sd = to_sd(ctrl);
 
-static int cs5345_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-	if (ctrl->id == V4L2_CID_AUDIO_MUTE) {
-		cs5345_write(sd, 0x04, ctrl->value ? 0x80 : 0);
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		cs5345_write(sd, 0x04, ctrl->val ? 0x80 : 0);
+		return 0;
+	case V4L2_CID_AUDIO_VOLUME:
+		cs5345_write(sd, 0x07, ((u8)ctrl->val) & 0x3f);
+		cs5345_write(sd, 0x08, ((u8)ctrl->val) & 0x3f);
 		return 0;
 	}
-	if (ctrl->id != V4L2_CID_AUDIO_VOLUME)
-		return -EINVAL;
-	if (ctrl->value > 24 || ctrl->value < -24)
-		return -EINVAL;
-	cs5345_write(sd, 0x07, ((u8)ctrl->value) & 0x3f);
-	cs5345_write(sd, 0x08, ((u8)ctrl->value) & 0x3f);
-	return 0;
+	return -EINVAL;
 }
 
 #ifdef CONFIG_VIDEO_ADV_DEBUG
@@ -144,11 +146,20 @@ static int cs5345_log_status(struct v4l2_subdev *sd)
 
 /* ----------------------------------------------------------------------- */
 
+static const struct v4l2_ctrl_ops cs5345_ctrl_ops = {
+	.s_ctrl = cs5345_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops cs5345_core_ops = {
 	.log_status = cs5345_log_status,
 	.g_chip_ident = cs5345_g_chip_ident,
-	.g_ctrl = cs5345_g_ctrl,
-	.s_ctrl = cs5345_s_ctrl,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 	.g_register = cs5345_g_register,
 	.s_register = cs5345_s_register,
@@ -169,6 +180,7 @@ static const struct v4l2_subdev_ops cs5345_ops = {
 static int cs5345_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
+	struct cs5345_state *state;
 	struct v4l2_subdev *sd;
 
 	/* Check if the adapter supports the needed features */
@@ -178,11 +190,28 @@ static int cs5345_probe(struct i2c_client *client,
 	v4l_info(client, "chip found @ 0x%x (%s)\n",
 			client->addr << 1, client->adapter->name);
 
-	sd = kzalloc(sizeof(struct v4l2_subdev), GFP_KERNEL);
-	if (sd == NULL)
+	state = kzalloc(sizeof(struct cs5345_state), GFP_KERNEL);
+	if (state == NULL)
 		return -ENOMEM;
+	sd = &state->sd;
 	v4l2_i2c_subdev_init(sd, client, &cs5345_ops);
 
+	v4l2_ctrl_handler_init(&state->hdl, 2);
+	v4l2_ctrl_new_std(&state->hdl, &cs5345_ctrl_ops,
+			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&state->hdl, &cs5345_ctrl_ops,
+			V4L2_CID_AUDIO_VOLUME, -24, 24, 1, 0);
+	sd->ctrl_handler = &state->hdl;
+	if (state->hdl.error) {
+		int err = state->hdl.error;
+
+		v4l2_ctrl_handler_free(&state->hdl);
+		kfree(state);
+		return err;
+	}
+	/* set volume/mute */
+	v4l2_ctrl_handler_setup(&state->hdl);
+
 	cs5345_write(sd, 0x02, 0x00);
 	cs5345_write(sd, 0x04, 0x01);
 	cs5345_write(sd, 0x09, 0x01);
@@ -194,9 +223,11 @@ static int cs5345_probe(struct i2c_client *client,
 static int cs5345_remove(struct i2c_client *client)
 {
 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct cs5345_state *state = to_state(sd);
 
 	v4l2_device_unregister_subdev(sd);
-	kfree(sd);
+	v4l2_ctrl_handler_free(&state->hdl);
+	kfree(state);
 	return 0;
 }
 
Signature · 1 line
1.7.0.4
#2 lore raw

PATCH 2/19 tvaudio: use the control framework, fix vol/balance bugs

In reply to Hans Verkuil

Implement the control framework in tvaudio.

While doing that I noticed that the handling of balance was completely broken. It's now fixed.

---
 drivers/media/video/tvaudio.c |  221 ++++++++++++++---------------------------
 1 files changed, 75 insertions(+), 146 deletions(-)
drivers/media/video/tvaudio.c +75 -146
index a25e2b5..e1534f8 100644
@@ -35,6 +35,7 @@
 #include <media/tvaudio.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
 
 #include <media/i2c-addr.h>
 
@@ -87,13 +88,13 @@ struct CHIPDESC {
 	audiocmd   init;
 
 	/* which register has which value */
-	int    leftreg,rightreg,treblereg,bassreg;
+	int    leftreg, rightreg, treblereg, bassreg;
 
-	/* initialize with (defaults to 65535/65535/32768/32768 */
-	int    leftinit,rightinit,trebleinit,bassinit;
+	/* initialize with (defaults to 65535/32768/32768 */
+	int    volinit, trebleinit, bassinit;
 
 	/* functions to convert the values (v4l -> chip) */
-	getvalue volfunc,treblefunc,bassfunc;
+	getvalue volfunc, treblefunc, bassfunc;
 
 	/* get/set mode */
 	getmode  getmode;
@@ -109,6 +110,12 @@ struct CHIPDESC {
 /* current state of the chip */
 struct CHIPSTATE {
 	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+	struct {
+		/* volume/balance cluster */
+		struct v4l2_ctrl *volume;
+		struct v4l2_ctrl *balance;
+	};
 
 	/* chip-specific description - should point to
 	   an entry at CHIPDESC table */
@@ -118,7 +125,7 @@ struct CHIPSTATE {
 	audiocmd   shadow;
 
 	/* current settings */
-	__u16 left,right,treble,bass,muted,mode;
+	u16 muted, mode;
 	int prevmode;
 	int radio;
 	int input;
@@ -135,6 +142,11 @@ static inline struct CHIPSTATE *to_state(struct v4l2_subdev *sd)
 	return container_of(sd, struct CHIPSTATE, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct CHIPSTATE, hdl)->sd;
+}
+
 
 /* ---------------------------------------------------------------------- */
 /* i2c I/O functions                                                      */
@@ -1450,8 +1462,7 @@ static struct CHIPDESC chiplist[] = {
 		.rightreg   = TDA9875_MVR,
 		.bassreg    = TDA9875_MBA,
 		.treblereg  = TDA9875_MTR,
-		.leftinit   = 58880,
-		.rightinit  = 58880,
+		.volinit    = 58880,
 	},
 	{
 		.name       = "tda9850",
@@ -1607,118 +1618,39 @@ static struct CHIPDESC chiplist[] = {
 
 /* ---------------------------------------------------------------------- */
 
-static int tvaudio_g_ctrl(struct v4l2_subdev *sd,
-			    struct v4l2_control *ctrl)
+static int tvaudio_s_ctrl(struct v4l2_ctrl *ctrl)
 {
+	struct v4l2_subdev *sd = to_sd(ctrl);
 	struct CHIPSTATE *chip = to_state(sd);
 	struct CHIPDESC *desc = chip->desc;
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
-		if (!(desc->flags & CHIP_HAS_INPUTSEL))
-			break;
-		ctrl->value=chip->muted;
-		return 0;
-	case V4L2_CID_AUDIO_VOLUME:
-		if (!(desc->flags & CHIP_HAS_VOLUME))
-			break;
-		ctrl->value = max(chip->left,chip->right);
-		return 0;
-	case V4L2_CID_AUDIO_BALANCE:
-	{
-		int volume;
-		if (!(desc->flags & CHIP_HAS_VOLUME))
-			break;
-		volume = max(chip->left,chip->right);
-		if (volume)
-			ctrl->value=(32768*min(chip->left,chip->right))/volume;
-		else
-			ctrl->value=32768;
-		return 0;
-	}
-	case V4L2_CID_AUDIO_BASS:
-		if (!(desc->flags & CHIP_HAS_BASSTREBLE))
-			break;
-		ctrl->value = chip->bass;
-		return 0;
-	case V4L2_CID_AUDIO_TREBLE:
-		if (!(desc->flags & CHIP_HAS_BASSTREBLE))
-			break;
-		ctrl->value = chip->treble;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static int tvaudio_s_ctrl(struct v4l2_subdev *sd,
-			    struct v4l2_control *ctrl)
-{
-	struct CHIPSTATE *chip = to_state(sd);
-	struct CHIPDESC *desc = chip->desc;
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		if (!(desc->flags & CHIP_HAS_INPUTSEL))
-			break;
-
-		if (ctrl->value < 0 || ctrl->value >= 2)
-			return -ERANGE;
-		chip->muted = ctrl->value;
+		chip->muted = ctrl->val;
 		if (chip->muted)
 			chip_write_masked(chip,desc->inputreg,desc->inputmute,desc->inputmask);
 		else
 			chip_write_masked(chip,desc->inputreg,
 					desc->inputmap[chip->input],desc->inputmask);
 		return 0;
-	case V4L2_CID_AUDIO_VOLUME:
-	{
-		int volume,balance;
-
-		if (!(desc->flags & CHIP_HAS_VOLUME))
-			break;
-
-		volume = max(chip->left,chip->right);
-		if (volume)
-			balance=(32768*min(chip->left,chip->right))/volume;
-		else
-			balance=32768;
-
-		volume=ctrl->value;
-		chip->left = (min(65536 - balance,32768) * volume) / 32768;
-		chip->right = (min(balance,volume *(__u16)32768)) / 32768;
+	case V4L2_CID_AUDIO_VOLUME: {
+		u32 volume, balance;
+		u32 left, right;
 
-		chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
-		chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
-
-		return 0;
-	}
-	case V4L2_CID_AUDIO_BALANCE:
-	{
-		int volume, balance;
-		if (!(desc->flags & CHIP_HAS_VOLUME))
-			break;
-
-		volume = max(chip->left,chip->right);
-		balance = ctrl->value;
-
-		chip_write(chip,desc->leftreg,desc->volfunc(chip->left));
-		chip_write(chip,desc->rightreg,desc->volfunc(chip->right));
+		volume = chip->volume->val;
+		balance = chip->balance->val;
+		left = (min(65536U - balance, 32768U) * volume) / 32768U;
+		right = (min(balance, 32768U) * volume) / 32768U;
 
+		chip_write(chip, desc->leftreg, desc->volfunc(left));
+		chip_write(chip, desc->rightreg, desc->volfunc(right));
 		return 0;
 	}
 	case V4L2_CID_AUDIO_BASS:
-		if (!(desc->flags & CHIP_HAS_BASSTREBLE))
-			break;
-		chip->bass = ctrl->value;
-		chip_write(chip,desc->bassreg,desc->bassfunc(chip->bass));
-
+		chip_write(chip, desc->bassreg, desc->bassfunc(ctrl->val));
 		return 0;
 	case V4L2_CID_AUDIO_TREBLE:
-		if (!(desc->flags & CHIP_HAS_BASSTREBLE))
-			break;
-		chip->treble = ctrl->value;
-		chip_write(chip,desc->treblereg,desc->treblefunc(chip->treble));
-
+		chip_write(chip, desc->treblereg, desc->treblefunc(ctrl->val));
 		return 0;
 	}
 	return -EINVAL;
@@ -1738,35 +1670,6 @@ static int tvaudio_s_radio(struct v4l2_subdev *sd)
 	return 0;
 }
 
-static int tvaudio_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
-	struct CHIPSTATE *chip = to_state(sd);
-	struct CHIPDESC *desc = chip->desc;
-
-	switch (qc->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		if (desc->flags & CHIP_HAS_INPUTSEL)
-			return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
-		break;
-	case V4L2_CID_AUDIO_VOLUME:
-		if (desc->flags & CHIP_HAS_VOLUME)
-			return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
-		break;
-	case V4L2_CID_AUDIO_BALANCE:
-		if (desc->flags & CHIP_HAS_VOLUME)
-			return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
-		break;
-	case V4L2_CID_AUDIO_BASS:
-	case V4L2_CID_AUDIO_TREBLE:
-		if (desc->flags & CHIP_HAS_BASSTREBLE)
-			return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
-		break;
-	default:
-		break;
-	}
-	return -EINVAL;
-}
-
 static int tvaudio_s_routing(struct v4l2_subdev *sd,
 			     u32 input, u32 output, u32 config)
 {
@@ -1893,11 +1796,19 @@ static int tvaudio_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ide
 
 /* ----------------------------------------------------------------------- */
 
+static const struct v4l2_ctrl_ops tvaudio_ctrl_ops = {
+	.s_ctrl = tvaudio_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops tvaudio_core_ops = {
 	.g_chip_ident = tvaudio_g_chip_ident,
-	.queryctrl = tvaudio_queryctrl,
-	.g_ctrl = tvaudio_g_ctrl,
-	.s_ctrl = tvaudio_s_ctrl,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
 	.s_std = tvaudio_s_std,
 };
 
@@ -1982,6 +1893,10 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
 	else
 		chip_cmd(chip, "init", &desc->init);
 
+	v4l2_ctrl_handler_init(&chip->hdl, 5);
+	if (desc->flags & CHIP_HAS_INPUTSEL)
+		v4l2_ctrl_new_std(&chip->hdl, &tvaudio_ctrl_ops,
+			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
 	if (desc->flags & CHIP_HAS_VOLUME) {
 		if (!desc->volfunc) {
 			/* This shouldn't be happen. Warn user, but keep working
@@ -1990,12 +1905,14 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
 			v4l2_info(sd, "volume callback undefined!\n");
 			desc->flags &= ~CHIP_HAS_VOLUME;
 		} else {
-			chip->left  = desc->leftinit  ? desc->leftinit  : 65535;
-			chip->right = desc->rightinit ? desc->rightinit : 65535;
-			chip_write(chip, desc->leftreg,
-				   desc->volfunc(chip->left));
-			chip_write(chip, desc->rightreg,
-				   desc->volfunc(chip->right));
+			chip->volume = v4l2_ctrl_new_std(&chip->hdl,
+				&tvaudio_ctrl_ops, V4L2_CID_AUDIO_VOLUME,
+				0, 65535, 65535 / 100,
+				desc->volinit ? desc->volinit : 65535);
+			chip->balance = v4l2_ctrl_new_std(&chip->hdl,
+				&tvaudio_ctrl_ops, V4L2_CID_AUDIO_BALANCE,
+				0, 65535, 65535 / 100, 32768);
+			v4l2_ctrl_cluster(2, &chip->volume);
 		}
 	}
 	if (desc->flags & CHIP_HAS_BASSTREBLE) {
@@ -2006,17 +1923,28 @@ static int tvaudio_probe(struct i2c_client *client, const struct i2c_device_id *
 			v4l2_info(sd, "bass/treble callbacks undefined!\n");
 			desc->flags &= ~CHIP_HAS_BASSTREBLE;
 		} else {
-			chip->treble = desc->trebleinit ?
-						desc->trebleinit : 32768;
-			chip->bass   = desc->bassinit   ?
-						desc->bassinit   : 32768;
-			chip_write(chip, desc->bassreg,
-				   desc->bassfunc(chip->bass));
-			chip_write(chip, desc->treblereg,
-				   desc->treblefunc(chip->treble));
+			v4l2_ctrl_new_std(&chip->hdl,
+				&tvaudio_ctrl_ops, V4L2_CID_AUDIO_BASS,
+				0, 65535, 65535 / 100,
+				desc->bassinit ? desc->bassinit : 32768);
+			v4l2_ctrl_new_std(&chip->hdl,
+				&tvaudio_ctrl_ops, V4L2_CID_AUDIO_TREBLE,
+				0, 65535, 65535 / 100,
+				desc->trebleinit ? desc->trebleinit : 32768);
 		}
 	}
 
+	sd->ctrl_handler = &chip->hdl;
+	if (chip->hdl.error) {
+		int err = chip->hdl.error;
+
+		v4l2_ctrl_handler_free(&chip->hdl);
+		kfree(chip);
+		return err;
+	}
+	/* set controls to the default values */
+	v4l2_ctrl_handler_setup(&chip->hdl);
+
 	chip->thread = NULL;
 	init_timer(&chip->wt);
 	if (desc->flags & CHIP_NEED_CHECKMODE) {
@@ -2052,6 +1980,7 @@ static int tvaudio_remove(struct i2c_client *client)
 	}
 
 	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&chip->hdl);
 	kfree(chip);
 	return 0;
 }
Signature · 1 line
1.7.0.4
#3 lore raw

PATCH 3/19 cx18: Use the control framework.

In reply to Hans Verkuil
---
 drivers/media/video/cx18/cx18-av-audio.c |   92 ++---------
 drivers/media/video/cx18/cx18-av-core.c  |  162 ++++++-----------
 drivers/media/video/cx18/cx18-av-core.h  |   12 +-
 drivers/media/video/cx18/cx18-controls.c |  285 ++++--------------------------
 drivers/media/video/cx18/cx18-controls.h |    7 +-
 drivers/media/video/cx18/cx18-driver.c   |   30 ++--
 drivers/media/video/cx18/cx18-driver.h   |    2 +-
 drivers/media/video/cx18/cx18-fileops.c  |   32 +---
 drivers/media/video/cx18/cx18-ioctl.c    |   24 +--
 drivers/media/video/cx18/cx18-mailbox.c  |    5 +-
 drivers/media/video/cx18/cx18-mailbox.h  |    5 -
 drivers/media/video/cx18/cx18-streams.c  |   16 +-
 12 files changed, 160 insertions(+), 512 deletions(-)
drivers/media/video/cx18/cx18-av-audio.c +12 -80
index 43d09a2..4a24ffb 100644
@@ -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)
 {
 	/* 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));
 }
 
-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)
 {
 	/* PATH1_EQ_BASS_VOL */
 	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)
 {
 	/* PATH1_EQ_TREBLE_VOL */
 	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)
 {
 	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)
 {
 	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;
 }
 
-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) {
-	case V4L2_CID_AUDIO_VOLUME:
-		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;
-}
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	struct cx18 *cx = v4l2_get_subdevdata(sd);
 
-int cx18_av_audio_s_ctrl(struct cx18 *cx, struct v4l2_control *ctrl)
-{
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_VOLUME:
-		set_volume(cx, ctrl->value);
+		set_volume(cx, ctrl->val);
 		break;
 	case V4L2_CID_AUDIO_BASS:
-		set_bass(cx, ctrl->value);
+		set_bass(cx, ctrl->val);
 		break;
 	case V4L2_CID_AUDIO_TREBLE:
-		set_treble(cx, ctrl->value);
+		set_treble(cx, ctrl->val);
 		break;
 	case V4L2_CID_AUDIO_BALANCE:
-		set_balance(cx, ctrl->value);
+		set_balance(cx, ctrl->val);
 		break;
 	case V4L2_CID_AUDIO_MUTE:
-		set_mute(cx, ctrl->value);
+		set_mute(cx, ctrl->val);
 		break;
 	default:
 		return -EINVAL;
 	}
 	return 0;
 }
+
+const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops = {
+	.s_ctrl = cx18_av_audio_s_ctrl,
+};
drivers/media/video/cx18/cx18-av-core.c +58 -104

220 lines not on this page · raw message

drivers/media/video/cx18/cx18-av-core.h +9 -3
index 1956991..188c9c3 100644
@@ -26,6 +26,7 @@
 #define _CX18_AV_CORE_H_
 
 #include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
 
 struct cx18;
 
@@ -95,13 +96,14 @@ enum cx18_av_audio_input {
 
 struct cx18_av_state {
 	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+	struct v4l2_ctrl *volume;
 	int radio;
 	v4l2_std_id std;
 	enum cx18_av_video_input vid_input;
 	enum cx18_av_audio_input aud_input;
 	u32 audclk_freq;
 	int audmode;
-	int default_volume;
 	u32 id;
 	u32 rev;
 	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);
 }
 
+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 							   */
 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                                                         */
-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);
 void cx18_av_audio_set_path(struct cx18 *cx);
+extern const struct v4l2_ctrl_ops cx18_av_audio_ctrl_ops;
 
 /* ----------------------------------------------------------------------- */
 /* cx18_av-vbi.c                                                           */
drivers/media/video/cx18/cx18-controls.c +33 -252

306 lines not on this page · raw message

drivers/media/video/cx18/cx18-controls.h +1 -6
index e463237..cb5dfc7 100644
@@ -21,9 +21,4 @@
  *  02111-1307  USA
  */
 
-int cx18_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a);
-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);
+extern struct cx2341x_handler_ops cx18_cxhdl_ops;
drivers/media/video/cx18/cx18-driver.c +19 -11
index 98ac2e9..8ea7110 100644
@@ -36,6 +36,7 @@
 #include "cx18-scb.h"
 #include "cx18-mailbox.h"
 #include "cx18-ioctl.h"
+#include "cx18-controls.h"
 #include "tuner-xc2028.h"
 
 #include <media/tveeprom.h>
@@ -720,15 +721,21 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
 	cx->open_id = 1;
 
 	/* Initial settings */
-	cx2341x_fill_defaults(&cx->params);
-	cx->temporal_strength = cx->params.video_temporal_filter;
-	cx->spatial_strength = cx->params.video_spatial_filter;
-	cx->filter_mode = cx->params.video_spatial_filter_mode |
-		(cx->params.video_temporal_filter_mode << 1) |
-		(cx->params.video_median_filter_type << 2);
-	cx->params.port = CX2341X_PORT_MEMORY;
-	cx->params.capabilities =
-				CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI;
+	cx->cxhdl.port = CX2341X_PORT_MEMORY;
+	cx->cxhdl.capabilities = CX2341X_CAP_HAS_TS | CX2341X_CAP_HAS_SLICED_VBI;
+	cx->cxhdl.ops = &cx18_cxhdl_ops;
+	cx->cxhdl.func = cx18_api_func;
+	ret = cx2341x_handler_init(&cx->cxhdl, 50);
+	if (ret)
+		return ret;
+	cx->v4l2_dev.ctrl_handler = &cx->cxhdl.hdl;
+
+	cx->temporal_strength = cx->cxhdl.video_temporal_filter->cur.val;
+	cx->spatial_strength = cx->cxhdl.video_spatial_filter->cur.val;
+	cx->filter_mode = cx->cxhdl.video_spatial_filter_mode->cur.val |
+		(cx->cxhdl.video_temporal_filter_mode->cur.val << 1) |
+		(cx->cxhdl.video_median_filter_type->cur.val << 2);
+
 	init_waitqueue_head(&cx->cap_w);
 	init_waitqueue_head(&cx->mb_apu_waitq);
 	init_waitqueue_head(&cx->mb_cpu_waitq);
@@ -1035,7 +1042,7 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
 	else
 		cx->is_50hz = 1;
 
-	cx->params.video_gop_size = cx->is_60hz ? 15 : 12;
+	cx2341x_handler_set_50hz(&cx->cxhdl, !cx->is_60hz);
 
 	if (cx->options.radio > 0)
 		cx->v4l2_cap |= V4L2_CAP_RADIO;
@@ -1081,7 +1088,6 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
 
 	/* Load cx18 submodules (cx18-alsa) */
 	request_modules(cx);
-
 	return 0;
 
 free_streams:
@@ -1264,6 +1270,8 @@ static void cx18_remove(struct pci_dev *pci_dev)
 		for (i = 0; i < CX18_VBI_FRAMES; i++)
 			kfree(cx->vbi.sliced_mpeg_data[i]);
 
+	v4l2_ctrl_handler_free(&cx->av_state.hdl);
+
 	CX18_INFO("Removed %s\n", cx->card_name);
 
 	v4l2_device_unregister(v4l2_dev);
drivers/media/video/cx18/cx18-driver.h +1 -1
index cf4f20e..cbd2753 100644
@@ -563,7 +563,7 @@ struct cx18 {
 	struct cx18_av_state av_state;
 
 	/* codec settings */
-	struct cx2341x_mpeg_params params;
+	struct cx2341x_handler cxhdl;
 	u32 filter_mode;
 	u32 temporal_strength;
 	u32 spatial_strength;
drivers/media/video/cx18/cx18-fileops.c +7 -25
index 9f23b90..98ef33e 100644
@@ -160,13 +160,10 @@ EXPORT_SYMBOL(cx18_release_stream);
 static void cx18_dualwatch(struct cx18 *cx)
 {
 	struct v4l2_tuner vt;
-	u32 new_bitmap;
 	u32 new_stereo_mode;
-	const u32 stereo_mask = 0x0300;
 	const u32 dual = 0x0200;
-	u32 h;
 
-	new_stereo_mode = cx->params.audio_properties & stereo_mask;
+	new_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode);
 	memset(&vt, 0, sizeof(vt));
 	cx18_call_all(cx, tuner, g_tuner, &vt);
 	if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 &&
@@ -176,25 +173,10 @@ static void cx18_dualwatch(struct cx18 *cx)
 	if (new_stereo_mode == cx->dualwatch_stereo_mode)
 		return;
 
-	new_bitmap = new_stereo_mode
-			| (cx->params.audio_properties & ~stereo_mask);
-
-	CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. "
-			"new audio_bitmask=0x%ux\n",
-			cx->dualwatch_stereo_mode, new_stereo_mode, new_bitmap);
-
-	h = cx18_find_handle(cx);
-	if (h == CX18_INVALID_TASK_HANDLE) {
-		CX18_DEBUG_INFO("dualwatch: can't find valid task handle\n");
-		return;
-	}
-
-	if (cx18_vapi(cx,
-		      CX18_CPU_SET_AUDIO_PARAMETERS, 2, h, new_bitmap) == 0) {
-		cx->dualwatch_stereo_mode = new_stereo_mode;
-		return;
-	}
-	CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
+	CX18_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n",
+			   cx->dualwatch_stereo_mode, new_stereo_mode);
+	if (v4l2_ctrl_s_ctrl(cx->cxhdl.audio_mode, new_stereo_mode))
+		CX18_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
 }
 
 
@@ -724,8 +706,8 @@ int cx18_v4l2_close(struct file *filp)
 		if (atomic_read(&cx->ana_capturing) > 0) {
 			/* Undo video mute */
 			cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
-				cx->params.video_mute |
-					(cx->params.video_mute_yuv << 8));
+			    (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute) |
+			    (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8)));
 		}
 		/* Done! Unmute and continue. */
 		cx18_unmute(cx);
drivers/media/video/cx18/cx18-ioctl.c +10 -14
index 7150195..36b018c 100644
@@ -152,8 +152,8 @@ static int cx18_g_fmt_vid_cap(struct file *file, void *fh,
 	struct cx18 *cx = id->cx;
 	struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
 
-	pixfmt->width = cx->params.width;
-	pixfmt->height = cx->params.height;
+	pixfmt->width = cx->cxhdl.width;
+	pixfmt->height = cx->cxhdl.height;
 	pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
 	pixfmt->field = V4L2_FIELD_INTERLACED;
 	pixfmt->priv = 0;
@@ -287,14 +287,14 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
 	w = fmt->fmt.pix.width;
 	h = fmt->fmt.pix.height;
 
-	if (cx->params.width == w && cx->params.height == h)
+	if (cx->cxhdl.width == w && cx->cxhdl.height == h)
 		return 0;
 
 	if (atomic_read(&cx->ana_capturing) > 0)
 		return -EBUSY;
 
-	mbus_fmt.width = cx->params.width = w;
-	mbus_fmt.height = cx->params.height = h;
+	mbus_fmt.width = cx->cxhdl.width = w;
+	mbus_fmt.height = cx->cxhdl.height = h;
 	mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
 	v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt);
 	return cx18_g_fmt_vid_cap(file, fh, fmt);
@@ -696,9 +696,10 @@ int cx18_s_std(struct file *file, void *fh, v4l2_std_id *std)
 
 	cx->std = *std;
 	cx->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
-	cx->params.is_50hz = cx->is_50hz = !cx->is_60hz;
-	cx->params.width = 720;
-	cx->params.height = cx->is_50hz ? 576 : 480;
+	cx->is_50hz = !cx->is_60hz;
+	cx2341x_handler_set_50hz(&cx->cxhdl, cx->is_50hz);
+	cx->cxhdl.width = 720;
+	cx->cxhdl.height = cx->is_50hz ? 576 : 480;
 	cx->vbi.count = cx->is_50hz ? 18 : 12;
 	cx->vbi.start[0] = cx->is_50hz ? 6 : 10;
 	cx->vbi.start[1] = cx->is_50hz ? 318 : 273;
@@ -1035,7 +1036,7 @@ static int cx18_log_status(struct file *file, void *fh)
 	mutex_unlock(&cx->gpio_lock);
 	CX18_INFO("Tuner: %s\n",
 		test_bit(CX18_F_I_RADIO_USER, &cx->i_flags) ?  "Radio" : "TV");
-	cx2341x_log_status(&cx->params, cx->v4l2_dev.name);
+	v4l2_ctrl_handler_log_status(&cx->cxhdl.hdl, cx->v4l2_dev.name);
 	CX18_INFO("Status flags: 0x%08lx\n", cx->i_flags);
 	for (i = 0; i < CX18_MAX_STREAMS; i++) {
 		struct cx18_stream *s = &cx->streams[i];
@@ -1136,11 +1137,6 @@ static const struct v4l2_ioctl_ops cx18_ioctl_ops = {
 	.vidioc_s_register              = cx18_s_register,
 #endif
 	.vidioc_default                 = cx18_default,
-	.vidioc_queryctrl               = cx18_queryctrl,
-	.vidioc_querymenu               = cx18_querymenu,
-	.vidioc_g_ext_ctrls             = cx18_g_ext_ctrls,
-	.vidioc_s_ext_ctrls             = cx18_s_ext_ctrls,
-	.vidioc_try_ext_ctrls           = cx18_try_ext_ctrls,
 };
 
 void cx18_set_funcs(struct video_device *vdev)
drivers/media/video/cx18/cx18-mailbox.c +2 -3
index 956aa19..d366d65 100644
@@ -716,9 +716,8 @@ static int cx18_set_filter_param(struct cx18_stream *s)
 int cx18_api_func(void *priv, u32 cmd, int in, int out,
 		u32 data[CX2341X_MBOX_MAX_DATA])
 {
-	struct cx18_api_func_private *api_priv = priv;
-	struct cx18 *cx = api_priv->cx;
-	struct cx18_stream *s = api_priv->s;
+	struct cx18_stream *s = priv;
+	struct cx18 *cx = s->cx;
 
 	switch (cmd) {
 	case CX2341X_ENC_SET_OUTPUT_PORT:
drivers/media/video/cx18/cx18-mailbox.h +0 -5
index 077952f..05fe6bd 100644
@@ -81,11 +81,6 @@ struct cx18_mailbox {
 
 struct cx18_stream;
 
-struct cx18_api_func_private {
-	struct cx18 *cx;
-	struct cx18_stream *s;
-};
-
 int cx18_api(struct cx18 *cx, u32 cmd, int args, u32 data[]);
 int cx18_vapi_result(struct cx18 *cx, u32 data[MAX_MB_ARGUMENTS], u32 cmd,
 		int args, ...);
drivers/media/video/cx18/cx18-streams.c +8 -8
index 9045f1e..d0c923e 100644
@@ -555,7 +555,7 @@ static void cx18_stream_configure_mdls(struct cx18_stream *s)
 		 * Set the MDL size to the exact size needed for one frame.
 		 * Use enough buffers per MDL to cover the MDL size
 		 */
-		s->mdl_size = 720 * s->cx->params.height * 3 / 2;
+		s->mdl_size = 720 * s->cx->cxhdl.height * 3 / 2;
 		s->bufs_per_mdl = s->mdl_size / s->buf_size;
 		if (s->mdl_size % s->buf_size)
 			s->bufs_per_mdl++;
@@ -590,7 +590,6 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
 	u32 data[MAX_MB_ARGUMENTS];
 	struct cx18 *cx = s->cx;
 	int captype = 0;
-	struct cx18_api_func_private priv;
 	struct cx18_stream *s_idx;
 
 	if (!cx18_stream_enabled(s))
@@ -603,7 +602,7 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
 		captype = CAPTURE_CHANNEL_TYPE_MPEG;
 		cx->mpg_data_received = cx->vbi_data_inserted = 0;
 		cx->dualwatch_jiffies = jiffies;
-		cx->dualwatch_stereo_mode = cx->params.audio_properties & 0x300;
+		cx->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(cx->cxhdl.audio_mode);
 		cx->search_pack_header = 0;
 		break;
 
@@ -693,21 +692,21 @@ int cx18_start_v4l2_encode_stream(struct cx18_stream *s)
 				 s->handle, cx18_stream_enabled(s_idx) ? 7 : 0);
 
 		/* Call out to the common CX2341x API setup for user controls */
-		priv.cx = cx;
-		priv.s = s;
-		cx2341x_update(&priv, cx18_api_func, NULL, &cx->params);
+		cx->cxhdl.priv = s;
+		cx2341x_handler_setup(&cx->cxhdl);
 
 		/*
 		 * When starting a capture and we're set for radio,
 		 * ensure the video is muted, despite the user control.
 		 */
-		if (!cx->params.video_mute &&
+		if (!cx->cxhdl.video_mute &&
 		    test_bit(CX18_F_I_RADIO_USER, &cx->i_flags))
 			cx18_vapi(cx, CX18_CPU_SET_VIDEO_MUTE, 2, s->handle,
-				  (cx->params.video_mute_yuv << 8) | 1);
+			  (v4l2_ctrl_g_ctrl(cx->cxhdl.video_mute_yuv) << 8) | 1);
 	}
 
 	if (atomic_read(&cx->tot_capturing) == 0) {
+		cx2341x_handler_set_busy(&cx->cxhdl, 1);
 		clear_bit(CX18_F_I_EOS, &cx->i_flags);
 		cx18_write_reg(cx, 7, CX18_DSP0_INTERRUPT_MASK);
 	}
@@ -809,6 +808,7 @@ int cx18_stop_v4l2_encode_stream(struct cx18_stream *s, int gop_end)
 	if (atomic_read(&cx->tot_capturing) > 0)
 		return 0;
 
+	cx2341x_handler_set_busy(&cx->cxhdl, 0);
 	cx18_write_reg(cx, 5, CX18_DSP0_INTERRUPT_MASK);
 	wake_up(&s->waitq);
 
Signature · 1 line
1.7.0.4
#4 lore raw

PATCH 4/19 adv7343: use control framework

In reply to Hans Verkuil

Also fixed a memory leak in the probe function if an error occurred. The gain control range was also fixed (a proper range from -64 to 64).

---
 drivers/media/video/adv7343.c      |  167 +++++++++++++-----------------------
 drivers/media/video/adv7343_regs.h |    8 +--
 2 files changed, 63 insertions(+), 112 deletions(-)
drivers/media/video/adv7343.c +61 -106
index 41b2930..021fab2 100644
@@ -29,6 +29,7 @@
 #include <media/adv7343.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
 
 #include "adv7343_regs.h"
 
@@ -41,15 +42,13 @@ MODULE_PARM_DESC(debug, "Debug level 0-1");
 
 struct adv7343_state {
 	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
 	u8 reg00;
 	u8 reg01;
 	u8 reg02;
 	u8 reg35;
 	u8 reg80;
 	u8 reg82;
-	int bright;
-	int hue;
-	int gain;
 	u32 output;
 	v4l2_std_id std;
 };
@@ -59,6 +58,11 @@ static inline struct adv7343_state *to_state(struct v4l2_subdev *sd)
 	return container_of(sd, struct adv7343_state, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct adv7343_state, hdl)->sd;
+}
+
 static inline int adv7343_write(struct v4l2_subdev *sd, u8 reg, u8 value)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -268,111 +272,22 @@ static int adv7343_log_status(struct v4l2_subdev *sd)
 	return 0;
 }
 
-static int adv7343_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
-	switch (qc->id) {
-	case V4L2_CID_BRIGHTNESS:
-		return v4l2_ctrl_query_fill(qc, ADV7343_BRIGHTNESS_MIN,
-						ADV7343_BRIGHTNESS_MAX, 1,
-						ADV7343_BRIGHTNESS_DEF);
-	case V4L2_CID_HUE:
-		return v4l2_ctrl_query_fill(qc, ADV7343_HUE_MIN,
-						ADV7343_HUE_MAX, 1 ,
-						ADV7343_HUE_DEF);
-	case V4L2_CID_GAIN:
-		return v4l2_ctrl_query_fill(qc, ADV7343_GAIN_MIN,
-						ADV7343_GAIN_MAX, 1,
-						ADV7343_GAIN_DEF);
-	default:
-		break;
-	}
-
-	return 0;
-}
-
-static int adv7343_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-	struct adv7343_state *state = to_state(sd);
-	int err = 0;
-
-	switch (ctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-		if (ctrl->value < ADV7343_BRIGHTNESS_MIN ||
-					ctrl->value > ADV7343_BRIGHTNESS_MAX) {
-			v4l2_dbg(1, debug, sd,
-					"invalid brightness settings %d\n",
-								ctrl->value);
-			return -ERANGE;
-		}
-
-		state->bright = ctrl->value;
-		err = adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS,
-					state->bright);
-		break;
-
-	case V4L2_CID_HUE:
-		if (ctrl->value < ADV7343_HUE_MIN ||
-					ctrl->value > ADV7343_HUE_MAX) {
-			v4l2_dbg(1, debug, sd, "invalid hue settings %d\n",
-								ctrl->value);
-			return -ERANGE;
-		}
-
-		state->hue = ctrl->value;
-		err = adv7343_write(sd, ADV7343_SD_HUE_REG, state->hue);
-		break;
-
-	case V4L2_CID_GAIN:
-		if (ctrl->value < ADV7343_GAIN_MIN ||
-					ctrl->value > ADV7343_GAIN_MAX) {
-			v4l2_dbg(1, debug, sd, "invalid gain settings %d\n",
-								ctrl->value);
-			return -ERANGE;
-		}
-
-		if ((ctrl->value > POSITIVE_GAIN_MAX) &&
-			(ctrl->value < NEGATIVE_GAIN_MIN)) {
-			v4l2_dbg(1, debug, sd,
-				"gain settings not within the specified range\n");
-			return -ERANGE;
-		}
-
-		state->gain = ctrl->value;
-		err = adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, state->gain);
-		break;
-
-	default:
-		return -EINVAL;
-	}
-
-	if (err < 0)
-		v4l2_err(sd, "Failed to set the encoder controls\n");
-
-	return err;
-}
-
-static int adv7343_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int adv7343_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	struct adv7343_state *state = to_state(sd);
+	struct v4l2_subdev *sd = to_sd(ctrl);
 
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		ctrl->value = state->bright;
-		break;
+		return adv7343_write(sd, ADV7343_SD_BRIGHTNESS_WSS,
+					ctrl->val);
 
 	case V4L2_CID_HUE:
-		ctrl->value = state->hue;
-		break;
+		return adv7343_write(sd, ADV7343_SD_HUE_REG, ctrl->val);
 
 	case V4L2_CID_GAIN:
-		ctrl->value = state->gain;
-		break;
-
-	default:
-		return -EINVAL;
+		return adv7343_write(sd, ADV7343_DAC2_OUTPUT_LEVEL, ctrl->val);
 	}
-
-	return 0;
+	return -EINVAL;
 }
 
 static int adv7343_g_chip_ident(struct v4l2_subdev *sd,
@@ -383,12 +298,20 @@ static int adv7343_g_chip_ident(struct v4l2_subdev *sd,
 	return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7343, 0);
 }
 
+static const struct v4l2_ctrl_ops adv7343_ctrl_ops = {
+	.s_ctrl = adv7343_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops adv7343_core_ops = {
-	.log_status	= adv7343_log_status,
-	.g_chip_ident	= adv7343_g_chip_ident,
-	.g_ctrl		= adv7343_g_ctrl,
-	.s_ctrl		= adv7343_s_ctrl,
-	.queryctrl	= adv7343_queryctrl,
+	.log_status = adv7343_log_status,
+	.g_chip_ident = adv7343_g_chip_ident,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
 };
 
 static int adv7343_s_std_output(struct v4l2_subdev *sd, v4l2_std_id std)
@@ -468,6 +391,7 @@ static int adv7343_probe(struct i2c_client *client,
 				const struct i2c_device_id *id)
 {
 	struct adv7343_state *state;
+	int err;
 
 	if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
 		return -ENODEV;
@@ -490,15 +414,46 @@ static int adv7343_probe(struct i2c_client *client,
 	state->std = V4L2_STD_NTSC;
 
 	v4l2_i2c_subdev_init(&state->sd, client, &adv7343_ops);
-	return adv7343_initialize(&state->sd);
+
+	v4l2_ctrl_handler_init(&state->hdl, 2);
+	v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, ADV7343_BRIGHTNESS_MIN,
+					     ADV7343_BRIGHTNESS_MAX, 1,
+					     ADV7343_BRIGHTNESS_DEF);
+	v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops,
+			V4L2_CID_HUE, ADV7343_HUE_MIN,
+				      ADV7343_HUE_MAX, 1,
+				      ADV7343_HUE_DEF);
+	v4l2_ctrl_new_std(&state->hdl, &adv7343_ctrl_ops,
+			V4L2_CID_GAIN, ADV7343_GAIN_MIN,
+				       ADV7343_GAIN_MAX, 1,
+				       ADV7343_GAIN_DEF);
+	state->sd.ctrl_handler = &state->hdl;
+	if (state->hdl.error) {
+		int err = state->hdl.error;
+
+		v4l2_ctrl_handler_free(&state->hdl);
+		kfree(state);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&state->hdl);
+
+	err = adv7343_initialize(&state->sd);
+	if (err) {
+		v4l2_ctrl_handler_free(&state->hdl);
+		kfree(state);
+	}
+	return err;
 }
 
 static int adv7343_remove(struct i2c_client *client)
 {
 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct adv7343_state *state = to_state(sd);
 
 	v4l2_device_unregister_subdev(sd);
-	kfree(to_state(sd));
+	v4l2_ctrl_handler_free(&state->hdl);
+	kfree(state);
 
 	return 0;
 }
drivers/media/video/adv7343_regs.h +2 -6
index 3431045..4466067 100644
@@ -102,10 +102,6 @@ struct adv7343_std_info {
 
 /* Bit masks for DAC output levels */
 #define DAC_OUTPUT_LEVEL_MASK		(0xFF)
-#define POSITIVE_GAIN_MAX		(0x40)
-#define POSITIVE_GAIN_MIN		(0x00)
-#define NEGATIVE_GAIN_MAX		(0xFF)
-#define NEGATIVE_GAIN_MIN		(0xC0)
 
 /* Bit masks for soft reset register */
 #define SOFT_RESET			(0x02)
@@ -178,8 +174,8 @@ struct adv7343_std_info {
 #define ADV7343_HUE_MAX		(255)
 #define ADV7343_HUE_MIN		(0)
 #define ADV7343_HUE_DEF		(127)
-#define ADV7343_GAIN_MAX	(255)
-#define ADV7343_GAIN_MIN	(0)
+#define ADV7343_GAIN_MAX	(64)
+#define ADV7343_GAIN_MIN	(-64)
 #define ADV7343_GAIN_DEF	(0)
 
 #endif
Signature · 1 line
1.7.0.4
#5 lore raw

PATCH 5/19 bt819: use control framework

In reply to Hans Verkuil
---
 drivers/media/video/bt819.c |  129 ++++++++++++++++--------------------------
 1 files changed, 49 insertions(+), 80 deletions(-)
drivers/media/video/bt819.c +49 -80
index c38300f..f872044 100644
@@ -37,6 +37,7 @@
 #include <linux/slab.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
 #include <media/bt819.h>
 
 MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
@@ -52,16 +53,13 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 struct bt819 {
 	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
 	unsigned char reg[32];
 
 	v4l2_std_id norm;
 	int ident;
 	int input;
 	int enable;
-	int bright;
-	int contrast;
-	int hue;
-	int sat;
 };
 
 static inline struct bt819 *to_bt819(struct v4l2_subdev *sd)
@@ -69,6 +67,11 @@ static inline struct bt819 *to_bt819(struct v4l2_subdev *sd)
 	return container_of(sd, struct bt819, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct bt819, hdl)->sd;
+}
+
 struct timing {
 	int hactive;
 	int hdelay;
@@ -333,71 +336,35 @@ static int bt819_s_stream(struct v4l2_subdev *sd, int enable)
 	return 0;
 }
 
-static int bt819_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
-	switch (qc->id) {
-	case V4L2_CID_BRIGHTNESS:
-		v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
-		break;
-
-	case V4L2_CID_CONTRAST:
-		v4l2_ctrl_query_fill(qc, 0, 511, 1, 256);
-		break;
-
-	case V4L2_CID_SATURATION:
-		v4l2_ctrl_query_fill(qc, 0, 511, 1, 256);
-		break;
-
-	case V4L2_CID_HUE:
-		v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
-		break;
-
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int bt819_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int bt819_s_ctrl(struct v4l2_ctrl *ctrl)
 {
+	struct v4l2_subdev *sd = to_sd(ctrl);
 	struct bt819 *decoder = to_bt819(sd);
 	int temp;
 
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		if (decoder->bright == ctrl->value)
-			break;
-		decoder->bright = ctrl->value;
-		bt819_write(decoder, 0x0a, decoder->bright);
+		bt819_write(decoder, 0x0a, ctrl->val);
 		break;
 
 	case V4L2_CID_CONTRAST:
-		if (decoder->contrast == ctrl->value)
-			break;
-		decoder->contrast = ctrl->value;
-		bt819_write(decoder, 0x0c, decoder->contrast & 0xff);
-		bt819_setbit(decoder, 0x0b, 2, ((decoder->contrast >> 8) & 0x01));
+		bt819_write(decoder, 0x0c, ctrl->val & 0xff);
+		bt819_setbit(decoder, 0x0b, 2, ((ctrl->val >> 8) & 0x01));
 		break;
 
 	case V4L2_CID_SATURATION:
-		if (decoder->sat == ctrl->value)
-			break;
-		decoder->sat = ctrl->value;
-		bt819_write(decoder, 0x0d, (decoder->sat >> 7) & 0xff);
-		bt819_setbit(decoder, 0x0b, 1, ((decoder->sat >> 15) & 0x01));
+		bt819_write(decoder, 0x0d, (ctrl->val >> 7) & 0xff);
+		bt819_setbit(decoder, 0x0b, 1, ((ctrl->val >> 15) & 0x01));
 
 		/* Ratio between U gain and V gain must stay the same as
 		   the ratio between the default U and V gain values. */
-		temp = (decoder->sat * 180) / 254;
+		temp = (ctrl->val * 180) / 254;
 		bt819_write(decoder, 0x0e, (temp >> 7) & 0xff);
 		bt819_setbit(decoder, 0x0b, 0, (temp >> 15) & 0x01);
 		break;
 
 	case V4L2_CID_HUE:
-		if (decoder->hue == ctrl->value)
-			break;
-		decoder->hue = ctrl->value;
-		bt819_write(decoder, 0x0f, decoder->hue);
+		bt819_write(decoder, 0x0f, ctrl->val);
 		break;
 
 	default:
@@ -406,29 +373,6 @@ static int bt819_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
 	return 0;
 }
 
-static int bt819_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-	struct bt819 *decoder = to_bt819(sd);
-
-	switch (ctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-		ctrl->value = decoder->bright;
-		break;
-	case V4L2_CID_CONTRAST:
-		ctrl->value = decoder->contrast;
-		break;
-	case V4L2_CID_SATURATION:
-		ctrl->value = decoder->sat;
-		break;
-	case V4L2_CID_HUE:
-		ctrl->value = decoder->hue;
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
 static int bt819_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
 {
 	struct bt819 *decoder = to_bt819(sd);
@@ -439,11 +383,19 @@ static int bt819_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident
 
 /* ----------------------------------------------------------------------- */
 
+static const struct v4l2_ctrl_ops bt819_ctrl_ops = {
+	.s_ctrl = bt819_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops bt819_core_ops = {
 	.g_chip_ident = bt819_g_chip_ident,
-	.g_ctrl = bt819_g_ctrl,
-	.s_ctrl = bt819_s_ctrl,
-	.queryctrl = bt819_queryctrl,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
 	.s_std = bt819_s_std,
 };
 
@@ -505,23 +457,40 @@ static int bt819_probe(struct i2c_client *client,
 	decoder->norm = V4L2_STD_NTSC;
 	decoder->input = 0;
 	decoder->enable = 1;
-	decoder->bright = 0;
-	decoder->contrast = 0xd8;	/* 100% of original signal */
-	decoder->hue = 0;
-	decoder->sat = 0xfe;		/* 100% of original signal */
 
 	i = bt819_init(sd);
 	if (i < 0)
 		v4l2_dbg(1, debug, sd, "init status %d\n", i);
+
+	v4l2_ctrl_handler_init(&decoder->hdl, 4);
+	v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
+	v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 511, 1, 0xd8);
+	v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 511, 1, 0xfe);
+	v4l2_ctrl_new_std(&decoder->hdl, &bt819_ctrl_ops,
+			V4L2_CID_HUE, -128, 127, 1, 0);
+	sd->ctrl_handler = &decoder->hdl;
+	if (decoder->hdl.error) {
+		int err = decoder->hdl.error;
+
+		v4l2_ctrl_handler_free(&decoder->hdl);
+		kfree(decoder);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&decoder->hdl);
 	return 0;
 }
 
 static int bt819_remove(struct i2c_client *client)
 {
 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct bt819 *decoder = to_bt819(sd);
 
 	v4l2_device_unregister_subdev(sd);
-	kfree(to_bt819(sd));
+	v4l2_ctrl_handler_free(&decoder->hdl);
+	kfree(decoder);
 	return 0;
 }
 
Signature · 1 line
1.7.0.4
#6 lore raw

PATCH 6/19 ov7670: use the control framework

In reply to Hans Verkuil
---
 drivers/media/video/ov7670.c |  296 ++++++++++++++++-------------------------
 1 files changed, 116 insertions(+), 180 deletions(-)
drivers/media/video/ov7670.c +116 -180
index c881a64..9d6458f 100644
@@ -19,6 +19,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-mediabus.h>
+#include <media/v4l2-ctrls.h>
 
 #include "ov7670.h"
 
@@ -191,9 +192,23 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 struct ov7670_format_struct;  /* coming later */
 struct ov7670_info {
 	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
+	struct {
+		/* gain cluster */
+		struct v4l2_ctrl *auto_gain;
+		struct v4l2_ctrl *gain;
+	};
+	struct {
+		/* exposure cluster */
+		struct v4l2_ctrl *auto_exposure;
+		struct v4l2_ctrl *exposure;
+	};
+	struct {
+		/* saturation/hue cluster */
+		struct v4l2_ctrl *saturation;
+		struct v4l2_ctrl *hue;
+	};
 	struct ov7670_format_struct *fmt;  /* Current format */
-	unsigned char sat;		/* Saturation value */
-	int hue;			/* Hue value */
 	int min_width;			/* Filter out smaller sizes */
 	int min_height;			/* Filter out smaller sizes */
 	int clock_speed;		/* External clock speed (MHz) */
@@ -206,6 +221,11 @@ static inline struct ov7670_info *to_state(struct v4l2_subdev *sd)
 	return container_of(sd, struct ov7670_info, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct ov7670_info, hdl)->sd;
+}
+
 
 
 /*
@@ -1043,23 +1063,23 @@ static int ov7670_cosine(int theta)
 
 
 static void ov7670_calc_cmatrix(struct ov7670_info *info,
-		int matrix[CMATRIX_LEN])
+		int matrix[CMATRIX_LEN], int sat, int hue)
 {
 	int i;
 	/*
 	 * Apply the current saturation setting first.
 	 */
 	for (i = 0; i < CMATRIX_LEN; i++)
-		matrix[i] = (info->fmt->cmatrix[i]*info->sat) >> 7;
+		matrix[i] = (info->fmt->cmatrix[i] * sat) >> 7;
 	/*
 	 * Then, if need be, rotate the hue value.
 	 */
-	if (info->hue != 0) {
+	if (hue != 0) {
 		int sinth, costh, tmpmatrix[CMATRIX_LEN];
 
 		memcpy(tmpmatrix, matrix, CMATRIX_LEN*sizeof(int));
-		sinth = ov7670_sine(info->hue);
-		costh = ov7670_cosine(info->hue);
+		sinth = ov7670_sine(hue);
+		costh = ov7670_cosine(hue);
 
 		matrix[0] = (matrix[3]*sinth + matrix[0]*costh)/1000;
 		matrix[1] = (matrix[4]*sinth + matrix[1]*costh)/1000;
@@ -1072,60 +1092,21 @@ static void ov7670_calc_cmatrix(struct ov7670_info *info,
 
 
 
-static int ov7670_s_sat(struct v4l2_subdev *sd, int value)
-{
-	struct ov7670_info *info = to_state(sd);
-	int matrix[CMATRIX_LEN];
-	int ret;
-
-	info->sat = value;
-	ov7670_calc_cmatrix(info, matrix);
-	ret = ov7670_store_cmatrix(sd, matrix);
-	return ret;
-}
-
-static int ov7670_g_sat(struct v4l2_subdev *sd, __s32 *value)
-{
-	struct ov7670_info *info = to_state(sd);
-
-	*value = info->sat;
-	return 0;
-}
-
-static int ov7670_s_hue(struct v4l2_subdev *sd, int value)
+static int ov7670_s_sat_hue(struct v4l2_subdev *sd, int sat, int hue)
 {
 	struct ov7670_info *info = to_state(sd);
 	int matrix[CMATRIX_LEN];
 	int ret;
 
-	if (value < -180 || value > 180)
-		return -EINVAL;
-	info->hue = value;
-	ov7670_calc_cmatrix(info, matrix);
+	ov7670_calc_cmatrix(info, matrix, sat, hue);
 	ret = ov7670_store_cmatrix(sd, matrix);
 	return ret;
 }
 
 
-static int ov7670_g_hue(struct v4l2_subdev *sd, __s32 *value)
-{
-	struct ov7670_info *info = to_state(sd);
-
-	*value = info->hue;
-	return 0;
-}
-
-
 /*
  * Some weird registers seem to store values in a sign/magnitude format!
  */
-static unsigned char ov7670_sm_to_abs(unsigned char v)
-{
-	if ((v & 0x80) == 0)
-		return v + 128;
-	return 128 - (v & 0x7f);
-}
-
 
 static unsigned char ov7670_abs_to_sm(unsigned char v)
 {
@@ -1147,40 +1128,11 @@ static int ov7670_s_brightness(struct v4l2_subdev *sd, int value)
 	return ret;
 }
 
-static int ov7670_g_brightness(struct v4l2_subdev *sd, __s32 *value)
-{
-	unsigned char v = 0;
-	int ret = ov7670_read(sd, REG_BRIGHT, &v);
-
-	*value = ov7670_sm_to_abs(v);
-	return ret;
-}
-
 static int ov7670_s_contrast(struct v4l2_subdev *sd, int value)
 {
 	return ov7670_write(sd, REG_CONTRAS, (unsigned char) value);
 }
 
-static int ov7670_g_contrast(struct v4l2_subdev *sd, __s32 *value)
-{
-	unsigned char v = 0;
-	int ret = ov7670_read(sd, REG_CONTRAS, &v);
-
-	*value = v;
-	return ret;
-}
-
-static int ov7670_g_hflip(struct v4l2_subdev *sd, __s32 *value)
-{
-	int ret;
-	unsigned char v = 0;
-
-	ret = ov7670_read(sd, REG_MVFP, &v);
-	*value = (v & MVFP_MIRROR) == MVFP_MIRROR;
-	return ret;
-}
-
-
 static int ov7670_s_hflip(struct v4l2_subdev *sd, int value)
 {
 	unsigned char v = 0;
@@ -1196,19 +1148,6 @@ static int ov7670_s_hflip(struct v4l2_subdev *sd, int value)
 	return ret;
 }
 
-
-
-static int ov7670_g_vflip(struct v4l2_subdev *sd, __s32 *value)
-{
-	int ret;
-	unsigned char v = 0;
-
-	ret = ov7670_read(sd, REG_MVFP, &v);
-	*value = (v & MVFP_FLIP) == MVFP_FLIP;
-	return ret;
-}
-
-
 static int ov7670_s_vflip(struct v4l2_subdev *sd, int value)
 {
 	unsigned char v = 0;
@@ -1244,6 +1183,7 @@ static int ov7670_s_gain(struct v4l2_subdev *sd, int value)
 {
 	int ret;
 	unsigned char com8;
+	struct ov7670_info *info = to_state(sd);
 
 	ret = ov7670_write(sd, REG_GAIN, value & 0xff);
 	/* Have to turn off AGC as well */
@@ -1251,22 +1191,14 @@ static int ov7670_s_gain(struct v4l2_subdev *sd, int value)
 		ret = ov7670_read(sd, REG_COM8, &com8);
 		ret = ov7670_write(sd, REG_COM8, com8 & ~COM8_AGC);
 	}
+	if (ret == 0)
+		info->auto_gain->cur.val = 0;
 	return ret;
 }
 
 /*
  * Tweak autogain.
  */
-static int ov7670_g_autogain(struct v4l2_subdev *sd, __s32 *value)
-{
-	int ret;
-	unsigned char com8;
-
-	ret = ov7670_read(sd, REG_COM8, &com8);
-	*value = (com8 & COM8_AGC) != 0;
-	return ret;
-}
-
 static int ov7670_s_autogain(struct v4l2_subdev *sd, int value)
 {
 	int ret;
@@ -1303,6 +1235,7 @@ static int ov7670_s_exp(struct v4l2_subdev *sd, int value)
 {
 	int ret;
 	unsigned char com1, com8, aech, aechh;
+	struct ov7670_info *info = to_state(sd);
 
 	ret = ov7670_read(sd, REG_COM1, &com1) +
 		ov7670_read(sd, REG_COM8, &com8);
@@ -1319,26 +1252,14 @@ static int ov7670_s_exp(struct v4l2_subdev *sd, int value)
 	/* Have to turn off AEC as well */
 	if (ret == 0)
 		ret = ov7670_write(sd, REG_COM8, com8 & ~COM8_AEC);
+	if (ret == 0)
+		info->auto_exposure->cur.val = 0;
 	return ret;
 }
 
 /*
  * Tweak autoexposure.
  */
-static int ov7670_g_autoexp(struct v4l2_subdev *sd, __s32 *value)
-{
-	int ret;
-	unsigned char com8;
-	enum v4l2_exposure_auto_type *atype = (enum v4l2_exposure_auto_type *) value;
-
-	ret = ov7670_read(sd, REG_COM8, &com8);
-	if (com8 & COM8_AEC)
-		*atype = V4L2_EXPOSURE_AUTO;
-	else
-		*atype = V4L2_EXPOSURE_MANUAL;
-	return ret;
-}
-
 static int ov7670_s_autoexp(struct v4l2_subdev *sd,
 		enum v4l2_exposure_auto_type value)
 {
@@ -1357,90 +1278,64 @@ static int ov7670_s_autoexp(struct v4l2_subdev *sd,
 }
 
 
-
-static int ov7670_queryctrl(struct v4l2_subdev *sd,
-		struct v4l2_queryctrl *qc)
+static int ov7670_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
 {
-	/* Fill in min, max, step and default value for these controls. */
-	switch (qc->id) {
-	case V4L2_CID_BRIGHTNESS:
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
-	case V4L2_CID_CONTRAST:
-		return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
-	case V4L2_CID_VFLIP:
-	case V4L2_CID_HFLIP:
-		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
-	case V4L2_CID_SATURATION:
-		return v4l2_ctrl_query_fill(qc, 0, 256, 1, 128);
-	case V4L2_CID_HUE:
-		return v4l2_ctrl_query_fill(qc, -180, 180, 5, 0);
-	case V4L2_CID_GAIN:
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
-	case V4L2_CID_AUTOGAIN:
-		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
-	case V4L2_CID_EXPOSURE:
-		return v4l2_ctrl_query_fill(qc, 0, 65535, 1, 500);
-	case V4L2_CID_EXPOSURE_AUTO:
-		return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
-	}
-	return -EINVAL;
-}
+	struct v4l2_subdev *sd = to_sd(ctrl);
 
-static int ov7670_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
 	switch (ctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-		return ov7670_g_brightness(sd, &ctrl->value);
-	case V4L2_CID_CONTRAST:
-		return ov7670_g_contrast(sd, &ctrl->value);
-	case V4L2_CID_SATURATION:
-		return ov7670_g_sat(sd, &ctrl->value);
-	case V4L2_CID_HUE:
-		return ov7670_g_hue(sd, &ctrl->value);
-	case V4L2_CID_VFLIP:
-		return ov7670_g_vflip(sd, &ctrl->value);
-	case V4L2_CID_HFLIP:
-		return ov7670_g_hflip(sd, &ctrl->value);
 	case V4L2_CID_GAIN:
-		return ov7670_g_gain(sd, &ctrl->value);
-	case V4L2_CID_AUTOGAIN:
-		return ov7670_g_autogain(sd, &ctrl->value);
+		return ov7670_g_gain(sd, &ctrl->cur.val);
 	case V4L2_CID_EXPOSURE:
-		return ov7670_g_exp(sd, &ctrl->value);
-	case V4L2_CID_EXPOSURE_AUTO:
-		return ov7670_g_autoexp(sd, &ctrl->value);
+		return ov7670_g_exp(sd, &ctrl->cur.val);
 	}
 	return -EINVAL;
 }
 
-static int ov7670_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int ov7670_s_ctrl(struct v4l2_ctrl *ctrl)
 {
+	struct v4l2_subdev *sd = to_sd(ctrl);
+	struct ov7670_info *info = to_state(sd);
+
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		return ov7670_s_brightness(sd, ctrl->value);
+		return ov7670_s_brightness(sd, ctrl->val);
 	case V4L2_CID_CONTRAST:
-		return ov7670_s_contrast(sd, ctrl->value);
+		return ov7670_s_contrast(sd, ctrl->val);
 	case V4L2_CID_SATURATION:
-		return ov7670_s_sat(sd, ctrl->value);
-	case V4L2_CID_HUE:
-		return ov7670_s_hue(sd, ctrl->value);
+		return ov7670_s_sat_hue(sd,
+				info->saturation->val, info->hue->val);
 	case V4L2_CID_VFLIP:
-		return ov7670_s_vflip(sd, ctrl->value);
+		return ov7670_s_vflip(sd, ctrl->val);
 	case V4L2_CID_HFLIP:
-		return ov7670_s_hflip(sd, ctrl->value);
-	case V4L2_CID_GAIN:
-		return ov7670_s_gain(sd, ctrl->value);
+		return ov7670_s_hflip(sd, ctrl->val);
 	case V4L2_CID_AUTOGAIN:
-		return ov7670_s_autogain(sd, ctrl->value);
-	case V4L2_CID_EXPOSURE:
-		return ov7670_s_exp(sd, ctrl->value);
+		/* Only set manual gain if auto gain is not explicitly
+		   turned on. */
+		if (!ctrl->has_new || !ctrl->val) {
+			ctrl->val = 0;
+			/* ov7670_s_gain turns off auto gain */
+			return ov7670_s_gain(sd, ctrl->val);
+		}
+		return ov7670_s_autogain(sd, ctrl->val);
 	case V4L2_CID_EXPOSURE_AUTO:
+		/* Only set manual exposure if auto exposure is not explicitly
+		   turned on. */
+		if (!ctrl->has_new || !ctrl->val) {
+			ctrl->val = 0;
+			/* ov7670_s_exp turns off auto exposure */
+			return ov7670_s_exp(sd, ctrl->val);
+		}
 		return ov7670_s_autoexp(sd,
-				(enum v4l2_exposure_auto_type) ctrl->value);
+			(enum v4l2_exposure_auto_type)ctrl->val);
 	}
 	return -EINVAL;
 }
 
+static const struct v4l2_ctrl_ops ov7670_ctrl_ops = {
+	.s_ctrl = ov7670_s_ctrl,
+	.g_volatile_ctrl = ov7670_g_volatile_ctrl,
+};
+
 static int ov7670_g_chip_ident(struct v4l2_subdev *sd,
 		struct v4l2_dbg_chip_ident *chip)
 {
@@ -1484,9 +1379,44 @@ static int ov7670_s_config(struct v4l2_subdev *sd, int dumb, void *data)
 			client->addr << 1, client->adapter->name);
 
 	info->fmt = &ov7670_formats[0];
-	info->sat = 128;	/* Review this */
 	info->clkrc = info->clock_speed / 30;
 
+	v4l2_ctrl_handler_init(&info->hdl, 10);
+	v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 127, 1, 64);
+	v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
+			V4L2_CID_VFLIP, 0, 1, 1, 0);
+	v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
+			V4L2_CID_HFLIP, 0, 1, 1, 0);
+	info->saturation = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 256, 1, 128);
+	info->hue = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
+			V4L2_CID_HUE, -180, 180, 5, 0);
+	info->gain = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
+			V4L2_CID_GAIN, 0, 255, 1, 128);
+	info->auto_gain = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
+			V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+	info->exposure = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
+			V4L2_CID_EXPOSURE, 0, 65535, 1, 500);
+	info->auto_exposure = v4l2_ctrl_new_std(&info->hdl, &ov7670_ctrl_ops,
+			V4L2_CID_EXPOSURE_AUTO, 0, 1, 1, 0);
+	sd->ctrl_handler = &info->hdl;
+	if (info->hdl.error) {
+		int err = info->hdl.error;
+
+		v4l2_ctrl_handler_free(&info->hdl);
+		kfree(info);
+		return err;
+	}
+	info->gain->is_volatile = true;
+	info->exposure->is_volatile = true;
+	v4l2_ctrl_cluster(2, &info->auto_gain);
+	v4l2_ctrl_cluster(2, &info->auto_exposure);
+	v4l2_ctrl_cluster(2, &info->saturation);
+	v4l2_ctrl_handler_setup(&info->hdl);
+
 	return 0;
 }
 
@@ -1524,9 +1454,13 @@ static int ov7670_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *r
 
 static const struct v4l2_subdev_core_ops ov7670_core_ops = {
 	.g_chip_ident = ov7670_g_chip_ident,
-	.g_ctrl = ov7670_g_ctrl,
-	.s_ctrl = ov7670_s_ctrl,
-	.queryctrl = ov7670_queryctrl,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
 	.reset = ov7670_reset,
 	.s_config = ov7670_s_config,
 	.init = ov7670_init,
@@ -1572,9 +1506,11 @@ static int ov7670_probe(struct i2c_client *client,
 static int ov7670_remove(struct i2c_client *client)
 {
 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct ov7670_info *info = to_state(sd);
 
 	v4l2_device_unregister_subdev(sd);
-	kfree(to_state(sd));
+	v4l2_ctrl_handler_free(&info->hdl);
+	kfree(info);
 	return 0;
 }
 
Signature · 1 line
1.7.0.4
#7 lore raw

PATCH 7/19 saa7110: use control framework

In reply to Hans Verkuil
---
 drivers/media/video/saa7110.c |  115 ++++++++++++++++------------------------
 1 files changed, 46 insertions(+), 69 deletions(-)
drivers/media/video/saa7110.c +46 -69
index 7913f93..9966420 100644
@@ -36,6 +36,7 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
 
 MODULE_DESCRIPTION("Philips SAA7110 video decoder driver");
 MODULE_AUTHOR("Pauline Middelink");
@@ -53,15 +54,12 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 struct saa7110 {
 	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
 	u8 reg[SAA7110_NR_REG];
 
 	v4l2_std_id norm;
 	int input;
 	int enable;
-	int bright;
-	int contrast;
-	int hue;
-	int sat;
 
 	wait_queue_head_t wq;
 };
@@ -71,6 +69,11 @@ static inline struct saa7110 *to_saa7110(struct v4l2_subdev *sd)
 	return container_of(sd, struct saa7110, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct saa7110, hdl)->sd;
+}
+
 /* ----------------------------------------------------------------------- */
 /* I2C support functions						   */
 /* ----------------------------------------------------------------------- */
@@ -326,73 +329,22 @@ static int saa7110_s_stream(struct v4l2_subdev *sd, int enable)
 	return 0;
 }
 
-static int saa7110_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
-	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:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int saa7110_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-	struct saa7110 *decoder = to_saa7110(sd);
-
-	switch (ctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-		ctrl->value = decoder->bright;
-		break;
-	case V4L2_CID_CONTRAST:
-		ctrl->value = decoder->contrast;
-		break;
-	case V4L2_CID_SATURATION:
-		ctrl->value = decoder->sat;
-		break;
-	case V4L2_CID_HUE:
-		ctrl->value = decoder->hue;
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int saa7110_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int saa7110_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	struct saa7110 *decoder = to_saa7110(sd);
+	struct v4l2_subdev *sd = to_sd(ctrl);
 
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		if (decoder->bright != ctrl->value) {
-			decoder->bright = ctrl->value;
-			saa7110_write(sd, 0x19, decoder->bright);
-		}
+		saa7110_write(sd, 0x19, ctrl->val);
 		break;
 	case V4L2_CID_CONTRAST:
-		if (decoder->contrast != ctrl->value) {
-			decoder->contrast = ctrl->value;
-			saa7110_write(sd, 0x13, decoder->contrast);
-		}
+		saa7110_write(sd, 0x13, ctrl->val);
 		break;
 	case V4L2_CID_SATURATION:
-		if (decoder->sat != ctrl->value) {
-			decoder->sat = ctrl->value;
-			saa7110_write(sd, 0x12, decoder->sat);
-		}
+		saa7110_write(sd, 0x12, ctrl->val);
 		break;
 	case V4L2_CID_HUE:
-		if (decoder->hue != ctrl->value) {
-			decoder->hue = ctrl->value;
-			saa7110_write(sd, 0x07, decoder->hue);
-		}
+		saa7110_write(sd, 0x07, ctrl->val);
 		break;
 	default:
 		return -EINVAL;
@@ -409,11 +361,19 @@ static int saa7110_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ide
 
 /* ----------------------------------------------------------------------- */
 
+static const struct v4l2_ctrl_ops saa7110_ctrl_ops = {
+	.s_ctrl = saa7110_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops saa7110_core_ops = {
 	.g_chip_ident = saa7110_g_chip_ident,
-	.g_ctrl = saa7110_g_ctrl,
-	.s_ctrl = saa7110_s_ctrl,
-	.queryctrl = saa7110_queryctrl,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
 	.s_std = saa7110_s_std,
 };
 
@@ -454,10 +414,25 @@ static int saa7110_probe(struct i2c_client *client,
 	decoder->norm = V4L2_STD_PAL;
 	decoder->input = 0;
 	decoder->enable = 1;
-	decoder->bright = 32768;
-	decoder->contrast = 32768;
-	decoder->hue = 32768;
-	decoder->sat = 32768;
+	v4l2_ctrl_handler_init(&decoder->hdl, 2);
+	v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
+		V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
+		V4L2_CID_CONTRAST, 0, 127, 1, 64);
+	v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
+		V4L2_CID_SATURATION, 0, 127, 1, 64);
+	v4l2_ctrl_new_std(&decoder->hdl, &saa7110_ctrl_ops,
+		V4L2_CID_HUE, -128, 127, 1, 0);
+	sd->ctrl_handler = &decoder->hdl;
+	if (decoder->hdl.error) {
+		int err = decoder->hdl.error;
+
+		v4l2_ctrl_handler_free(&decoder->hdl);
+		kfree(decoder);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&decoder->hdl);
+
 	init_waitqueue_head(&decoder->wq);
 
 	rv = saa7110_write_block(sd, initseq, sizeof(initseq));
@@ -490,9 +465,11 @@ static int saa7110_probe(struct i2c_client *client,
 static int saa7110_remove(struct i2c_client *client)
 {
 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct saa7110 *decoder = to_saa7110(sd);
 
 	v4l2_device_unregister_subdev(sd);
-	kfree(to_saa7110(sd));
+	v4l2_ctrl_handler_free(&decoder->hdl);
+	kfree(decoder);
 	return 0;
 }
 
Signature · 1 line
1.7.0.4
#8 lore raw

PATCH 8/19 tda7432: use control framework

In reply to Hans Verkuil
---
 drivers/media/video/tda7432.c |  277 ++++++++++++++++-------------------------
 1 files changed, 106 insertions(+), 171 deletions(-)
drivers/media/video/tda7432.c +106 -171
index 3941f95..2e430a6 100644
@@ -35,6 +35,7 @@
 
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
 #include <media/i2c-addr.h>
 
 #ifndef VIDEO_AUDIO_BALANCE
@@ -50,7 +51,7 @@ static int loudness; /* disable loudness by default */
 static int debug;	 /* insmod parameter */
 module_param(debug, int, S_IRUGO | S_IWUSR);
 module_param(loudness, int, S_IRUGO);
-MODULE_PARM_DESC(maxvol,"Set maximium volume to +20db (0), default is 0db(1)");
+MODULE_PARM_DESC(maxvol, "Set maximum volume to +20db (0), default is 0db(1)");
 module_param(maxvol, int, S_IRUGO | S_IWUSR);
 
 
@@ -59,13 +60,17 @@ module_param(maxvol, int, S_IRUGO | S_IWUSR);
 
 struct tda7432 {
 	struct v4l2_subdev sd;
-	int addr;
-	int input;
-	int volume;
-	int muted;
-	int bass, treble;
-	int lf, lr, rf, rr;
-	int loud;
+	struct v4l2_ctrl_handler hdl;
+	struct {
+		/* bass/treble cluster */
+		struct v4l2_ctrl *bass;
+		struct v4l2_ctrl *treble;
+	};
+	struct {
+		/* mute/balance cluster */
+		struct v4l2_ctrl *mute;
+		struct v4l2_ctrl *balance;
+	};
 };
 
 static inline struct tda7432 *to_state(struct v4l2_subdev *sd)
@@ -73,6 +78,11 @@ static inline struct tda7432 *to_state(struct v4l2_subdev *sd)
 	return container_of(sd, struct tda7432, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct tda7432, hdl)->sd;
+}
+
 /* The TDA7432 is made by STS-Thompson
  * http://www.st.com
  * http://us.st.com/stonline/books/pdf/docs/4056.pdf
@@ -226,24 +236,22 @@ static int tda7432_write(struct v4l2_subdev *sd, int subaddr, int val)
 static int tda7432_set(struct v4l2_subdev *sd)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
-	struct tda7432 *t = to_state(sd);
 	unsigned char buf[16];
 
-	v4l2_dbg(1, debug, sd,
-		"tda7432: 7432_set(0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x,0x%02x)\n",
-		t->input, t->volume, t->bass, t->treble, t->lf, t->lr,
-		t->rf, t->rr, t->loud);
 	buf[0]  = TDA7432_IN;
-	buf[1]  = t->input;
-	buf[2]  = t->volume;
-	buf[3]  = t->bass;
-	buf[4]	= t->treble;
-	buf[5]  = t->lf;
-	buf[6]  = t->lr;
-	buf[7]  = t->rf;
-	buf[8]  = t->rr;
-	buf[9]  = t->loud;
-	if (10 != i2c_master_send(client, buf, 10)) {
+	buf[1]  = TDA7432_STEREO_IN |  /* Main (stereo) input   */
+		  TDA7432_BASS_SYM  |  /* Symmetric bass cut    */
+		  TDA7432_BASS_NORM;   /* Normal bass range     */
+	buf[2]  = 0x3b;
+	if (loudness)			 /* Turn loudness on?     */
+		buf[2] |= TDA7432_LD_ON;
+	buf[3]  = TDA7432_TREBLE_0DB | (TDA7432_BASS_0DB << 4);
+	buf[4]  = TDA7432_ATTEN_0DB;
+	buf[5]  = TDA7432_ATTEN_0DB;
+	buf[6]  = TDA7432_ATTEN_0DB;
+	buf[7]  = TDA7432_ATTEN_0DB;
+	buf[8]  = loudness;
+	if (9 != i2c_master_send(client, buf, 9)) {
 		v4l2_err(sd, "I/O error, trying tda7432_set\n");
 		return -1;
 	}
@@ -251,174 +259,77 @@ static int tda7432_set(struct v4l2_subdev *sd)
 	return 0;
 }
 
-static void do_tda7432_init(struct v4l2_subdev *sd)
-{
-	struct tda7432 *t = to_state(sd);
-
-	v4l2_dbg(2, debug, sd, "In tda7432_init\n");
-
-	t->input  = TDA7432_STEREO_IN |  /* Main (stereo) input   */
-		    TDA7432_BASS_SYM  |  /* Symmetric bass cut    */
-		    TDA7432_BASS_NORM;   /* Normal bass range     */
-	t->volume =  0x3b ;				 /* -27dB Volume            */
-	if (loudness)			 /* Turn loudness on?     */
-		t->volume |= TDA7432_LD_ON;
-	t->muted    = 1;
-	t->treble   = TDA7432_TREBLE_0DB; /* 0dB Treble            */
-	t->bass		= TDA7432_BASS_0DB; 	 /* 0dB Bass              */
-	t->lf     = TDA7432_ATTEN_0DB;	 /* 0dB attenuation       */
-	t->lr     = TDA7432_ATTEN_0DB;	 /* 0dB attenuation       */
-	t->rf     = TDA7432_ATTEN_0DB;	 /* 0dB attenuation       */
-	t->rr     = TDA7432_ATTEN_0DB;	 /* 0dB attenuation       */
-	t->loud   = loudness;		 /* insmod parameter      */
-
-	tda7432_set(sd);
-}
-
-static int tda7432_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-	struct tda7432 *t = to_state(sd);
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_MUTE:
-		ctrl->value=t->muted;
-		return 0;
-	case V4L2_CID_AUDIO_VOLUME:
-		if (!maxvol){  /* max +20db */
-			ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 630;
-		} else {       /* max 0db   */
-			ctrl->value = ( 0x6f - (t->volume & 0x7F) ) * 829;
-		}
-		return 0;
-	case V4L2_CID_AUDIO_BALANCE:
-	{
-		if ( (t->lf) < (t->rf) )
-			/* right is attenuated, balance shifted left */
-			ctrl->value = (32768 - 1057*(t->rf));
-		else
-			/* left is attenuated, balance shifted right */
-			ctrl->value = (32768 + 1057*(t->lf));
-		return 0;
-	}
-	case V4L2_CID_AUDIO_BASS:
-	{
-		/* Bass/treble 4 bits each */
-		int bass=t->bass;
-		if(bass >= 0x8)
-			bass = ~(bass - 0x8) & 0xf;
-		ctrl->value = (bass << 12)+(bass << 8)+(bass << 4)+(bass);
-		return 0;
-	}
-	case V4L2_CID_AUDIO_TREBLE:
-	{
-		int treble=t->treble;
-		if(treble >= 0x8)
-			treble = ~(treble - 0x8) & 0xf;
-		ctrl->value = (treble << 12)+(treble << 8)+(treble << 4)+(treble);
-		return 0;
-	}
-	}
-	return -EINVAL;
-}
-
-static int tda7432_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int tda7432_s_ctrl(struct v4l2_ctrl *ctrl)
 {
+	struct v4l2_subdev *sd = to_sd(ctrl);
 	struct tda7432 *t = to_state(sd);
+	u8 bass, treble, volume;
+	u8 lf, lr, rf, rr;
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_MUTE:
-		t->muted=ctrl->value;
-		break;
-	case V4L2_CID_AUDIO_VOLUME:
-		if(!maxvol){ /* max +20db */
-			t->volume = 0x6f - ((ctrl->value)/630);
-		} else {    /* max 0db   */
-			t->volume = 0x6f - ((ctrl->value)/829);
-		}
-		if (loudness)		/* Turn on the loudness bit */
-			t->volume |= TDA7432_LD_ON;
-
-		tda7432_write(sd, TDA7432_VL, t->volume);
-		return 0;
-	case V4L2_CID_AUDIO_BALANCE:
-		if (ctrl->value < 32768) {
+		if (t->balance->val < 0) {
 			/* shifted to left, attenuate right */
-			t->rr = (32768 - ctrl->value)/1057;
-			t->rf = t->rr;
-			t->lr = TDA7432_ATTEN_0DB;
-			t->lf = TDA7432_ATTEN_0DB;
-		} else if(ctrl->value > 32769) {
+			rr = rf = -t->balance->val;
+			lr = lf = TDA7432_ATTEN_0DB;
+		} else if (t->balance->val > 0) {
 			/* shifted to right, attenuate left */
-			t->lf = (ctrl->value - 32768)/1057;
-			t->lr = t->lf;
-			t->rr = TDA7432_ATTEN_0DB;
-			t->rf = TDA7432_ATTEN_0DB;
+			rr = rf = TDA7432_ATTEN_0DB;
+			lr = lf = t->balance->val;
 		} else {
 			/* centered */
-			t->rr = TDA7432_ATTEN_0DB;
-			t->rf = TDA7432_ATTEN_0DB;
-			t->lf = TDA7432_ATTEN_0DB;
-			t->lr = TDA7432_ATTEN_0DB;
+			rr = rf = TDA7432_ATTEN_0DB;
+			lr = lf = TDA7432_ATTEN_0DB;
 		}
-		break;
-	case V4L2_CID_AUDIO_BASS:
-		t->bass = ctrl->value >> 12;
-		if(t->bass>= 0x8)
-				t->bass = (~t->bass & 0xf) + 0x8 ;
-
-		tda7432_write(sd, TDA7432_TN, 0x10 | (t->bass << 4) | t->treble);
+		if (t->mute->val) {
+			lf |= TDA7432_MUTE;
+			lr |= TDA7432_MUTE;
+			lf |= TDA7432_MUTE;
+			rr |= TDA7432_MUTE;
+		}
+		/* Mute & update balance*/
+		tda7432_write(sd, TDA7432_LF, lf);
+		tda7432_write(sd, TDA7432_LR, lr);
+		tda7432_write(sd, TDA7432_RF, rf);
+		tda7432_write(sd, TDA7432_RR, rr);
 		return 0;
-	case V4L2_CID_AUDIO_TREBLE:
-		t->treble= ctrl->value >> 12;
-		if(t->treble>= 0x8)
-				t->treble = (~t->treble & 0xf) + 0x8 ;
+	case V4L2_CID_AUDIO_VOLUME:
+		volume = 0x6f - ctrl->val;
+		if (loudness)		/* Turn on the loudness bit */
+			volume |= TDA7432_LD_ON;
 
-		tda7432_write(sd, TDA7432_TN, 0x10 | (t->bass << 4) | t->treble);
+		tda7432_write(sd, TDA7432_VL, volume);
 		return 0;
-	default:
-		return -EINVAL;
-	}
-
-	/* Used for both mute and balance changes */
-	if (t->muted)
-	{
-		/* Mute & update balance*/
-		tda7432_write(sd, TDA7432_LF, t->lf | TDA7432_MUTE);
-		tda7432_write(sd, TDA7432_LR, t->lr | TDA7432_MUTE);
-		tda7432_write(sd, TDA7432_RF, t->rf | TDA7432_MUTE);
-		tda7432_write(sd, TDA7432_RR, t->rr | TDA7432_MUTE);
-	} else {
-		tda7432_write(sd, TDA7432_LF, t->lf);
-		tda7432_write(sd, TDA7432_LR, t->lr);
-		tda7432_write(sd, TDA7432_RF, t->rf);
-		tda7432_write(sd, TDA7432_RR, t->rr);
-	}
-	return 0;
-}
-
-static int tda7432_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
-	switch (qc->id) {
-	case V4L2_CID_AUDIO_VOLUME:
-		return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
-	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);
+		bass = t->bass->val;
+		treble = t->treble->val;
+		if (bass >= 0x8)
+			bass = 14 - (bass - 8);
+		if (treble >= 0x8)
+			treble = 14 - (treble - 8);
+
+		tda7432_write(sd, TDA7432_TN, 0x10 | (bass << 4) | treble);
+		return 0;
 	}
 	return -EINVAL;
 }
 
 /* ----------------------------------------------------------------------- */
 
-static const struct v4l2_subdev_core_ops tda7432_core_ops = {
-	.queryctrl = tda7432_queryctrl,
-	.g_ctrl = tda7432_g_ctrl,
+static const struct v4l2_ctrl_ops tda7432_ctrl_ops = {
 	.s_ctrl = tda7432_s_ctrl,
 };
 
+static const struct v4l2_subdev_core_ops tda7432_core_ops = {
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+};
+
 static const struct v4l2_subdev_ops tda7432_ops = {
 	.core = &tda7432_core_ops,
 };
@@ -443,6 +354,28 @@ static int tda7432_probe(struct i2c_client *client,
 		return -ENOMEM;
 	sd = &t->sd;
 	v4l2_i2c_subdev_init(sd, client, &tda7432_ops);
+	v4l2_ctrl_handler_init(&t->hdl, 5);
+	v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops,
+		V4L2_CID_AUDIO_VOLUME, 0, maxvol ? 0x68 : 0x4f, 1, maxvol ? 0x5d : 0x47);
+	t->mute = v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops,
+		V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+	t->balance = v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops,
+		V4L2_CID_AUDIO_BALANCE, -31, 31, 1, 0);
+	t->bass = v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops,
+		V4L2_CID_AUDIO_BASS, 0, 14, 1, 7);
+	t->treble = v4l2_ctrl_new_std(&t->hdl, &tda7432_ctrl_ops,
+		V4L2_CID_AUDIO_TREBLE, 0, 14, 1, 7);
+	sd->ctrl_handler = &t->hdl;
+	if (t->hdl.error) {
+		int err = t->hdl.error;
+
+		v4l2_ctrl_handler_free(&t->hdl);
+		kfree(t);
+		return err;
+	}
+	v4l2_ctrl_cluster(2, &t->bass);
+	v4l2_ctrl_cluster(2, &t->mute);
+	v4l2_ctrl_handler_setup(&t->hdl);
 	if (loudness < 0 || loudness > 15) {
 		v4l2_warn(sd, "loudness parameter must be between 0 and 15\n");
 		if (loudness < 0)
@@ -451,17 +384,19 @@ static int tda7432_probe(struct i2c_client *client,
 			loudness = 15;
 	}
 
-	do_tda7432_init(sd);
+	tda7432_set(sd);
 	return 0;
 }
 
 static int tda7432_remove(struct i2c_client *client)
 {
 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct tda7432 *t = to_state(sd);
 
-	do_tda7432_init(sd);
+	tda7432_set(sd);
 	v4l2_device_unregister_subdev(sd);
-	kfree(to_state(sd));
+	v4l2_ctrl_handler_free(&t->hdl);
+	kfree(t);
 	return 0;
 }
 
Signature · 1 line
1.7.0.4
#9 lore raw

PATCH 9/19 tda9875: use control framework

In reply to Hans Verkuil
---
 drivers/media/video/tda9875.c |  192 ++++++++++++-----------------------------
 1 files changed, 57 insertions(+), 135 deletions(-)
drivers/media/video/tda9875.c +57 -135
index 35b6ff5..6d8ff21 100644
@@ -28,6 +28,7 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
 #include <media/i2c-addr.h>
 
 static int debug; /* insmod parameter */
@@ -38,8 +39,12 @@ MODULE_LICENSE("GPL");
 /* This is a superset of the TDA9875 */
 struct tda9875 {
 	struct v4l2_subdev sd;
-	int rvol, lvol;
-	int bass, treble;
+	struct v4l2_ctrl_handler hdl;
+	struct {
+		/* volume/balance cluster */
+		struct v4l2_ctrl *volume;
+		struct v4l2_ctrl *balance;
+	};
 };
 
 static inline struct tda9875 *to_state(struct v4l2_subdev *sd)
@@ -47,6 +52,11 @@ static inline struct tda9875 *to_state(struct v4l2_subdev *sd)
 	return container_of(sd, struct tda9875, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct tda9875, hdl)->sd;
+}
+
 #define dprintk  if (debug) printk
 
 /* The TDA9875 is made by Philips Semiconductor
@@ -134,28 +144,8 @@ static int i2c_read_register(struct i2c_client *client, int addr, int reg)
 	return read[0];
 }
 
-static void tda9875_set(struct v4l2_subdev *sd)
-{
-	struct tda9875 *tda = to_state(sd);
-	unsigned char a;
-
-	v4l2_dbg(1, debug, sd, "tda9875_set(%04x,%04x,%04x,%04x)\n",
-		tda->lvol, tda->rvol, tda->bass, tda->treble);
-
-	a = tda->lvol & 0xff;
-	tda9875_write(sd, TDA9875_MVL, a);
-	a =tda->rvol & 0xff;
-	tda9875_write(sd, TDA9875_MVR, a);
-	a =tda->bass & 0xff;
-	tda9875_write(sd, TDA9875_MBA, a);
-	a =tda->treble  & 0xff;
-	tda9875_write(sd, TDA9875_MTR, a);
-}
-
 static void do_tda9875_init(struct v4l2_subdev *sd)
 {
-	struct tda9875 *t = to_state(sd);
-
 	v4l2_dbg(1, debug, sd, "In tda9875_init\n");
 	tda9875_write(sd, TDA9875_CFG, 0xd0); /*reg de config 0 (reset)*/
 	tda9875_write(sd, TDA9875_MSR, 0x03);    /* Monitor 0b00000XXX*/
@@ -189,138 +179,49 @@ static void do_tda9875_init(struct v4l2_subdev *sd)
 	tda9875_write(sd, TDA9875_ATR, 0x00);   /* Aux Aigus Main 0dB*/
 
 	tda9875_write(sd, TDA9875_MUT, 0xcc);   /* General mute  */
-
-	t->lvol = t->rvol = 0;  	/* 0dB */
-	t->bass = 0; 			/* 0dB */
-	t->treble = 0;  		/* 0dB */
-	tda9875_set(sd);
 }
 
-
-static int tda9875_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int tda9875_s_ctrl(struct v4l2_ctrl *ctrl)
 {
+	struct v4l2_subdev *sd = to_sd(ctrl);
 	struct tda9875 *t = to_state(sd);
+	int volume, balance, left, right;
 
 	switch (ctrl->id) {
 	case V4L2_CID_AUDIO_VOLUME:
-	{
-		int left = (t->lvol+84)*606;
-		int right = (t->rvol+84)*606;
-
-		ctrl->value=max(left,right);
-		return 0;
-	}
-	case V4L2_CID_AUDIO_BALANCE:
-	{
-		int left = (t->lvol+84)*606;
-		int right = (t->rvol+84)*606;
-		int volume = max(left,right);
-		int balance = (32768*min(left,right))/
-			      (volume ? volume : 1);
-		ctrl->value=(left<right)?
-			(65535-balance) : balance;
+		volume = t->volume->val + 84;
+		balance = t->balance->val;
+		left = (min(255 - balance, 128) * volume) / 128 - 84;
+		right = (min(balance, 128) * volume) / 128 - 84;
+		tda9875_write(sd, TDA9875_MVL, left);
+		tda9875_write(sd, TDA9875_MVR, right);
 		return 0;
-	}
 	case V4L2_CID_AUDIO_BASS:
-		ctrl->value = (t->bass+12)*2427;    /* min -12 max +15 */
+		tda9875_write(sd, TDA9875_MBA, ctrl->val & 0x1f);
 		return 0;
 	case V4L2_CID_AUDIO_TREBLE:
-		ctrl->value = (t->treble+12)*2730;/* min -12 max +12 */
+		tda9875_write(sd, TDA9875_MTR, ctrl->val & 0x1f);
 		return 0;
 	}
 	return -EINVAL;
 }
 
-static int tda9875_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-	struct tda9875 *t = to_state(sd);
-	int chvol = 0, volume = 0, balance = 0, left, right;
-
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_VOLUME:
-		left = (t->lvol+84)*606;
-		right = (t->rvol+84)*606;
-
-		volume = max(left,right);
-		balance = (32768*min(left,right))/
-			      (volume ? volume : 1);
-		balance =(left<right)?
-			(65535-balance) : balance;
-
-		volume = ctrl->value;
-
-		chvol=1;
-		break;
-	case V4L2_CID_AUDIO_BALANCE:
-		left = (t->lvol+84)*606;
-		right = (t->rvol+84)*606;
-
-		volume=max(left,right);
-
-		balance = ctrl->value;
-
-		chvol=1;
-		break;
-	case V4L2_CID_AUDIO_BASS:
-		t->bass = ((ctrl->value/2400)-12) & 0xff;
-		if (t->bass > 15)
-			t->bass = 15;
-		if (t->bass < -12)
-			t->bass = -12 & 0xff;
-		break;
-	case V4L2_CID_AUDIO_TREBLE:
-		t->treble = ((ctrl->value/2700)-12) & 0xff;
-		if (t->treble > 12)
-			t->treble = 12;
-		if (t->treble < -12)
-			t->treble = -12 & 0xff;
-		break;
-	default:
-		return -EINVAL;
-	}
-
-	if (chvol) {
-		left = (min(65536 - balance,32768) *
-			volume) / 32768;
-		right = (min(balance,32768) *
-				volume) / 32768;
-		t->lvol = ((left/606)-84) & 0xff;
-		if (t->lvol > 24)
-			t->lvol = 24;
-		if (t->lvol < -84)
-			t->lvol = -84 & 0xff;
-
-		t->rvol = ((right/606)-84) & 0xff;
-		if (t->rvol > 24)
-			t->rvol = 24;
-		if (t->rvol < -84)
-			t->rvol = -84 & 0xff;
-	}
-
-	tda9875_set(sd);
-	return 0;
-}
-
-static int tda9875_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
-	switch (qc->id) {
-	case V4L2_CID_AUDIO_VOLUME:
-		return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
-	case V4L2_CID_AUDIO_BASS:
-	case V4L2_CID_AUDIO_TREBLE:
-		return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
-	}
-	return -EINVAL;
-}
-
 /* ----------------------------------------------------------------------- */
 
-static const struct v4l2_subdev_core_ops tda9875_core_ops = {
-	.queryctrl = tda9875_queryctrl,
-	.g_ctrl = tda9875_g_ctrl,
+static const struct v4l2_ctrl_ops tda9875_ctrl_ops = {
 	.s_ctrl = tda9875_s_ctrl,
 };
 
+static const struct v4l2_subdev_core_ops tda9875_core_ops = {
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
+};
+
 static const struct v4l2_subdev_ops tda9875_ops = {
 	.core = &tda9875_core_ops,
 };
@@ -366,18 +267,39 @@ static int tda9875_probe(struct i2c_client *client,
 		return -ENOMEM;
 	sd = &t->sd;
 	v4l2_i2c_subdev_init(sd, client, &tda9875_ops);
-
+	v4l2_ctrl_handler_init(&t->hdl, 4);
+	t->volume = v4l2_ctrl_new_std(&t->hdl, &tda9875_ctrl_ops,
+		V4L2_CID_AUDIO_VOLUME, -84, 24, 1, 13);
+	t->balance = v4l2_ctrl_new_std(&t->hdl, &tda9875_ctrl_ops,
+		V4L2_CID_AUDIO_BALANCE, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(&t->hdl, &tda9875_ctrl_ops,
+		V4L2_CID_AUDIO_BASS, -12, 15, 1, 0);
+	v4l2_ctrl_new_std(&t->hdl, &tda9875_ctrl_ops,
+		V4L2_CID_AUDIO_TREBLE, -12, 12, 1, 0);
+	sd->ctrl_handler = &t->hdl;
+	if (t->hdl.error) {
+		int err = t->hdl.error;
+
+		v4l2_ctrl_handler_free(&t->hdl);
+		kfree(t);
+		return err;
+	}
+	v4l2_ctrl_cluster(2, &t->volume);
 	do_tda9875_init(sd);
+	v4l2_ctrl_handler_setup(&t->hdl);
+
 	return 0;
 }
 
 static int tda9875_remove(struct i2c_client *client)
 {
 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct tda9875 *t = to_state(sd);
 
 	do_tda9875_init(sd);
 	v4l2_device_unregister_subdev(sd);
-	kfree(to_state(sd));
+	v4l2_ctrl_handler_free(&t->hdl);
+	kfree(t);
 	return 0;
 }
 
Signature · 1 line
1.7.0.4
#10 lore raw

PATCH 10/19 tlv320aic23b: use control framework

In reply to Hans Verkuil
---
 drivers/media/video/tlv320aic23b.c |   74 +++++++++++++++++++++++-------------
 1 files changed, 47 insertions(+), 27 deletions(-)
drivers/media/video/tlv320aic23b.c +47 -27
index dfc4dd7..286ec7e 100644
@@ -31,6 +31,7 @@
 #include <linux/i2c.h>
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
 
 MODULE_DESCRIPTION("tlv320aic23b driver");
 MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil");
@@ -41,7 +42,7 @@ MODULE_LICENSE("GPL");
 
 struct tlv320aic23b_state {
 	struct v4l2_subdev sd;
-	u8 muted;
+	struct v4l2_ctrl_handler hdl;
 };
 
 static inline struct tlv320aic23b_state *to_state(struct v4l2_subdev *sd)
@@ -49,6 +50,11 @@ static inline struct tlv320aic23b_state *to_state(struct v4l2_subdev *sd)
 	return container_of(sd, struct tlv320aic23b_state, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct tlv320aic23b_state, hdl)->sd;
+}
+
 static int tlv320aic23b_write(struct v4l2_subdev *sd, int reg, u16 val)
 {
 	struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -85,44 +91,44 @@ static int tlv320aic23b_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
 	return 0;
 }
 
-static int tlv320aic23b_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-	struct tlv320aic23b_state *state = to_state(sd);
-
-	if (ctrl->id != V4L2_CID_AUDIO_MUTE)
-		return -EINVAL;
-	ctrl->value = state->muted;
-	return 0;
-}
-
-static int tlv320aic23b_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int tlv320aic23b_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	struct tlv320aic23b_state *state = to_state(sd);
-
-	if (ctrl->id != V4L2_CID_AUDIO_MUTE)
-		return -EINVAL;
-	state->muted = ctrl->value;
-	tlv320aic23b_write(sd, 0, 0x180); /* mute both channels */
-	/* set gain on both channels to +3.0 dB */
-	if (!state->muted)
-		tlv320aic23b_write(sd, 0, 0x119);
-	return 0;
+	struct v4l2_subdev *sd = to_sd(ctrl);
+
+	switch (ctrl->id) {
+	case V4L2_CID_AUDIO_MUTE:
+		tlv320aic23b_write(sd, 0, 0x180); /* mute both channels */
+		/* set gain on both channels to +3.0 dB */
+		if (!ctrl->val)
+			tlv320aic23b_write(sd, 0, 0x119);
+		return 0;
+	}
+	return -EINVAL;
 }
 
 static int tlv320aic23b_log_status(struct v4l2_subdev *sd)
 {
 	struct tlv320aic23b_state *state = to_state(sd);
 
-	v4l2_info(sd, "Input: %s\n", state->muted ? "muted" : "active");
+	v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
 	return 0;
 }
 
 /* ----------------------------------------------------------------------- */
 
+static const struct v4l2_ctrl_ops tlv320aic23b_ctrl_ops = {
+	.s_ctrl = tlv320aic23b_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops tlv320aic23b_core_ops = {
 	.log_status = tlv320aic23b_log_status,
-	.g_ctrl = tlv320aic23b_g_ctrl,
-	.s_ctrl = tlv320aic23b_s_ctrl,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
 };
 
 static const struct v4l2_subdev_audio_ops tlv320aic23b_audio_ops = {
@@ -161,7 +167,6 @@ static int tlv320aic23b_probe(struct i2c_client *client,
 		return -ENOMEM;
 	sd = &state->sd;
 	v4l2_i2c_subdev_init(sd, client, &tlv320aic23b_ops);
-	state->muted = 0;
 
 	/* Initialize tlv320aic23b */
 
@@ -177,15 +182,30 @@ static int tlv320aic23b_probe(struct i2c_client *client,
 	tlv320aic23b_write(sd, 8, 0x000);
 	/* activate digital interface */
 	tlv320aic23b_write(sd, 9, 0x001);
+
+	v4l2_ctrl_handler_init(&state->hdl, 1);
+	v4l2_ctrl_new_std(&state->hdl, &tlv320aic23b_ctrl_ops,
+			V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+	sd->ctrl_handler = &state->hdl;
+	if (state->hdl.error) {
+		int err = state->hdl.error;
+
+		v4l2_ctrl_handler_free(&state->hdl);
+		kfree(state);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&state->hdl);
 	return 0;
 }
 
 static int tlv320aic23b_remove(struct i2c_client *client)
 {
 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct tlv320aic23b_state *state = to_state(sd);
 
 	v4l2_device_unregister_subdev(sd);
-	kfree(to_state(sd));
+	v4l2_ctrl_handler_free(&state->hdl);
+	kfree(state);
 	return 0;
 }
 
Signature · 1 line
1.7.0.4
#11 lore raw

PATCH 11/19 tvp514x: use the control framework

In reply to Hans Verkuil
---
 drivers/media/video/tvp514x.c |  236 ++++++++++-------------------------------
 1 files changed, 57 insertions(+), 179 deletions(-)
drivers/media/video/tvp514x.c +57 -179
index 45bcf03..9b3e828 100644
@@ -37,6 +37,7 @@
 #include <media/v4l2-common.h>
 #include <media/v4l2-mediabus.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
 #include <media/tvp514x.h>
 
 #include "tvp514x_regs.h"
@@ -97,6 +98,7 @@ static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable);
  */
 struct tvp514x_decoder {
 	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
 	struct tvp514x_reg tvp514x_regs[ARRAY_SIZE(tvp514x_reg_list_default)];
 	const struct tvp514x_platform_data *pdata;
 
@@ -238,6 +240,11 @@ static inline struct tvp514x_decoder *to_decoder(struct v4l2_subdev *sd)
 	return container_of(sd, struct tvp514x_decoder, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct tvp514x_decoder, hdl)->sd;
+}
+
 
 /**
  * tvp514x_read_reg() - Read a value from a register in an TVP5146/47.
@@ -719,213 +726,54 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd,
 }
 
 /**
- * tvp514x_queryctrl() - V4L2 decoder interface handler for queryctrl
- * @sd: pointer to standard V4L2 sub-device structure
- * @qctrl: standard V4L2 v4l2_queryctrl structure
- *
- * If the requested control is supported, returns the control information.
- * Otherwise, returns -EINVAL if the control is not supported.
- */
-static int
-tvp514x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl)
-{
-	int err = -EINVAL;
-
-	if (qctrl == NULL)
-		return err;
-
-	switch (qctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-		/* Brightness supported is (0-255), */
-		err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
-		break;
-	case V4L2_CID_CONTRAST:
-	case V4L2_CID_SATURATION:
-		/**
-		 * Saturation and Contrast supported is -
-		 *	Contrast: 0 - 255 (Default - 128)
-		 *	Saturation: 0 - 255 (Default - 128)
-		 */
-		err = v4l2_ctrl_query_fill(qctrl, 0, 255, 1, 128);
-		break;
-	case V4L2_CID_HUE:
-		/* Hue Supported is -
-		 *	Hue - -180 - +180 (Default - 0, Step - +180)
-		 */
-		err = v4l2_ctrl_query_fill(qctrl, -180, 180, 180, 0);
-		break;
-	case V4L2_CID_AUTOGAIN:
-		/**
-		 * Auto Gain supported is -
-		 * 	0 - 1 (Default - 1)
-		 */
-		err = v4l2_ctrl_query_fill(qctrl, 0, 1, 1, 1);
-		break;
-	default:
-		v4l2_err(sd, "invalid control id %d\n", qctrl->id);
-		return err;
-	}
-
-	v4l2_dbg(1, debug, sd, "Query Control:%s: Min - %d, Max - %d, Def - %d\n",
-			qctrl->name, qctrl->minimum, qctrl->maximum,
-			qctrl->default_value);
-
-	return err;
-}
-
-/**
- * tvp514x_g_ctrl() - V4L2 decoder interface handler for g_ctrl
- * @sd: pointer to standard V4L2 sub-device structure
- * @ctrl: pointer to v4l2_control structure
- *
- * If the requested control is supported, returns the control's current
- * value from the decoder. Otherwise, returns -EINVAL if the control is not
- * supported.
- */
-static int
-tvp514x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-	struct tvp514x_decoder *decoder = to_decoder(sd);
-
-	if (ctrl == NULL)
-		return -EINVAL;
-
-	switch (ctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-		ctrl->value = decoder->tvp514x_regs[REG_BRIGHTNESS].val;
-		break;
-	case V4L2_CID_CONTRAST:
-		ctrl->value = decoder->tvp514x_regs[REG_CONTRAST].val;
-		break;
-	case V4L2_CID_SATURATION:
-		ctrl->value = decoder->tvp514x_regs[REG_SATURATION].val;
-		break;
-	case V4L2_CID_HUE:
-		ctrl->value = decoder->tvp514x_regs[REG_HUE].val;
-		if (ctrl->value == 0x7F)
-			ctrl->value = 180;
-		else if (ctrl->value == 0x80)
-			ctrl->value = -180;
-		else
-			ctrl->value = 0;
-
-		break;
-	case V4L2_CID_AUTOGAIN:
-		ctrl->value = decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val;
-		if ((ctrl->value & 0x3) == 3)
-			ctrl->value = 1;
-		else
-			ctrl->value = 0;
-
-		break;
-	default:
-		v4l2_err(sd, "invalid control id %d\n", ctrl->id);
-		return -EINVAL;
-	}
-
-	v4l2_dbg(1, debug, sd, "Get Control: ID - %d - %d\n",
-			ctrl->id, ctrl->value);
-	return 0;
-}
-
-/**
  * tvp514x_s_ctrl() - V4L2 decoder interface handler for s_ctrl
- * @sd: pointer to standard V4L2 sub-device structure
- * @ctrl: pointer to v4l2_control structure
+ * @ctrl: pointer to v4l2_ctrl structure
  *
  * If the requested control is supported, sets the control's current
  * value in HW. Otherwise, returns -EINVAL if the control is not supported.
  */
-static int
-tvp514x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int tvp514x_s_ctrl(struct v4l2_ctrl *ctrl)
 {
+	struct v4l2_subdev *sd = to_sd(ctrl);
 	struct tvp514x_decoder *decoder = to_decoder(sd);
 	int err = -EINVAL, value;
 
-	if (ctrl == NULL)
-		return err;
-
-	value = ctrl->value;
+	value = ctrl->val;
 
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		if (ctrl->value < 0 || ctrl->value > 255) {
-			v4l2_err(sd, "invalid brightness setting %d\n",
-					ctrl->value);
-			return -ERANGE;
-		}
-		err = tvp514x_write_reg(sd, REG_BRIGHTNESS,
-				value);
-		if (err)
-			return err;
-
-		decoder->tvp514x_regs[REG_BRIGHTNESS].val = value;
+		err = tvp514x_write_reg(sd, REG_BRIGHTNESS, value);
+		if (!err)
+			decoder->tvp514x_regs[REG_BRIGHTNESS].val = value;
 		break;
 	case V4L2_CID_CONTRAST:
-		if (ctrl->value < 0 || ctrl->value > 255) {
-			v4l2_err(sd, "invalid contrast setting %d\n",
-					ctrl->value);
-			return -ERANGE;
-		}
 		err = tvp514x_write_reg(sd, REG_CONTRAST, value);
-		if (err)
-			return err;
-
-		decoder->tvp514x_regs[REG_CONTRAST].val = value;
+		if (!err)
+			decoder->tvp514x_regs[REG_CONTRAST].val = value;
 		break;
 	case V4L2_CID_SATURATION:
-		if (ctrl->value < 0 || ctrl->value > 255) {
-			v4l2_err(sd, "invalid saturation setting %d\n",
-					ctrl->value);
-			return -ERANGE;
-		}
 		err = tvp514x_write_reg(sd, REG_SATURATION, value);
-		if (err)
-			return err;
-
-		decoder->tvp514x_regs[REG_SATURATION].val = value;
+		if (!err)
+			decoder->tvp514x_regs[REG_SATURATION].val = value;
 		break;
 	case V4L2_CID_HUE:
 		if (value == 180)
 			value = 0x7F;
 		else if (value == -180)
 			value = 0x80;
-		else if (value == 0)
-			value = 0;
-		else {
-			v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
-			return -ERANGE;
-		}
 		err = tvp514x_write_reg(sd, REG_HUE, value);
-		if (err)
-			return err;
-
-		decoder->tvp514x_regs[REG_HUE].val = value;
+		if (!err)
+			decoder->tvp514x_regs[REG_HUE].val = value;
 		break;
 	case V4L2_CID_AUTOGAIN:
-		if (value == 1)
-			value = 0x0F;
-		else if (value == 0)
-			value = 0x0C;
-		else {
-			v4l2_err(sd, "invalid auto gain setting %d\n",
-					ctrl->value);
-			return -ERANGE;
-		}
-		err = tvp514x_write_reg(sd, REG_AFE_GAIN_CTRL, value);
-		if (err)
-			return err;
-
-		decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value;
+		err = tvp514x_write_reg(sd, REG_AFE_GAIN_CTRL, value ? 0x0f : 0x0c);
+		if (!err)
+			decoder->tvp514x_regs[REG_AFE_GAIN_CTRL].val = value;
 		break;
-	default:
-		v4l2_err(sd, "invalid control id %d\n", ctrl->id);
-		return err;
 	}
 
 	v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d\n",
-			ctrl->id, ctrl->value);
-
+			ctrl->id, ctrl->val);
 	return err;
 }
 
@@ -1104,10 +952,18 @@ static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable)
 	return err;
 }
 
-static const struct v4l2_subdev_core_ops tvp514x_core_ops = {
-	.queryctrl = tvp514x_queryctrl,
-	.g_ctrl = tvp514x_g_ctrl,
+static const struct v4l2_ctrl_ops tvp514x_ctrl_ops = {
 	.s_ctrl = tvp514x_s_ctrl,
+};
+
+static const struct v4l2_subdev_core_ops tvp514x_core_ops = {
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
 	.s_std = tvp514x_s_std,
 };
 
@@ -1190,6 +1046,27 @@ tvp514x_probe(struct i2c_client *client, const struct i2c_device_id *id)
 	sd = &decoder->sd;
 	v4l2_i2c_subdev_init(sd, client, &tvp514x_ops);
 
+	v4l2_ctrl_handler_init(&decoder->hdl, 5);
+	v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
+		V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
+		V4L2_CID_CONTRAST, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
+		V4L2_CID_SATURATION, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
+		V4L2_CID_HUE, -180, 180, 180, 0);
+	v4l2_ctrl_new_std(&decoder->hdl, &tvp514x_ctrl_ops,
+		V4L2_CID_AUTOGAIN, 0, 1, 1, 1);
+	sd->ctrl_handler = &decoder->hdl;
+	if (decoder->hdl.error) {
+		int err = decoder->hdl.error;
+
+		v4l2_ctrl_handler_free(&decoder->hdl);
+		kfree(decoder);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&decoder->hdl);
+
 	v4l2_info(sd, "%s decoder driver registered !!\n", sd->name);
 
 	return 0;
@@ -1209,6 +1086,7 @@ static int tvp514x_remove(struct i2c_client *client)
 	struct tvp514x_decoder *decoder = to_decoder(sd);
 
 	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&decoder->hdl);
 	kfree(decoder);
 	return 0;
 }
Signature · 1 line
1.7.0.4
#12 lore raw

PATCH 12/19 tvp5150: use the control framework

In reply to Hans Verkuil
---
 drivers/media/video/tvp5150.c |  157 ++++++++++++-----------------------------
 1 files changed, 46 insertions(+), 111 deletions(-)
drivers/media/video/tvp5150.c +46 -111
index 5892766..959d690 100644
@@ -12,6 +12,7 @@
 #include <media/v4l2-device.h>
 #include <media/tvp5150.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
 
 #include "tvp5150_reg.h"
 
@@ -24,58 +25,14 @@ static int debug;
 module_param(debug, int, 0);
 MODULE_PARM_DESC(debug, "Debug level (0-2)");
 
-/* supported controls */
-static struct v4l2_queryctrl tvp5150_qctrl[] = {
-	{
-		.id = V4L2_CID_BRIGHTNESS,
-		.type = V4L2_CTRL_TYPE_INTEGER,
-		.name = "Brightness",
-		.minimum = 0,
-		.maximum = 255,
-		.step = 1,
-		.default_value = 128,
-		.flags = 0,
-	}, {
-		.id = V4L2_CID_CONTRAST,
-		.type = V4L2_CTRL_TYPE_INTEGER,
-		.name = "Contrast",
-		.minimum = 0,
-		.maximum = 255,
-		.step = 0x1,
-		.default_value = 128,
-		.flags = 0,
-	}, {
-		 .id = V4L2_CID_SATURATION,
-		 .type = V4L2_CTRL_TYPE_INTEGER,
-		 .name = "Saturation",
-		 .minimum = 0,
-		 .maximum = 255,
-		 .step = 0x1,
-		 .default_value = 128,
-		 .flags = 0,
-	}, {
-		.id = V4L2_CID_HUE,
-		.type = V4L2_CTRL_TYPE_INTEGER,
-		.name = "Hue",
-		.minimum = -128,
-		.maximum = 127,
-		.step = 0x1,
-		.default_value = 0,
-		.flags = 0,
-	}
-};
-
 struct tvp5150 {
 	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
 
 	v4l2_std_id norm;	/* Current set standard */
 	u32 input;
 	u32 output;
 	int enable;
-	int bright;
-	int contrast;
-	int hue;
-	int sat;
 };
 
 static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd)
@@ -83,6 +40,11 @@ static inline struct tvp5150 *to_tvp5150(struct v4l2_subdev *sd)
 	return container_of(sd, struct tvp5150, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct tvp5150, hdl)->sd;
+}
+
 static int tvp5150_read(struct v4l2_subdev *sd, unsigned char addr)
 {
 	struct i2c_client *c = v4l2_get_subdevdata(sd);
@@ -810,64 +772,28 @@ static int tvp5150_reset(struct v4l2_subdev *sd, u32 val)
 	tvp5150_write_inittab(sd, tvp5150_init_enable);
 
 	/* Initialize image preferences */
-	tvp5150_write(sd, TVP5150_BRIGHT_CTL, decoder->bright);
-	tvp5150_write(sd, TVP5150_CONTRAST_CTL, decoder->contrast);
-	tvp5150_write(sd, TVP5150_SATURATION_CTL, decoder->contrast);
-	tvp5150_write(sd, TVP5150_HUE_CTL, decoder->hue);
+	v4l2_ctrl_handler_setup(&decoder->hdl);
 
 	tvp5150_set_std(sd, decoder->norm);
 	return 0;
 };
 
-static int tvp5150_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-	v4l2_dbg(1, debug, sd, "g_ctrl called\n");
-
-	switch (ctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-		ctrl->value = tvp5150_read(sd, TVP5150_BRIGHT_CTL);
-		return 0;
-	case V4L2_CID_CONTRAST:
-		ctrl->value = tvp5150_read(sd, TVP5150_CONTRAST_CTL);
-		return 0;
-	case V4L2_CID_SATURATION:
-		ctrl->value = tvp5150_read(sd, TVP5150_SATURATION_CTL);
-		return 0;
-	case V4L2_CID_HUE:
-		ctrl->value = tvp5150_read(sd, TVP5150_HUE_CTL);
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static int tvp5150_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int tvp5150_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	u8 i, n;
-	n = ARRAY_SIZE(tvp5150_qctrl);
-
-	for (i = 0; i < n; i++) {
-		if (ctrl->id != tvp5150_qctrl[i].id)
-			continue;
-		if (ctrl->value < tvp5150_qctrl[i].minimum ||
-		    ctrl->value > tvp5150_qctrl[i].maximum)
-			return -ERANGE;
-		v4l2_dbg(1, debug, sd, "s_ctrl: id=%d, value=%d\n",
-					ctrl->id, ctrl->value);
-		break;
-	}
+	struct v4l2_subdev *sd = to_sd(ctrl);
 
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		tvp5150_write(sd, TVP5150_BRIGHT_CTL, ctrl->value);
+		tvp5150_write(sd, TVP5150_BRIGHT_CTL, ctrl->val);
 		return 0;
 	case V4L2_CID_CONTRAST:
-		tvp5150_write(sd, TVP5150_CONTRAST_CTL, ctrl->value);
+		tvp5150_write(sd, TVP5150_CONTRAST_CTL, ctrl->val);
 		return 0;
 	case V4L2_CID_SATURATION:
-		tvp5150_write(sd, TVP5150_SATURATION_CTL, ctrl->value);
+		tvp5150_write(sd, TVP5150_SATURATION_CTL, ctrl->val);
 		return 0;
 	case V4L2_CID_HUE:
-		tvp5150_write(sd, TVP5150_HUE_CTL, ctrl->value);
+		tvp5150_write(sd, TVP5150_HUE_CTL, ctrl->val);
 		return 0;
 	}
 	return -EINVAL;
@@ -995,29 +921,21 @@ static int tvp5150_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
 	return 0;
 }
 
-static int tvp5150_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
-	int i;
-
-	v4l2_dbg(1, debug, sd, "queryctrl called\n");
-
-	for (i = 0; i < ARRAY_SIZE(tvp5150_qctrl); i++)
-		if (qc->id && qc->id == tvp5150_qctrl[i].id) {
-			memcpy(qc, &(tvp5150_qctrl[i]),
-			       sizeof(*qc));
-			return 0;
-		}
-
-	return -EINVAL;
-}
-
 /* ----------------------------------------------------------------------- */
 
+static const struct v4l2_ctrl_ops tvp5150_ctrl_ops = {
+	.s_ctrl = tvp5150_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops tvp5150_core_ops = {
 	.log_status = tvp5150_log_status,
-	.g_ctrl = tvp5150_g_ctrl,
-	.s_ctrl = tvp5150_s_ctrl,
-	.queryctrl = tvp5150_queryctrl,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
 	.s_std = tvp5150_s_std,
 	.reset = tvp5150_reset,
 	.g_chip_ident = tvp5150_g_chip_ident,
@@ -1077,10 +995,25 @@ static int tvp5150_probe(struct i2c_client *c,
 	core->norm = V4L2_STD_ALL;	/* Default is autodetect */
 	core->input = TVP5150_COMPOSITE1;
 	core->enable = 1;
-	core->bright = 128;
-	core->contrast = 128;
-	core->hue = 0;
-	core->sat = 128;
+
+	v4l2_ctrl_handler_init(&core->hdl, 4);
+	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 255, 1, 128);
+	v4l2_ctrl_new_std(&core->hdl, &tvp5150_ctrl_ops,
+			V4L2_CID_HUE, -128, 127, 1, 0);
+	sd->ctrl_handler = &core->hdl;
+	if (core->hdl.error) {
+		int err = core->hdl.error;
+
+		v4l2_ctrl_handler_free(&core->hdl);
+		kfree(core);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&core->hdl);
 
 	if (debug > 1)
 		tvp5150_log_status(sd);
@@ -1090,12 +1023,14 @@ static int tvp5150_probe(struct i2c_client *c,
 static int tvp5150_remove(struct i2c_client *c)
 {
 	struct v4l2_subdev *sd = i2c_get_clientdata(c);
+	struct tvp5150 *decoder = to_tvp5150(sd);
 
 	v4l2_dbg(1, debug, sd,
 		"tvp5150.c: removing tvp5150 adapter on address 0x%x\n",
 		c->addr << 1);
 
 	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&decoder->hdl);
 	kfree(to_tvp5150(sd));
 	return 0;
 }
Signature · 1 line
1.7.0.4
#13 lore raw

PATCH 13/19 vpx3220: use control framework

In reply to Hans Verkuil
---
 drivers/media/video/vpx3220.c |  137 +++++++++++++++--------------------------
 1 files changed, 51 insertions(+), 86 deletions(-)
drivers/media/video/vpx3220.c +51 -86
index 91a01b3..75301d1 100644
@@ -28,6 +28,7 @@
 #include <linux/videodev2.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
 
 MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
 MODULE_AUTHOR("Laurent Pinchart");
@@ -44,16 +45,13 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 
 struct vpx3220 {
 	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
 	unsigned char reg[255];
 
 	v4l2_std_id norm;
 	int ident;
 	int input;
 	int enable;
-	int bright;
-	int contrast;
-	int hue;
-	int sat;
 };
 
 static inline struct vpx3220 *to_vpx3220(struct v4l2_subdev *sd)
@@ -61,6 +59,11 @@ static inline struct vpx3220 *to_vpx3220(struct v4l2_subdev *sd)
 	return container_of(sd, struct vpx3220, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct vpx3220, hdl)->sd;
+}
+
 static char *inputs[] = { "internal", "composite", "svideo" };
 
 /* ----------------------------------------------------------------------- */
@@ -417,88 +420,26 @@ static int vpx3220_s_stream(struct v4l2_subdev *sd, int enable)
 	return 0;
 }
 
-static int vpx3220_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
-	switch (qc->id) {
-	case V4L2_CID_BRIGHTNESS:
-		v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
-		break;
-
-	case V4L2_CID_CONTRAST:
-		v4l2_ctrl_query_fill(qc, 0, 63, 1, 32);
-		break;
-
-	case V4L2_CID_SATURATION:
-		v4l2_ctrl_query_fill(qc, 0, 4095, 1, 2048);
-		break;
-
-	case V4L2_CID_HUE:
-		v4l2_ctrl_query_fill(qc, -512, 511, 1, 0);
-		break;
-
-	default:
-		return -EINVAL;
-	}
-	return 0;
-}
-
-static int vpx3220_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int vpx3220_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	struct vpx3220 *decoder = to_vpx3220(sd);
+	struct v4l2_subdev *sd = to_sd(ctrl);
 
 	switch (ctrl->id) {
 	case V4L2_CID_BRIGHTNESS:
-		ctrl->value = decoder->bright;
-		break;
+		vpx3220_write(sd, 0xe6, ctrl->val);
+		return 0;
 	case V4L2_CID_CONTRAST:
-		ctrl->value = decoder->contrast;
-		break;
+		/* Bit 7 and 8 is for noise shaping */
+		vpx3220_write(sd, 0xe7, ctrl->val + 192);
+		return 0;
 	case V4L2_CID_SATURATION:
-		ctrl->value = decoder->sat;
-		break;
+		vpx3220_fp_write(sd, 0xa0, ctrl->val);
+		return 0;
 	case V4L2_CID_HUE:
-		ctrl->value = decoder->hue;
-		break;
-	default:
-		return -EINVAL;
+		vpx3220_fp_write(sd, 0x1c, ctrl->val);
+		return 0;
 	}
-	return 0;
-}
-
-static int vpx3220_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-	struct vpx3220 *decoder = to_vpx3220(sd);
-
-	switch (ctrl->id) {
-	case V4L2_CID_BRIGHTNESS:
-		if (decoder->bright != ctrl->value) {
-			decoder->bright = ctrl->value;
-			vpx3220_write(sd, 0xe6, decoder->bright);
-		}
-		break;
-	case V4L2_CID_CONTRAST:
-		if (decoder->contrast != ctrl->value) {
-			/* Bit 7 and 8 is for noise shaping */
-			decoder->contrast = ctrl->value;
-			vpx3220_write(sd, 0xe7, decoder->contrast + 192);
-		}
-		break;
-	case V4L2_CID_SATURATION:
-		if (decoder->sat != ctrl->value) {
-			decoder->sat = ctrl->value;
-			vpx3220_fp_write(sd, 0xa0, decoder->sat);
-		}
-		break;
-	case V4L2_CID_HUE:
-		if (decoder->hue != ctrl->value) {
-			decoder->hue = ctrl->value;
-			vpx3220_fp_write(sd, 0x1c, decoder->hue);
-		}
-		break;
-	default:
-		return -EINVAL;
-	}
-	return 0;
+	return -EINVAL;
 }
 
 static int vpx3220_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
@@ -511,12 +452,20 @@ static int vpx3220_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ide
 
 /* ----------------------------------------------------------------------- */
 
+static const struct v4l2_ctrl_ops vpx3220_ctrl_ops = {
+	.s_ctrl = vpx3220_s_ctrl,
+};
+
 static const struct v4l2_subdev_core_ops vpx3220_core_ops = {
 	.g_chip_ident = vpx3220_g_chip_ident,
 	.init = vpx3220_init,
-	.g_ctrl = vpx3220_g_ctrl,
-	.s_ctrl = vpx3220_s_ctrl,
-	.queryctrl = vpx3220_queryctrl,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
 	.s_std = vpx3220_s_std,
 };
 
@@ -558,10 +507,24 @@ static int vpx3220_probe(struct i2c_client *client,
 	decoder->norm = V4L2_STD_PAL;
 	decoder->input = 0;
 	decoder->enable = 1;
-	decoder->bright = 32768;
-	decoder->contrast = 32768;
-	decoder->hue = 32768;
-	decoder->sat = 32768;
+	v4l2_ctrl_handler_init(&decoder->hdl, 4);
+	v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
+		V4L2_CID_BRIGHTNESS, -128, 127, 1, 0);
+	v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
+		V4L2_CID_CONTRAST, 0, 63, 1, 32);
+	v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
+		V4L2_CID_SATURATION, 0, 4095, 1, 2048);
+	v4l2_ctrl_new_std(&decoder->hdl, &vpx3220_ctrl_ops,
+		V4L2_CID_HUE, -512, 511, 1, 0);
+	sd->ctrl_handler = &decoder->hdl;
+	if (decoder->hdl.error) {
+		int err = decoder->hdl.error;
+
+		v4l2_ctrl_handler_free(&decoder->hdl);
+		kfree(decoder);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&decoder->hdl);
 
 	ver = i2c_smbus_read_byte_data(client, 0x00);
 	pn = (i2c_smbus_read_byte_data(client, 0x02) << 8) +
@@ -599,9 +562,11 @@ static int vpx3220_probe(struct i2c_client *client,
 static int vpx3220_remove(struct i2c_client *client)
 {
 	struct v4l2_subdev *sd = i2c_get_clientdata(client);
+	struct vpx3220 *decoder = to_vpx3220(sd);
 
 	v4l2_device_unregister_subdev(sd);
-	kfree(to_vpx3220(sd));
+	v4l2_ctrl_handler_free(&decoder->hdl);
+	kfree(decoder);
 	return 0;
 }
 
Signature · 1 line
1.7.0.4
#14 lore raw

PATCH 14/19 tvp7002: use control framework

In reply to Hans Verkuil
---
 drivers/media/video/tvp7002.c |  117 +++++++++++++++--------------------------
 1 files changed, 43 insertions(+), 74 deletions(-)
drivers/media/video/tvp7002.c +43 -74
index e63b40f..2c4a6fd 100644
@@ -32,6 +32,7 @@
 #include <media/v4l2-device.h>
 #include <media/v4l2-chip-ident.h>
 #include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
 #include "tvp7002_reg.h"
 
 MODULE_DESCRIPTION("TI TVP7002 Video and Graphics Digitizer driver");
@@ -421,13 +422,13 @@ static const struct tvp7002_preset_definition tvp7002_presets[] = {
 /* Device definition */
 struct tvp7002 {
 	struct v4l2_subdev sd;
+	struct v4l2_ctrl_handler hdl;
 	const struct tvp7002_config *pdata;
 
 	int ver;
 	int streaming;
 
 	const struct tvp7002_preset_definition *current_preset;
-	u8 gain;
 };
 
 /*
@@ -441,6 +442,11 @@ static inline struct tvp7002 *to_tvp7002(struct v4l2_subdev *sd)
 	return container_of(sd, struct tvp7002, sd);
 }
 
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+	return &container_of(ctrl->handler, struct tvp7002, hdl)->sd;
+}
+
 /*
  * tvp7002_read - Read a value from a register in an TVP7002
  * @sd: ptr to v4l2_subdev struct
@@ -606,78 +612,25 @@ static int tvp7002_s_dv_preset(struct v4l2_subdev *sd,
 }
 
 /*
- * tvp7002_g_ctrl() - Get a control
- * @sd: ptr to v4l2_subdev struct
- * @ctrl: ptr to v4l2_control struct
- *
- * Get a control for a TVP7002 decoder device.
- * Returns zero when successful or -EINVAL if register access fails.
- */
-static int tvp7002_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
-	struct tvp7002 *device = to_tvp7002(sd);
-
-	switch (ctrl->id) {
-	case V4L2_CID_GAIN:
-		ctrl->value = device->gain;
-		return 0;
-	default:
-		return -EINVAL;
-	}
-}
-
-/*
  * tvp7002_s_ctrl() - Set a control
- * @sd: ptr to v4l2_subdev struct
- * @ctrl: ptr to v4l2_control struct
+ * @ctrl: ptr to v4l2_ctrl struct
  *
  * Set a control in TVP7002 decoder device.
  * Returns zero when successful or -EINVAL if register access fails.
  */
-static int tvp7002_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int tvp7002_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	struct tvp7002 *device = to_tvp7002(sd);
+	struct v4l2_subdev *sd = to_sd(ctrl);
 	int error = 0;
 
 	switch (ctrl->id) {
 	case V4L2_CID_GAIN:
-		tvp7002_write_err(sd, TVP7002_R_FINE_GAIN,
-						ctrl->value & 0xff, &error);
-		tvp7002_write_err(sd, TVP7002_G_FINE_GAIN,
-						ctrl->value & 0xff, &error);
-		tvp7002_write_err(sd, TVP7002_B_FINE_GAIN,
-						ctrl->value & 0xff, &error);
-
-		if (error < 0)
-			return error;
-
-		/* Set only after knowing there is no error */
-		device->gain = ctrl->value & 0xff;
-		return 0;
-	default:
-		return -EINVAL;
-	}
-}
-
-/*
- * tvp7002_queryctrl() - Query a control
- * @sd: ptr to v4l2_subdev struct
- * @qc: ptr to v4l2_queryctrl struct
- *
- * Query a control of a TVP7002 decoder device.
- * Returns zero when successful or -EINVAL if register read fails.
- */
-static int tvp7002_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
-	switch (qc->id) {
-	case V4L2_CID_GAIN:
-		/*
-		 * Gain is supported [0-255, default=0, step=1]
-		 */
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 0);
-	default:
-		return -EINVAL;
+		tvp7002_write_err(sd, TVP7002_R_FINE_GAIN, ctrl->val, &error);
+		tvp7002_write_err(sd, TVP7002_G_FINE_GAIN, ctrl->val, &error);
+		tvp7002_write_err(sd, TVP7002_B_FINE_GAIN, ctrl->val, &error);
+		return error;
 	}
+	return -EINVAL;
 }
 
 /*
@@ -924,7 +877,7 @@ static int tvp7002_log_status(struct v4l2_subdev *sd)
 					device->streaming ? "yes" : "no");
 
 	/* Print the current value of the gain control */
-	v4l2_info(sd, "Gain: %u\n", device->gain);
+	v4l2_ctrl_handler_log_status(&device->hdl, sd->name);
 
 	return 0;
 }
@@ -946,13 +899,21 @@ static int tvp7002_enum_dv_presets(struct v4l2_subdev *sd,
 	return v4l_fill_dv_preset_info(tvp7002_presets[preset->index].preset, preset);
 }
 
+static const struct v4l2_ctrl_ops tvp7002_ctrl_ops = {
+	.s_ctrl = tvp7002_s_ctrl,
+};
+
 /* V4L2 core operation handlers */
 static const struct v4l2_subdev_core_ops tvp7002_core_ops = {
 	.g_chip_ident = tvp7002_g_chip_ident,
 	.log_status = tvp7002_log_status,
-	.g_ctrl = tvp7002_g_ctrl,
-	.s_ctrl = tvp7002_s_ctrl,
-	.queryctrl = tvp7002_queryctrl,
+	.g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+	.try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+	.s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+	.g_ctrl = v4l2_subdev_g_ctrl,
+	.s_ctrl = v4l2_subdev_s_ctrl,
+	.queryctrl = v4l2_subdev_queryctrl,
+	.querymenu = v4l2_subdev_querymenu,
 #ifdef CONFIG_VIDEO_ADV_DEBUG
 	.g_register = tvp7002_g_register,
 	.s_register = tvp7002_s_register,
@@ -977,12 +938,6 @@ static const struct v4l2_subdev_ops tvp7002_ops = {
 	.video = &tvp7002_video_ops,
 };
 
-static struct tvp7002 tvp7002_dev = {
-	.streaming = 0,
-	.current_preset = tvp7002_presets,
-	.gain = 0,
-};
-
 /*
  * tvp7002_probe - Probe a TVP7002 device
  * @c: ptr to i2c_client struct
@@ -1013,14 +968,14 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id)
 		return -ENODEV;
 	}
 
-	device = kmalloc(sizeof(struct tvp7002), GFP_KERNEL);
+	device = kzalloc(sizeof(struct tvp7002), GFP_KERNEL);
 
 	if (!device)
 		return -ENOMEM;
 
-	*device = tvp7002_dev;
 	sd = &device->sd;
 	device->pdata = c->dev.platform_data;
+	device->current_preset = tvp7002_presets;
 
 	/* Tell v4l2 the device is ready */
 	v4l2_i2c_subdev_init(sd, c, &tvp7002_ops);
@@ -1060,6 +1015,19 @@ static int tvp7002_probe(struct i2c_client *c, const struct i2c_device_id *id)
 	preset.preset = device->current_preset->preset;
 	error = tvp7002_s_dv_preset(sd, &preset);
 
+	v4l2_ctrl_handler_init(&device->hdl, 1);
+	v4l2_ctrl_new_std(&device->hdl, &tvp7002_ctrl_ops,
+			V4L2_CID_GAIN, 0, 255, 1, 0);
+	sd->ctrl_handler = &device->hdl;
+	if (device->hdl.error) {
+		int err = device->hdl.error;
+
+		v4l2_ctrl_handler_free(&device->hdl);
+		kfree(device);
+		return err;
+	}
+	v4l2_ctrl_handler_setup(&device->hdl);
+
 found_error:
 	if (error < 0)
 		kfree(device);
@@ -1083,6 +1051,7 @@ static int tvp7002_remove(struct i2c_client *c)
 				"on address 0x%x\n", c->addr);
 
 	v4l2_device_unregister_subdev(sd);
+	v4l2_ctrl_handler_free(&device->hdl);
 	kfree(device);
 	return 0;
 }
Signature · 1 line
1.7.0.4
#15 lore raw

PATCH 15/19 v4l2-ctrls: use const char * const * for the menu arrays

In reply to Hans Verkuil

This prevents checkpatch warnings generated when defining 'static const char *foo[]' arrays. It makes sense to use const char * const * anyway since the pointers in the array are indeed const.

---
 drivers/media/video/cx2341x.c                      |    8 ++--
 drivers/media/video/pvrusb2/pvrusb2-ctrl.c         |    6 +-
 drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h |    2 +-
 drivers/media/video/v4l2-common.c                  |    6 +-
 drivers/media/video/v4l2-ctrls.c                   |   46 ++++++++++----------
 include/media/cx2341x.h                            |    2 +-
 include/media/v4l2-common.h                        |    6 +-
 include/media/v4l2-ctrls.h                         |    4 +-
 8 files changed, 40 insertions(+), 40 deletions(-)
drivers/media/video/cx2341x.c +4 -4
index e5c3c8d..103ef6b 100644
@@ -853,9 +853,9 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
 }
 EXPORT_SYMBOL(cx2341x_ctrl_query);
 
-const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id)
+const char * const *cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id)
 {
-	static const char *mpeg_stream_type_without_ts[] = {
+	static const char * const mpeg_stream_type_without_ts[] = {
 		"MPEG-2 Program Stream",
 		"",
 		"MPEG-1 System Stream",
@@ -952,7 +952,7 @@ int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
 	for (i = 0; i < ctrls->count; i++) {
 		struct v4l2_ext_control *ctrl = ctrls->controls + i;
 		struct v4l2_queryctrl qctrl;
-		const char **menu_items = NULL;
+		const char * const *menu_items = NULL;
 
 		qctrl.id = ctrl->id;
 		err = cx2341x_ctrl_query(params, &qctrl);
@@ -1135,7 +1135,7 @@ EXPORT_SYMBOL(cx2341x_update);
 
 static const char *cx2341x_menu_item(const struct cx2341x_mpeg_params *p, u32 id)
 {
-	const char **menu = cx2341x_ctrl_get_menu(p, id);
+	const char * const *menu = cx2341x_ctrl_get_menu(p, id);
 	struct v4l2_ext_control ctrl;
 
 	if (menu == NULL)
drivers/media/video/pvrusb2/pvrusb2-ctrl.c +3 -3
index 55ea914..7d5a713 100644
@@ -203,7 +203,7 @@ int pvr2_ctrl_get_valname(struct pvr2_ctrl *cptr,int val,
 	*blen = 0;
 	LOCK_TAKE(cptr->hdw->big_lock); do {
 		if (cptr->info->type == pvr2_ctl_enum) {
-			const char **names;
+			const char * const *names;
 			names = cptr->info->def.type_enum.value_names;
 			if (pvr2_ctrl_range_check(cptr,val) == 0) {
 				if (names[val]) {
@@ -367,7 +367,7 @@ static const char *boolNames[] = {
 
 static int parse_token(const char *ptr,unsigned int len,
 		       int *valptr,
-		       const char **names,unsigned int namecnt)
+		       const char * const *names, unsigned int namecnt)
 {
 	char buf[33];
 	unsigned int slen;
@@ -559,7 +559,7 @@ int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *cptr,
 		*len = scnprintf(buf,maxlen,"%s",val ? "true" : "false");
 		ret = 0;
 	} else if (cptr->info->type == pvr2_ctl_enum) {
-		const char **names;
+		const char * const *names;
 		names = cptr->info->def.type_enum.value_names;
 		if ((val >= 0) &&
 		    (val < cptr->info->def.type_enum.count)) {
drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h +1 -1
index cb4057b..ac94a8b 100644
@@ -115,7 +115,7 @@ struct pvr2_ctl_info {
 		} type_int;
 		struct { /* enumerated control */
 			unsigned int count;       /* enum value count */
-			const char **value_names; /* symbol names */
+			const char * const *value_names; /* symbol names */
 		} type_enum;
 		struct { /* bitmask control */
 			unsigned int valid_bits; /* bits in use */
drivers/media/video/v4l2-common.c +3 -3
index b5eb1f3..3f0871b 100644
@@ -150,7 +150,7 @@ EXPORT_SYMBOL(v4l2_prio_check);
    struct v4l2_queryctrl and the available menu items. Note that
    menu_items may be NULL, in that case it is ignored. */
 int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
-		const char **menu_items)
+		const char * const *menu_items)
 {
 	if (qctrl->flags & V4L2_CTRL_FLAG_DISABLED)
 		return -EINVAL;
@@ -199,7 +199,7 @@ EXPORT_SYMBOL(v4l2_ctrl_query_fill);
    If menu_items is NULL, then the menu items are retrieved using
    v4l2_ctrl_get_menu. */
 int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qctrl,
-	       const char **menu_items)
+	       const char * const *menu_items)
 {
 	int i;
 
@@ -222,7 +222,7 @@ EXPORT_SYMBOL(v4l2_ctrl_query_menu);
    Use this if there are 'holes' in the list of valid menu items. */
 int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *ids)
 {
-	const char **menu_items = v4l2_ctrl_get_menu(qmenu->id);
+	const char * const *menu_items = v4l2_ctrl_get_menu(qmenu->id);
 
 	qmenu->reserved = 0;
 	if (menu_items == NULL || ids == NULL)
drivers/media/video/v4l2-ctrls.c +23 -23

169 lines not on this page · raw message

include/media/cx2341x.h +1 -1
index 8d08ebf..9635eeb 100644
@@ -95,7 +95,7 @@ int cx2341x_update(void *priv, cx2341x_mbox_func func,
 		const struct cx2341x_mpeg_params *new);
 int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
 		struct v4l2_queryctrl *qctrl);
-const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id);
+const char * const *cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id);
 int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
 		struct v4l2_ext_controls *ctrls, unsigned int cmd);
 void cx2341x_fill_defaults(struct cx2341x_mpeg_params *p);
include/media/v4l2-common.h +3 -3
index 239125a..2d65b35 100644
@@ -98,12 +98,12 @@ int v4l2_prio_check(struct v4l2_prio_state *global, enum v4l2_priority local);
 /* Control helper functions */
 
 int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
-		const char **menu_items);
+		const char * const *menu_items);
 const char *v4l2_ctrl_get_name(u32 id);
-const char **v4l2_ctrl_get_menu(u32 id);
+const char * const *v4l2_ctrl_get_menu(u32 id);
 int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def);
 int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu,
-		struct v4l2_queryctrl *qctrl, const char **menu_items);
+		struct v4l2_queryctrl *qctrl, const char * const *menu_items);
 #define V4L2_CTRL_MENU_IDS_END (0xffffffff)
 int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *ids);
 
include/media/v4l2-ctrls.h +2 -2
index 9b7bea9..d69ab4a 100644
@@ -112,7 +112,7 @@ struct v4l2_ctrl {
 		u32 step;
 		u32 menu_skip_mask;
 	};
-	const char **qmenu;
+	const char * const *qmenu;
 	unsigned long flags;
 	union {
 		s32 val;
@@ -202,7 +202,7 @@ struct v4l2_ctrl_config {
 	s32 def;
 	u32 flags;
 	u32 menu_skip_mask;
-	const char **qmenu;
+	const char * const *qmenu;
 	unsigned int is_private:1;
 	unsigned int is_volatile:1;
 };
Signature · 1 line
1.7.0.4
#16 lore raw

PATCH 16/19 vivi: convert to the control framework and add test controls.

In reply to Hans Verkuil
---
 drivers/media/video/vivi.c |  228 +++++++++++++++++++++++++++-----------------
 1 files changed, 139 insertions(+), 89 deletions(-)
drivers/media/video/vivi.c +139 -89
index 9797e5a..6e1f37f 100644
@@ -29,6 +29,7 @@
 #include <media/videobuf-vmalloc.h>
 #include <media/v4l2-device.h>
 #include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
 #include <media/v4l2-common.h>
 
 #define VIVI_MODULE_NAME "vivi"
@@ -162,13 +163,20 @@ static LIST_HEAD(vivi_devlist);
 struct vivi_dev {
 	struct list_head           vivi_devlist;
 	struct v4l2_device 	   v4l2_dev;
+	struct v4l2_ctrl_handler   ctrl_handler;
 
 	/* controls */
-	int 			   brightness;
-	int 			   contrast;
-	int 			   saturation;
-	int 			   hue;
-	int 			   volume;
+	struct v4l2_ctrl	   *brightness;
+	struct v4l2_ctrl	   *contrast;
+	struct v4l2_ctrl	   *saturation;
+	struct v4l2_ctrl	   *hue;
+	struct v4l2_ctrl	   *volume;
+	struct v4l2_ctrl	   *button;
+	struct v4l2_ctrl	   *boolean;
+	struct v4l2_ctrl	   *int32;
+	struct v4l2_ctrl	   *int64;
+	struct v4l2_ctrl	   *menu;
+	struct v4l2_ctrl	   *string;
 
 	spinlock_t                 slock;
 	struct mutex		   mutex;
@@ -181,6 +189,7 @@ struct vivi_dev {
 	/* Several counters */
 	unsigned 		   ms;
 	unsigned long              jiffies;
+	unsigned		   button_pressed;
 
 	int			   mv_count;	/* Controls bars movement */
 
@@ -472,14 +481,30 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
 			dev->width, dev->height, dev->input);
 	gen_text(dev, vbuf, line++ * 16, 16, str);
 
+	mutex_lock(&dev->ctrl_handler.lock);
 	snprintf(str, sizeof(str), " brightness %3d, contrast %3d, saturation %3d, hue %d ",
-			dev->brightness,
-			dev->contrast,
-			dev->saturation,
-			dev->hue);
+			dev->brightness->cur.val,
+			dev->contrast->cur.val,
+			dev->saturation->cur.val,
+			dev->hue->cur.val);
 	gen_text(dev, vbuf, line++ * 16, 16, str);
-	snprintf(str, sizeof(str), " volume %3d ", dev->volume);
+	snprintf(str, sizeof(str), " volume %3d ", dev->volume->cur.val);
 	gen_text(dev, vbuf, line++ * 16, 16, str);
+	snprintf(str, sizeof(str), " int32 %d, int64 %lld ",
+			dev->int32->cur.val,
+			dev->int64->cur.val64);
+	gen_text(dev, vbuf, line++ * 16, 16, str);
+	snprintf(str, sizeof(str), " boolean %d, menu %s, string \"%s\" ",
+			dev->boolean->cur.val,
+			dev->menu->qmenu[dev->menu->cur.val],
+			dev->string->cur.string);
+	mutex_unlock(&dev->ctrl_handler.lock);
+	gen_text(dev, vbuf, line++ * 16, 16, str);
+	if (dev->button_pressed) {
+		dev->button_pressed--;
+		snprintf(str, sizeof(str), " button pressed!");
+		gen_text(dev, vbuf, line++ * 16, 16, str);
+	}
 
 	dev->mv_count += 2;
 
@@ -947,80 +972,14 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
 }
 
 /* --- controls ---------------------------------------------- */
-static int vidioc_queryctrl(struct file *file, void *priv,
-			    struct v4l2_queryctrl *qc)
-{
-	switch (qc->id) {
-	case V4L2_CID_AUDIO_VOLUME:
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 200);
-	case V4L2_CID_BRIGHTNESS:
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 127);
-	case V4L2_CID_CONTRAST:
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 16);
-	case V4L2_CID_SATURATION:
-		return v4l2_ctrl_query_fill(qc, 0, 255, 1, 127);
-	case V4L2_CID_HUE:
-		return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
-	}
-	return -EINVAL;
-}
 
-static int vidioc_g_ctrl(struct file *file, void *priv,
-			 struct v4l2_control *ctrl)
+static int vivi_s_ctrl(struct v4l2_ctrl *ctrl)
 {
-	struct vivi_dev *dev = video_drvdata(file);
+	struct vivi_dev *dev = container_of(ctrl->handler, struct vivi_dev, ctrl_handler);
 
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_VOLUME:
-		ctrl->value = dev->volume;
-		return 0;
-	case V4L2_CID_BRIGHTNESS:
-		ctrl->value = dev->brightness;
-		return 0;
-	case V4L2_CID_CONTRAST:
-		ctrl->value = dev->contrast;
-		return 0;
-	case V4L2_CID_SATURATION:
-		ctrl->value = dev->saturation;
-		return 0;
-	case V4L2_CID_HUE:
-		ctrl->value = dev->hue;
-		return 0;
-	}
-	return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
-				struct v4l2_control *ctrl)
-{
-	struct vivi_dev *dev = video_drvdata(file);
-	struct v4l2_queryctrl qc;
-	int err;
-
-	qc.id = ctrl->id;
-	err = vidioc_queryctrl(file, priv, &qc);
-	if (err < 0)
-		return err;
-	if (ctrl->value < qc.minimum || ctrl->value > qc.maximum)
-		return -ERANGE;
-	switch (ctrl->id) {
-	case V4L2_CID_AUDIO_VOLUME:
-		dev->volume = ctrl->value;
-		return 0;
-	case V4L2_CID_BRIGHTNESS:
-		dev->brightness = ctrl->value;
-		return 0;
-	case V4L2_CID_CONTRAST:
-		dev->contrast = ctrl->value;
-		return 0;
-	case V4L2_CID_SATURATION:
-		dev->saturation = ctrl->value;
-		return 0;
-	case V4L2_CID_HUE:
-		dev->hue = ctrl->value;
-		return 0;
-	}
-	return -EINVAL;
+	if (ctrl == dev->button)
+		dev->button_pressed = 30;
+	return 0;
 }
 
 /* ------------------------------------------------------------------
@@ -1077,6 +1036,79 @@ static int vivi_mmap(struct file *file, struct vm_area_struct *vma)
 	return ret;
 }
 
+static const struct v4l2_ctrl_ops vivi_ctrl_ops = {
+	.s_ctrl = vivi_s_ctrl,
+};
+
+#define VIVI_CID_CUSTOM_BASE	(V4L2_CID_USER_BASE | 0xf000)
+
+static const struct v4l2_ctrl_config vivi_ctrl_button = {
+	.ops = &vivi_ctrl_ops,
+	.id = VIVI_CID_CUSTOM_BASE + 0,
+	.name = "Button",
+	.type = V4L2_CTRL_TYPE_BUTTON,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_boolean = {
+	.ops = &vivi_ctrl_ops,
+	.id = VIVI_CID_CUSTOM_BASE + 1,
+	.name = "Boolean",
+	.type = V4L2_CTRL_TYPE_BOOLEAN,
+	.min = 0,
+	.max = 1,
+	.step = 1,
+	.def = 1,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_int32 = {
+	.ops = &vivi_ctrl_ops,
+	.id = VIVI_CID_CUSTOM_BASE + 2,
+	.name = "Integer 32 Bits",
+	.type = V4L2_CTRL_TYPE_INTEGER,
+	.min = -2147483648,
+	.max = 2147483647,
+	.step = 1,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_int64 = {
+	.ops = &vivi_ctrl_ops,
+	.id = VIVI_CID_CUSTOM_BASE + 3,
+	.name = "Integer 64 Bits",
+	.type = V4L2_CTRL_TYPE_INTEGER64,
+};
+
+static const char * const vivi_ctrl_menu_strings[] = {
+	"Menu Item 0 (Skipped)",
+	"Menu Item 1",
+	"Menu Item 2 (Skipped)",
+	"Menu Item 3",
+	"Menu Item 4",
+	"Menu Item 5 (Skipped)",
+	NULL,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_menu = {
+	.ops = &vivi_ctrl_ops,
+	.id = VIVI_CID_CUSTOM_BASE + 4,
+	.name = "Menu",
+	.type = V4L2_CTRL_TYPE_MENU,
+	.min = 1,
+	.max = 4,
+	.def = 3,
+	.menu_skip_mask = 0x04,
+	.qmenu = vivi_ctrl_menu_strings,
+};
+
+static const struct v4l2_ctrl_config vivi_ctrl_string = {
+	.ops = &vivi_ctrl_ops,
+	.id = VIVI_CID_CUSTOM_BASE + 5,
+	.name = "String",
+	.type = V4L2_CTRL_TYPE_STRING,
+	.min = 2,
+	.max = 4,
+	.step = 1,
+};
+
 static const struct v4l2_file_operations vivi_fops = {
 	.owner		= THIS_MODULE,
 	.release        = vivi_close,
@@ -1102,9 +1134,6 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
 	.vidioc_s_input       = vidioc_s_input,
 	.vidioc_streamon      = vidioc_streamon,
 	.vidioc_streamoff     = vidioc_streamoff,
-	.vidioc_queryctrl     = vidioc_queryctrl,
-	.vidioc_g_ctrl        = vidioc_g_ctrl,
-	.vidioc_s_ctrl        = vidioc_s_ctrl,
 #ifdef CONFIG_VIDEO_V4L1_COMPAT
 	.vidiocgmbuf          = vidiocgmbuf,
 #endif
@@ -1138,6 +1167,7 @@ static int vivi_release(void)
 			video_device_node_name(dev->vfd));
 		video_unregister_device(dev->vfd);
 		v4l2_device_unregister(&dev->v4l2_dev);
+		v4l2_ctrl_handler_free(&dev->ctrl_handler);
 		kfree(dev);
 	}
 
@@ -1148,6 +1178,7 @@ static int __init vivi_create_instance(int inst)
 {
 	struct vivi_dev *dev;
 	struct video_device *vfd;
+	struct v4l2_ctrl_handler *hdl;
 	int ret;
 
 	dev = kzalloc(sizeof(*dev), GFP_KERNEL);
@@ -1163,11 +1194,29 @@ static int __init vivi_create_instance(int inst)
 	dev->fmt = &formats[0];
 	dev->width = 640;
 	dev->height = 480;
-	dev->volume = 200;
-	dev->brightness = 127;
-	dev->contrast = 16;
-	dev->saturation = 127;
-	dev->hue = 0;
+	hdl = &dev->ctrl_handler;
+	v4l2_ctrl_handler_init(hdl, 11);
+	dev->volume = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+			V4L2_CID_AUDIO_VOLUME, 0, 255, 1, 200);
+	dev->brightness = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+			V4L2_CID_BRIGHTNESS, 0, 255, 1, 127);
+	dev->contrast = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+			V4L2_CID_CONTRAST, 0, 255, 1, 16);
+	dev->saturation = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+			V4L2_CID_SATURATION, 0, 255, 1, 127);
+	dev->hue = v4l2_ctrl_new_std(hdl, &vivi_ctrl_ops,
+			V4L2_CID_HUE, -128, 127, 1, 0);
+	dev->button = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_button, NULL);
+	dev->int32 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int32, NULL);
+	dev->int64 = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_int64, NULL);
+	dev->boolean = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_boolean, NULL);
+	dev->menu = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_menu, NULL);
+	dev->string = v4l2_ctrl_new_custom(hdl, &vivi_ctrl_string, NULL);
+	if (hdl->error) {
+		ret = hdl->error;
+		goto unreg_dev;
+	}
+	dev->v4l2_dev.ctrl_handler = hdl;
 
 	/* initialize locks */
 	spin_lock_init(&dev->slock);
@@ -1212,6 +1261,7 @@ static int __init vivi_create_instance(int inst)
 rel_vdev:
 	video_device_release(vfd);
 unreg_dev:
+	v4l2_ctrl_handler_free(hdl);
 	v4l2_device_unregister(&dev->v4l2_dev);
 free_dev:
 	kfree(dev);
Signature · 1 line
1.7.0.4
#17 lore raw

PATCH 17/19 v4l: fix handling of v4l2_input.capabilities

In reply to Hans Verkuil

The v4l core sets the v4l2_input.capabilities field based on the supplied v4l2_ioctl_ops. However, several drivers do a memset or memcpy of the v4l2_input struct, thus overwriting that field incorrectly.

Either remove the memset (which is already done by the v4l core), or add the proper capabilities field in case of a memcpy.

The same is also true for v4l2_output, but that only affected the ivtv driver.

---
 drivers/media/dvb/ttpci/av7110_v4l.c         |    4 ++++
 drivers/media/dvb/ttpci/budget-av.c          |    6 ++++--
 drivers/media/video/cx18/cx18-cards.c        |    1 -
 drivers/media/video/cx23885/cx23885-video.c  |    1 -
 drivers/media/video/et61x251/et61x251_core.c |    1 +
 drivers/media/video/hexium_gemini.c          |   18 +++++++++---------
 drivers/media/video/hexium_orion.c           |   18 +++++++++---------
 drivers/media/video/ivtv/ivtv-cards.c        |    2 --
 drivers/media/video/mxb.c                    |    8 ++++----
 drivers/media/video/saa7134/saa7134-video.c  |    1 -
 drivers/media/video/sn9c102/sn9c102_core.c   |    1 +
 drivers/media/video/timblogiw.c              |    1 -
 drivers/media/video/vino.c                   |    3 ---
 drivers/media/video/zoran/zoran_driver.c     |    6 ------
 drivers/staging/cx25821/cx25821-video.c      |    2 --
 15 files changed, 32 insertions(+), 41 deletions(-)
drivers/media/dvb/ttpci/av7110_v4l.c +4 -0
index ac20c5b..cdd31ca 100644
@@ -100,6 +100,7 @@ static struct v4l2_input inputs[4] = {
 		.tuner		= 0, /* ignored */
 		.std		= V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
 		.status		= 0,
+		.capabilities	= V4L2_IN_CAP_STD,
 	}, {
 		.index		= 1,
 		.name		= "Television",
@@ -108,6 +109,7 @@ static struct v4l2_input inputs[4] = {
 		.tuner		= 0,
 		.std		= V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
 		.status		= 0,
+		.capabilities	= V4L2_IN_CAP_STD,
 	}, {
 		.index		= 2,
 		.name		= "Video",
@@ -116,6 +118,7 @@ static struct v4l2_input inputs[4] = {
 		.tuner		= 0,
 		.std		= V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
 		.status		= 0,
+		.capabilities	= V4L2_IN_CAP_STD,
 	}, {
 		.index		= 3,
 		.name		= "Y/C",
@@ -124,6 +127,7 @@ static struct v4l2_input inputs[4] = {
 		.tuner		= 0,
 		.std		= V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
 		.status		= 0,
+		.capabilities	= V4L2_IN_CAP_STD,
 	}
 };
 
drivers/media/dvb/ttpci/budget-av.c +4 -2
index 97afc01..e957d76 100644
@@ -1406,8 +1406,10 @@ static int budget_av_detach(struct saa7146_dev *dev)
 
 #define KNC1_INPUTS 2
 static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
-	{0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
-	{1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
+	{ 0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0,
+		V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ 1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0,
+		V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
 };
 
 static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
drivers/media/video/cx18/cx18-cards.c +0 -1
index 52ba913..8717773 100644
@@ -546,7 +546,6 @@ int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input)
 		"Component 1"
 	};
 
-	memset(input, 0, sizeof(*input));
 	if (index >= cx->nof_inputs)
 		return -EINVAL;
 	input->index = index;
drivers/media/video/cx23885/cx23885-video.c +0 -1
index 8b2fb8a..fa08ea3 100644
@@ -1155,7 +1155,6 @@ static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
 	if (0 == INPUT(n)->type)
 		return -EINVAL;
 
-	memset(i, 0, sizeof(*i));
 	i->index = n;
 	i->type  = V4L2_INPUT_TYPE_CAMERA;
 	strcpy(i->name, iname[INPUT(n)->type]);
drivers/media/video/et61x251/et61x251_core.c +1 -0
index a5cfc76..f5892ee 100644
@@ -1610,6 +1610,7 @@ et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg)
 	memset(&i, 0, sizeof(i));
 	strcpy(i.name, "Camera");
 	i.type = V4L2_INPUT_TYPE_CAMERA;
+	i.capabilities = V4L2_IN_CAP_STD;
 
 	if (copy_to_user(arg, &i, sizeof(i)))
 		return -EFAULT;
drivers/media/video/hexium_gemini.c +9 -9
index 7ae9636..cdf8b19 100644
@@ -37,15 +37,15 @@ static int hexium_num;
 
 #define HEXIUM_INPUTS	9
 static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
-	{ 0, "CVBS 1",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-	{ 1, "CVBS 2",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-	{ 2, "CVBS 3",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-	{ 3, "CVBS 4",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-	{ 4, "CVBS 5",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-	{ 5, "CVBS 6",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-	{ 6, "Y/C 1",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-	{ 7, "Y/C 2",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-	{ 8, "Y/C 3",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+	{ 0, "CVBS 1",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ 1, "CVBS 2",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ 2, "CVBS 3",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ 3, "CVBS 4",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ 4, "CVBS 5",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ 5, "CVBS 6",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ 6, "Y/C 1",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ 7, "Y/C 2",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ 8, "Y/C 3",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
 };
 
 #define HEXIUM_AUDIOS	0
drivers/media/video/hexium_orion.c +9 -9
index b72d0f0..6ad7e1c 100644
@@ -38,15 +38,15 @@ static int hexium_num;
 
 #define HEXIUM_INPUTS	9
 static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
-	{ 0, "CVBS 1",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-	{ 1, "CVBS 2",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-	{ 2, "CVBS 3",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-	{ 3, "CVBS 4",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-	{ 4, "CVBS 5",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-	{ 5, "CVBS 6",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-	{ 6, "Y/C 1",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-	{ 7, "Y/C 2",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-	{ 8, "Y/C 3",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+	{ 0, "CVBS 1",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ 1, "CVBS 2",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ 2, "CVBS 3",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ 3, "CVBS 4",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ 4, "CVBS 5",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ 5, "CVBS 6",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ 6, "Y/C 1",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ 7, "Y/C 2",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ 8, "Y/C 3",	V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
 };
 
 #define HEXIUM_AUDIOS	0
drivers/media/video/ivtv/ivtv-cards.c +0 -2
index 87afbbe..b6f2a2b 100644
@@ -1313,7 +1313,6 @@ int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input)
 		"Composite 3"
 	};
 
-	memset(input, 0, sizeof(*input));
 	if (index >= itv->nof_inputs)
 		return -EINVAL;
 	input->index = index;
@@ -1331,7 +1330,6 @@ int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output)
 {
 	const struct ivtv_card_output *card_output = itv->card->video_outputs + index;
 
-	memset(output, 0, sizeof(*output));
 	if (index >= itv->card->nof_outputs)
 		return -EINVAL;
 	output->index = index;
drivers/media/video/mxb.c +4 -4
index 4e8fd96..e8846a0 100644
@@ -59,10 +59,10 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
 enum { TUNER, AUX1, AUX3, AUX3_YC };
 
 static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
-	{ TUNER,	"Tuner",		V4L2_INPUT_TYPE_TUNER,	1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-	{ AUX1,		"AUX1",			V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-	{ AUX3,		"AUX3 Composite",	V4L2_INPUT_TYPE_CAMERA,	4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
-	{ AUX3_YC,	"AUX3 S-Video",		V4L2_INPUT_TYPE_CAMERA,	4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+	{ TUNER,	"Tuner",		V4L2_INPUT_TYPE_TUNER,	1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ AUX1,		"AUX1",			V4L2_INPUT_TYPE_CAMERA,	2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ AUX3,		"AUX3 Composite",	V4L2_INPUT_TYPE_CAMERA,	4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+	{ AUX3_YC,	"AUX3 S-Video",		V4L2_INPUT_TYPE_CAMERA,	4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
 };
 
 /* this array holds the information, which port of the saa7146 each
drivers/media/video/saa7134/saa7134-video.c +0 -1
index f0b1573..25e5af4 100644
@@ -1748,7 +1748,6 @@ static int saa7134_enum_input(struct file *file, void *priv,
 		return -EINVAL;
 	if (NULL == card_in(dev, i->index).name)
 		return -EINVAL;
-	memset(i, 0, sizeof(*i));
 	i->index = n;
 	i->type  = V4L2_INPUT_TYPE_CAMERA;
 	strcpy(i->name, card_in(dev, n).name);
drivers/media/video/sn9c102/sn9c102_core.c +1 -0
index 28e19da..b5ca3b8 100644
@@ -2189,6 +2189,7 @@ sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
 	memset(&i, 0, sizeof(i));
 	strcpy(i.name, "Camera");
 	i.type = V4L2_INPUT_TYPE_CAMERA;
+	i.capabilities = V4L2_IN_CAP_STD;
 
 	if (copy_to_user(arg, &i, sizeof(i)))
 		return -EFAULT;
drivers/media/video/timblogiw.c +0 -1
index cf48aa9..67911c0 100644
@@ -369,7 +369,6 @@ static int timblogiw_enuminput(struct file *file, void  *priv,
 	if (inp->index != 0)
 		return -EINVAL;
 
-	memset(inp, 0, sizeof(*inp));
 	inp->index = 0;
 
 	strncpy(inp->name, "Timb input 1", sizeof(inp->name) - 1);
drivers/media/video/vino.c +0 -3
index 7e7eec4..d63e9d9 100644
@@ -2954,9 +2954,6 @@ static int vino_enum_input(struct file *file, void *__fh,
 	if (input == VINO_INPUT_NONE)
 		return -EINVAL;
 
-	memset(i, 0, sizeof(struct v4l2_input));
-
-	i->index = index;
 	i->type = V4L2_INPUT_TYPE_CAMERA;
 	i->std = vino_inputs[input].std;
 	strcpy(i->name, vino_inputs[input].name);
drivers/media/video/zoran/zoran_driver.c +0 -6
index 67a52e8..dc17acb 100644
@@ -2766,11 +2766,6 @@ static int zoran_enum_input(struct file *file, void *__fh,
 
 	if (inp->index >= zr->card.inputs)
 		return -EINVAL;
-	else {
-		int id = inp->index;
-		memset(inp, 0, sizeof(*inp));
-		inp->index = id;
-	}
 
 	strncpy(inp->name, zr->card.input[inp->index].name,
 		sizeof(inp->name) - 1);
@@ -2820,7 +2815,6 @@ static int zoran_enum_output(struct file *file, void *__fh,
 	if (outp->index != 0)
 		return -EINVAL;
 
-	memset(outp, 0, sizeof(*outp));
 	outp->index = 0;
 	outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
 	strncpy(outp->name, "Autodetect", sizeof(outp->name)-1);
drivers/staging/cx25821/cx25821-video.c +0 -2
index 4e184e8..596f414 100644
@@ -1300,8 +1300,6 @@ int cx25821_enum_input(struct cx25821_dev *dev, struct v4l2_input *i)
 	if (0 == INPUT(n)->type)
 		return -EINVAL;
 
-	memset(i, 0, sizeof(*i));
-	i->index = n;
 	i->type = V4L2_INPUT_TYPE_CAMERA;
 	strcpy(i->name, iname[INPUT(n)->type]);
 
Signature · 1 line
1.7.0.4
#18 lore raw

PATCH 18/19 em28xx: fix incorrect s_ctrl error code and wrong call to res_free

In reply to Hans Verkuil

Calling subdevs to handle s_ctrl returned a non-zero return code even if everything went fine.

Calling STREAMOFF if no STREAMON happened earlier would hit a BUG_ON in res_free.

---
 drivers/media/video/em28xx/em28xx-video.c |   14 +++++++++-----
 1 files changed, 9 insertions(+), 5 deletions(-)
drivers/media/video/em28xx/em28xx-video.c +9 -5
index 908e3bc..37d6f16 100644
@@ -1434,7 +1434,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
 
 	/* It isn't an AC97 control. Sends it to the v4l2 dev interface */
 	if (rc == 1) {
-		v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
+		rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
 
 		/*
 		 * In the case of non-AC97 volume controls, we still need
@@ -1708,11 +1708,15 @@ static int vidioc_streamoff(struct file *file, void *priv,
 			fh, type, fh->resources, dev->resources);
 
 	if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
-		videobuf_streamoff(&fh->vb_vidq);
-		res_free(fh, EM28XX_RESOURCE_VIDEO);
+		if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
+			videobuf_streamoff(&fh->vb_vidq);
+			res_free(fh, EM28XX_RESOURCE_VIDEO);
+		}
 	} else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
-		videobuf_streamoff(&fh->vb_vbiq);
-		res_free(fh, EM28XX_RESOURCE_VBI);
+		if (res_check(fh, EM28XX_RESOURCE_VBI)) {
+			videobuf_streamoff(&fh->vb_vbiq);
+			res_free(fh, EM28XX_RESOURCE_VBI);
+		}
 	}
 
 	return 0;
Signature · 1 line
1.7.0.4
#19 lore raw

PATCH 19/19 v4l2-ctrls: only check def for menu, integer and boolean controls

In reply to Hans Verkuil

The 'def' field is only valid for menus, integers and booleans.

---
 drivers/media/video/v4l2-ctrls.c |    9 ++++++++-
 1 files changed, 8 insertions(+), 1 deletions(-)
drivers/media/video/v4l2-ctrls.c +8 -1
index 6c0fadc..8f81efc 100644
@@ -962,13 +962,20 @@ static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
 
 	/* Sanity checks */
 	if (id == 0 || name == NULL || id >= V4L2_CID_PRIVATE_BASE ||
-	    def < min || def > max || max < min ||
+	    max < min ||
 	    (type == V4L2_CTRL_TYPE_INTEGER && step == 0) ||
 	    (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
 	    (type == V4L2_CTRL_TYPE_STRING && max == 0)) {
 		handler_set_err(hdl, -ERANGE);
 		return NULL;
 	}
+	if ((type == V4L2_CTRL_TYPE_INTEGER ||
+	     type == V4L2_CTRL_TYPE_MENU ||
+	     type == V4L2_CTRL_TYPE_BOOLEAN) &&
+	    (def < min || def > max)) {
+		handler_set_err(hdl, -ERANGE);
+		return NULL;
+	}
 
 	if (type == V4L2_CTRL_TYPE_BUTTON)
 		flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
Signature · 1 line
1.7.0.4