patch-2.4.21 linux-2.4.21/drivers/media/radio/radio-cadet.c
Next file: linux-2.4.21/drivers/media/radio/radio-gemtek.c
Previous file: linux-2.4.21/drivers/media/radio/radio-aimslab.c
Back to the patch index
Back to the overall index
- Lines: 483
- Date:
2003-06-13 07:51:34.000000000 -0700
- Orig file:
linux-2.4.20/drivers/media/radio/radio-cadet.c
- Orig date:
2001-09-30 12:26:06.000000000 -0700
diff -urN linux-2.4.20/drivers/media/radio/radio-cadet.c linux-2.4.21/drivers/media/radio/radio-cadet.c
@@ -20,7 +20,9 @@
* Removed dead CONFIG_RADIO_CADET_PORT code
* PnP detection on load is now default (no args necessary)
*
-*/
+ * 2003-01-31 Alan Cox <alan@redhat.com>
+ * Cleaned up locking, delay code, general odds and ends
+ */
#include <linux/module.h> /* Modules */
#include <linux/init.h> /* Initdata */
@@ -40,11 +42,11 @@
static int curtuner=0;
static int tunestat=0;
static int sigstrength=0;
-static wait_queue_head_t tunerq,rdsq,readq;
+static wait_queue_head_t readq;
struct timer_list tunertimer,rdstimer,readtimer;
static __u8 rdsin=0,rdsout=0,rdsstat=0;
static unsigned char rdsbuf[RDS_BUFFER];
-static int cadet_lock=0;
+static spinlock_t cadet_io_lock;
static int cadet_probe(void);
static struct pci_dev *dev;
@@ -57,37 +59,19 @@
*/
static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}};
-void cadet_wake(unsigned long qnum)
-{
- switch(qnum) {
- case 0: /* cadet_setfreq */
- wake_up(&tunerq);
- break;
- case 1: /* cadet_getrds */
- wake_up(&rdsq);
- break;
- }
-}
-
-
-
static int cadet_getrds(void)
{
int rdsstat=0;
- cadet_lock++;
+ spin_lock(&cadet_io_lock);
outb(3,io); /* Select Decoder Control/Status */
outb(inb(io+1)&0x7f,io+1); /* Reset RDS detection */
- cadet_lock--;
- init_timer(&rdstimer);
- rdstimer.function=cadet_wake;
- rdstimer.data=(unsigned long)1;
- rdstimer.expires=jiffies+(HZ/10);
- init_waitqueue_head(&rdsq);
- add_timer(&rdstimer);
- sleep_on(&rdsq);
+ spin_unlock(&cadet_io_lock);
- cadet_lock++;
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ/10);
+
+ spin_lock(&cadet_io_lock);
outb(3,io); /* Select Decoder Control/Status */
if((inb(io+1)&0x80)!=0) {
rdsstat|=VIDEO_TUNER_RDS_ON;
@@ -95,32 +79,24 @@
if((inb(io+1)&0x10)!=0) {
rdsstat|=VIDEO_TUNER_MBS_ON;
}
- cadet_lock--;
+ spin_unlock(&cadet_io_lock);
return rdsstat;
+
}
-
-
-
static int cadet_getstereo(void)
{
- if(curtuner!=0) { /* Only FM has stereo capability! */
+ int ret = 0;
+ if(curtuner != 0) /* Only FM has stereo capability! */
return 0;
- }
- cadet_lock++;
+ spin_lock(&cadet_io_lock);
outb(7,io); /* Select tuner control */
- if((inb(io+1)&0x40)==0) {
- cadet_lock--;
- return 1; /* Stereo pilot detected */
- }
- else {
- cadet_lock--;
- return 0; /* Mono */
- }
+ if( (inb(io+1) & 0x40) == 0)
+ ret = 1;
+ spin_unlock(&cadet_io_lock);
+ return ret;
}
-
-
static unsigned cadet_gettune(void)
{
int curvol,i;
@@ -129,7 +105,9 @@
/*
* Prepare for read
*/
- cadet_lock++;
+
+ spin_lock(&cadet_io_lock);
+
outb(7,io); /* Select tuner control */
curvol=inb(io+1); /* Save current volume/mute setting */
outb(0x00,io+1); /* Ensure WRITE-ENABLE is LOW */
@@ -151,7 +129,8 @@
* Restore volume/mute setting
*/
outb(curvol,io+1);
- cadet_lock--;
+
+ spin_unlock(&cadet_io_lock);
return fifo;
}
@@ -197,7 +176,8 @@
int i;
unsigned test;
- cadet_lock++;
+ spin_lock(&cadet_io_lock);
+
outb(7,io); /* Select tuner control */
/*
* Write the shift register
@@ -216,7 +196,7 @@
test=0x1c|((fifo>>23)&0x02);
outb(test,io+1);
}
- cadet_lock--;
+ spin_unlock(&cadet_io_lock);
}
@@ -252,92 +232,92 @@
/*
* Save current volume/mute setting
*/
- cadet_lock++;
+
+ spin_lock(&cadet_io_lock);
outb(7,io); /* Select tuner control */
curvol=inb(io+1);
+ spin_unlock(&cadet_io_lock);
/*
* Tune the card
*/
for(j=3;j>-1;j--) {
cadet_settune(fifo|(j<<16));
+
+ spin_lock(&cadet_io_lock);
outb(7,io); /* Select tuner control */
outb(curvol,io+1);
- cadet_lock--;
- init_timer(&tunertimer);
- tunertimer.function=cadet_wake;
- tunertimer.data=(unsigned long)0;
- tunertimer.expires=jiffies+(HZ/10);
- init_waitqueue_head(&tunerq);
- add_timer(&tunertimer);
- sleep_on(&tunerq);
+ spin_unlock(&cadet_io_lock);
+
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_timeout(HZ/10);
+
cadet_gettune();
- if((tunestat&0x40)==0) { /* Tuned */
+ if((tunestat & 0x40) == 0) { /* Tuned */
sigstrength=sigtable[curtuner][j];
return;
}
- cadet_lock++;
}
- cadet_lock--;
sigstrength=0;
}
static int cadet_getvol(void)
{
- cadet_lock++;
+ int ret = 0;
+
+ spin_lock(&cadet_io_lock);
+
outb(7,io); /* Select tuner control */
- if((inb(io+1)&0x20)!=0) {
- cadet_lock--;
- return 0xffff;
- }
- else {
- cadet_lock--;
- return 0;
- }
+ if((inb(io + 1) & 0x20) != 0)
+ ret = 0xffff;
+
+ spin_unlock(&cadet_io_lock);
+ return ret;
}
static void cadet_setvol(int vol)
{
- cadet_lock++;
+ spin_lock(&cadet_io_lock);
outb(7,io); /* Select tuner control */
- if(vol>0) {
+ if(vol>0)
outb(0x20,io+1);
- }
- else {
+ else
outb(0x00,io+1);
- }
- cadet_lock--;
-}
+ spin_unlock(&cadet_io_lock);
+}
-void cadet_handler(unsigned long data)
+static void cadet_handler(unsigned long data)
{
/*
* Service the RDS fifo
*/
- if(cadet_lock==0) {
+
+ if(spin_trylock(&cadet_io_lock))
+ {
outb(0x3,io); /* Select RDS Decoder Control */
if((inb(io+1)&0x20)!=0) {
printk(KERN_CRIT "cadet: RDS fifo overflow\n");
}
outb(0x80,io); /* Select RDS fifo */
while((inb(io)&0x80)!=0) {
- rdsbuf[rdsin++]=inb(io+1);
+ rdsbuf[rdsin]=inb(io+1);
if(rdsin==rdsout) {
- printk(KERN_CRIT "cadet: RDS buffer overflow\n");
+ printk(KERN_WARNING "cadet: RDS buffer overflow\n");
}
+ else rdsin++;
}
+ spin_unlock(&cadet_io_lock);
}
/*
* Service pending read
*/
- if( rdsin!=rdsout) {
+ if( rdsin!=rdsout)
wake_up_interruptible(&readq);
- }
/*
* Clean up and exit
@@ -358,10 +338,10 @@
unsigned char readbuf[RDS_BUFFER];
if(rdsstat==0) {
- cadet_lock++;
+ spin_lock(&cadet_io_lock);
rdsstat=1;
outb(0x80,io); /* Select RDS fifo */
- cadet_lock--;
+ spin_unlock(&cadet_io_lock);
init_timer(&readtimer);
readtimer.function=cadet_handler;
readtimer.data=(unsigned long)0;
@@ -369,17 +349,15 @@
add_timer(&readtimer);
}
if(rdsin==rdsout) {
- if(nonblock) {
+ if(nonblock)
return -EWOULDBLOCK;
- }
interruptible_sleep_on(&readq);
}
- while((i<count)&&(rdsin!=rdsout)) {
+ while( i < count && rdsin != rdsout) {
readbuf[i++]=rdsbuf[rdsout++];
}
- if(copy_to_user(buf,readbuf,i)) {
+ if(copy_to_user(buf,readbuf,i))
return -EFAULT;
- }
return i;
}
@@ -393,14 +371,10 @@
case VIDIOCGCAP:
{
struct video_capability v;
+ memset(&v, 0, sizeof(v));
v.type=VID_TYPE_TUNER;
v.channels=2;
v.audios=1;
- /* No we don't do pictures */
- v.maxwidth=0;
- v.maxheight=0;
- v.minwidth=0;
- v.minheight=0;
strcpy(v.name, "ADS Cadet");
if(copy_to_user(arg,&v,sizeof(v)))
return -EFAULT;
@@ -409,54 +383,46 @@
case VIDIOCGTUNER:
{
struct video_tuner v;
- if(copy_from_user(&v, arg,sizeof(v))!=0) {
+ if(copy_from_user(&v, arg,sizeof(v))!=0)
return -EFAULT;
- }
- if((v.tuner<0)||(v.tuner>1)) {
- return -EINVAL;
- }
+
switch(v.tuner) {
- case 0:
+ case 0:
strcpy(v.name,"FM");
v.rangelow=1400; /* 87.5 MHz */
v.rangehigh=1728; /* 108.0 MHz */
v.flags=0;
- v.mode=0;
v.mode|=VIDEO_MODE_AUTO;
- v.signal=sigstrength;
- if(cadet_getstereo()==1) {
+ if(cadet_getstereo()==1)
v.flags|=VIDEO_TUNER_STEREO_ON;
- }
+
v.flags|=cadet_getrds();
- if(copy_to_user(arg,&v, sizeof(v))) {
- return -EFAULT;
- }
break;
- case 1:
+ case 1:
strcpy(v.name,"AM");
v.rangelow=8320; /* 520 kHz */
v.rangehigh=26400; /* 1650 kHz */
- v.flags=0;
- v.flags|=VIDEO_TUNER_LOW;
- v.mode=0;
- v.mode|=VIDEO_MODE_AUTO;
- v.signal=sigstrength;
- if(copy_to_user(arg,&v, sizeof(v))) {
- return -EFAULT;
- }
+ v.flags = VIDEO_TUNER_LOW;
+ v.mode = VIDEO_MODE_AUTO;
break;
+ default:
+ return -EINVAL;
}
+ v.signal=sigstrength;
+ if(copy_to_user(arg,&v, sizeof(v))) {
+ return -EFAULT;
+ }
return 0;
}
case VIDIOCSTUNER:
{
struct video_tuner v;
- if(copy_from_user(&v, arg, sizeof(v))) {
+ if(copy_from_user(&v, arg, sizeof(v)))
return -EFAULT;
- }
- if((v.tuner<0)||(v.tuner>1)) {
+
+ if(v.tuner < 0 || v.tuner > 1)
return -EINVAL;
- }
+
curtuner=v.tuner;
return 0;
}
@@ -468,25 +434,24 @@
case VIDIOCSFREQ:
if(copy_from_user(&freq, arg,sizeof(freq)))
return -EFAULT;
- if((curtuner==0)&&((freq<1400)||(freq>1728))) {
+ if(curtuner==0 && (freq<1400 || freq>1728))
return -EINVAL;
- }
- if((curtuner==1)&&((freq<8320)||(freq>26400))) {
+ if(curtuner==1 && (freq<8320 || freq>26400))
return -EINVAL;
- }
+
cadet_setfreq(freq);
return 0;
+
case VIDIOCGAUDIO:
{
struct video_audio v;
memset(&v,0, sizeof(v));
v.flags=VIDEO_AUDIO_MUTABLE|VIDEO_AUDIO_VOLUME;
- if(cadet_getstereo()==0) {
+ if(cadet_getstereo()==0)
v.mode=VIDEO_SOUND_MONO;
- }
- else {
- v.mode=VIDEO_SOUND_STEREO;
- }
+ else
+ v.mode=VIDEO_SOUND_STEREO;
+
v.volume=cadet_getvol();
v.step=0xffff;
strcpy(v.name, "Radio");
@@ -525,10 +490,8 @@
static void cadet_close(struct video_device *dev)
{
- if(rdsstat==1) {
- del_timer(&readtimer);
- rdsstat=0;
- }
+ del_timer_sync(&readtimer);
+ rdsstat=0;
users--;
}
@@ -557,13 +520,13 @@
if (!(dev->resource[0].flags & IORESOURCE_IO))
return -ENODEV;
if (dev->activate(dev)<0) {
- printk ("radio-cadet: isapnp configure failed (out of resources?)\n");
+ printk(KERN_ERR "radio-cadet: isapnp configure failed (out of resources?)\n");
return -ENOMEM;
}
io = dev->resource[0].start;
- printk ("radio-cadet: ISAPnP reports card at %#x\n", io);
+ printk(KERN_INFO "radio-cadet: ISAPnP reports card at %#x\n", io);
return io;
}
@@ -575,7 +538,7 @@
for(i=0;i<8;i++) {
io=iovals[i];
- if(request_region(io,2, "cadet-probe")>=0) {
+ if(request_region(io,2, "cadet-probe") != NULL) {
cadet_setfreq(1410);
if(cadet_getfreq()==1410) {
release_region(io, 2);
@@ -594,6 +557,9 @@
static int __init cadet_init(void)
{
+
+ spin_lock_init(&cadet_io_lock);
+
/*
* If a probe was requested then probe ISAPnP first (safest)
*/
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)