Skip to content

Commit

Permalink
[media] radio-cadet: fix RDS handling
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Hans Verkuil authored and Mauro Carvalho Chehab committed Jul 30, 2012
1 parent b54c97d commit cc0d326
Showing 1 changed file with 39 additions and 17 deletions.
56 changes: 39 additions & 17 deletions drivers/media/radio/radio-cadet.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 }
};


Expand Down Expand Up @@ -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);
}


Expand All @@ -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++;
Expand All @@ -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)
{
Expand All @@ -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);
Expand Down Expand Up @@ -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));
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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);
}
Expand Down

0 comments on commit cc0d326

Please sign in to comment.