summaryrefslogtreecommitdiff
path: root/linux
diff options
context:
space:
mode:
Diffstat (limited to 'linux')
-rw-r--r--linux/drivers/media/radio/radio-cadet.c6
-rw-r--r--linux/drivers/media/radio/radio-si470x.c9
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-driver.c2
-rw-r--r--linux/drivers/media/video/saa6588.c60
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-core.c4
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-video.c2
-rw-r--r--linux/drivers/media/video/saa7134/saa7134.h1
-rw-r--r--linux/include/linux/videodev2.h23
8 files changed, 89 insertions, 18 deletions
diff --git a/linux/drivers/media/radio/radio-cadet.c b/linux/drivers/media/radio/radio-cadet.c
index 2fd4aae2e..99551d836 100644
--- a/linux/drivers/media/radio/radio-cadet.c
+++ b/linux/drivers/media/radio/radio-cadet.c
@@ -386,7 +386,8 @@ static int vidioc_querycap(struct file *file, void *priv,
strlcpy(v->card, "ADS Cadet", sizeof(v->card));
strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
v->version = CADET_VERSION;
- v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_READWRITE;
+ v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
+ V4L2_CAP_READWRITE | V4L2_CAP_RDS_CAPTURE;
return 0;
}
@@ -399,7 +400,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
switch (v->index) {
case 0:
strlcpy(v->name, "FM", sizeof(v->name));
- v->capability = V4L2_TUNER_CAP_STEREO;
+ v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS;
v->rangelow = 1400; /* 87.5 MHz */
v->rangehigh = 1728; /* 108.0 MHz */
v->rxsubchans = cadet_getstereo(dev);
@@ -413,6 +414,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
default:
break;
}
+ v->rxsubchans |= V4L2_TUNER_SUB_RDS;
break;
case 1:
strlcpy(v->name, "AM", sizeof(v->name));
diff --git a/linux/drivers/media/radio/radio-si470x.c b/linux/drivers/media/radio/radio-si470x.c
index 20aa447cc..3efd397d1 100644
--- a/linux/drivers/media/radio/radio-si470x.c
+++ b/linux/drivers/media/radio/radio-si470x.c
@@ -1254,7 +1254,7 @@ static int si470x_vidioc_querycap(struct file *file, void *priv,
usb_make_path(radio->usbdev, capability->bus_info, sizeof(capability->bus_info));
capability->version = DRIVER_KERNEL_VERSION;
capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
- V4L2_CAP_TUNER | V4L2_CAP_RADIO;
+ V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_RDS_CAPTURE;
return 0;
}
@@ -1413,7 +1413,8 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
/* driver constants */
strcpy(tuner->name, "FM");
tuner->type = V4L2_TUNER_RADIO;
- tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
+ tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
+ V4L2_TUNER_CAP_RDS;
/* range limits */
switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
@@ -1439,6 +1440,10 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
else
tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
+ /* If there is a reliable method of detecting an RDS channel,
+ then this code should check for that before setting this
+ RDS subchannel. */
+ tuner->rxsubchans |= V4L2_TUNER_SUB_RDS;
/* mono/stereo selector */
if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0)
diff --git a/linux/drivers/media/video/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c
index bd5dde3f8..9c25efe06 100644
--- a/linux/drivers/media/video/bt8xx/bttv-driver.c
+++ b/linux/drivers/media/video/bt8xx/bttv-driver.c
@@ -2679,6 +2679,8 @@ static int bttv_querycap(struct file *file, void *priv,
V4L2_CAP_VBI_CAPTURE |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
+ if (btv->has_saa6588)
+ cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
if (no_overlay <= 0)
cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
diff --git a/linux/drivers/media/video/saa6588.c b/linux/drivers/media/video/saa6588.c
index 58aff8305..dcc83511e 100644
--- a/linux/drivers/media/video/saa6588.c
+++ b/linux/drivers/media/video/saa6588.c
@@ -51,7 +51,7 @@ I2C_CLIENT_INSMOD;
/* insmod options */
static unsigned int debug;
static unsigned int xtal;
-static unsigned int rbds;
+static unsigned int mmbs;
static unsigned int plvl;
static unsigned int bufblocks = 100;
@@ -59,8 +59,8 @@ module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable debug messages");
module_param(xtal, int, 0);
MODULE_PARM_DESC(xtal, "select oscillator frequency (0..3), default 0");
-module_param(rbds, int, 0);
-MODULE_PARM_DESC(rbds, "select mode, 0=RDS, 1=RBDS, default 0");
+module_param(mmbs, int, 0);
+MODULE_PARM_DESC(mmbs, "enable MMBS mode: 0=off (default), 1=on");
module_param(plvl, int, 0);
MODULE_PARM_DESC(plvl, "select pause level (0..3), default 0");
module_param(bufblocks, int, 0);
@@ -89,6 +89,7 @@ struct saa6588 {
unsigned char last_blocknum;
wait_queue_head_t read_queue;
int data_available_for_read;
+ u8 sync;
};
static inline struct saa6588 *to_saa6588(struct v4l2_subdev *sd)
@@ -272,13 +273,16 @@ static void saa6588_i2c_poll(struct saa6588 *s)
unsigned char tmp;
/* Although we only need 3 bytes, we have to read at least 6.
- SAA6588 returns garbage otherwise */
+ SAA6588 returns garbage otherwise. */
if (6 != i2c_master_recv(client, &tmpbuf[0], 6)) {
if (debug > 1)
dprintk(PREFIX "read error!\n");
return;
}
+ s->sync = tmpbuf[0] & 0x10;
+ if (!s->sync)
+ return;
blocknum = tmpbuf[0] >> 5;
if (blocknum == s->last_blocknum) {
if (debug > 3)
@@ -297,9 +301,8 @@ static void saa6588_i2c_poll(struct saa6588 *s)
occurred during reception of this block.
Bit 6: Corrected bit. Indicates that an error was
corrected for this data block.
- Bits 5-3: Received Offset. Indicates the offset received
- by the sync system.
- Bits 2-0: Offset Name. Indicates the offset applied to this data.
+ Bits 5-3: Same as bits 0-2.
+ Bits 2-0: Block number.
SAA6588 byte order is Status-MSB-LSB, so we have to swap the
first and the last of the 3 bytes block.
@@ -309,12 +312,21 @@ static void saa6588_i2c_poll(struct saa6588 *s)
tmpbuf[2] = tmpbuf[0];
tmpbuf[0] = tmp;
+ /* Map 'Invalid block E' to 'Invalid Block' */
+ if (blocknum == 6)
+ blocknum = V4L2_RDS_BLOCK_INVALID;
+ /* And if are not in mmbs mode, then 'Block E' is also mapped
+ to 'Invalid Block'. As far as I can tell MMBS is discontinued,
+ and if there is ever a need to support E blocks, then please
+ contact the linux-media mailinglist. */
+ else if (!mmbs && blocknum == 5)
+ blocknum = V4L2_RDS_BLOCK_INVALID;
tmp = blocknum;
tmp |= blocknum << 3; /* Received offset == Offset Name (OK ?) */
if ((tmpbuf[2] & 0x03) == 0x03)
- tmp |= 0x80; /* uncorrectable error */
+ tmp |= V4L2_RDS_BLOCK_ERROR; /* uncorrectable error */
else if ((tmpbuf[2] & 0x03) != 0x00)
- tmp |= 0x40; /* corrected error */
+ tmp |= V4L2_RDS_BLOCK_CORRECTED; /* corrected error */
tmpbuf[2] = tmp; /* Is this enough ? Should we also check other bits ? */
spin_lock_irqsave(&s->lock, flags);
@@ -340,14 +352,14 @@ static void saa6588_work(struct work_struct *work)
schedule_delayed_work(&s->work, msecs_to_jiffies(20));
}
-static int saa6588_configure(struct saa6588 *s)
+static void saa6588_configure(struct saa6588 *s)
{
struct i2c_client *client = v4l2_get_subdevdata(&s->sd);
unsigned char buf[3];
int rc;
buf[0] = cSyncRestart;
- if (rbds)
+ if (mmbs)
buf[0] |= cProcessingModeRBDS;
buf[1] = cFlywheelDefault;
@@ -393,8 +405,6 @@ static int saa6588_configure(struct saa6588 *s)
rc = i2c_master_send(client, buf, 3);
if (rc != 3)
printk(PREFIX "i2c i/o error: rc == %d (should be 3)\n", rc);
-
- return 0;
}
/* ---------------------------------------------------------------------- */
@@ -435,6 +445,24 @@ static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
return 0;
}
+static int saa6588_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct saa6588 *s = to_saa6588(sd);
+
+ vt->capability |= V4L2_TUNER_CAP_RDS;
+ if (s->sync)
+ vt->rxsubchans |= V4L2_TUNER_SUB_RDS;
+ return 0;
+}
+
+static int saa6588_s_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
+{
+ struct saa6588 *s = to_saa6588(sd);
+
+ saa6588_configure(s);
+ return 0;
+}
+
static int saa6588_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -449,8 +477,14 @@ static const struct v4l2_subdev_core_ops saa6588_core_ops = {
.ioctl = saa6588_ioctl,
};
+static const struct v4l2_subdev_tuner_ops saa6588_tuner_ops = {
+ .g_tuner = saa6588_g_tuner,
+ .s_tuner = saa6588_s_tuner,
+};
+
static const struct v4l2_subdev_ops saa6588_ops = {
.core = &saa6588_core_ops,
+ .tuner = &saa6588_tuner_ops,
};
/* ---------------------------------------------------------------------- */
diff --git a/linux/drivers/media/video/saa7134/saa7134-core.c b/linux/drivers/media/video/saa7134/saa7134-core.c
index da73430ad..e466afd18 100644
--- a/linux/drivers/media/video/saa7134/saa7134-core.c
+++ b/linux/drivers/media/video/saa7134/saa7134-core.c
@@ -1073,8 +1073,10 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
sd = v4l2_i2c_new_probed_subdev_addr(&dev->v4l2_dev,
&dev->i2c_adap, "saa6588", "saa6588",
saa7134_boards[dev->board].rds_addr);
- if (sd)
+ if (sd) {
printk(KERN_INFO "%s: found RDS decoder\n", dev->name);
+ dev->has_rds = 1;
+ }
}
request_submodules(dev);
diff --git a/linux/drivers/media/video/saa7134/saa7134-video.c b/linux/drivers/media/video/saa7134/saa7134-video.c
index e7f78fcb8..5be072c57 100644
--- a/linux/drivers/media/video/saa7134/saa7134-video.c
+++ b/linux/drivers/media/video/saa7134/saa7134-video.c
@@ -1826,6 +1826,8 @@ static int saa7134_querycap(struct file *file, void *priv,
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING |
V4L2_CAP_TUNER;
+ if (dev->has_rds)
+ cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
if (saa7134_no_overlay <= 0)
cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h
index 454802e73..be5abf059 100644
--- a/linux/drivers/media/video/saa7134/saa7134.h
+++ b/linux/drivers/media/video/saa7134/saa7134.h
@@ -544,6 +544,7 @@ struct saa7134_dev {
struct i2c_adapter i2c_adap;
struct i2c_client i2c_client;
unsigned char eedata[256];
+ int has_rds;
/* video overlay */
struct v4l2_framebuffer ovbuf;
diff --git a/linux/include/linux/videodev2.h b/linux/include/linux/videodev2.h
index ee6458f74..b5c4f7295 100644
--- a/linux/include/linux/videodev2.h
+++ b/linux/include/linux/videodev2.h
@@ -1185,6 +1185,7 @@ struct v4l2_modulator {
#define V4L2_TUNER_CAP_LANG2 0x0020
#define V4L2_TUNER_CAP_SAP 0x0020
#define V4L2_TUNER_CAP_LANG1 0x0040
+#define V4L2_TUNER_CAP_RDS 0x0080
/* Flags for the 'rxsubchans' field */
#define V4L2_TUNER_SUB_MONO 0x0001
@@ -1192,6 +1193,7 @@ struct v4l2_modulator {
#define V4L2_TUNER_SUB_LANG2 0x0004
#define V4L2_TUNER_SUB_SAP 0x0004
#define V4L2_TUNER_SUB_LANG1 0x0008
+#define V4L2_TUNER_SUB_RDS 0x0010
/* Values for the 'audmode' field */
#define V4L2_TUNER_MODE_MONO 0x0000
@@ -1217,6 +1219,27 @@ struct v4l2_hw_freq_seek {
};
/*
+ * R D S
+ */
+
+struct v4l2_rds_data {
+ __u8 lsb;
+ __u8 msb;
+ __u8 block;
+} __attribute__ ((packed));
+
+#define V4L2_RDS_BLOCK_MSK 0x7
+#define V4L2_RDS_BLOCK_A 0
+#define V4L2_RDS_BLOCK_B 1
+#define V4L2_RDS_BLOCK_C 2
+#define V4L2_RDS_BLOCK_D 3
+#define V4L2_RDS_BLOCK_C_ALT 4
+#define V4L2_RDS_BLOCK_INVALID 7
+
+#define V4L2_RDS_BLOCK_CORRECTED 0x40
+#define V4L2_RDS_BLOCK_ERROR 0x80
+
+/*
* A U D I O
*/
struct v4l2_audio {