Commit cc0d3266 authored by Hans Verkuil's avatar Hans Verkuil Committed by Mauro Carvalho Chehab

[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: default avatarHans Verkuil <hans.verkuil@cisco.com>
Signed-off-by: default avatarMauro Carvalho Chehab <mchehab@redhat.com>
parent b54c97db
...@@ -71,7 +71,7 @@ struct cadet { ...@@ -71,7 +71,7 @@ struct cadet {
int sigstrength; int sigstrength;
wait_queue_head_t read_queue; wait_queue_head_t read_queue;
struct timer_list readtimer; struct timer_list readtimer;
__u8 rdsin, rdsout, rdsstat; u8 rdsin, rdsout, rdsstat;
unsigned char rdsbuf[RDS_BUFFER]; unsigned char rdsbuf[RDS_BUFFER];
struct mutex lock; struct mutex lock;
int reading; int reading;
...@@ -85,8 +85,8 @@ static struct cadet cadet_card; ...@@ -85,8 +85,8 @@ static struct cadet cadet_card;
* strength value. These values are in microvolts of RF at the tuner's input. * strength value. These values are in microvolts of RF at the tuner's input.
*/ */
static __u16 sigtable[2][4] = { static __u16 sigtable[2][4] = {
{ 5, 10, 30, 150 }, { 2185, 4369, 13107, 65535 },
{ 28, 40, 63, 1000 } { 1835, 2621, 4128, 65535 }
}; };
...@@ -240,10 +240,13 @@ static void cadet_setfreq(struct cadet *dev, unsigned freq) ...@@ -240,10 +240,13 @@ static void cadet_setfreq(struct cadet *dev, unsigned freq)
cadet_gettune(dev); cadet_gettune(dev);
if ((dev->tunestat & 0x40) == 0) { /* Tuned */ if ((dev->tunestat & 0x40) == 0) { /* Tuned */
dev->sigstrength = sigtable[dev->curtuner][j]; dev->sigstrength = sigtable[dev->curtuner][j];
return; goto reset_rds;
} }
} }
dev->sigstrength = 0; 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) ...@@ -259,7 +262,7 @@ static void cadet_handler(unsigned long data)
outb(0x80, dev->io); /* Select RDS fifo */ outb(0x80, dev->io); /* Select RDS fifo */
while ((inb(dev->io) & 0x80) != 0) { while ((inb(dev->io) & 0x80) != 0) {
dev->rdsbuf[dev->rdsin] = inb(dev->io + 1); 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"); printk(KERN_WARNING "cadet: RDS buffer overflow\n");
else else
dev->rdsin++; dev->rdsin++;
...@@ -278,20 +281,13 @@ static void cadet_handler(unsigned long data) ...@@ -278,20 +281,13 @@ static void cadet_handler(unsigned long data)
*/ */
init_timer(&dev->readtimer); init_timer(&dev->readtimer);
dev->readtimer.function = cadet_handler; dev->readtimer.function = cadet_handler;
dev->readtimer.data = (unsigned long)0; dev->readtimer.data = data;
dev->readtimer.expires = jiffies + msecs_to_jiffies(50); dev->readtimer.expires = jiffies + msecs_to_jiffies(50);
add_timer(&dev->readtimer); add_timer(&dev->readtimer);
} }
static void cadet_start_rds(struct cadet *dev)
static ssize_t cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{ {
struct cadet *dev = video_drvdata(file);
unsigned char readbuf[RDS_BUFFER];
int i = 0;
mutex_lock(&dev->lock);
if (dev->rdsstat == 0) {
dev->rdsstat = 1; dev->rdsstat = 1;
outb(0x80, dev->io); /* Select RDS fifo */ outb(0x80, dev->io); /* Select RDS fifo */
init_timer(&dev->readtimer); init_timer(&dev->readtimer);
...@@ -299,18 +295,30 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo ...@@ -299,18 +295,30 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo
dev->readtimer.data = (unsigned long)dev; dev->readtimer.data = (unsigned long)dev;
dev->readtimer.expires = jiffies + msecs_to_jiffies(50); dev->readtimer.expires = jiffies + msecs_to_jiffies(50);
add_timer(&dev->readtimer); add_timer(&dev->readtimer);
} }
static ssize_t cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
{
struct cadet *dev = video_drvdata(file);
unsigned char readbuf[RDS_BUFFER];
int i = 0;
mutex_lock(&dev->lock);
if (dev->rdsstat == 0)
cadet_start_rds(dev);
if (dev->rdsin == dev->rdsout) { if (dev->rdsin == dev->rdsout) {
if (file->f_flags & O_NONBLOCK) { if (file->f_flags & O_NONBLOCK) {
i = -EWOULDBLOCK; i = -EWOULDBLOCK;
goto unlock; goto unlock;
} }
mutex_unlock(&dev->lock);
interruptible_sleep_on(&dev->read_queue); interruptible_sleep_on(&dev->read_queue);
mutex_lock(&dev->lock);
} }
while (i < count && dev->rdsin != dev->rdsout) while (i < count && dev->rdsin != dev->rdsout)
readbuf[i++] = dev->rdsbuf[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; i = -EFAULT;
unlock: unlock:
mutex_unlock(&dev->lock); mutex_unlock(&dev->lock);
...@@ -345,6 +353,11 @@ static int vidioc_g_tuner(struct file *file, void *priv, ...@@ -345,6 +353,11 @@ static int vidioc_g_tuner(struct file *file, void *priv,
v->rangehigh = 1728000; /* 108.0 MHz */ v->rangehigh = 1728000; /* 108.0 MHz */
v->rxsubchans = cadet_getstereo(dev); v->rxsubchans = cadet_getstereo(dev);
v->audmode = V4L2_TUNER_MODE_STEREO; v->audmode = V4L2_TUNER_MODE_STEREO;
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; v->rxsubchans |= V4L2_TUNER_SUB_RDS;
break; break;
case 1: case 1:
...@@ -455,9 +468,16 @@ static int cadet_release(struct file *file) ...@@ -455,9 +468,16 @@ static int cadet_release(struct file *file)
static unsigned int cadet_poll(struct file *file, struct poll_table_struct *wait) static unsigned int cadet_poll(struct file *file, struct poll_table_struct *wait)
{ {
struct cadet *dev = video_drvdata(file); struct cadet *dev = video_drvdata(file);
unsigned long req_events = poll_requested_events(wait);
unsigned int res = v4l2_ctrl_poll(file, wait); unsigned int res = v4l2_ctrl_poll(file, wait);
poll_wait(file, &dev->read_queue, 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) if (dev->rdsin != dev->rdsout)
res |= POLLIN | POLLRDNORM; res |= POLLIN | POLLRDNORM;
return res; return res;
...@@ -628,6 +648,8 @@ static void __exit cadet_exit(void) ...@@ -628,6 +648,8 @@ static void __exit cadet_exit(void)
video_unregister_device(&dev->vdev); video_unregister_device(&dev->vdev);
v4l2_ctrl_handler_free(&dev->ctrl_handler); v4l2_ctrl_handler_free(&dev->ctrl_handler);
v4l2_device_unregister(&dev->v4l2_dev); v4l2_device_unregister(&dev->v4l2_dev);
outb(7, dev->io); /* Mute */
outb(0x00, dev->io + 1);
release_region(dev->io, 2); release_region(dev->io, 2);
pnp_unregister_driver(&cadet_pnp_driver); pnp_unregister_driver(&cadet_pnp_driver);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment