V4L/DVB (8151): saa7134-empress: fix MPEG control support
authorHans Verkuil <hverkuil@xs4all.nl>
Sat, 28 Jun 2008 00:18:15 +0000 (21:18 -0300)
committerMauro Carvalho Chehab <mchehab@infradead.org>
Sun, 20 Jul 2008 10:14:23 +0000 (07:14 -0300)
The MPEG controls could not be enumerated and so could not be read or set
through the v4l2-ctl utility or shown in control panels.

Signed-off-by: Hans Verkuil <hverkuil@xs4all.nl>
Signed-off-by: Mauro Carvalho Chehab <mchehab@infradead.org>
drivers/media/video/saa7134/saa6752hs.c
drivers/media/video/saa7134/saa7134-empress.c
drivers/media/video/saa7134/saa7134-i2c.c
drivers/media/video/saa7134/saa7134.h

index 002e70a33a4f6bf2fe847c6223a1a6518f25955a..fc32c3f68af1ebaae2cc03403a91ef1966ad8861 100644 (file)
@@ -448,6 +448,104 @@ static int handle_ctrl(struct saa6752hs_mpeg_params *params,
        return 0;
 }
 
+static int saa6752hs_qctrl(struct saa6752hs_mpeg_params *params,
+               struct v4l2_queryctrl *qctrl)
+{
+       int err;
+
+       switch (qctrl->id) {
+       case V4L2_CID_MPEG_AUDIO_ENCODING:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_ENCODING_LAYER_2,
+                               V4L2_MPEG_AUDIO_ENCODING_LAYER_2, 1,
+                               V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+
+       case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_L2_BITRATE_256K,
+                               V4L2_MPEG_AUDIO_L2_BITRATE_384K, 1,
+                               V4L2_MPEG_AUDIO_L2_BITRATE_256K);
+
+       case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000,
+                               V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000, 1,
+                               V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
+
+       case V4L2_CID_MPEG_VIDEO_ENCODING:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_VIDEO_ENCODING_MPEG_2,
+                               V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 1,
+                               V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
+
+       case V4L2_CID_MPEG_VIDEO_ASPECT:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_VIDEO_ASPECT_4x3,
+                               V4L2_MPEG_VIDEO_ASPECT_16x9, 1,
+                               V4L2_MPEG_VIDEO_ASPECT_4x3);
+
+       case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+               err = v4l2_ctrl_query_fill_std(qctrl);
+               if (err == 0 &&
+                   params->vi_bitrate_mode ==
+                               V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+                       qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+               return err;
+
+       case V4L2_CID_MPEG_STREAM_TYPE:
+               return v4l2_ctrl_query_fill(qctrl,
+                               V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
+                               V4L2_MPEG_STREAM_TYPE_MPEG2_TS, 1,
+                               V4L2_MPEG_STREAM_TYPE_MPEG2_TS);
+
+       case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+       case V4L2_CID_MPEG_VIDEO_BITRATE:
+       case V4L2_CID_MPEG_STREAM_PID_PMT:
+       case V4L2_CID_MPEG_STREAM_PID_AUDIO:
+       case V4L2_CID_MPEG_STREAM_PID_VIDEO:
+       case V4L2_CID_MPEG_STREAM_PID_PCR:
+               return v4l2_ctrl_query_fill_std(qctrl);
+
+       default:
+               break;
+       }
+       return -EINVAL;
+}
+
+static int saa6752hs_qmenu(struct saa6752hs_mpeg_params *params,
+               struct v4l2_querymenu *qmenu)
+{
+       static const char *mpeg_audio_l2_bitrate[] = {
+               "",
+               "",
+               "",
+               "",
+               "",
+               "",
+               "",
+               "",
+               "",
+               "",
+               "",
+               "256 kbps",
+               "",
+               "384 kbps",
+               NULL
+       };
+       struct v4l2_queryctrl qctrl;
+       int err;
+
+       qctrl.id = qmenu->id;
+       err = saa6752hs_qctrl(params, &qctrl);
+       if (err)
+               return err;
+       if (qmenu->id == V4L2_CID_MPEG_AUDIO_L2_BITRATE)
+               return v4l2_ctrl_query_menu(qmenu, &qctrl,
+                               mpeg_audio_l2_bitrate);
+       return v4l2_ctrl_query_menu(qmenu, &qctrl,
+                       v4l2_ctrl_get_menu(qmenu->id));
+}
+
 static int saa6752hs_init(struct i2c_client* client)
 {
        unsigned char buf[9], buf2[4];
@@ -662,6 +760,10 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg)
                }
                h->params = params;
                break;
+       case VIDIOC_QUERYCTRL:
+               return saa6752hs_qctrl(&h->params, arg);
+       case VIDIOC_QUERYMENU:
+               return saa6752hs_qmenu(&h->params, arg);
        case VIDIOC_G_FMT:
        {
           struct v4l2_format *f = arg;
index e11700eb3e5a47d73feb15b16429ae99cb403319..2a5ab957542dfacab6e3e73dfe77da44c2975280 100644 (file)
@@ -294,10 +294,20 @@ static int empress_streamoff(struct file *file, void *priv,
        return videobuf_streamoff(&dev->empress_tsq);
 }
 
+static int saa7134_i2c_call_saa6752(struct saa7134_dev *dev,
+                                             unsigned int cmd, void *arg)
+{
+       if (dev->mpeg_i2c_client == NULL)
+               return -EINVAL;
+       return dev->mpeg_i2c_client->driver->command(dev->mpeg_i2c_client,
+                                                               cmd, arg);
+}
+
 static int empress_s_ext_ctrls(struct file *file, void *priv,
                               struct v4l2_ext_controls *ctrls)
 {
        struct saa7134_dev *dev = file->private_data;
+       int err;
 
        /* count == 0 is abused in saa6752hs.c, so that special
                case is handled here explicitly. */
@@ -307,10 +317,10 @@ static int empress_s_ext_ctrls(struct file *file, void *priv,
        if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
                return -EINVAL;
 
-       saa7134_i2c_call_clients(dev, VIDIOC_S_EXT_CTRLS, ctrls);
+       err = saa7134_i2c_call_saa6752(dev, VIDIOC_S_EXT_CTRLS, ctrls);
        ts_init_encoder(dev);
 
-       return 0;
+       return err;
 }
 
 static int empress_g_ext_ctrls(struct file *file, void *priv,
@@ -320,9 +330,62 @@ static int empress_g_ext_ctrls(struct file *file, void *priv,
 
        if (ctrls->ctrl_class != V4L2_CTRL_CLASS_MPEG)
                return -EINVAL;
-       saa7134_i2c_call_clients(dev, VIDIOC_G_EXT_CTRLS, ctrls);
+       return saa7134_i2c_call_saa6752(dev, VIDIOC_G_EXT_CTRLS, ctrls);
+}
 
-       return 0;
+static int empress_queryctrl(struct file *file, void *priv,
+                                       struct v4l2_queryctrl *c)
+{
+       static const u32 user_ctrls[] = {
+               V4L2_CID_USER_CLASS,
+               V4L2_CID_BRIGHTNESS,
+               V4L2_CID_CONTRAST,
+               V4L2_CID_SATURATION,
+               V4L2_CID_HUE,
+               V4L2_CID_AUDIO_VOLUME,
+               V4L2_CID_AUDIO_MUTE,
+               V4L2_CID_HFLIP,
+               0
+       };
+
+       static const u32 mpeg_ctrls[] = {
+               V4L2_CID_MPEG_CLASS,
+               V4L2_CID_MPEG_STREAM_TYPE,
+               V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+               V4L2_CID_MPEG_AUDIO_ENCODING,
+               V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+               V4L2_CID_MPEG_VIDEO_ENCODING,
+               V4L2_CID_MPEG_VIDEO_ASPECT,
+               V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+               V4L2_CID_MPEG_VIDEO_BITRATE,
+               V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+               0
+       };
+       static const u32 *ctrl_classes[] = {
+               user_ctrls,
+               mpeg_ctrls,
+               NULL
+       };
+       struct saa7134_dev *dev = file->private_data;
+
+       c->id = v4l2_ctrl_next(ctrl_classes, c->id);
+       if (c->id == 0)
+               return -EINVAL;
+       if (c->id == V4L2_CID_USER_CLASS || c->id == V4L2_CID_MPEG_CLASS)
+               return v4l2_ctrl_query_fill_std(c);
+       if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG)
+               return saa7134_queryctrl(file, priv, c);
+       return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYCTRL, c);
+}
+
+static int empress_querymenu(struct file *file, void *priv,
+                                       struct v4l2_querymenu *c)
+{
+       struct saa7134_dev *dev = file->private_data;
+
+       if (V4L2_CTRL_ID2CLASS(c->id) != V4L2_CTRL_CLASS_MPEG)
+               return -EINVAL;
+       return saa7134_i2c_call_saa6752(dev, VIDIOC_QUERYMENU, c);
 }
 
 static const struct file_operations ts_fops =
@@ -363,7 +426,8 @@ static struct video_device saa7134_empress_template =
        .vidioc_g_input                 = empress_g_input,
        .vidioc_s_input                 = empress_s_input,
 
-       .vidioc_queryctrl               = saa7134_queryctrl,
+       .vidioc_queryctrl               = empress_queryctrl,
+       .vidioc_querymenu               = empress_querymenu,
        .vidioc_g_ctrl                  = saa7134_g_ctrl,
        .vidioc_s_ctrl                  = saa7134_s_ctrl,
 
index d8af3863f2d3de675492e34d8a84ec2269d1e5ff..5f713e6376839a3cac595821c736866bf1cbcc65 100644 (file)
@@ -327,6 +327,8 @@ static int attach_inform(struct i2c_client *client)
 
        d1printk( "%s i2c attach [addr=0x%x,client=%s]\n",
                client->driver->driver.name, client->addr, client->name);
+       if (client->addr == 0x20 && client->driver && client->driver->command)
+               dev->mpeg_i2c_client = client;
 
        /* Am I an i2c remote control? */
 
index 0a94be7afc1ef181a510e02380206c44ad9553d0..4e491ad389ac4d64fb43b1010d6fd1f2c8cbd13d 100644 (file)
@@ -553,6 +553,7 @@ struct saa7134_dev {
        struct saa7134_ts          ts;
        struct saa7134_dmaqueue    ts_q;
        struct saa7134_mpeg_ops    *mops;
+       struct i2c_client          *mpeg_i2c_client;
 
        /* SAA7134_MPEG_EMPRESS only */
        struct video_device        *empress_dev;