[media] radio-mr800: add support for stereo and signal detection
authorHans Verkuil <hans.verkuil@cisco.com>
Fri, 27 Apr 2012 16:28:34 +0000 (13:28 -0300)
committerMauro Carvalho Chehab <mchehab@redhat.com>
Mon, 7 May 2012 18:29:10 +0000 (15:29 -0300)
Thanks to an older driver by Faidon Liambotis <paravoid@debian.org> (as noted
in the radio-mr800 comment block at the start) for figuring out how to get the
signal/stereo state.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
drivers/media/radio/radio-mr800.c

index 0a96eda..0b39a8c 100644 (file)
@@ -103,6 +103,7 @@ devices, that would be 76 and 91.  */
  * List isn't full and will be updated with implementation of new functions
  */
 #define AMRADIO_SET_FREQ       0xa4
+#define AMRADIO_GET_SIGNAL     0xa7
 #define AMRADIO_SET_MUTE       0xab
 #define AMRADIO_SET_MONO       0xae
 
@@ -236,6 +237,35 @@ static int amradio_set_stereo(struct amradio_device *radio, char argument)
        return 0;
 }
 
+static int amradio_get_stat(struct amradio_device *radio, bool *is_stereo, u32 *signal)
+{
+       int retval;
+       int size;
+
+       radio->buffer[0] = 0x00;
+       radio->buffer[1] = 0x55;
+       radio->buffer[2] = 0xaa;
+       radio->buffer[3] = 0x00;
+       radio->buffer[4] = AMRADIO_GET_SIGNAL;
+       radio->buffer[5] = 0x00;
+       radio->buffer[6] = 0x00;
+       radio->buffer[7] = 0x08;
+
+       retval = usb_bulk_msg(radio->usbdev, usb_sndbulkpipe(radio->usbdev, 0x02),
+               radio->buffer, BUFFER_LENGTH, &size, USB_TIMEOUT);
+       if (!retval)
+               retval = usb_bulk_msg(radio->usbdev, usb_rcvbulkpipe(radio->usbdev, 0x81),
+                       radio->buffer, BUFFER_LENGTH, &size, USB_TIMEOUT);
+
+       if (retval || size != BUFFER_LENGTH) {
+               amradio_dev_warn(&radio->vdev.dev, "get stat failed\n");
+               return retval;
+       }
+       *is_stereo = radio->buffer[2] >> 7;
+       *signal = (radio->buffer[3] & 0xf0) << 8;
+       return 0;
+}
+
 /* Handle unplugging the device.
  * We call video_unregister_device in any case.
  * The last function called in this procedure is
@@ -272,20 +302,23 @@ static int vidioc_g_tuner(struct file *file, void *priv,
                                struct v4l2_tuner *v)
 {
        struct amradio_device *radio = video_drvdata(file);
+       bool is_stereo = false;
+       int retval;
 
        if (v->index > 0)
                return -EINVAL;
 
+       v->signal = 0;
+       retval = amradio_get_stat(radio, &is_stereo, &v->signal);
+       if (retval)
+               return retval;
+
        strcpy(v->name, "FM");
        v->type = V4L2_TUNER_RADIO;
        v->rangelow = FREQ_MIN * FREQ_MUL;
        v->rangehigh = FREQ_MAX * FREQ_MUL;
        v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
-       /* We do not know how to get hold of the stereo indicator, so
-          all we can do is give back both mono and stereo, which
-          effectively means that we don't know. */
-       v->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
-       v->signal = 0xffff;
+       v->rxsubchans = is_stereo ? V4L2_TUNER_SUB_STEREO : V4L2_TUNER_SUB_MONO;
        v->audmode = radio->stereo ?
                V4L2_TUNER_MODE_STEREO : V4L2_TUNER_MODE_MONO;
        return 0;