Commit 768b5218 authored by Gerd Knorr's avatar Gerd Knorr Committed by Linus Torvalds

[PATCH] v4l: typhoon radio update

This is the update for the typhoon radio driver.
parent bc81efb0
...@@ -59,6 +59,7 @@ struct typhoon_device { ...@@ -59,6 +59,7 @@ struct typhoon_device {
int muted; int muted;
unsigned long curfreq; unsigned long curfreq;
unsigned long mutefreq; unsigned long mutefreq;
struct semaphore lock;
}; };
static void typhoon_setvol_generic(struct typhoon_device *dev, int vol); static void typhoon_setvol_generic(struct typhoon_device *dev, int vol);
...@@ -68,19 +69,20 @@ static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency); ...@@ -68,19 +69,20 @@ static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency);
static void typhoon_mute(struct typhoon_device *dev); static void typhoon_mute(struct typhoon_device *dev);
static void typhoon_unmute(struct typhoon_device *dev); static void typhoon_unmute(struct typhoon_device *dev);
static int typhoon_setvol(struct typhoon_device *dev, int vol); static int typhoon_setvol(struct typhoon_device *dev, int vol);
static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg); static int typhoon_ioctl(struct inode *inode, struct file *file,
static int typhoon_open(struct video_device *dev, int flags); unsigned int cmd, void *arg);
static void typhoon_close(struct video_device *dev);
#ifdef CONFIG_RADIO_TYPHOON_PROC_FS #ifdef CONFIG_RADIO_TYPHOON_PROC_FS
static int typhoon_get_info(char *buf, char **start, off_t offset, int len); static int typhoon_get_info(char *buf, char **start, off_t offset, int len);
#endif #endif
static void typhoon_setvol_generic(struct typhoon_device *dev, int vol) static void typhoon_setvol_generic(struct typhoon_device *dev, int vol)
{ {
down(&dev->lock);
vol >>= 14; /* Map 16 bit to 2 bit */ vol >>= 14; /* Map 16 bit to 2 bit */
vol &= 3; vol &= 3;
outb_p(vol / 2, dev->iobase); /* Set the volume, high bit. */ outb_p(vol / 2, dev->iobase); /* Set the volume, high bit. */
outb_p(vol % 2, dev->iobase + 2); /* Set the volume, low bit. */ outb_p(vol % 2, dev->iobase + 2); /* Set the volume, low bit. */
up(&dev->lock);
} }
static int typhoon_setfreq_generic(struct typhoon_device *dev, static int typhoon_setfreq_generic(struct typhoon_device *dev,
...@@ -100,6 +102,7 @@ static int typhoon_setfreq_generic(struct typhoon_device *dev, ...@@ -100,6 +102,7 @@ static int typhoon_setfreq_generic(struct typhoon_device *dev,
* *
*/ */
down(&dev->lock);
x = frequency / 160; x = frequency / 160;
outval = (x * x + 2500) / 5000; outval = (x * x + 2500) / 5000;
outval = (outval * x + 5000) / 10000; outval = (outval * x + 5000) / 10000;
...@@ -109,6 +112,7 @@ static int typhoon_setfreq_generic(struct typhoon_device *dev, ...@@ -109,6 +112,7 @@ static int typhoon_setfreq_generic(struct typhoon_device *dev,
outb_p((outval >> 8) & 0x01, dev->iobase + 4); outb_p((outval >> 8) & 0x01, dev->iobase + 4);
outb_p(outval >> 9, dev->iobase + 6); outb_p(outval >> 9, dev->iobase + 6);
outb_p(outval & 0xff, dev->iobase + 8); outb_p(outval & 0xff, dev->iobase + 8);
up(&dev->lock);
return 0; return 0;
} }
...@@ -159,94 +163,79 @@ static int typhoon_setvol(struct typhoon_device *dev, int vol) ...@@ -159,94 +163,79 @@ static int typhoon_setvol(struct typhoon_device *dev, int vol)
} }
static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg) static int typhoon_ioctl(struct inode *inode, struct file *file,
unsigned int cmd, void *arg)
{ {
struct video_device *dev = video_devdata(file);
struct typhoon_device *typhoon = dev->priv; struct typhoon_device *typhoon = dev->priv;
switch (cmd) { switch (cmd) {
case VIDIOCGCAP: case VIDIOCGCAP:
{ {
struct video_capability v; struct video_capability *v = arg;
v.type = VID_TYPE_TUNER; memset(v,0,sizeof(*v));
v.channels = 1; v->type = VID_TYPE_TUNER;
v.audios = 1; v->channels = 1;
/* No we don't do pictures */ v->audios = 1;
v.maxwidth = 0; strcpy(v->name, "Typhoon Radio");
v.maxheight = 0;
v.minwidth = 0;
v.minheight = 0;
strcpy(v.name, "Typhoon Radio");
if (copy_to_user(arg, &v, sizeof(v)))
return -EFAULT;
return 0; return 0;
} }
case VIDIOCGTUNER: case VIDIOCGTUNER:
{ {
struct video_tuner v; struct video_tuner *v = arg;
if (copy_from_user(&v, arg, sizeof(v)) != 0) if (v->tuner) /* Only 1 tuner */
return -EFAULT;
if (v.tuner) /* Only 1 tuner */
return -EINVAL; return -EINVAL;
v.rangelow = 875 * 1600; v->rangelow = 875 * 1600;
v.rangehigh = 1080 * 1600; v->rangehigh = 1080 * 1600;
v.flags = VIDEO_TUNER_LOW; v->flags = VIDEO_TUNER_LOW;
v.mode = VIDEO_MODE_AUTO; v->mode = VIDEO_MODE_AUTO;
v.signal = 0xFFFF; /* We can't get the signal strength */ v->signal = 0xFFFF; /* We can't get the signal strength */
strcpy(v.name, "FM"); strcpy(v->name, "FM");
if (copy_to_user(arg, &v, sizeof(v)))
return -EFAULT;
return 0; return 0;
} }
case VIDIOCSTUNER: case VIDIOCSTUNER:
{ {
struct video_tuner v; struct video_tuner *v = arg;
if (copy_from_user(&v, arg, sizeof(v))) if (v->tuner != 0)
return -EFAULT;
if (v.tuner != 0)
return -EINVAL; return -EINVAL;
/* Only 1 tuner so no setting needed ! */ /* Only 1 tuner so no setting needed ! */
return 0; return 0;
} }
case VIDIOCGFREQ: case VIDIOCGFREQ:
if (copy_to_user(arg, &typhoon->curfreq, {
sizeof(typhoon->curfreq))) unsigned long *freq = arg;
return -EFAULT; *freq = typhoon->curfreq;
return 0; return 0;
}
case VIDIOCSFREQ: case VIDIOCSFREQ:
if (copy_from_user(&typhoon->curfreq, arg, {
sizeof(typhoon->curfreq))) unsigned long *freq = arg;
return -EFAULT; typhoon->curfreq = *freq;
typhoon_setfreq(typhoon, typhoon->curfreq); typhoon_setfreq(typhoon, typhoon->curfreq);
return 0; return 0;
}
case VIDIOCGAUDIO: case VIDIOCGAUDIO:
{ {
struct video_audio v; struct video_audio *v = arg;
memset(&v, 0, sizeof(v)); memset(v, 0, sizeof(*v));
v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME; v->flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME;
v.mode |= VIDEO_SOUND_MONO; v->mode |= VIDEO_SOUND_MONO;
v.volume = typhoon->curvol; v->volume = typhoon->curvol;
v.step = 1 << 14; v->step = 1 << 14;
strcpy(v.name, "Typhoon Radio"); strcpy(v->name, "Typhoon Radio");
if (copy_to_user(arg, &v, sizeof(v)))
return -EFAULT;
return 0; return 0;
} }
case VIDIOCSAUDIO: case VIDIOCSAUDIO:
{ {
struct video_audio v; struct video_audio *v = arg;
if (copy_from_user(&v, arg, sizeof(v))) if (v->audio)
return -EFAULT;
if (v.audio)
return -EINVAL; return -EINVAL;
if (v->flags & VIDEO_AUDIO_MUTE)
if (v.flags & VIDEO_AUDIO_MUTE)
typhoon_mute(typhoon); typhoon_mute(typhoon);
else else
typhoon_unmute(typhoon); typhoon_unmute(typhoon);
if (v->flags & VIDEO_AUDIO_VOLUME)
if (v.flags & VIDEO_AUDIO_VOLUME) typhoon_setvol(typhoon, v->volume);
typhoon_setvol(typhoon, v.volume);
return 0; return 0;
} }
default: default:
...@@ -254,21 +243,6 @@ static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg) ...@@ -254,21 +243,6 @@ static int typhoon_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
} }
} }
static int typhoon_open(struct video_device *dev, int flags)
{
struct typhoon_device *typhoon = dev->priv;
if (typhoon->users)
return -EBUSY;
typhoon->users++;
return 0;
}
static void typhoon_close(struct video_device *dev)
{
struct typhoon_device *typhoon = dev->priv;
typhoon->users--;
}
static struct typhoon_device typhoon_unit = static struct typhoon_device typhoon_unit =
{ {
iobase: CONFIG_RADIO_TYPHOON_PORT, iobase: CONFIG_RADIO_TYPHOON_PORT,
...@@ -276,15 +250,22 @@ static struct typhoon_device typhoon_unit = ...@@ -276,15 +250,22 @@ static struct typhoon_device typhoon_unit =
mutefreq: CONFIG_RADIO_TYPHOON_MUTEFREQ, mutefreq: CONFIG_RADIO_TYPHOON_MUTEFREQ,
}; };
static struct file_operations typhoon_fops = {
owner: THIS_MODULE,
open: video_exclusive_open,
release: video_exclusive_release,
ioctl: video_generic_ioctl,
llseek: no_llseek,
};
static struct video_device typhoon_radio = static struct video_device typhoon_radio =
{ {
owner: THIS_MODULE, owner: THIS_MODULE,
name: "Typhoon Radio", name: "Typhoon Radio",
type: VID_TYPE_TUNER, type: VID_TYPE_TUNER,
hardware: VID_HARDWARE_TYPHOON, hardware: VID_HARDWARE_TYPHOON,
open: typhoon_open, fops: &typhoon_fops,
close: typhoon_close, kernel_ioctl: typhoon_ioctl,
ioctl: typhoon_ioctl,
}; };
#ifdef CONFIG_RADIO_TYPHOON_PROC_FS #ifdef CONFIG_RADIO_TYPHOON_PROC_FS
...@@ -342,6 +323,7 @@ static int __init typhoon_init(void) ...@@ -342,6 +323,7 @@ static int __init typhoon_init(void)
return -EINVAL; return -EINVAL;
} }
typhoon_unit.iobase = io; typhoon_unit.iobase = io;
init_MUTEX(&typhoon_unit.lock);
if (mutefreq < 87000 || mutefreq > 108500) { if (mutefreq < 87000 || mutefreq > 108500) {
printk(KERN_ERR "radio-typhoon: You must set a frequency (in kHz) used when muting the card,\n"); printk(KERN_ERR "radio-typhoon: You must set a frequency (in kHz) used when muting the card,\n");
......
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