diff options
author | Hans Verkuil <hans.verkuil@cisco.com> | 2012-07-02 08:46:46 -0400 |
---|---|---|
committer | Mauro Carvalho Chehab <mchehab@redhat.com> | 2012-07-30 19:23:09 -0400 |
commit | cc0d32665f9f8d4e7297a470e91b8848c7f0436c (patch) | |
tree | 9520764083b3d4db657b30840ed2bf5b92324f85 | |
parent | b54c97db7f51c47c361533956db18c8b191033b5 (diff) |
[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>
-rw-r--r-- | drivers/media/radio/radio-cadet.c | 56 |
1 files changed, 39 insertions, 17 deletions
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index 93536b7e75c7..d1fb42746fc2 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c | |||
@@ -71,7 +71,7 @@ struct cadet { | |||
71 | int sigstrength; | 71 | int sigstrength; |
72 | wait_queue_head_t read_queue; | 72 | wait_queue_head_t read_queue; |
73 | struct timer_list readtimer; | 73 | struct timer_list readtimer; |
74 | __u8 rdsin, rdsout, rdsstat; | 74 | u8 rdsin, rdsout, rdsstat; |
75 | unsigned char rdsbuf[RDS_BUFFER]; | 75 | unsigned char rdsbuf[RDS_BUFFER]; |
76 | struct mutex lock; | 76 | struct mutex lock; |
77 | int reading; | 77 | int reading; |
@@ -85,8 +85,8 @@ static struct cadet cadet_card; | |||
85 | * strength value. These values are in microvolts of RF at the tuner's input. | 85 | * strength value. These values are in microvolts of RF at the tuner's input. |
86 | */ | 86 | */ |
87 | static __u16 sigtable[2][4] = { | 87 | static __u16 sigtable[2][4] = { |
88 | { 5, 10, 30, 150 }, | 88 | { 2185, 4369, 13107, 65535 }, |
89 | { 28, 40, 63, 1000 } | 89 | { 1835, 2621, 4128, 65535 } |
90 | }; | 90 | }; |
91 | 91 | ||
92 | 92 | ||
@@ -240,10 +240,13 @@ static void cadet_setfreq(struct cadet *dev, unsigned freq) | |||
240 | cadet_gettune(dev); | 240 | cadet_gettune(dev); |
241 | if ((dev->tunestat & 0x40) == 0) { /* Tuned */ | 241 | if ((dev->tunestat & 0x40) == 0) { /* Tuned */ |
242 | dev->sigstrength = sigtable[dev->curtuner][j]; | 242 | dev->sigstrength = sigtable[dev->curtuner][j]; |
243 | return; | 243 | goto reset_rds; |
244 | } | 244 | } |
245 | } | 245 | } |
246 | dev->sigstrength = 0; | 246 | dev->sigstrength = 0; |
247 | reset_rds: | ||
248 | outb(3, dev->io); | ||
249 | outb(inb(dev->io + 1) & 0x7f, dev->io + 1); | ||
247 | } | 250 | } |
248 | 251 | ||
249 | 252 | ||
@@ -259,7 +262,7 @@ static void cadet_handler(unsigned long data) | |||
259 | outb(0x80, dev->io); /* Select RDS fifo */ | 262 | outb(0x80, dev->io); /* Select RDS fifo */ |
260 | while ((inb(dev->io) & 0x80) != 0) { | 263 | while ((inb(dev->io) & 0x80) != 0) { |
261 | dev->rdsbuf[dev->rdsin] = inb(dev->io + 1); | 264 | dev->rdsbuf[dev->rdsin] = inb(dev->io + 1); |
262 | if (dev->rdsin == dev->rdsout) | 265 | if (dev->rdsin + 1 == dev->rdsout) |
263 | printk(KERN_WARNING "cadet: RDS buffer overflow\n"); | 266 | printk(KERN_WARNING "cadet: RDS buffer overflow\n"); |
264 | else | 267 | else |
265 | dev->rdsin++; | 268 | dev->rdsin++; |
@@ -278,11 +281,21 @@ static void cadet_handler(unsigned long data) | |||
278 | */ | 281 | */ |
279 | init_timer(&dev->readtimer); | 282 | init_timer(&dev->readtimer); |
280 | dev->readtimer.function = cadet_handler; | 283 | dev->readtimer.function = cadet_handler; |
281 | dev->readtimer.data = (unsigned long)0; | 284 | dev->readtimer.data = data; |
282 | dev->readtimer.expires = jiffies + msecs_to_jiffies(50); | 285 | dev->readtimer.expires = jiffies + msecs_to_jiffies(50); |
283 | add_timer(&dev->readtimer); | 286 | add_timer(&dev->readtimer); |
284 | } | 287 | } |
285 | 288 | ||
289 | static void cadet_start_rds(struct cadet *dev) | ||
290 | { | ||
291 | dev->rdsstat = 1; | ||
292 | outb(0x80, dev->io); /* Select RDS fifo */ | ||
293 | init_timer(&dev->readtimer); | ||
294 | dev->readtimer.function = cadet_handler; | ||
295 | dev->readtimer.data = (unsigned long)dev; | ||
296 | dev->readtimer.expires = jiffies + msecs_to_jiffies(50); | ||
297 | add_timer(&dev->readtimer); | ||
298 | } | ||
286 | 299 | ||
287 | static ssize_t cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos) | 300 | static ssize_t cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos) |
288 | { | 301 | { |
@@ -291,26 +304,21 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo | |||
291 | int i = 0; | 304 | int i = 0; |
292 | 305 | ||
293 | mutex_lock(&dev->lock); | 306 | mutex_lock(&dev->lock); |
294 | if (dev->rdsstat == 0) { | 307 | if (dev->rdsstat == 0) |
295 | dev->rdsstat = 1; | 308 | cadet_start_rds(dev); |
296 | outb(0x80, dev->io); /* Select RDS fifo */ | ||
297 | init_timer(&dev->readtimer); | ||
298 | dev->readtimer.function = cadet_handler; | ||
299 | dev->readtimer.data = (unsigned long)dev; | ||
300 | dev->readtimer.expires = jiffies + msecs_to_jiffies(50); | ||
301 | add_timer(&dev->readtimer); | ||
302 | } | ||
303 | if (dev->rdsin == dev->rdsout) { | 309 | if (dev->rdsin == dev->rdsout) { |
304 | if (file->f_flags & O_NONBLOCK) { | 310 | if (file->f_flags & O_NONBLOCK) { |
305 | i = -EWOULDBLOCK; | 311 | i = -EWOULDBLOCK; |
306 | goto unlock; | 312 | goto unlock; |
307 | } | 313 | } |
314 | mutex_unlock(&dev->lock); | ||
308 | interruptible_sleep_on(&dev->read_queue); | 315 | interruptible_sleep_on(&dev->read_queue); |
316 | mutex_lock(&dev->lock); | ||
309 | } | 317 | } |
310 | while (i < count && dev->rdsin != dev->rdsout) | 318 | while (i < count && dev->rdsin != dev->rdsout) |
311 | readbuf[i++] = dev->rdsbuf[dev->rdsout++]; | 319 | readbuf[i++] = dev->rdsbuf[dev->rdsout++]; |
312 | 320 | ||
313 | if (copy_to_user(data, readbuf, i)) | 321 | if (i && copy_to_user(data, readbuf, i)) |
314 | i = -EFAULT; | 322 | i = -EFAULT; |
315 | unlock: | 323 | unlock: |
316 | mutex_unlock(&dev->lock); | 324 | mutex_unlock(&dev->lock); |
@@ -345,7 +353,12 @@ static int vidioc_g_tuner(struct file *file, void *priv, | |||
345 | v->rangehigh = 1728000; /* 108.0 MHz */ | 353 | v->rangehigh = 1728000; /* 108.0 MHz */ |
346 | v->rxsubchans = cadet_getstereo(dev); | 354 | v->rxsubchans = cadet_getstereo(dev); |
347 | v->audmode = V4L2_TUNER_MODE_STEREO; | 355 | v->audmode = V4L2_TUNER_MODE_STEREO; |
348 | v->rxsubchans |= V4L2_TUNER_SUB_RDS; | 356 | outb(3, dev->io); |
357 | outb(inb(dev->io + 1) & 0x7f, dev->io + 1); | ||
358 | mdelay(100); | ||
359 | outb(3, dev->io); | ||
360 | if (inb(dev->io + 1) & 0x80) | ||
361 | v->rxsubchans |= V4L2_TUNER_SUB_RDS; | ||
349 | break; | 362 | break; |
350 | case 1: | 363 | case 1: |
351 | strlcpy(v->name, "AM", sizeof(v->name)); | 364 | strlcpy(v->name, "AM", sizeof(v->name)); |
@@ -455,9 +468,16 @@ static int cadet_release(struct file *file) | |||
455 | static unsigned int cadet_poll(struct file *file, struct poll_table_struct *wait) | 468 | static unsigned int cadet_poll(struct file *file, struct poll_table_struct *wait) |
456 | { | 469 | { |
457 | struct cadet *dev = video_drvdata(file); | 470 | struct cadet *dev = video_drvdata(file); |
471 | unsigned long req_events = poll_requested_events(wait); | ||
458 | unsigned int res = v4l2_ctrl_poll(file, wait); | 472 | unsigned int res = v4l2_ctrl_poll(file, wait); |
459 | 473 | ||
460 | poll_wait(file, &dev->read_queue, wait); | 474 | poll_wait(file, &dev->read_queue, wait); |
475 | if (dev->rdsstat == 0 && (req_events & (POLLIN | POLLRDNORM))) { | ||
476 | mutex_lock(&dev->lock); | ||
477 | if (dev->rdsstat == 0) | ||
478 | cadet_start_rds(dev); | ||
479 | mutex_unlock(&dev->lock); | ||
480 | } | ||
461 | if (dev->rdsin != dev->rdsout) | 481 | if (dev->rdsin != dev->rdsout) |
462 | res |= POLLIN | POLLRDNORM; | 482 | res |= POLLIN | POLLRDNORM; |
463 | return res; | 483 | return res; |
@@ -628,6 +648,8 @@ static void __exit cadet_exit(void) | |||
628 | video_unregister_device(&dev->vdev); | 648 | video_unregister_device(&dev->vdev); |
629 | v4l2_ctrl_handler_free(&dev->ctrl_handler); | 649 | v4l2_ctrl_handler_free(&dev->ctrl_handler); |
630 | v4l2_device_unregister(&dev->v4l2_dev); | 650 | v4l2_device_unregister(&dev->v4l2_dev); |
651 | outb(7, dev->io); /* Mute */ | ||
652 | outb(0x00, dev->io + 1); | ||
631 | release_region(dev->io, 2); | 653 | release_region(dev->io, 2); |
632 | pnp_unregister_driver(&cadet_pnp_driver); | 654 | pnp_unregister_driver(&cadet_pnp_driver); |
633 | } | 655 | } |