[media] radio-cadet: fix RDS handling

The current RDS code suffered from bit rot. Clean it up and make it work again.

Signed-off-by: Hans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
This commit is contained in:
Hans Verkuil 2012-07-02 09:46:46 -03:00 committed by Mauro Carvalho Chehab
parent b54c97db7f
commit cc0d32665f

View File

@ -71,7 +71,7 @@ struct cadet {
int sigstrength;
wait_queue_head_t read_queue;
struct timer_list readtimer;
__u8 rdsin, rdsout, rdsstat;
u8 rdsin, rdsout, rdsstat;
unsigned char rdsbuf[RDS_BUFFER];
struct mutex lock;
int reading;
@ -85,8 +85,8 @@ static struct cadet cadet_card;
* strength value. These values are in microvolts of RF at the tuner's input.
*/
static __u16 sigtable[2][4] = {
{ 5, 10, 30, 150 },
{ 28, 40, 63, 1000 }
{ 2185, 4369, 13107, 65535 },
{ 1835, 2621, 4128, 65535 }
};
@ -240,10 +240,13 @@ static void cadet_setfreq(struct cadet *dev, unsigned freq)
cadet_gettune(dev);
if ((dev->tunestat & 0x40) == 0) { /* Tuned */
dev->sigstrength = sigtable[dev->curtuner][j];
return;
goto reset_rds;
}
}
dev->sigstrength = 0;
reset_rds:
outb(3, dev->io);
outb(inb(dev->io + 1) & 0x7f, dev->io + 1);
}
@ -259,7 +262,7 @@ static void cadet_handler(unsigned long data)
outb(0x80, dev->io); /* Select RDS fifo */
while ((inb(dev->io) & 0x80) != 0) {
dev->rdsbuf[dev->rdsin] = inb(dev->io + 1);
if (dev->rdsin == dev->rdsout)
if (dev->rdsin + 1 == dev->rdsout)
printk(KERN_WARNING "cadet: RDS buffer overflow\n");
else
dev->rdsin++;
@ -278,11 +281,21 @@ static void cadet_handler(unsigned long data)
*/
init_timer(&dev->readtimer);
dev->readtimer.function = cadet_handler;
dev->readtimer.data = (unsigned long)0;
dev->readtimer.data = data;
dev->readtimer.expires = jiffies + msecs_to_jiffies(50);
add_timer(&dev->readtimer);
}
static void cadet_start_rds(struct cadet *dev)
{
dev->rdsstat = 1;
outb(0x80, dev->io); /* Select RDS fifo */
init_timer(&dev->readtimer);
dev->readtimer.function = cadet_handler;
dev->readtimer.data = (unsigned long)dev;
dev->readtimer.expires = jiffies + msecs_to_jiffies(50);
add_timer(&dev->readtimer);
}
static ssize_t cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
@ -291,26 +304,21 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo
int i = 0;
mutex_lock(&dev->lock);
if (dev->rdsstat == 0) {
dev->rdsstat = 1;
outb(0x80, dev->io); /* Select RDS fifo */
init_timer(&dev->readtimer);
dev->readtimer.function = cadet_handler;
dev->readtimer.data = (unsigned long)dev;
dev->readtimer.expires = jiffies + msecs_to_jiffies(50);
add_timer(&dev->readtimer);
}
if (dev->rdsstat == 0)
cadet_start_rds(dev);
if (dev->rdsin == dev->rdsout) {
if (file->f_flags & O_NONBLOCK) {
i = -EWOULDBLOCK;
goto unlock;
}
mutex_unlock(&dev->lock);
interruptible_sleep_on(&dev->read_queue);
mutex_lock(&dev->lock);
}
while (i < count && dev->rdsin != dev->rdsout)
readbuf[i++] = dev->rdsbuf[dev->rdsout++];
if (copy_to_user(data, readbuf, i))
if (i && copy_to_user(data, readbuf, i))
i = -EFAULT;
unlock:
mutex_unlock(&dev->lock);
@ -345,7 +353,12 @@ static int vidioc_g_tuner(struct file *file, void *priv,
v->rangehigh = 1728000; /* 108.0 MHz */
v->rxsubchans = cadet_getstereo(dev);
v->audmode = V4L2_TUNER_MODE_STEREO;
v->rxsubchans |= V4L2_TUNER_SUB_RDS;
outb(3, dev->io);
outb(inb(dev->io + 1) & 0x7f, dev->io + 1);
mdelay(100);
outb(3, dev->io);
if (inb(dev->io + 1) & 0x80)
v->rxsubchans |= V4L2_TUNER_SUB_RDS;
break;
case 1:
strlcpy(v->name, "AM", sizeof(v->name));
@ -455,9 +468,16 @@ static int cadet_release(struct file *file)
static unsigned int cadet_poll(struct file *file, struct poll_table_struct *wait)
{
struct cadet *dev = video_drvdata(file);
unsigned long req_events = poll_requested_events(wait);
unsigned int res = v4l2_ctrl_poll(file, wait);
poll_wait(file, &dev->read_queue, wait);
if (dev->rdsstat == 0 && (req_events & (POLLIN | POLLRDNORM))) {
mutex_lock(&dev->lock);
if (dev->rdsstat == 0)
cadet_start_rds(dev);
mutex_unlock(&dev->lock);
}
if (dev->rdsin != dev->rdsout)
res |= POLLIN | POLLRDNORM;
return res;
@ -628,6 +648,8 @@ static void __exit cadet_exit(void)
video_unregister_device(&dev->vdev);
v4l2_ctrl_handler_free(&dev->ctrl_handler);
v4l2_device_unregister(&dev->v4l2_dev);
outb(7, dev->io); /* Mute */
outb(0x00, dev->io + 1);
release_region(dev->io, 2);
pnp_unregister_driver(&cadet_pnp_driver);
}