diff options
author | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-30 12:39:15 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-09-30 12:39:15 -0400 |
commit | 5ffd1a6aaacc25be8cd0770a51ec6d46add3a276 (patch) | |
tree | 5b076c44f8b7ff88dba9a554d7748c6f083c9071 /drivers/media/radio/radio-cadet.c | |
parent | 0cd43f83d381c4246a08cd775834833d6fd64805 (diff) | |
parent | 8dd86eebc5315910ebfd9f30f1674254308be4b3 (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.c | 250 |
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 | ||
43 | static int io=-1; /* default to isapnp activation */ | 51 | static int io=-1; /* default to isapnp activation */ |
44 | static int radio_nr = -1; | 52 | static int radio_nr = -1; |
@@ -61,44 +69,24 @@ static int cadet_probe(void); | |||
61 | */ | 69 | */ |
62 | static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}}; | 70 | static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}}; |
63 | 71 | ||
64 | static 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 | ||
87 | static int cadet_getstereo(void) | 73 | static int |
74 | cadet_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 | ||
101 | static unsigned cadet_gettune(void) | 88 | static unsigned |
89 | cadet_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 | ||
138 | static unsigned cadet_getfreq(void) | 126 | static unsigned |
127 | cadet_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 | ||
170 | static void cadet_settune(unsigned fifo) | 159 | static void |
160 | cadet_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 | ||
198 | static void cadet_setfreq(unsigned freq) | 188 | static void |
189 | cadet_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 | ||
258 | static int cadet_getvol(void) | 249 | static int |
250 | cadet_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 | ||
273 | static void cadet_setvol(int vol) | 265 | static void |
266 | cadet_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 | ||
284 | static void cadet_handler(unsigned long data) | 277 | static void |
278 | cadet_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 | ||
325 | static ssize_t cadet_read(struct file *file, char __user *data, | 319 | static ssize_t |
326 | size_t count, loff_t *ppos) | 320 | cadet_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 | ||
464 | static int cadet_ioctl(struct inode *inode, struct file *file, | 474 | static int |
475 | cadet_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 | ||
470 | static int cadet_open(struct inode *inode, struct file *file) | 481 | static int |
482 | cadet_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 | ||
479 | static int cadet_release(struct inode *inode, struct file *file) | 489 | static int |
490 | cadet_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 | |||
500 | static unsigned int | ||
501 | cadet_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 | ||