aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/radio/radio-cadet.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@g5.osdl.org>2006-09-30 12:39:15 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2006-09-30 12:39:15 -0400
commit5ffd1a6aaacc25be8cd0770a51ec6d46add3a276 (patch)
tree5b076c44f8b7ff88dba9a554d7748c6f083c9071 /drivers/media/radio/radio-cadet.c
parent0cd43f83d381c4246a08cd775834833d6fd64805 (diff)
parent8dd86eebc5315910ebfd9f30f1674254308be4b3 (diff)
Merge master.kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb
* master.kernel.org:/pub/scm/linux/kernel/git/mchehab/v4l-dvb: (180 commits) V4L/DVB (4641): Trivial: use lowercase letters in hex subsystem ids V4L/DVB (4639): Cx88: add autodetection for alternate revision of Leadtek PVR V4L/DVB (4638): Basic DVB-T and analog TV support for the HVR1300. V4L/DVB (4637): Add a default method for VIDIOC_G_PARM V4L/DVB (4635): Extend bttv and saa7134 to check for both AGP and PCI PCI failure case V4L/DVB (4634): Zr36120: implement pcipci checks V4L/DVB (4632): Zoran: Implement pcipci failure check V4L/DVB (4631): Av7110: remove V4L2_CAP_VBI_CAPTURE flag V4L/DVB (4630): Av7110: FW_LOADER depemdency fixed V4L/DVB (4629): Saa7134: add card support for Proteus Pro 2309 V4L/DVB (4628): Fix VIDIOC_ENUMSTD ioctl in videodev.c V4L/DVB (4627): Vivi crashes with mplayer V4L/DVB (4626): On saa7111/7113, LUMA_CTRL need a different value V4L/DVB (4624): Tvaudio: Replaced kernel_thread() with kthread_run() V4L/DVB (4622): Copy-paste bug in videodev.c V4L/DVB (4620): Fix AGC configuration for MOD3000P-based boards V4L/DVB (4619): Fixes some I2C dependencies on V4L devices V4L/DVB (4617): Problem with dibusb-mb.c USB IDs V4L/DVB (4616): [PATCH] Nebula DigiTV USB RC support V4L/DVB (4614): Export symbol saa7134_tvaudio_setmute from saa7134 for saa7134-alsa ...
Diffstat (limited to 'drivers/media/radio/radio-cadet.c')
-rw-r--r--drivers/media/radio/radio-cadet.c250
1 files changed, 136 insertions, 114 deletions
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 8641aec7baf8..69d4b7919c5a 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -25,20 +25,28 @@
25 * 25 *
26 * 2003-01-31 Alan Cox <alan@redhat.com> 26 * 2003-01-31 Alan Cox <alan@redhat.com>
27 * Cleaned up locking, delay code, general odds and ends 27 * Cleaned up locking, delay code, general odds and ends
28 *
29 * 2006-07-30 Hans J. Koch <koch@hjk-az.de>
30 * Changed API to V4L2
28 */ 31 */
29 32
33#include <linux/version.h>
30#include <linux/module.h> /* Modules */ 34#include <linux/module.h> /* Modules */
31#include <linux/init.h> /* Initdata */ 35#include <linux/init.h> /* Initdata */
32#include <linux/ioport.h> /* request_region */ 36#include <linux/ioport.h> /* request_region */
33#include <linux/delay.h> /* udelay */ 37#include <linux/delay.h> /* udelay */
34#include <asm/io.h> /* outb, outb_p */ 38#include <asm/io.h> /* outb, outb_p */
35#include <asm/uaccess.h> /* copy to/from user */ 39#include <asm/uaccess.h> /* copy to/from user */
36#include <linux/videodev.h> /* kernel radio structs */ 40#include <linux/videodev2.h> /* V4L2 API defs */
37#include <media/v4l2-common.h> 41#include <media/v4l2-common.h>
38#include <linux/param.h> 42#include <linux/param.h>
39#include <linux/pnp.h> 43#include <linux/pnp.h>
40 44
41#define RDS_BUFFER 256 45#define RDS_BUFFER 256
46#define RDS_RX_FLAG 1
47#define MBS_RX_FLAG 2
48
49#define CADET_VERSION KERNEL_VERSION(0,3,3)
42 50
43static int io=-1; /* default to isapnp activation */ 51static int io=-1; /* default to isapnp activation */
44static int radio_nr = -1; 52static int radio_nr = -1;
@@ -61,44 +69,24 @@ static int cadet_probe(void);
61 */ 69 */
62static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}}; 70static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}};
63 71
64static int cadet_getrds(void)
65{
66 int rdsstat=0;
67
68 spin_lock(&cadet_io_lock);
69 outb(3,io); /* Select Decoder Control/Status */
70 outb(inb(io+1)&0x7f,io+1); /* Reset RDS detection */
71 spin_unlock(&cadet_io_lock);
72
73 msleep(100);
74
75 spin_lock(&cadet_io_lock);
76 outb(3,io); /* Select Decoder Control/Status */
77 if((inb(io+1)&0x80)!=0) {
78 rdsstat|=VIDEO_TUNER_RDS_ON;
79 }
80 if((inb(io+1)&0x10)!=0) {
81 rdsstat|=VIDEO_TUNER_MBS_ON;
82 }
83 spin_unlock(&cadet_io_lock);
84 return rdsstat;
85}
86 72
87static int cadet_getstereo(void) 73static int
74cadet_getstereo(void)
88{ 75{
89 int ret = 0; 76 int ret = V4L2_TUNER_SUB_MONO;
90 if(curtuner != 0) /* Only FM has stereo capability! */ 77 if(curtuner != 0) /* Only FM has stereo capability! */
91 return 0; 78 return V4L2_TUNER_SUB_MONO;
92 79
93 spin_lock(&cadet_io_lock); 80 spin_lock(&cadet_io_lock);
94 outb(7,io); /* Select tuner control */ 81 outb(7,io); /* Select tuner control */
95 if( (inb(io+1) & 0x40) == 0) 82 if( (inb(io+1) & 0x40) == 0)
96 ret = 1; 83 ret = V4L2_TUNER_SUB_STEREO;
97 spin_unlock(&cadet_io_lock); 84 spin_unlock(&cadet_io_lock);
98 return ret; 85 return ret;
99} 86}
100 87
101static unsigned cadet_gettune(void) 88static unsigned
89cadet_gettune(void)
102{ 90{
103 int curvol,i; 91 int curvol,i;
104 unsigned fifo=0; 92 unsigned fifo=0;
@@ -135,7 +123,8 @@ static unsigned cadet_gettune(void)
135 return fifo; 123 return fifo;
136} 124}
137 125
138static unsigned cadet_getfreq(void) 126static unsigned
127cadet_getfreq(void)
139{ 128{
140 int i; 129 int i;
141 unsigned freq=0,test,fifo=0; 130 unsigned freq=0,test,fifo=0;
@@ -167,7 +156,8 @@ static unsigned cadet_getfreq(void)
167 return freq; 156 return freq;
168} 157}
169 158
170static void cadet_settune(unsigned fifo) 159static void
160cadet_settune(unsigned fifo)
171{ 161{
172 int i; 162 int i;
173 unsigned test; 163 unsigned test;
@@ -195,7 +185,8 @@ static void cadet_settune(unsigned fifo)
195 spin_unlock(&cadet_io_lock); 185 spin_unlock(&cadet_io_lock);
196} 186}
197 187
198static void cadet_setfreq(unsigned freq) 188static void
189cadet_setfreq(unsigned freq)
199{ 190{
200 unsigned fifo; 191 unsigned fifo;
201 int i,j,test; 192 int i,j,test;
@@ -255,7 +246,8 @@ static void cadet_setfreq(unsigned freq)
255} 246}
256 247
257 248
258static int cadet_getvol(void) 249static int
250cadet_getvol(void)
259{ 251{
260 int ret = 0; 252 int ret = 0;
261 253
@@ -270,7 +262,8 @@ static int cadet_getvol(void)
270} 262}
271 263
272 264
273static void cadet_setvol(int vol) 265static void
266cadet_setvol(int vol)
274{ 267{
275 spin_lock(&cadet_io_lock); 268 spin_lock(&cadet_io_lock);
276 outb(7,io); /* Select tuner control */ 269 outb(7,io); /* Select tuner control */
@@ -281,7 +274,8 @@ static void cadet_setvol(int vol)
281 spin_unlock(&cadet_io_lock); 274 spin_unlock(&cadet_io_lock);
282} 275}
283 276
284static void cadet_handler(unsigned long data) 277static void
278cadet_handler(unsigned long data)
285{ 279{
286 /* 280 /*
287 * Service the RDS fifo 281 * Service the RDS fifo
@@ -322,8 +316,8 @@ static void cadet_handler(unsigned long data)
322 316
323 317
324 318
325static ssize_t cadet_read(struct file *file, char __user *data, 319static ssize_t
326 size_t count, loff_t *ppos) 320cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
327{ 321{
328 int i=0; 322 int i=0;
329 unsigned char readbuf[RDS_BUFFER]; 323 unsigned char readbuf[RDS_BUFFER];
@@ -359,128 +353,156 @@ static int cadet_do_ioctl(struct inode *inode, struct file *file,
359{ 353{
360 switch(cmd) 354 switch(cmd)
361 { 355 {
362 case VIDIOCGCAP: 356 case VIDIOC_QUERYCAP:
363 { 357 {
364 struct video_capability *v = arg; 358 struct v4l2_capability *cap = arg;
365 memset(v,0,sizeof(*v)); 359 memset(cap,0,sizeof(*cap));
366 v->type=VID_TYPE_TUNER; 360 cap->capabilities =
367 v->channels=2; 361 V4L2_CAP_TUNER |
368 v->audios=1; 362 V4L2_CAP_READWRITE;
369 strcpy(v->name, "ADS Cadet"); 363 cap->version = CADET_VERSION;
364 strcpy(cap->driver, "ADS Cadet");
365 strcpy(cap->card, "ADS Cadet");
370 return 0; 366 return 0;
371 } 367 }
372 case VIDIOCGTUNER: 368 case VIDIOC_G_TUNER:
373 { 369 {
374 struct video_tuner *v = arg; 370 struct v4l2_tuner *t = arg;
375 if((v->tuner<0)||(v->tuner>1)) { 371 memset(t,0,sizeof(*t));
376 return -EINVAL; 372 t->type = V4L2_TUNER_RADIO;
377 } 373 switch (t->index)
378 switch(v->tuner) { 374 {
379 case 0: 375 case 0: strcpy(t->name, "FM");
380 strcpy(v->name,"FM"); 376 t->capability = V4L2_TUNER_CAP_STEREO;
381 v->rangelow=1400; /* 87.5 MHz */ 377 t->rangelow = 1400; /* 87.5 MHz */
382 v->rangehigh=1728; /* 108.0 MHz */ 378 t->rangehigh = 1728; /* 108.0 MHz */
383 v->flags=0; 379 t->rxsubchans=cadet_getstereo();
384 v->mode=0; 380 switch (t->rxsubchans){
385 v->mode|=VIDEO_MODE_AUTO; 381 case V4L2_TUNER_SUB_MONO:
386 v->signal=sigstrength; 382 t->audmode = V4L2_TUNER_MODE_MONO;
387 if(cadet_getstereo()==1) { 383 break;
388 v->flags|=VIDEO_TUNER_STEREO_ON; 384 case V4L2_TUNER_SUB_STEREO:
389 } 385 t->audmode = V4L2_TUNER_MODE_STEREO;
390 v->flags|=cadet_getrds(); 386 break;
391 break; 387 default: ;
392 case 1: 388 }
393 strcpy(v->name,"AM"); 389 break;
394 v->rangelow=8320; /* 520 kHz */ 390 case 1: strcpy(t->name, "AM");
395 v->rangehigh=26400; /* 1650 kHz */ 391 t->capability = V4L2_TUNER_CAP_LOW;
396 v->flags=0; 392 t->rangelow = 8320; /* 520 kHz */
397 v->flags|=VIDEO_TUNER_LOW; 393 t->rangehigh = 26400; /* 1650 kHz */
398 v->mode=0; 394 t->rxsubchans = V4L2_TUNER_SUB_MONO;
399 v->mode|=VIDEO_MODE_AUTO; 395 t->audmode = V4L2_TUNER_MODE_MONO;
400 v->signal=sigstrength; 396 break;
401 break; 397 default:
398 return -EINVAL;
402 } 399 }
400
401 t->signal = sigstrength; /* We might need to modify scaling of this */
403 return 0; 402 return 0;
404 } 403 }
405 case VIDIOCSTUNER: 404 case VIDIOC_S_TUNER:
406 { 405 {
407 struct video_tuner *v = arg; 406 struct v4l2_tuner *t = arg;
408 if((v->tuner<0)||(v->tuner>1)) { 407 if((t->index != 0)&&(t->index != 1))
409 return -EINVAL; 408 return -EINVAL;
410 } 409
411 curtuner=v->tuner; 410 curtuner = t->index;
412 return 0; 411 return 0;
413 } 412 }
414 case VIDIOCGFREQ: 413 case VIDIOC_G_FREQUENCY:
415 { 414 {
416 unsigned long *freq = arg; 415 struct v4l2_frequency *f = arg;
417 *freq = cadet_getfreq(); 416 memset(f,0,sizeof(*f));
417 f->tuner = curtuner;
418 f->type = V4L2_TUNER_RADIO;
419 f->frequency = cadet_getfreq();
418 return 0; 420 return 0;
419 } 421 }
420 case VIDIOCSFREQ: 422 case VIDIOC_S_FREQUENCY:
421 { 423 {
422 unsigned long *freq = arg; 424 struct v4l2_frequency *f = arg;
423 if((curtuner==0)&&((*freq<1400)||(*freq>1728))) { 425 if (f->type != V4L2_TUNER_RADIO){
426 return -EINVAL;
427 }
428 if((curtuner==0)&&((f->frequency<1400)||(f->frequency>1728))) {
424 return -EINVAL; 429 return -EINVAL;
425 } 430 }
426 if((curtuner==1)&&((*freq<8320)||(*freq>26400))) { 431 if((curtuner==1)&&((f->frequency<8320)||(f->frequency>26400))) {
427 return -EINVAL; 432 return -EINVAL;
428 } 433 }
429 cadet_setfreq(*freq); 434 cadet_setfreq(f->frequency);
430 return 0; 435 return 0;
431 } 436 }
432 case VIDIOCGAUDIO: 437 case VIDIOC_G_CTRL:
433 { 438 {
434 struct video_audio *v = arg; 439 struct v4l2_control *c = arg;
435 memset(v,0, sizeof(*v)); 440 switch (c->id){
436 v->flags=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME; 441 case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */
437 if(cadet_getstereo()==0) { 442 c->value = (cadet_getvol() == 0);
438 v->mode=VIDEO_SOUND_MONO; 443 break;
439 } else { 444 case V4L2_CID_AUDIO_VOLUME:
440 v->mode=VIDEO_SOUND_STEREO; 445 c->value = cadet_getvol();
446 break;
447 default:
448 return -EINVAL;
441 } 449 }
442 v->volume=cadet_getvol();
443 v->step=0xffff;
444 strcpy(v->name, "Radio");
445 return 0; 450 return 0;
446 } 451 }
447 case VIDIOCSAUDIO: 452 case VIDIOC_S_CTRL:
448 { 453 {
449 struct video_audio *v = arg; 454 struct v4l2_control *c = arg;
450 if(v->audio) 455 switch (c->id){
451 return -EINVAL; 456 case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */
452 cadet_setvol(v->volume); 457 if (c->value) cadet_setvol(0);
453 if(v->flags&VIDEO_AUDIO_MUTE) 458 else cadet_setvol(0xffff);
454 cadet_setvol(0); 459 break;
455 else 460 case V4L2_CID_AUDIO_VOLUME:
456 cadet_setvol(0xffff); 461 cadet_setvol(c->value);
462 break;
463 default:
464 return -EINVAL;
465 }
457 return 0; 466 return 0;
458 } 467 }
468
459 default: 469 default:
460 return -ENOIOCTLCMD; 470 return -ENOIOCTLCMD;
461 } 471 }
462} 472}
463 473
464static int cadet_ioctl(struct inode *inode, struct file *file, 474static int
475cadet_ioctl(struct inode *inode, struct file *file,
465 unsigned int cmd, unsigned long arg) 476 unsigned int cmd, unsigned long arg)
466{ 477{
467 return video_usercopy(inode, file, cmd, arg, cadet_do_ioctl); 478 return video_usercopy(inode, file, cmd, arg, cadet_do_ioctl);
468} 479}
469 480
470static int cadet_open(struct inode *inode, struct file *file) 481static int
482cadet_open(struct inode *inode, struct file *file)
471{ 483{
472 if(users)
473 return -EBUSY;
474 users++; 484 users++;
475 init_waitqueue_head(&read_queue); 485 if (1 == users) init_waitqueue_head(&read_queue);
476 return 0; 486 return 0;
477} 487}
478 488
479static int cadet_release(struct inode *inode, struct file *file) 489static int
490cadet_release(struct inode *inode, struct file *file)
480{ 491{
481 del_timer_sync(&readtimer);
482 rdsstat=0;
483 users--; 492 users--;
493 if (0 == users){
494 del_timer_sync(&readtimer);
495 rdsstat=0;
496 }
497 return 0;
498}
499
500static unsigned int
501cadet_poll(struct file *file, struct poll_table_struct *wait)
502{
503 poll_wait(file,&read_queue,wait);
504 if(rdsin != rdsout)
505 return POLLIN | POLLRDNORM;
484 return 0; 506 return 0;
485} 507}
486 508
@@ -491,6 +513,7 @@ static struct file_operations cadet_fops = {
491 .release = cadet_release, 513 .release = cadet_release,
492 .read = cadet_read, 514 .read = cadet_read,
493 .ioctl = cadet_ioctl, 515 .ioctl = cadet_ioctl,
516 .poll = cadet_poll,
494 .compat_ioctl = v4l_compat_ioctl32, 517 .compat_ioctl = v4l_compat_ioctl32,
495 .llseek = no_llseek, 518 .llseek = no_llseek,
496}; 519};
@@ -500,7 +523,6 @@ static struct video_device cadet_radio=
500 .owner = THIS_MODULE, 523 .owner = THIS_MODULE,
501 .name = "Cadet radio", 524 .name = "Cadet radio",
502 .type = VID_TYPE_TUNER, 525 .type = VID_TYPE_TUNER,
503 .hardware = VID_HARDWARE_CADET,
504 .fops = &cadet_fops, 526 .fops = &cadet_fops,
505}; 527};
506 528