V4L/DVB (3099): Fixed device controls for em28xx on WinTV USB2 devices
authorMauro Carvalho Chehab <mchehab@brturbo.com.br>
Mon, 9 Jan 2006 17:25:14 +0000 (15:25 -0200)
committerMauro Carvalho Chehab <mchehab@brturbo.com.br>
Mon, 9 Jan 2006 17:25:14 +0000 (15:25 -0200)
- 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: Mauro Carvalho Chehab <mchehab@brturbo.com.br>
drivers/media/video/em28xx/em28xx-video.c
drivers/media/video/msp3400.c
drivers/media/video/tvp5150.c

index 8516ec1..446ba3b 100644 (file)
@@ -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,8 +107,32 @@ 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,
                .name = "Brightness",
@@ -135,24 +160,6 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
                .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,
                .name = "Red chroma balance",
@@ -179,7 +186,7 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
                .step = 0x1,
                .default_value = 0x20,
                .flags = 0,
-        }
+       }
 };
 
 static struct usb_driver em28xx_usb_driver;
@@ -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++)
-                               if (qc->id && qc->id == em28xx_qctrl[i].id) {
-                                       memcpy(qc, &(em28xx_qctrl[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;
+
+                       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);
+                                       }
+                               }
+                       }
 
-                       n = sizeof(em28xx_qctrl) / sizeof(em28xx_qctrl[0]);
-                       for (i = 0; i < n; i++)
-                               if (ctrl->id == em28xx_qctrl[i].id) {
-                                       if (ctrl->value <
-                                           em28xx_qctrl[i].minimum
-                                           || ctrl->value >
-                                           em28xx_qctrl[i].maximum)
-                                               return -ERANGE;
+                       if (dev->decoder == EM28XX_TVP5150) {
+                               em28xx_i2c_call_clients(dev,cmd,arg);
+                               return 0;
+                       } else {
 
-                                       return em28xx_set_ctrl(dev, ctrl);
+                       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);
index fc2896b..8d47d78 100644 (file)
@@ -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 */
index a60442e..d62b230 100644 (file)
@@ -37,24 +37,24 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
 /* 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 = 0,
-        .flags = 0,
-        }, {
-            .id = V4L2_CID_CONTRAST,
-            .type = V4L2_CTRL_TYPE_INTEGER,
-            .name = "Contrast",
-            .minimum = 0,
-            .maximum = 255,
-            .step = 0x1,
-            .default_value = 0x10,
-            .flags = 0,
-            }, {
+               .id = V4L2_CID_BRIGHTNESS,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Brightness",
+               .minimum = 0,
+               .maximum = 255,
+               .step = 1,
+               .default_value = 0,
+               .flags = 0,
+       }, {
+               .id = V4L2_CID_CONTRAST,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Contrast",
+               .minimum = 0,
+               .maximum = 255,
+               .step = 0x1,
+               .default_value = 0x10,
+               .flags = 0,
+       }, {
                 .id = V4L2_CID_SATURATION,
                 .type = V4L2_CTRL_TYPE_INTEGER,
                 .name = "Saturation",
@@ -63,16 +63,16 @@ static struct v4l2_queryctrl tvp5150_qctrl[] = {
                 .step = 0x1,
                 .default_value = 0x10,
                 .flags = 0,
-                }, {
-                    .id = V4L2_CID_HUE,
-                    .type = V4L2_CTRL_TYPE_INTEGER,
-                    .name = "Hue",
-                    .minimum = -128,
-                    .maximum = 127,
-                    .step = 0x1,
-                    .default_value = 0x10,
-                    .flags = 0,
-                    }
+       }, {
+               .id = V4L2_CID_HUE,
+               .type = V4L2_CTRL_TYPE_INTEGER,
+               .name = "Hue",
+               .minimum = -128,
+               .maximum = 127,
+               .step = 0x1,
+               .default_value = 0x10,
+               .flags = 0,
+       }
 };
 
 struct tvp5150 {
@@ -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;