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

Commit c0477ad9 authored by Mauro Carvalho Chehab's avatar Mauro Carvalho Chehab
Browse files

V4L/DVB (3099): Fixed device controls for em28xx on WinTV USB2 devices



- Controls now come from video and audio decoder driver for msp3400 and tvp5150.
- Added audio and sound controls as provided by msp3400 and tvp5150.

Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@brturbo.com.br>
parent c432a072
Loading
Loading
Loading
Loading
+123 −38
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@

#include "em28xx.h"
#include <media/tuner.h>
#include <media/v4l2-common.h>

#define DRIVER_AUTHOR "Ludovico Cavedon <cavedon@sssup.it>, " \
		      "Markus Rechberger <mrechberger@gmail.com>, " \
@@ -106,7 +107,31 @@ static const unsigned char saa7114_i2c_init[] = {
#define TVNORMS ARRAY_SIZE(tvnorms)

/* supported controls */
/* Common to all boards */
static struct v4l2_queryctrl em28xx_qctrl[] = {
	{
		.id = V4L2_CID_AUDIO_VOLUME,
		.type = V4L2_CTRL_TYPE_INTEGER,
		.name = "Volume",
		.minimum = 0x0,
		.maximum = 0x1f,
		.step = 0x1,
		.default_value = 0x1f,
		.flags = 0,
	},{
		.id = V4L2_CID_AUDIO_MUTE,
		.type = V4L2_CTRL_TYPE_BOOLEAN,
		.name = "Mute",
		.minimum = 0,
		.maximum = 1,
		.step = 1,
		.default_value = 1,
		.flags = 0,
	}
};

/* FIXME: These are specific to saa711x - should be moved to its code */
static struct v4l2_queryctrl saa711x_qctrl[] = {
	{
		.id = V4L2_CID_BRIGHTNESS,
		.type = V4L2_CTRL_TYPE_INTEGER,
@@ -134,24 +159,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
		.step = 0x1,
		.default_value = 0x10,
		.flags = 0,
	},{
		.id = V4L2_CID_AUDIO_VOLUME,
		.type = V4L2_CTRL_TYPE_INTEGER,
		.name = "Volume",
		.minimum = 0x0,
		.maximum = 0x1f,
		.step = 0x1,
		.default_value = 0x1f,
		.flags = 0,
	},{
		.id = V4L2_CID_AUDIO_MUTE,
		.type = V4L2_CTRL_TYPE_BOOLEAN,
		.name = "Mute",
		.minimum = 0,
		.maximum = 1,
		.step = 1,
		.default_value = 1,
		.flags = 0,
	},{
		.id = V4L2_CID_RED_BALANCE,
		.type = V4L2_CTRL_TYPE_INTEGER,
@@ -674,7 +681,6 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
 */
static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
{
	s32 tmp;
	switch (ctrl->id) {
	case V4L2_CID_AUDIO_MUTE:
		ctrl->value = dev->mute;
@@ -682,6 +688,16 @@ static int em28xx_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
	case V4L2_CID_AUDIO_VOLUME:
		ctrl->value = dev->volume;
		return 0;
	default:
		return -EINVAL;
	}
}

/*FIXME: should be moved to saa711x */
static int saa711x_get_ctrl(struct em28xx *dev, struct v4l2_control *ctrl)
{
	s32 tmp;
	switch (ctrl->id) {
	case V4L2_CID_BRIGHTNESS:
		if ((tmp = em28xx_brightness_get(dev)) < 0)
			return -EIO;
@@ -731,6 +747,15 @@ static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
	case V4L2_CID_AUDIO_VOLUME:
		dev->volume = ctrl->value;
		return em28xx_audio_analog_set(dev);
	default:
		return -EINVAL;
	}
}

/*FIXME: should be moved to saa711x */
static int saa711x_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
{
	switch (ctrl->id) {
	case V4L2_CID_BRIGHTNESS:
		return em28xx_brightness_set(dev, ctrl->value);
	case V4L2_CID_CONTRAST:
@@ -994,14 +1019,34 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
	case VIDIOC_QUERYCTRL:
		{
			struct v4l2_queryctrl *qc = arg;
			u8 i, n;
			n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]);
			for (i = 0; i < n; i++)
			int i, id=qc->id;

			memset(qc,0,sizeof(*qc));
			qc->id=id;

			if (!dev->has_msp34xx) {
				for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
					if (qc->id && qc->id == em28xx_qctrl[i].id) {
						memcpy(qc, &(em28xx_qctrl[i]),
						sizeof(*qc));
						return 0;
					}
				}
			}
			if (dev->decoder == EM28XX_TVP5150) {
				em28xx_i2c_call_clients(dev,cmd,qc);
				if (qc->type)
					return 0;
				else
					return -EINVAL;
			}
			for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) {
				if (qc->id && qc->id == saa711x_qctrl[i].id) {
					memcpy(qc, &(saa711x_qctrl[i]),
					       sizeof(*qc));
					return 0;
				}
			}

			return -EINVAL;
		}
@@ -1009,29 +1054,66 @@ static int em28xx_do_ioctl(struct inode *inode, struct file *filp,
	case VIDIOC_G_CTRL:
		{
			struct v4l2_control *ctrl = arg;
			int retval=-EINVAL;

			if (!dev->has_msp34xx)
				retval=em28xx_get_ctrl(dev, ctrl);
			if (retval==-EINVAL) {
				if (dev->decoder == EM28XX_TVP5150) {
					em28xx_i2c_call_clients(dev,cmd,arg);
					return 0;
				}

			return em28xx_get_ctrl(dev, ctrl);
				return saa711x_get_ctrl(dev, ctrl);
			} else return retval;
		}

	case VIDIOC_S_CTRL_OLD:	/* ??? */
	case VIDIOC_S_CTRL:
		{
			struct v4l2_control *ctrl = arg;
			u8 i, n;

			u8 i;

			n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]);
			for (i = 0; i < n; i++)
			if (!dev->has_msp34xx){
				for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
					if (ctrl->id == em28xx_qctrl[i].id) {
						if (ctrl->value <
						em28xx_qctrl[i].minimum
						|| ctrl->value >
						em28xx_qctrl[i].maximum)
							return -ERANGE;
						return em28xx_set_ctrl(dev, ctrl);
					}
				}
			}

			if (dev->decoder == EM28XX_TVP5150) {
				em28xx_i2c_call_clients(dev,cmd,arg);
				return 0;
			} else {

			if (!dev->has_msp34xx){
				for (i = 0; i < ARRAY_SIZE(em28xx_qctrl); i++) {
					if (ctrl->id == em28xx_qctrl[i].id) {
						if (ctrl->value <
						em28xx_qctrl[i].minimum
						|| ctrl->value >
						em28xx_qctrl[i].maximum)
							return -ERANGE;
						return em28xx_set_ctrl(dev, ctrl);
					}
				}
				for (i = 0; i < ARRAY_SIZE(saa711x_qctrl); i++) {
					if (ctrl->id == saa711x_qctrl[i].id) {
						if (ctrl->value <
						saa711x_qctrl[i].minimum
						|| ctrl->value >
						saa711x_qctrl[i].maximum)
							return -ERANGE;
						return saa711x_set_ctrl(dev, ctrl);
					}
				}
			}

			return -EINVAL;
		}

@@ -1850,9 +1932,12 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
	struct em28xx *dev = usb_get_intfdata(interface);
	usb_set_intfdata(interface, NULL);

/*FIXME: IR should be disconnected */

	if (!dev)
		return;


	down_write(&em28xx_disconnect);

	down(&dev->lock);
+159 −0
Original line number Diff line number Diff line
@@ -1642,6 +1642,45 @@ static void msp_any_detect_stereo(struct i2c_client *client)
	}
}

static struct v4l2_queryctrl msp34xx_qctrl[] = {
	{
		.id            = V4L2_CID_AUDIO_VOLUME,
		.name          = "Volume",
		.minimum       = 0,
		.maximum       = 65535,
		.step          = 65535/100,
		.default_value = 58880,
		.flags         = 0,
		.type          = V4L2_CTRL_TYPE_INTEGER,
	},{
		.id            = V4L2_CID_AUDIO_MUTE,
		.name          = "Mute",
		.minimum       = 0,
		.maximum       = 1,
		.step          = 1,
		.default_value = 1,
		.flags         = 0,
		.type          = V4L2_CTRL_TYPE_BOOLEAN,
	},{
		.id            = V4L2_CID_AUDIO_BASS,
		.name          = "Bass",
		.minimum       = 0,
		.maximum       = 65535,
		.step          = 65535/100,
		.default_value = 32768,
		.type          = V4L2_CTRL_TYPE_INTEGER,
	},{
		.id            = V4L2_CID_AUDIO_TREBLE,
		.name          = "Treble",
		.minimum       = 0,
		.maximum       = 65535,
		.step          = 65535/100,
		.default_value = 32768,
		.type          = V4L2_CTRL_TYPE_INTEGER,
	},
};


static void msp_any_set_audmode(struct i2c_client *client, int audmode)
{
	struct msp3400c *msp  = i2c_get_clientdata(client);
@@ -1658,6 +1697,95 @@ static void msp_any_set_audmode(struct i2c_client *client, int audmode)
	}
}

static int msp_get_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
{
	struct msp3400c *msp  = i2c_get_clientdata(client);

	switch (ctrl->id) {
	case V4L2_CID_AUDIO_MUTE:
		ctrl->value = msp->muted;
		return 0;
	case V4L2_CID_AUDIO_BALANCE:
	{
		int volume = MAX(msp->left, msp->right);

		ctrl->value = (32768 * MIN(msp->left, msp->right)) /
		    (volume ? volume : 1);
		ctrl->value = (msp->left < msp->right) ?
		    (65535 - ctrl->value) : ctrl->value;
		if (0 == volume)
			ctrl->value = 32768;
		return 0;
	}
	case V4L2_CID_AUDIO_BASS:
		ctrl->value = msp->bass;
		return 0;
	case V4L2_CID_AUDIO_TREBLE:
		ctrl->value = msp->treble;
		return 0;
	case V4L2_CID_AUDIO_VOLUME:
		ctrl->value = MAX(msp->left, msp->right);
		return 0;
	default:
		return -EINVAL;
	}
}

static int msp_set_ctrl(struct i2c_client *client, struct v4l2_control *ctrl)
{
	struct msp3400c *msp  = i2c_get_clientdata(client);
	int set_volume=0, balance, volume;

	switch (ctrl->id) {
	case V4L2_CID_AUDIO_MUTE:
		if (ctrl->value>=0 && ctrl->value<2)
			msp->muted = ctrl->value;
		else
			return -ERANGE;

		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
		return 0;
	case V4L2_CID_AUDIO_BALANCE:
		balance=ctrl->value;
		volume = MAX(msp->left, msp->right);
		set_volume=1;
		break;
	case V4L2_CID_AUDIO_BASS:
		msp->bass=ctrl->value;
		msp3400c_setbass(client, msp->bass);
		return 0;
	case V4L2_CID_AUDIO_TREBLE:
		msp->treble=ctrl->value;
		msp3400c_settreble(client, msp->treble);
		return 0;
	case V4L2_CID_AUDIO_VOLUME:
		volume = MAX(msp->left, msp->right);

		balance = (32768 * MIN(msp->left, msp->right)) /
					(volume ? volume : 1);
		balance = (msp->left < msp->right) ?
					(65535 - balance) : balance;
		if (0 == volume)
			balance = 32768;

		volume=ctrl->value;
		set_volume=1;
		break;
	default:
		return -EINVAL;
	}

	if (set_volume) {
		msp->left = (MIN(65536 - balance, 32768) * volume) / 32768;
		msp->right = (MIN(balance, 32768) * volume) / 32768;

		msp3400_dbg("volume=%d, balance=%d, left=%d, right=%d",
			volume,balance,msp->left,msp->right);

		msp3400c_setvolume(client, msp->muted, msp->left, msp->right);
	}
	return 0;
}

static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
{
@@ -2027,6 +2155,37 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)

		break;
	}
	case VIDIOC_QUERYCTRL:
	{
		struct v4l2_queryctrl *qc = arg;
		int i;

		msp3400_dbg("VIDIOC_QUERYCTRL");

		for (i = 0; i < ARRAY_SIZE(msp34xx_qctrl); i++)
			if (qc->id && qc->id ==  msp34xx_qctrl[i].id) {
				memcpy(qc, &(msp34xx_qctrl[i]),
					sizeof(*qc));
				return 0;
			}

		return -EINVAL;
	}
	case VIDIOC_G_CTRL:
	{
		struct v4l2_control *ctrl = arg;
		msp3400_dbg("VIDIOC_G_CTRL\n");

		return msp_get_ctrl(client, ctrl);
	}
	case VIDIOC_S_CTRL:
	{
		struct v4l2_control *ctrl = arg;

		msp3400_dbg("VIDIOC_S_CTRL\n");

		return msp_set_ctrl(client, ctrl);
	}

	default:
		/* nothing */
+45 −36
Original line number Diff line number Diff line
@@ -437,11 +437,24 @@ enum tvp5150_input {
static inline void tvp5150_selmux(struct i2c_client *c,
				  enum tvp5150_input input)
{
	int opmode=0;

	struct tvp5150 *decoder = i2c_get_clientdata(c);

	if (!decoder->enable)
		input |= TVP5150_BLACK_SCREEN;

	switch (input) {
	case TVP5150_ANALOG_CH0:
	case TVP5150_ANALOG_CH1:
		opmode=0x30;		/* TV Mode */
		break;
	default:
		opmode=0;		/* Auto Mode */
		break;
	}

	tvp5150_write(c, TVP5150_OP_MODE_CTL, opmode);
	tvp5150_write(c, TVP5150_VD_IN_SRC_SEL_1, input);
};

@@ -498,9 +511,8 @@ static int tvp5150_get_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
	case V4L2_CID_HUE:
		ctrl->value = tvp5150_read(c, TVP5150_HUE_CTL);
		return 0;
	default:
		return -EINVAL;
	}
	return -EINVAL;
}

static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
@@ -520,9 +532,8 @@ static int tvp5150_set_ctrl(struct i2c_client *c, struct v4l2_control *ctrl)
	case V4L2_CID_HUE:
		tvp5150_write(c, TVP5150_HUE_CTL, ctrl->value);
		return 0;
	default:
		return -EINVAL;
	}
	return -EINVAL;
}

/****************************************************************************
@@ -627,12 +638,11 @@ static int tvp5150_command(struct i2c_client *client,
	case VIDIOC_QUERYCTRL:
		{
			struct v4l2_queryctrl *qc = arg;
			u8 i, n;
			int i;

			dprintk(1, KERN_DEBUG "VIDIOC_QUERYCTRL");

			n = sizeof(tvp5150_qctrl) / sizeof(tvp5150_qctrl[0]);
			for (i = 0; i < n; i++)
			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));
@@ -648,7 +658,6 @@ static int tvp5150_command(struct i2c_client *client,

			return tvp5150_get_ctrl(client, ctrl);
		}
	case VIDIOC_S_CTRL_OLD:	/* ??? */
	case VIDIOC_S_CTRL:
		{
			struct v4l2_control *ctrl = arg;