diff options
Diffstat (limited to 'drivers/media/radio')
-rw-r--r-- | drivers/media/radio/dsbr100.c | 98 | ||||
-rw-r--r-- | drivers/media/radio/radio-aimslab.c | 345 | ||||
-rw-r--r-- | drivers/media/radio/radio-aztech.c | 380 | ||||
-rw-r--r-- | drivers/media/radio/radio-cadet.c | 595 | ||||
-rw-r--r-- | drivers/media/radio/radio-gemtek-pci.c | 331 | ||||
-rw-r--r-- | drivers/media/radio/radio-gemtek.c | 397 | ||||
-rw-r--r-- | drivers/media/radio/radio-maestro.c | 329 | ||||
-rw-r--r-- | drivers/media/radio/radio-maxiradio.c | 362 | ||||
-rw-r--r-- | drivers/media/radio/radio-mr800.c | 302 | ||||
-rw-r--r-- | drivers/media/radio/radio-rtrack2.c | 274 | ||||
-rw-r--r-- | drivers/media/radio/radio-sf16fmi.c | 281 | ||||
-rw-r--r-- | drivers/media/radio/radio-sf16fmr2.c | 369 | ||||
-rw-r--r-- | drivers/media/radio/radio-si470x.c | 207 | ||||
-rw-r--r-- | drivers/media/radio/radio-terratec.c | 308 | ||||
-rw-r--r-- | drivers/media/radio/radio-trust.c | 341 | ||||
-rw-r--r-- | drivers/media/radio/radio-typhoon.c | 343 | ||||
-rw-r--r-- | drivers/media/radio/radio-zoltrix.c | 376 |
17 files changed, 2673 insertions, 2965 deletions
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c index 2014ebc4e984..613576202294 100644 --- a/drivers/media/radio/dsbr100.c +++ b/drivers/media/radio/dsbr100.c @@ -33,6 +33,9 @@ History: + Version 0.45: + Converted to v4l2_device. + Version 0.44: Add suspend/resume functions, fix unplug of device, a lot of cleanups and fixes by Alexey Klimov <klimov.linux@gmail.com> @@ -88,7 +91,7 @@ #include <linux/slab.h> #include <linux/input.h> #include <linux/videodev2.h> -#include <media/v4l2-common.h> +#include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <linux/usb.h> @@ -97,39 +100,8 @@ */ #include <linux/version.h> /* for KERNEL_VERSION MACRO */ -#define DRIVER_VERSION "v0.44" -#define RADIO_VERSION KERNEL_VERSION(0, 4, 4) - -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, -/* HINT: the disabled controls are only here to satify kradio and such apps */ - { .id = V4L2_CID_AUDIO_VOLUME, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_BALANCE, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_BASS, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_TREBLE, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_LOUDNESS, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, -}; +#define DRIVER_VERSION "v0.45" +#define RADIO_VERSION KERNEL_VERSION(0, 4, 5) #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>" #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver" @@ -167,6 +139,8 @@ module_param(radio_nr, int, 0); struct dsbr100_device { struct usb_device *usbdev; struct video_device videodev; + struct v4l2_device v4l2_dev; + u8 *transfer_buffer; struct mutex lock; /* buffer locking */ int curfreq; @@ -384,15 +358,18 @@ static void usb_dsbr100_disconnect(struct usb_interface *intf) mutex_unlock(&radio->lock); video_unregister_device(&radio->videodev); + v4l2_device_disconnect(&radio->v4l2_dev); } static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) { + struct dsbr100_device *radio = video_drvdata(file); + strlcpy(v->driver, "dsbr100", sizeof(v->driver)); strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card)); - sprintf(v->bus_info, "USB"); + usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); v->version = RADIO_VERSION; v->capabilities = V4L2_CAP_TUNER; return 0; @@ -450,7 +427,10 @@ static int vidioc_s_frequency(struct file *file, void *priv, if (radio->removed) return -EIO; + mutex_lock(&radio->lock); radio->curfreq = f->frequency; + mutex_unlock(&radio->lock); + retval = dsbr100_setfreq(radio, radio->curfreq); if (retval < 0) dev_warn(&radio->usbdev->dev, "Set frequency failed\n"); @@ -474,14 +454,11 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc) { - int i; - - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); - return 0; - } + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); } + return -EINVAL; } @@ -601,7 +578,10 @@ static int usb_dsbr100_close(struct file *file) if (!radio) return -ENODEV; + mutex_lock(&radio->lock); radio->users = 0; + mutex_unlock(&radio->lock); + if (!radio->removed) { retval = dsbr100_stop(radio); if (retval < 0) { @@ -648,6 +628,7 @@ static void usb_dsbr100_video_device_release(struct video_device *videodev) { struct dsbr100_device *radio = videodev_to_radio(videodev); + v4l2_device_unregister(&radio->v4l2_dev); kfree(radio->transfer_buffer); kfree(radio); } @@ -675,22 +656,15 @@ static const struct v4l2_ioctl_ops usb_dsbr100_ioctl_ops = { .vidioc_s_input = vidioc_s_input, }; -/* V4L2 interface */ -static struct video_device dsbr100_videodev_data = { - .name = "D-Link DSB-R 100", - .fops = &usb_dsbr100_fops, - .ioctl_ops = &usb_dsbr100_ioctl_ops, - .release = usb_dsbr100_video_device_release, -}; - /* check if the device is present and register with v4l and usb if it is */ static int usb_dsbr100_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct dsbr100_device *radio; + struct v4l2_device *v4l2_dev; int retval; - radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL); + radio = kzalloc(sizeof(struct dsbr100_device), GFP_KERNEL); if (!radio) return -ENOMEM; @@ -702,17 +676,35 @@ static int usb_dsbr100_probe(struct usb_interface *intf, return -ENOMEM; } + v4l2_dev = &radio->v4l2_dev; + + retval = v4l2_device_register(&intf->dev, v4l2_dev); + if (retval < 0) { + v4l2_err(v4l2_dev, "couldn't register v4l2_device\n"); + kfree(radio->transfer_buffer); + kfree(radio); + return retval; + } + + strlcpy(radio->videodev.name, v4l2_dev->name, sizeof(radio->videodev.name)); + radio->videodev.v4l2_dev = v4l2_dev; + radio->videodev.fops = &usb_dsbr100_fops; + radio->videodev.ioctl_ops = &usb_dsbr100_ioctl_ops; + radio->videodev.release = usb_dsbr100_video_device_release; + mutex_init(&radio->lock); - radio->videodev = dsbr100_videodev_data; radio->removed = 0; radio->users = 0; radio->usbdev = interface_to_usbdev(intf); radio->curfreq = FREQ_MIN * FREQ_MUL; + video_set_drvdata(&radio->videodev, radio); + retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr); if (retval < 0) { - dev_err(&intf->dev, "couldn't register video device\n"); + v4l2_err(v4l2_dev, "couldn't register video device\n"); + v4l2_device_unregister(v4l2_dev); kfree(radio->transfer_buffer); kfree(radio); return -EIO; diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c index bfa13b8b3043..35edee009ba8 100644 --- a/drivers/media/radio/radio-aimslab.c +++ b/drivers/media/radio/radio-aimslab.c @@ -32,14 +32,15 @@ #include <linux/init.h> /* Initdata */ #include <linux/ioport.h> /* request_region */ #include <linux/delay.h> /* udelay */ -#include <asm/io.h> /* outb, outb_p */ -#include <asm/uaccess.h> /* copy to/from user */ #include <linux/videodev2.h> /* kernel radio structs */ -#include <media/v4l2-common.h> +#include <linux/version.h> /* for KERNEL_VERSION MACRO */ +#include <linux/io.h> /* outb, outb_p */ +#include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> -#include <linux/version.h> /* for KERNEL_VERSION MACRO */ -#define RADIO_VERSION KERNEL_VERSION(0,0,2) +MODULE_AUTHOR("M.Kirkwood"); +MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card."); +MODULE_LICENSE("GPL"); #ifndef CONFIG_RADIO_RTRACK_PORT #define CONFIG_RADIO_RTRACK_PORT -1 @@ -47,86 +48,95 @@ static int io = CONFIG_RADIO_RTRACK_PORT; static int radio_nr = -1; -static struct mutex lock; -struct rt_device +module_param(io, int, 0); +MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)"); +module_param(radio_nr, int, 0); + +#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) + +struct rtrack { - unsigned long in_use; + struct v4l2_device v4l2_dev; + struct video_device vdev; int port; int curvol; unsigned long curfreq; int muted; + int io; + struct mutex lock; }; +static struct rtrack rtrack_card; /* local things */ static void sleep_delay(long n) { /* Sleep nicely for 'n' uS */ - int d=n/msecs_to_jiffies(1000); - if(!d) + int d = n / msecs_to_jiffies(1000); + if (!d) udelay(n); else msleep(jiffies_to_msecs(d)); } -static void rt_decvol(void) +static void rt_decvol(struct rtrack *rt) { - outb(0x58, io); /* volume down + sigstr + on */ + outb(0x58, rt->io); /* volume down + sigstr + on */ sleep_delay(100000); - outb(0xd8, io); /* volume steady + sigstr + on */ + outb(0xd8, rt->io); /* volume steady + sigstr + on */ } -static void rt_incvol(void) +static void rt_incvol(struct rtrack *rt) { - outb(0x98, io); /* volume up + sigstr + on */ + outb(0x98, rt->io); /* volume up + sigstr + on */ sleep_delay(100000); - outb(0xd8, io); /* volume steady + sigstr + on */ + outb(0xd8, rt->io); /* volume steady + sigstr + on */ } -static void rt_mute(struct rt_device *dev) +static void rt_mute(struct rtrack *rt) { - dev->muted = 1; - mutex_lock(&lock); - outb(0xd0, io); /* volume steady, off */ - mutex_unlock(&lock); + rt->muted = 1; + mutex_lock(&rt->lock); + outb(0xd0, rt->io); /* volume steady, off */ + mutex_unlock(&rt->lock); } -static int rt_setvol(struct rt_device *dev, int vol) +static int rt_setvol(struct rtrack *rt, int vol) { int i; - mutex_lock(&lock); + mutex_lock(&rt->lock); - if(vol == dev->curvol) { /* requested volume = current */ - if (dev->muted) { /* user is unmuting the card */ - dev->muted = 0; - outb (0xd8, io); /* enable card */ + if (vol == rt->curvol) { /* requested volume = current */ + if (rt->muted) { /* user is unmuting the card */ + rt->muted = 0; + outb(0xd8, rt->io); /* enable card */ } - mutex_unlock(&lock); + mutex_unlock(&rt->lock); return 0; } - if(vol == 0) { /* volume = 0 means mute the card */ - outb(0x48, io); /* volume down but still "on" */ + if (vol == 0) { /* volume = 0 means mute the card */ + outb(0x48, rt->io); /* volume down but still "on" */ sleep_delay(2000000); /* make sure it's totally down */ - outb(0xd0, io); /* volume steady, off */ - dev->curvol = 0; /* track the volume state! */ - mutex_unlock(&lock); + outb(0xd0, rt->io); /* volume steady, off */ + rt->curvol = 0; /* track the volume state! */ + mutex_unlock(&rt->lock); return 0; } - dev->muted = 0; - if(vol > dev->curvol) - for(i = dev->curvol; i < vol; i++) - rt_incvol(); + rt->muted = 0; + if (vol > rt->curvol) + for (i = rt->curvol; i < vol; i++) + rt_incvol(rt); else - for(i = dev->curvol; i > vol; i--) - rt_decvol(); + for (i = rt->curvol; i > vol; i--) + rt_decvol(rt); - dev->curvol = vol; - mutex_unlock(&lock); + rt->curvol = vol; + mutex_unlock(&rt->lock); return 0; } @@ -135,155 +145,137 @@ static int rt_setvol(struct rt_device *dev, int vol) * and bit 4 (+16) is to keep the signal strength meter enabled */ -static void send_0_byte(int port, struct rt_device *dev) +static void send_0_byte(struct rtrack *rt) { - if ((dev->curvol == 0) || (dev->muted)) { - outb_p(128+64+16+ 1, port); /* wr-enable + data low */ - outb_p(128+64+16+2+1, port); /* clock */ + if (rt->curvol == 0 || rt->muted) { + outb_p(128+64+16+ 1, rt->io); /* wr-enable + data low */ + outb_p(128+64+16+2+1, rt->io); /* clock */ } else { - outb_p(128+64+16+8+ 1, port); /* on + wr-enable + data low */ - outb_p(128+64+16+8+2+1, port); /* clock */ + outb_p(128+64+16+8+ 1, rt->io); /* on + wr-enable + data low */ + outb_p(128+64+16+8+2+1, rt->io); /* clock */ } sleep_delay(1000); } -static void send_1_byte(int port, struct rt_device *dev) +static void send_1_byte(struct rtrack *rt) { - if ((dev->curvol == 0) || (dev->muted)) { - outb_p(128+64+16+4 +1, port); /* wr-enable+data high */ - outb_p(128+64+16+4+2+1, port); /* clock */ + if (rt->curvol == 0 || rt->muted) { + outb_p(128+64+16+4 +1, rt->io); /* wr-enable+data high */ + outb_p(128+64+16+4+2+1, rt->io); /* clock */ } else { - outb_p(128+64+16+8+4 +1, port); /* on+wr-enable+data high */ - outb_p(128+64+16+8+4+2+1, port); /* clock */ + outb_p(128+64+16+8+4 +1, rt->io); /* on+wr-enable+data high */ + outb_p(128+64+16+8+4+2+1, rt->io); /* clock */ } sleep_delay(1000); } -static int rt_setfreq(struct rt_device *dev, unsigned long freq) +static int rt_setfreq(struct rtrack *rt, unsigned long freq) { int i; - /* adapted from radio-aztech.c */ + mutex_lock(&rt->lock); /* Stop other ops interfering */ + + rt->curfreq = freq; /* now uses VIDEO_TUNER_LOW for fine tuning */ freq += 171200; /* Add 10.7 MHz IF */ freq /= 800; /* Convert to 50 kHz units */ - mutex_lock(&lock); /* Stop other ops interfering */ - - send_0_byte (io, dev); /* 0: LSB of frequency */ + send_0_byte(rt); /* 0: LSB of frequency */ for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ if (freq & (1 << i)) - send_1_byte (io, dev); + send_1_byte(rt); else - send_0_byte (io, dev); + send_0_byte(rt); - send_0_byte (io, dev); /* 14: test bit - always 0 */ - send_0_byte (io, dev); /* 15: test bit - always 0 */ + send_0_byte(rt); /* 14: test bit - always 0 */ + send_0_byte(rt); /* 15: test bit - always 0 */ - send_0_byte (io, dev); /* 16: band data 0 - always 0 */ - send_0_byte (io, dev); /* 17: band data 1 - always 0 */ - send_0_byte (io, dev); /* 18: band data 2 - always 0 */ - send_0_byte (io, dev); /* 19: time base - always 0 */ + send_0_byte(rt); /* 16: band data 0 - always 0 */ + send_0_byte(rt); /* 17: band data 1 - always 0 */ + send_0_byte(rt); /* 18: band data 2 - always 0 */ + send_0_byte(rt); /* 19: time base - always 0 */ - send_0_byte (io, dev); /* 20: spacing (0 = 25 kHz) */ - send_1_byte (io, dev); /* 21: spacing (1 = 25 kHz) */ - send_0_byte (io, dev); /* 22: spacing (0 = 25 kHz) */ - send_1_byte (io, dev); /* 23: AM/FM (FM = 1, always) */ + send_0_byte(rt); /* 20: spacing (0 = 25 kHz) */ + send_1_byte(rt); /* 21: spacing (1 = 25 kHz) */ + send_0_byte(rt); /* 22: spacing (0 = 25 kHz) */ + send_1_byte(rt); /* 23: AM/FM (FM = 1, always) */ - if ((dev->curvol == 0) || (dev->muted)) - outb (0xd0, io); /* volume steady + sigstr */ + if (rt->curvol == 0 || rt->muted) + outb(0xd0, rt->io); /* volume steady + sigstr */ else - outb (0xd8, io); /* volume steady + sigstr + on */ + outb(0xd8, rt->io); /* volume steady + sigstr + on */ - mutex_unlock(&lock); + mutex_unlock(&rt->lock); return 0; } -static int rt_getsigstr(struct rt_device *dev) +static int rt_getsigstr(struct rtrack *rt) { - if (inb(io) & 2) /* bit set = no signal present */ - return 0; - return 1; /* signal present */ -} + int sig = 1; -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0xff, - .type = V4L2_CTRL_TYPE_INTEGER, - } -}; + mutex_lock(&rt->lock); + if (inb(rt->io) & 2) /* bit set = no signal present */ + sig = 0; + mutex_unlock(&rt->lock); + return sig; +} static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) { strlcpy(v->driver, "radio-aimslab", sizeof(v->driver)); strlcpy(v->card, "RadioTrack", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct rt_device *rt = video_drvdata(file); + struct rtrack *rt = video_drvdata(file); if (v->index > 0) return -EINVAL; - strcpy(v->name, "FM"); + strlcpy(v->name, "FM", sizeof(v->name)); v->type = V4L2_TUNER_RADIO; - v->rangelow = (87*16000); - v->rangehigh = (108*16000); + v->rangelow = 87 * 16000; + v->rangehigh = 108 * 16000; v->rxsubchans = V4L2_TUNER_SUB_MONO; v->capability = V4L2_TUNER_CAP_LOW; v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xffff*rt_getsigstr(rt); + v->signal = 0xffff * rt_getsigstr(rt); return 0; } static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - if (v->index > 0) - return -EINVAL; - return 0; + return v->index ? -EINVAL : 0; } static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct rt_device *rt = video_drvdata(file); + struct rtrack *rt = video_drvdata(file); - rt->curfreq = f->frequency; - rt_setfreq(rt, rt->curfreq); + rt_setfreq(rt, f->frequency); return 0; } static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct rt_device *rt = video_drvdata(file); + struct rtrack *rt = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = rt->curfreq; @@ -293,14 +285,11 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc) { - int i; - - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); - return 0; - } + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff); } return -EINVAL; } @@ -308,14 +297,14 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct rt_device *rt = video_drvdata(file); + struct rtrack *rt = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: ctrl->value = rt->muted; return 0; case V4L2_CID_AUDIO_VOLUME: - ctrl->value = rt->curvol * 6554; + ctrl->value = rt->curvol; return 0; } return -EINVAL; @@ -324,33 +313,22 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct rt_device *rt = video_drvdata(file); + struct rtrack *rt = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: if (ctrl->value) rt_mute(rt); else - rt_setvol(rt,rt->curvol); + rt_setvol(rt, rt->curvol); return 0; case V4L2_CID_AUDIO_VOLUME: - rt_setvol(rt,ctrl->value); + rt_setvol(rt, ctrl->value); return 0; } return -EINVAL; } -static int vidioc_g_audio (struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) { *i = 0; @@ -359,36 +337,26 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) { - if (i != 0) - return -EINVAL; - return 0; + return i ? -EINVAL : 0; } -static int vidioc_s_audio(struct file *file, void *priv, +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) { - if (a->index != 0) - return -EINVAL; + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; return 0; } -static struct rt_device rtrack_unit; - -static int rtrack_exclusive_open(struct file *file) -{ - return test_and_set_bit(0, &rtrack_unit.in_use) ? -EBUSY : 0; -} - -static int rtrack_exclusive_release(struct file *file) +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) { - clear_bit(0, &rtrack_unit.in_use); - return 0; + return a->index ? -EINVAL : 0; } static const struct v4l2_file_operations rtrack_fops = { .owner = THIS_MODULE, - .open = rtrack_exclusive_open, - .release = rtrack_exclusive_release, .ioctl = video_ioctl2, }; @@ -407,64 +375,69 @@ static const struct v4l2_ioctl_ops rtrack_ioctl_ops = { .vidioc_s_ctrl = vidioc_s_ctrl, }; -static struct video_device rtrack_radio = { - .name = "RadioTrack radio", - .fops = &rtrack_fops, - .ioctl_ops = &rtrack_ioctl_ops, - .release = video_device_release_empty, -}; - static int __init rtrack_init(void) { - if(io==-1) - { - printk(KERN_ERR "You must set an I/O address with io=0x???\n"); + struct rtrack *rt = &rtrack_card; + struct v4l2_device *v4l2_dev = &rt->v4l2_dev; + int res; + + strlcpy(v4l2_dev->name, "rtrack", sizeof(v4l2_dev->name)); + rt->io = io; + + if (rt->io == -1) { + v4l2_err(v4l2_dev, "you must set an I/O address with io=0x20f or 0x30f\n"); return -EINVAL; } - if (!request_region(io, 2, "rtrack")) - { - printk(KERN_ERR "rtrack: port 0x%x already in use\n", io); + if (!request_region(rt->io, 2, "rtrack")) { + v4l2_err(v4l2_dev, "port 0x%x already in use\n", rt->io); return -EBUSY; } - video_set_drvdata(&rtrack_radio, &rtrack_unit); + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + release_region(rt->io, 2); + v4l2_err(v4l2_dev, "could not register v4l2_device\n"); + return res; + } + + strlcpy(rt->vdev.name, v4l2_dev->name, sizeof(rt->vdev.name)); + rt->vdev.v4l2_dev = v4l2_dev; + rt->vdev.fops = &rtrack_fops; + rt->vdev.ioctl_ops = &rtrack_ioctl_ops; + rt->vdev.release = video_device_release_empty; + video_set_drvdata(&rt->vdev, rt); - if (video_register_device(&rtrack_radio, VFL_TYPE_RADIO, radio_nr) < 0) { - release_region(io, 2); + if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(&rt->v4l2_dev); + release_region(rt->io, 2); return -EINVAL; } - printk(KERN_INFO "AIMSlab RadioTrack/RadioReveal card driver.\n"); + v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n"); /* Set up the I/O locking */ - mutex_init(&lock); + mutex_init(&rt->lock); /* mute card - prevents noisy bootups */ /* this ensures that the volume is all the way down */ - outb(0x48, io); /* volume down but still "on" */ + outb(0x48, rt->io); /* volume down but still "on" */ sleep_delay(2000000); /* make sure it's totally down */ - outb(0xc0, io); /* steady volume, mute card */ - rtrack_unit.curvol = 0; + outb(0xc0, rt->io); /* steady volume, mute card */ return 0; } -MODULE_AUTHOR("M.Kirkwood"); -MODULE_DESCRIPTION("A driver for the RadioTrack/RadioReveal radio card."); -MODULE_LICENSE("GPL"); - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20f or 0x30f)"); -module_param(radio_nr, int, 0); - -static void __exit cleanup_rtrack_module(void) +static void __exit rtrack_exit(void) { - video_unregister_device(&rtrack_radio); - release_region(io,2); + struct rtrack *rt = &rtrack_card; + + video_unregister_device(&rt->vdev); + v4l2_device_unregister(&rt->v4l2_dev); + release_region(rt->io, 2); } module_init(rtrack_init); -module_exit(cleanup_rtrack_module); +module_exit(rtrack_exit); diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c index 5604e881e96c..8daf809eb01a 100644 --- a/drivers/media/radio/radio-aztech.c +++ b/drivers/media/radio/radio-aztech.c @@ -29,33 +29,15 @@ #include <linux/init.h> /* Initdata */ #include <linux/ioport.h> /* request_region */ #include <linux/delay.h> /* udelay */ -#include <asm/io.h> /* outb, outb_p */ -#include <asm/uaccess.h> /* copy to/from user */ #include <linux/videodev2.h> /* kernel radio structs */ -#include <media/v4l2-common.h> +#include <linux/version.h> /* for KERNEL_VERSION MACRO */ +#include <linux/io.h> /* outb, outb_p */ +#include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> -#include <linux/version.h> /* for KERNEL_VERSION MACRO */ -#define RADIO_VERSION KERNEL_VERSION(0,0,2) - -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0xff, - .type = V4L2_CTRL_TYPE_INTEGER, - } -}; +MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); +MODULE_DESCRIPTION("A driver for the Aztech radio card."); +MODULE_LICENSE("GPL"); /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ @@ -66,55 +48,64 @@ static struct v4l2_queryctrl radio_qctrl[] = { static int io = CONFIG_RADIO_AZTECH_PORT; static int radio_nr = -1; static int radio_wait_time = 1000; -static struct mutex lock; -struct az_device +module_param(io, int, 0); +module_param(radio_nr, int, 0); +MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)"); + +#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) + +struct aztech { - unsigned long in_use; + struct v4l2_device v4l2_dev; + struct video_device vdev; + int io; int curvol; unsigned long curfreq; int stereo; + struct mutex lock; }; +static struct aztech aztech_card; + static int volconvert(int level) { - level>>=14; /* Map 16bits down to 2 bit */ - level&=3; + level >>= 14; /* Map 16bits down to 2 bit */ + level &= 3; /* convert to card-friendly values */ - switch (level) - { - case 0: - return 0; - case 1: - return 1; - case 2: - return 4; - case 3: - return 5; + switch (level) { + case 0: + return 0; + case 1: + return 1; + case 2: + return 4; + case 3: + return 5; } return 0; /* Quieten gcc */ } -static void send_0_byte (struct az_device *dev) +static void send_0_byte(struct aztech *az) { udelay(radio_wait_time); - outb_p(2+volconvert(dev->curvol), io); - outb_p(64+2+volconvert(dev->curvol), io); + outb_p(2 + volconvert(az->curvol), az->io); + outb_p(64 + 2 + volconvert(az->curvol), az->io); } -static void send_1_byte (struct az_device *dev) +static void send_1_byte(struct aztech *az) { udelay (radio_wait_time); - outb_p(128+2+volconvert(dev->curvol), io); - outb_p(128+64+2+volconvert(dev->curvol), io); + outb_p(128 + 2 + volconvert(az->curvol), az->io); + outb_p(128 + 64 + 2 + volconvert(az->curvol), az->io); } -static int az_setvol(struct az_device *dev, int vol) +static int az_setvol(struct aztech *az, int vol) { - mutex_lock(&lock); - outb (volconvert(vol), io); - mutex_unlock(&lock); + mutex_lock(&az->lock); + outb(volconvert(vol), az->io); + mutex_unlock(&az->lock); return 0; } @@ -126,116 +117,110 @@ static int az_setvol(struct az_device *dev, int vol) * */ -static int az_getsigstr(struct az_device *dev) +static int az_getsigstr(struct aztech *az) { - if (inb(io) & 2) /* bit set = no signal present */ - return 0; - return 1; /* signal present */ + int sig = 1; + + mutex_lock(&az->lock); + if (inb(az->io) & 2) /* bit set = no signal present */ + sig = 0; + mutex_unlock(&az->lock); + return sig; } -static int az_getstereo(struct az_device *dev) +static int az_getstereo(struct aztech *az) { - if (inb(io) & 1) /* bit set = mono */ - return 0; - return 1; /* stereo */ + int stereo = 1; + + mutex_lock(&az->lock); + if (inb(az->io) & 1) /* bit set = mono */ + stereo = 0; + mutex_unlock(&az->lock); + return stereo; } -static int az_setfreq(struct az_device *dev, unsigned long frequency) +static int az_setfreq(struct aztech *az, unsigned long frequency) { int i; + mutex_lock(&az->lock); + + az->curfreq = frequency; frequency += 171200; /* Add 10.7 MHz IF */ frequency /= 800; /* Convert to 50 kHz units */ - mutex_lock(&lock); - - send_0_byte (dev); /* 0: LSB of frequency */ + send_0_byte(az); /* 0: LSB of frequency */ for (i = 0; i < 13; i++) /* : frequency bits (1-13) */ if (frequency & (1 << i)) - send_1_byte (dev); + send_1_byte(az); else - send_0_byte (dev); + send_0_byte(az); - send_0_byte (dev); /* 14: test bit - always 0 */ - send_0_byte (dev); /* 15: test bit - always 0 */ - send_0_byte (dev); /* 16: band data 0 - always 0 */ - if (dev->stereo) /* 17: stereo (1 to enable) */ - send_1_byte (dev); + send_0_byte(az); /* 14: test bit - always 0 */ + send_0_byte(az); /* 15: test bit - always 0 */ + send_0_byte(az); /* 16: band data 0 - always 0 */ + if (az->stereo) /* 17: stereo (1 to enable) */ + send_1_byte(az); else - send_0_byte (dev); + send_0_byte(az); - send_1_byte (dev); /* 18: band data 1 - unknown */ - send_0_byte (dev); /* 19: time base - always 0 */ - send_0_byte (dev); /* 20: spacing (0 = 25 kHz) */ - send_1_byte (dev); /* 21: spacing (1 = 25 kHz) */ - send_0_byte (dev); /* 22: spacing (0 = 25 kHz) */ - send_1_byte (dev); /* 23: AM/FM (FM = 1, always) */ + send_1_byte(az); /* 18: band data 1 - unknown */ + send_0_byte(az); /* 19: time base - always 0 */ + send_0_byte(az); /* 20: spacing (0 = 25 kHz) */ + send_1_byte(az); /* 21: spacing (1 = 25 kHz) */ + send_0_byte(az); /* 22: spacing (0 = 25 kHz) */ + send_1_byte(az); /* 23: AM/FM (FM = 1, always) */ /* latch frequency */ - udelay (radio_wait_time); - outb_p(128+64+volconvert(dev->curvol), io); + udelay(radio_wait_time); + outb_p(128 + 64 + volconvert(az->curvol), az->io); - mutex_unlock(&lock); + mutex_unlock(&az->lock); return 0; } -static int vidioc_querycap (struct file *file, void *priv, +static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) { - strlcpy(v->driver, "radio-aztech", sizeof (v->driver)); - strlcpy(v->card, "Aztech Radio", sizeof (v->card)); - sprintf(v->bus_info,"ISA"); + strlcpy(v->driver, "radio-aztech", sizeof(v->driver)); + strlcpy(v->card, "Aztech Radio", sizeof(v->card)); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } -static int vidioc_g_tuner (struct file *file, void *priv, +static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct az_device *az = video_drvdata(file); + struct aztech *az = video_drvdata(file); if (v->index > 0) return -EINVAL; - strcpy(v->name, "FM"); + strlcpy(v->name, "FM", sizeof(v->name)); v->type = V4L2_TUNER_RADIO; - v->rangelow=(87*16000); - v->rangehigh=(108*16000); - v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; - v->capability=V4L2_TUNER_CAP_LOW; - if(az_getstereo(az)) + v->rangelow = 87 * 16000; + v->rangehigh = 108 * 16000; + v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + v->capability = V4L2_TUNER_CAP_LOW; + if (az_getstereo(az)) v->audmode = V4L2_TUNER_MODE_STEREO; else v->audmode = V4L2_TUNER_MODE_MONO; - v->signal=0xFFFF*az_getsigstr(az); + v->signal = 0xFFFF * az_getsigstr(az); return 0; } - -static int vidioc_s_tuner (struct file *file, void *priv, +static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - if (v->index > 0) - return -EINVAL; - - return 0; -} - -static int vidioc_g_audio (struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; + return v->index ? -EINVAL : 0; } static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) @@ -246,113 +231,95 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) { - if (i != 0) - return -EINVAL; - return 0; + return i ? -EINVAL : 0; } - -static int vidioc_s_audio (struct file *file, void *priv, +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) { - if (a->index != 0) - return -EINVAL; - + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; return 0; } -static int vidioc_s_frequency (struct file *file, void *priv, +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + return a->index ? -EINVAL : 0; +} + +static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct az_device *az = video_drvdata(file); + struct aztech *az = video_drvdata(file); - az->curfreq = f->frequency; - az_setfreq(az, az->curfreq); + az_setfreq(az, f->frequency); return 0; } -static int vidioc_g_frequency (struct file *file, void *priv, +static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct az_device *az = video_drvdata(file); + struct aztech *az = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = az->curfreq; - return 0; } -static int vidioc_queryctrl (struct file *file, void *priv, +static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc) { - int i; - - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); - return (0); - } + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff); } return -EINVAL; } -static int vidioc_g_ctrl (struct file *file, void *priv, +static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct az_device *az = video_drvdata(file); + struct aztech *az = video_drvdata(file); switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (az->curvol==0) - ctrl->value=1; - else - ctrl->value=0; - return (0); - case V4L2_CID_AUDIO_VOLUME: - ctrl->value=az->curvol * 6554; - return (0); + case V4L2_CID_AUDIO_MUTE: + if (az->curvol == 0) + ctrl->value = 1; + else + ctrl->value = 0; + return 0; + case V4L2_CID_AUDIO_VOLUME: + ctrl->value = az->curvol * 6554; + return 0; } return -EINVAL; } -static int vidioc_s_ctrl (struct file *file, void *priv, +static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct az_device *az = video_drvdata(file); + struct aztech *az = video_drvdata(file); switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - if (ctrl->value) { - az_setvol(az,0); - } else { - az_setvol(az,az->curvol); - } - return (0); - case V4L2_CID_AUDIO_VOLUME: - az_setvol(az,ctrl->value); - return (0); + case V4L2_CID_AUDIO_MUTE: + if (ctrl->value) + az_setvol(az, 0); + else + az_setvol(az, az->curvol); + return 0; + case V4L2_CID_AUDIO_VOLUME: + az_setvol(az, ctrl->value); + return 0; } return -EINVAL; } -static struct az_device aztech_unit; - -static int aztech_exclusive_open(struct file *file) -{ - return test_and_set_bit(0, &aztech_unit.in_use) ? -EBUSY : 0; -} - -static int aztech_exclusive_release(struct file *file) -{ - clear_bit(0, &aztech_unit.in_use); - return 0; -} - static const struct v4l2_file_operations aztech_fops = { .owner = THIS_MODULE, - .open = aztech_exclusive_open, - .release = aztech_exclusive_release, .ioctl = video_ioctl2, }; @@ -371,57 +338,60 @@ static const struct v4l2_ioctl_ops aztech_ioctl_ops = { .vidioc_s_ctrl = vidioc_s_ctrl, }; -static struct video_device aztech_radio = { - .name = "Aztech radio", - .fops = &aztech_fops, - .ioctl_ops = &aztech_ioctl_ops, - .release = video_device_release_empty, -}; - -module_param_named(debug,aztech_radio.debug, int, 0644); -MODULE_PARM_DESC(debug,"activates debug info"); - static int __init aztech_init(void) { - if(io==-1) - { - printk(KERN_ERR "You must set an I/O address with io=0x???\n"); + struct aztech *az = &aztech_card; + struct v4l2_device *v4l2_dev = &az->v4l2_dev; + int res; + + strlcpy(v4l2_dev->name, "aztech", sizeof(v4l2_dev->name)); + az->io = io; + + if (az->io == -1) { + v4l2_err(v4l2_dev, "you must set an I/O address with io=0x350 or 0x358\n"); return -EINVAL; } - if (!request_region(io, 2, "aztech")) - { - printk(KERN_ERR "aztech: port 0x%x already in use\n", io); + if (!request_region(az->io, 2, "aztech")) { + v4l2_err(v4l2_dev, "port 0x%x already in use\n", az->io); return -EBUSY; } - mutex_init(&lock); - video_set_drvdata(&aztech_radio, &aztech_unit); + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + release_region(az->io, 2); + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return res; + } - if (video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr) < 0) { - release_region(io,2); + mutex_init(&az->lock); + strlcpy(az->vdev.name, v4l2_dev->name, sizeof(az->vdev.name)); + az->vdev.v4l2_dev = v4l2_dev; + az->vdev.fops = &aztech_fops; + az->vdev.ioctl_ops = &aztech_ioctl_ops; + az->vdev.release = video_device_release_empty; + video_set_drvdata(&az->vdev, az); + + if (video_register_device(&az->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(az->io, 2); return -EINVAL; } - printk(KERN_INFO "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n"); + v4l2_info(v4l2_dev, "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n"); /* mute card - prevents noisy bootups */ - outb (0, io); + outb(0, az->io); return 0; } -MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); -MODULE_DESCRIPTION("A driver for the Aztech radio card."); -MODULE_LICENSE("GPL"); - -module_param(io, int, 0); -module_param(radio_nr, int, 0); -MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)"); - -static void __exit aztech_cleanup(void) +static void __exit aztech_exit(void) { - video_unregister_device(&aztech_radio); - release_region(io,2); + struct aztech *az = &aztech_card; + + video_unregister_device(&az->vdev); + v4l2_device_unregister(&az->v4l2_dev); + release_region(az->io, 2); } module_init(aztech_init); -module_exit(aztech_cleanup); +module_exit(aztech_exit); diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c index cb3075ac104c..d30fc0ce82c0 100644 --- a/drivers/media/radio/radio-cadet.c +++ b/drivers/media/radio/radio-cadet.c @@ -35,333 +35,318 @@ #include <linux/init.h> /* Initdata */ #include <linux/ioport.h> /* request_region */ #include <linux/delay.h> /* udelay */ -#include <asm/io.h> /* outb, outb_p */ -#include <asm/uaccess.h> /* copy to/from user */ #include <linux/videodev2.h> /* V4L2 API defs */ -#include <media/v4l2-common.h> -#include <media/v4l2-ioctl.h> #include <linux/param.h> #include <linux/pnp.h> +#include <linux/io.h> /* outb, outb_p */ +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> + +MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); +MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card."); +MODULE_LICENSE("GPL"); + +static int io = -1; /* default to isapnp activation */ +static int radio_nr = -1; + +module_param(io, int, 0); +MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)"); +module_param(radio_nr, int, 0); + +#define CADET_VERSION KERNEL_VERSION(0, 3, 3) #define RDS_BUFFER 256 #define RDS_RX_FLAG 1 #define MBS_RX_FLAG 2 -#define CADET_VERSION KERNEL_VERSION(0,3,3) - -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 0xff, - .step = 1, - .default_value = 0xff, - .type = V4L2_CTRL_TYPE_INTEGER, - } +struct cadet { + struct v4l2_device v4l2_dev; + struct video_device vdev; + int io; + int users; + int curtuner; + int tunestat; + int sigstrength; + wait_queue_head_t read_queue; + struct timer_list readtimer; + __u8 rdsin, rdsout, rdsstat; + unsigned char rdsbuf[RDS_BUFFER]; + struct mutex lock; + int reading; }; -static int io=-1; /* default to isapnp activation */ -static int radio_nr = -1; -static int users; -static int curtuner; -static int tunestat; -static int sigstrength; -static wait_queue_head_t read_queue; -static struct timer_list readtimer; -static __u8 rdsin, rdsout, rdsstat; -static unsigned char rdsbuf[RDS_BUFFER]; -static spinlock_t cadet_io_lock; - -static int cadet_probe(void); +static struct cadet cadet_card; /* * Signal Strength Threshold Values * The V4L API spec does not define any particular unit for the signal * strength value. These values are in microvolts of RF at the tuner's input. */ -static __u16 sigtable[2][4]={{5,10,30,150},{28,40,63,1000}}; +static __u16 sigtable[2][4] = { + { 5, 10, 30, 150 }, + { 28, 40, 63, 1000 } +}; -static int -cadet_getstereo(void) +static int cadet_getstereo(struct cadet *dev) { int ret = V4L2_TUNER_SUB_MONO; - if(curtuner != 0) /* Only FM has stereo capability! */ + + if (dev->curtuner != 0) /* Only FM has stereo capability! */ return V4L2_TUNER_SUB_MONO; - spin_lock(&cadet_io_lock); - outb(7,io); /* Select tuner control */ - if( (inb(io+1) & 0x40) == 0) + mutex_lock(&dev->lock); + outb(7, dev->io); /* Select tuner control */ + if ((inb(dev->io + 1) & 0x40) == 0) ret = V4L2_TUNER_SUB_STEREO; - spin_unlock(&cadet_io_lock); + mutex_unlock(&dev->lock); return ret; } -static unsigned -cadet_gettune(void) +static unsigned cadet_gettune(struct cadet *dev) { - int curvol,i; - unsigned fifo=0; + int curvol, i; + unsigned fifo = 0; /* * Prepare for read */ - spin_lock(&cadet_io_lock); + mutex_lock(&dev->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 */ - tunestat=0xffff; + outb(7, dev->io); /* Select tuner control */ + curvol = inb(dev->io + 1); /* Save current volume/mute setting */ + outb(0x00, dev->io + 1); /* Ensure WRITE-ENABLE is LOW */ + dev->tunestat = 0xffff; /* * Read the shift register */ - for(i=0;i<25;i++) { - fifo=(fifo<<1)|((inb(io+1)>>7)&0x01); - if(i<24) { - outb(0x01,io+1); - tunestat&=inb(io+1); - outb(0x00,io+1); + for (i = 0; i < 25; i++) { + fifo = (fifo << 1) | ((inb(dev->io + 1) >> 7) & 0x01); + if (i < 24) { + outb(0x01, dev->io + 1); + dev->tunestat &= inb(dev->io + 1); + outb(0x00, dev->io + 1); } } /* * Restore volume/mute setting */ - outb(curvol,io+1); - spin_unlock(&cadet_io_lock); + outb(curvol, dev->io + 1); + mutex_unlock(&dev->lock); return fifo; } -static unsigned -cadet_getfreq(void) +static unsigned cadet_getfreq(struct cadet *dev) { int i; - unsigned freq=0,test,fifo=0; + unsigned freq = 0, test, fifo = 0; /* * Read current tuning */ - fifo=cadet_gettune(); + fifo = cadet_gettune(dev); /* * Convert to actual frequency */ - if(curtuner==0) { /* FM */ - test=12500; - for(i=0;i<14;i++) { - if((fifo&0x01)!=0) { - freq+=test; - } - test=test<<1; - fifo=fifo>>1; + if (dev->curtuner == 0) { /* FM */ + test = 12500; + for (i = 0; i < 14; i++) { + if ((fifo & 0x01) != 0) + freq += test; + test = test << 1; + fifo = fifo >> 1; } - freq-=10700000; /* IF frequency is 10.7 MHz */ - freq=(freq*16)/1000000; /* Make it 1/16 MHz */ - } - if(curtuner==1) { /* AM */ - freq=((fifo&0x7fff)-2010)*16; + freq -= 10700000; /* IF frequency is 10.7 MHz */ + freq = (freq * 16) / 1000000; /* Make it 1/16 MHz */ } + if (dev->curtuner == 1) /* AM */ + freq = ((fifo & 0x7fff) - 2010) * 16; return freq; } -static void -cadet_settune(unsigned fifo) +static void cadet_settune(struct cadet *dev, unsigned fifo) { int i; unsigned test; - spin_lock(&cadet_io_lock); + mutex_lock(&dev->lock); - outb(7,io); /* Select tuner control */ + outb(7, dev->io); /* Select tuner control */ /* * Write the shift register */ - test=0; - test=(fifo>>23)&0x02; /* Align data for SDO */ - test|=0x1c; /* SDM=1, SWE=1, SEN=1, SCK=0 */ - outb(7,io); /* Select tuner control */ - outb(test,io+1); /* Initialize for write */ - for(i=0;i<25;i++) { - test|=0x01; /* Toggle SCK High */ - outb(test,io+1); - test&=0xfe; /* Toggle SCK Low */ - outb(test,io+1); - fifo=fifo<<1; /* Prepare the next bit */ - test=0x1c|((fifo>>23)&0x02); - outb(test,io+1); + test = 0; + test = (fifo >> 23) & 0x02; /* Align data for SDO */ + test |= 0x1c; /* SDM=1, SWE=1, SEN=1, SCK=0 */ + outb(7, dev->io); /* Select tuner control */ + outb(test, dev->io + 1); /* Initialize for write */ + for (i = 0; i < 25; i++) { + test |= 0x01; /* Toggle SCK High */ + outb(test, dev->io + 1); + test &= 0xfe; /* Toggle SCK Low */ + outb(test, dev->io + 1); + fifo = fifo << 1; /* Prepare the next bit */ + test = 0x1c | ((fifo >> 23) & 0x02); + outb(test, dev->io + 1); } - spin_unlock(&cadet_io_lock); + mutex_unlock(&dev->lock); } -static void -cadet_setfreq(unsigned freq) +static void cadet_setfreq(struct cadet *dev, unsigned freq) { unsigned fifo; - int i,j,test; + int i, j, test; int curvol; /* * Formulate a fifo command */ - fifo=0; - if(curtuner==0) { /* FM */ - test=102400; - freq=(freq*1000)/16; /* Make it kHz */ - freq+=10700; /* IF is 10700 kHz */ - for(i=0;i<14;i++) { - fifo=fifo<<1; - if(freq>=test) { - fifo|=0x01; - freq-=test; + fifo = 0; + if (dev->curtuner == 0) { /* FM */ + test = 102400; + freq = (freq * 1000) / 16; /* Make it kHz */ + freq += 10700; /* IF is 10700 kHz */ + for (i = 0; i < 14; i++) { + fifo = fifo << 1; + if (freq >= test) { + fifo |= 0x01; + freq -= test; } - test=test>>1; + test = test >> 1; } } - if(curtuner==1) { /* AM */ - fifo=(freq/16)+2010; /* Make it kHz */ - fifo|=0x100000; /* Select AM Band */ + if (dev->curtuner == 1) { /* AM */ + fifo = (freq / 16) + 2010; /* Make it kHz */ + fifo |= 0x100000; /* Select AM Band */ } /* * Save current volume/mute setting */ - spin_lock(&cadet_io_lock); - outb(7,io); /* Select tuner control */ - curvol=inb(io+1); - spin_unlock(&cadet_io_lock); + mutex_lock(&dev->lock); + outb(7, dev->io); /* Select tuner control */ + curvol = inb(dev->io + 1); + mutex_unlock(&dev->lock); /* * Tune the card */ - for(j=3;j>-1;j--) { - cadet_settune(fifo|(j<<16)); + for (j = 3; j > -1; j--) { + cadet_settune(dev, fifo | (j << 16)); - spin_lock(&cadet_io_lock); - outb(7,io); /* Select tuner control */ - outb(curvol,io+1); - spin_unlock(&cadet_io_lock); + mutex_lock(&dev->lock); + outb(7, dev->io); /* Select tuner control */ + outb(curvol, dev->io + 1); + mutex_unlock(&dev->lock); msleep(100); - cadet_gettune(); - if((tunestat & 0x40) == 0) { /* Tuned */ - sigstrength=sigtable[curtuner][j]; + cadet_gettune(dev); + if ((dev->tunestat & 0x40) == 0) { /* Tuned */ + dev->sigstrength = sigtable[dev->curtuner][j]; return; } } - sigstrength=0; + dev->sigstrength = 0; } -static int -cadet_getvol(void) +static int cadet_getvol(struct cadet *dev) { int ret = 0; - spin_lock(&cadet_io_lock); + mutex_lock(&dev->lock); - outb(7,io); /* Select tuner control */ - if((inb(io + 1) & 0x20) != 0) + outb(7, dev->io); /* Select tuner control */ + if ((inb(dev->io + 1) & 0x20) != 0) ret = 0xffff; - spin_unlock(&cadet_io_lock); + mutex_unlock(&dev->lock); return ret; } -static void -cadet_setvol(int vol) +static void cadet_setvol(struct cadet *dev, int vol) { - spin_lock(&cadet_io_lock); - outb(7,io); /* Select tuner control */ - if(vol>0) - outb(0x20,io+1); + mutex_lock(&dev->lock); + outb(7, dev->io); /* Select tuner control */ + if (vol > 0) + outb(0x20, dev->io + 1); else - outb(0x00,io+1); - spin_unlock(&cadet_io_lock); + outb(0x00, dev->io + 1); + mutex_unlock(&dev->lock); } -static void -cadet_handler(unsigned long data) +static void cadet_handler(unsigned long data) { - /* - * Service the RDS fifo - */ + struct cadet *dev = (void *)data; - if(spin_trylock(&cadet_io_lock)) - { - outb(0x3,io); /* Select RDS Decoder Control */ - if((inb(io+1)&0x20)!=0) { + /* Service the RDS fifo */ + if (mutex_trylock(&dev->lock)) { + outb(0x3, dev->io); /* Select RDS Decoder Control */ + if ((inb(dev->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); - if(rdsin==rdsout) + outb(0x80, dev->io); /* Select RDS fifo */ + while ((inb(dev->io) & 0x80) != 0) { + dev->rdsbuf[dev->rdsin] = inb(dev->io + 1); + if (dev->rdsin == dev->rdsout) printk(KERN_WARNING "cadet: RDS buffer overflow\n"); else - rdsin++; + dev->rdsin++; } - spin_unlock(&cadet_io_lock); + mutex_unlock(&dev->lock); } /* * Service pending read */ - if( rdsin!=rdsout) - wake_up_interruptible(&read_queue); + if (dev->rdsin != dev->rdsout) + wake_up_interruptible(&dev->read_queue); /* * Clean up and exit */ - init_timer(&readtimer); - readtimer.function=cadet_handler; - readtimer.data=(unsigned long)0; - readtimer.expires=jiffies+msecs_to_jiffies(50); - add_timer(&readtimer); + init_timer(&dev->readtimer); + dev->readtimer.function = cadet_handler; + dev->readtimer.data = (unsigned long)0; + dev->readtimer.expires = jiffies + msecs_to_jiffies(50); + add_timer(&dev->readtimer); } - -static ssize_t -cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos) +static ssize_t cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos) { - int i=0; + struct cadet *dev = video_drvdata(file); unsigned char readbuf[RDS_BUFFER]; - - if(rdsstat==0) { - spin_lock(&cadet_io_lock); - rdsstat=1; - outb(0x80,io); /* Select RDS fifo */ - spin_unlock(&cadet_io_lock); - init_timer(&readtimer); - readtimer.function=cadet_handler; - readtimer.data=(unsigned long)0; - readtimer.expires=jiffies+msecs_to_jiffies(50); - add_timer(&readtimer); + int i = 0; + + if (dev->rdsstat == 0) { + mutex_lock(&dev->lock); + dev->rdsstat = 1; + outb(0x80, dev->io); /* Select RDS fifo */ + mutex_unlock(&dev->lock); + init_timer(&dev->readtimer); + dev->readtimer.function = cadet_handler; + dev->readtimer.data = (unsigned long)dev; + dev->readtimer.expires = jiffies + msecs_to_jiffies(50); + add_timer(&dev->readtimer); } - if(rdsin==rdsout) { + if (dev->rdsin == dev->rdsout) { if (file->f_flags & O_NONBLOCK) return -EWOULDBLOCK; - interruptible_sleep_on(&read_queue); + interruptible_sleep_on(&dev->read_queue); } - while( i<count && rdsin!=rdsout) - readbuf[i++]=rdsbuf[rdsout++]; + while (i < count && dev->rdsin != dev->rdsout) + readbuf[i++] = dev->rdsbuf[dev->rdsout++]; - if (copy_to_user(data,readbuf,i)) + if (copy_to_user(data, readbuf, i)) return -EFAULT; return i; } @@ -370,38 +355,40 @@ cadet_read(struct file *file, char __user *data, size_t count, loff_t *ppos) static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) { - v->capabilities = - V4L2_CAP_TUNER | - V4L2_CAP_READWRITE; + strlcpy(v->driver, "ADS Cadet", sizeof(v->driver)); + strlcpy(v->card, "ADS Cadet", sizeof(v->card)); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); v->version = CADET_VERSION; - strcpy(v->driver, "ADS Cadet"); - strcpy(v->card, "ADS Cadet"); + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_READWRITE; return 0; } static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { + struct cadet *dev = video_drvdata(file); + v->type = V4L2_TUNER_RADIO; switch (v->index) { case 0: - strcpy(v->name, "FM"); + strlcpy(v->name, "FM", sizeof(v->name)); v->capability = V4L2_TUNER_CAP_STEREO; v->rangelow = 1400; /* 87.5 MHz */ v->rangehigh = 1728; /* 108.0 MHz */ - v->rxsubchans=cadet_getstereo(); - switch (v->rxsubchans){ + v->rxsubchans = cadet_getstereo(dev); + switch (v->rxsubchans) { case V4L2_TUNER_SUB_MONO: v->audmode = V4L2_TUNER_MODE_MONO; break; case V4L2_TUNER_SUB_STEREO: v->audmode = V4L2_TUNER_MODE_STEREO; break; - default: ; + default: + break; } break; case 1: - strcpy(v->name, "AM"); + strlcpy(v->name, "AM", sizeof(v->name)); v->capability = V4L2_TUNER_CAP_LOW; v->rangelow = 8320; /* 520 kHz */ v->rangehigh = 26400; /* 1650 kHz */ @@ -411,25 +398,29 @@ static int vidioc_g_tuner(struct file *file, void *priv, default: return -EINVAL; } - v->signal = sigstrength; /* We might need to modify scaling of this */ + v->signal = dev->sigstrength; /* We might need to modify scaling of this */ return 0; } static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - if((v->index != 0)&&(v->index != 1)) + struct cadet *dev = video_drvdata(file); + + if (v->index != 0 && v->index != 1) return -EINVAL; - curtuner = v->index; + dev->curtuner = v->index; return 0; } static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - f->tuner = curtuner; + struct cadet *dev = video_drvdata(file); + + f->tuner = dev->curtuner; f->type = V4L2_TUNER_RADIO; - f->frequency = cadet_getfreq(); + f->frequency = cadet_getfreq(dev); return 0; } @@ -437,27 +428,26 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { + struct cadet *dev = video_drvdata(file); + if (f->type != V4L2_TUNER_RADIO) return -EINVAL; - if((curtuner==0)&&((f->frequency<1400)||(f->frequency>1728))) + if (dev->curtuner == 0 && (f->frequency < 1400 || f->frequency > 1728)) return -EINVAL; - if((curtuner==1)&&((f->frequency<8320)||(f->frequency>26400))) + if (dev->curtuner == 1 && (f->frequency < 8320 || f->frequency > 26400)) return -EINVAL; - cadet_setfreq(f->frequency); + cadet_setfreq(dev, f->frequency); return 0; } static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc) { - int i; - - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); - return 0; - } + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 0xff, 1, 0xff); } return -EINVAL; } @@ -465,12 +455,14 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - switch (ctrl->id){ + struct cadet *dev = video_drvdata(file); + + switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */ - ctrl->value = (cadet_getvol() == 0); + ctrl->value = (cadet_getvol(dev) == 0); break; case V4L2_CID_AUDIO_VOLUME: - ctrl->value = cadet_getvol(); + ctrl->value = cadet_getvol(dev); break; default: return -EINVAL; @@ -481,15 +473,17 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { + struct cadet *dev = video_drvdata(file); + switch (ctrl->id){ case V4L2_CID_AUDIO_MUTE: /* TODO: Handle this correctly */ if (ctrl->value) - cadet_setvol(0); + cadet_setvol(dev, 0); else - cadet_setvol(0xffff); + cadet_setvol(dev, 0xffff); break; case V4L2_CID_AUDIO_VOLUME: - cadet_setvol(ctrl->value); + cadet_setvol(dev, ctrl->value); break; default: return -EINVAL; @@ -497,16 +491,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv, return 0; } -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) { *i = 0; @@ -515,43 +499,52 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) { - if (i != 0) - return -EINVAL; + return i ? -EINVAL : 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; return 0; } static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) { - if (a->index != 0) - return -EINVAL; - return 0; + return a->index ? -EINVAL : 0; } -static int -cadet_open(struct file *file) +static int cadet_open(struct file *file) { - users++; - if (1 == users) init_waitqueue_head(&read_queue); + struct cadet *dev = video_drvdata(file); + + dev->users++; + if (1 == dev->users) + init_waitqueue_head(&dev->read_queue); return 0; } -static int -cadet_release(struct file *file) +static int cadet_release(struct file *file) { - users--; - if (0 == users){ - del_timer_sync(&readtimer); - rdsstat=0; + struct cadet *dev = video_drvdata(file); + + dev->users--; + if (0 == dev->users) { + del_timer_sync(&dev->readtimer); + dev->rdsstat = 0; } return 0; } -static unsigned int -cadet_poll(struct file *file, struct poll_table_struct *wait) +static unsigned int cadet_poll(struct file *file, struct poll_table_struct *wait) { - poll_wait(file,&read_queue,wait); - if(rdsin != rdsout) + struct cadet *dev = video_drvdata(file); + + poll_wait(file, &dev->read_queue, wait); + if (dev->rdsin != dev->rdsout) return POLLIN | POLLRDNORM; return 0; } @@ -581,13 +574,6 @@ static const struct v4l2_ioctl_ops cadet_ioctl_ops = { .vidioc_s_input = vidioc_s_input, }; -static struct video_device cadet_radio = { - .name = "Cadet radio", - .fops = &cadet_fops, - .ioctl_ops = &cadet_ioctl_ops, - .release = video_device_release_empty, -}; - #ifdef CONFIG_PNP static struct pnp_device_id cadet_pnp_devices[] = { @@ -598,7 +584,7 @@ static struct pnp_device_id cadet_pnp_devices[] = { MODULE_DEVICE_TABLE(pnp, cadet_pnp_devices); -static int cadet_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev_id) +static int cadet_pnp_probe(struct pnp_dev *dev, const struct pnp_device_id *dev_id) { if (!dev) return -ENODEV; @@ -606,13 +592,12 @@ static int cadet_pnp_probe(struct pnp_dev * dev, const struct pnp_device_id *dev if (io > 0) return -EBUSY; - if (!pnp_port_valid(dev, 0)) { + if (!pnp_port_valid(dev, 0)) return -ENODEV; - } io = pnp_port_start(dev, 0); - printk ("radio-cadet: PnP reports device at %#x\n", io); + printk(KERN_INFO "radio-cadet: PnP reports device at %#x\n", io); return io; } @@ -628,23 +613,23 @@ static struct pnp_driver cadet_pnp_driver = { static struct pnp_driver cadet_pnp_driver; #endif -static int cadet_probe(void) +static void cadet_probe(struct cadet *dev) { - static int iovals[8]={0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e}; + static int iovals[8] = { 0x330, 0x332, 0x334, 0x336, 0x338, 0x33a, 0x33c, 0x33e }; int i; - for(i=0;i<8;i++) { - io=iovals[i]; - if (request_region(io, 2, "cadet-probe")) { - cadet_setfreq(1410); - if(cadet_getfreq()==1410) { - release_region(io, 2); - return io; + for (i = 0; i < 8; i++) { + dev->io = iovals[i]; + if (request_region(dev->io, 2, "cadet-probe")) { + cadet_setfreq(dev, 1410); + if (cadet_getfreq(dev) == 1410) { + release_region(dev->io, 2); + return; } - release_region(io, 2); + release_region(dev->io, 2); } } - return -1; + dev->io = -1; } /* @@ -654,59 +639,69 @@ static int cadet_probe(void) static int __init cadet_init(void) { - spin_lock_init(&cadet_io_lock); + struct cadet *dev = &cadet_card; + struct v4l2_device *v4l2_dev = &dev->v4l2_dev; + int res; - /* - * If a probe was requested then probe ISAPnP first (safest) - */ + strlcpy(v4l2_dev->name, "cadet", sizeof(v4l2_dev->name)); + mutex_init(&dev->lock); + + /* If a probe was requested then probe ISAPnP first (safest) */ if (io < 0) pnp_register_driver(&cadet_pnp_driver); - /* - * If that fails then probe unsafely if probe is requested - */ - if(io < 0) - io = cadet_probe (); + dev->io = io; - /* - * Else we bail out - */ + /* If that fails then probe unsafely if probe is requested */ + if (dev->io < 0) + cadet_probe(dev); - if(io < 0) { + /* Else we bail out */ + if (dev->io < 0) { #ifdef MODULE - printk(KERN_ERR "You must set an I/O address with io=0x???\n"); + v4l2_err(v4l2_dev, "you must set an I/O address with io=0x330, 0x332, 0x334,\n"); + v4l2_err(v4l2_dev, "0x336, 0x338, 0x33a, 0x33c or 0x33e\n"); #endif goto fail; } - if (!request_region(io,2,"cadet")) + if (!request_region(dev->io, 2, "cadet")) + goto fail; + + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + release_region(dev->io, 2); + v4l2_err(v4l2_dev, "could not register v4l2_device\n"); goto fail; - if (video_register_device(&cadet_radio, VFL_TYPE_RADIO, radio_nr) < 0) { - release_region(io,2); + } + + strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); + dev->vdev.v4l2_dev = v4l2_dev; + dev->vdev.fops = &cadet_fops; + dev->vdev.ioctl_ops = &cadet_ioctl_ops; + dev->vdev.release = video_device_release_empty; + video_set_drvdata(&dev->vdev, dev); + + if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(dev->io, 2); goto fail; } - printk(KERN_INFO "ADS Cadet Radio Card at 0x%x\n",io); + v4l2_info(v4l2_dev, "ADS Cadet Radio Card at 0x%x\n", dev->io); return 0; fail: pnp_unregister_driver(&cadet_pnp_driver); - return -1; + return -ENODEV; } - - -MODULE_AUTHOR("Fred Gleason, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); -MODULE_DESCRIPTION("A driver for the ADS Cadet AM/FM/RDS radio card."); -MODULE_LICENSE("GPL"); - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of Cadet card (0x330,0x332,0x334,0x336,0x338,0x33a,0x33c,0x33e)"); -module_param(radio_nr, int, 0); - -static void __exit cadet_cleanup_module(void) +static void __exit cadet_exit(void) { - video_unregister_device(&cadet_radio); - release_region(io,2); + struct cadet *dev = &cadet_card; + + video_unregister_device(&dev->vdev); + v4l2_device_unregister(&dev->v4l2_dev); + release_region(dev->io, 2); pnp_unregister_driver(&cadet_pnp_driver); } module_init(cadet_init); -module_exit(cadet_cleanup_module); +module_exit(cadet_exit); diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c index 0c96bf8525b0..c3f579de6e71 100644 --- a/drivers/media/radio/radio-gemtek-pci.c +++ b/drivers/media/radio/radio-gemtek-pci.c @@ -45,34 +45,25 @@ #include <linux/init.h> #include <linux/pci.h> #include <linux/videodev2.h> -#include <media/v4l2-common.h> -#include <media/v4l2-ioctl.h> #include <linux/errno.h> - #include <linux/version.h> /* for KERNEL_VERSION MACRO */ -#define RADIO_VERSION KERNEL_VERSION(0,0,2) - -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 65535, - .step = 65535, - .default_value = 0xff, - .type = V4L2_CTRL_TYPE_INTEGER, - } -}; +#include <linux/io.h> +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> + +MODULE_AUTHOR("Vladimir Shebordaev <vshebordaev@mail.ru>"); +MODULE_DESCRIPTION("The video4linux driver for the Gemtek PCI Radio Card"); +MODULE_LICENSE("GPL"); + +static int nr_radio = -1; +static int mx = 1; -#include <asm/io.h> -#include <asm/uaccess.h> +module_param(mx, bool, 0); +MODULE_PARM_DESC(mx, "single digit: 1 - turn off the turner upon module exit (default), 0 - do not"); +module_param(nr_radio, int, 0); +MODULE_PARM_DESC(nr_radio, "video4linux device number to use"); + +#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) #ifndef PCI_VENDOR_ID_GEMTEK #define PCI_VENDOR_ID_GEMTEK 0x5046 @@ -90,8 +81,11 @@ static struct v4l2_queryctrl radio_qctrl[] = { #define GEMTEK_PCI_RANGE_HIGH (108*16000) #endif -struct gemtek_pci_card { - struct video_device *videodev; +struct gemtek_pci { + struct v4l2_device v4l2_dev; + struct video_device vdev; + struct mutex lock; + struct pci_dev *pdev; u32 iobase; u32 length; @@ -100,116 +94,133 @@ struct gemtek_pci_card { u8 mute; }; -static int nr_radio = -1; -static unsigned long in_use; +static inline struct gemtek_pci *to_gemtek_pci(struct v4l2_device *v4l2_dev) +{ + return container_of(v4l2_dev, struct gemtek_pci, v4l2_dev); +} -static inline u8 gemtek_pci_out( u16 value, u32 port ) +static inline u8 gemtek_pci_out(u16 value, u32 port) { - outw( value, port ); + outw(value, port); return (u8)value; } -#define _b0( v ) *((u8 *)&v) -static void __gemtek_pci_cmd( u16 value, u32 port, u8 *last_byte, int keep ) +#define _b0(v) (*((u8 *)&v)) + +static void __gemtek_pci_cmd(u16 value, u32 port, u8 *last_byte, int keep) { - register u8 byte = *last_byte; + u8 byte = *last_byte; - if ( !value ) { - if ( !keep ) + if (!value) { + if (!keep) value = (u16)port; byte &= 0xfd; } else byte |= 2; - _b0( value ) = byte; - outw( value, port ); + _b0(value) = byte; + outw(value, port); byte |= 1; - _b0( value ) = byte; - outw( value, port ); + _b0(value) = byte; + outw(value, port); byte &= 0xfe; - _b0( value ) = byte; - outw( value, port ); + _b0(value) = byte; + outw(value, port); *last_byte = byte; } -static inline void gemtek_pci_nil( u32 port, u8 *last_byte ) +static inline void gemtek_pci_nil(u32 port, u8 *last_byte) { - __gemtek_pci_cmd( 0x00, port, last_byte, false ); + __gemtek_pci_cmd(0x00, port, last_byte, false); } -static inline void gemtek_pci_cmd( u16 cmd, u32 port, u8 *last_byte ) +static inline void gemtek_pci_cmd(u16 cmd, u32 port, u8 *last_byte) { - __gemtek_pci_cmd( cmd, port, last_byte, true ); + __gemtek_pci_cmd(cmd, port, last_byte, true); } -static void gemtek_pci_setfrequency( struct gemtek_pci_card *card, unsigned long frequency ) +static void gemtek_pci_setfrequency(struct gemtek_pci *card, unsigned long frequency) { - register int i; - register u32 value = frequency / 200 + 856; - register u16 mask = 0x8000; + int i; + u32 value = frequency / 200 + 856; + u16 mask = 0x8000; u8 last_byte; u32 port = card->iobase; - last_byte = gemtek_pci_out( 0x06, port ); + mutex_lock(&card->lock); + card->current_frequency = frequency; + last_byte = gemtek_pci_out(0x06, port); i = 0; do { - gemtek_pci_nil( port, &last_byte ); + gemtek_pci_nil(port, &last_byte); i++; - } while ( i < 9 ); + } while (i < 9); i = 0; do { - gemtek_pci_cmd( value & mask, port, &last_byte ); + gemtek_pci_cmd(value & mask, port, &last_byte); mask >>= 1; i++; - } while ( i < 16 ); + } while (i < 16); - outw( 0x10, port ); + outw(0x10, port); + mutex_unlock(&card->lock); } -static inline void gemtek_pci_mute( struct gemtek_pci_card *card ) +static void gemtek_pci_mute(struct gemtek_pci *card) { - outb( 0x1f, card->iobase ); + mutex_lock(&card->lock); + outb(0x1f, card->iobase); card->mute = true; + mutex_unlock(&card->lock); } -static inline void gemtek_pci_unmute( struct gemtek_pci_card *card ) +static void gemtek_pci_unmute(struct gemtek_pci *card) { - if ( card->mute ) { - gemtek_pci_setfrequency( card, card->current_frequency ); + mutex_lock(&card->lock); + if (card->mute) { + gemtek_pci_setfrequency(card, card->current_frequency); card->mute = false; } + mutex_unlock(&card->lock); } -static inline unsigned int gemtek_pci_getsignal( struct gemtek_pci_card *card ) +static int gemtek_pci_getsignal(struct gemtek_pci *card) { - return ( inb( card->iobase ) & 0x08 ) ? 0 : 1; + int sig; + + mutex_lock(&card->lock); + sig = (inb(card->iobase) & 0x08) ? 0 : 1; + mutex_unlock(&card->lock); + return sig; } static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) { + struct gemtek_pci *card = video_drvdata(file); + strlcpy(v->driver, "radio-gemtek-pci", sizeof(v->driver)); strlcpy(v->card, "GemTek PCI Radio", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); + snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(card->pdev)); v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct gemtek_pci_card *card = video_drvdata(file); + struct gemtek_pci *card = video_drvdata(file); if (v->index > 0) return -EINVAL; - strcpy(v->name, "FM"); + strlcpy(v->name, "FM", sizeof(v->name)); v->type = V4L2_TUNER_RADIO; v->rangelow = GEMTEK_PCI_RANGE_LOW; v->rangehigh = GEMTEK_PCI_RANGE_HIGH; @@ -223,21 +234,18 @@ static int vidioc_g_tuner(struct file *file, void *priv, static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - if (v->index > 0) - return -EINVAL; - return 0; + return v->index ? -EINVAL : 0; } static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct gemtek_pci_card *card = video_drvdata(file); + struct gemtek_pci *card = video_drvdata(file); - if ( (f->frequency < GEMTEK_PCI_RANGE_LOW) || - (f->frequency > GEMTEK_PCI_RANGE_HIGH) ) + if (f->frequency < GEMTEK_PCI_RANGE_LOW || + f->frequency > GEMTEK_PCI_RANGE_HIGH) return -EINVAL; gemtek_pci_setfrequency(card, f->frequency); - card->current_frequency = f->frequency; card->mute = false; return 0; } @@ -245,7 +253,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct gemtek_pci_card *card = video_drvdata(file); + struct gemtek_pci *card = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = card->current_frequency; @@ -255,13 +263,11 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc) { - int i; - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); - return 0; - } + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535); } return -EINVAL; } @@ -269,7 +275,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct gemtek_pci_card *card = video_drvdata(file); + struct gemtek_pci *card = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -288,7 +294,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct gemtek_pci_card *card = video_drvdata(file); + struct gemtek_pci *card = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -307,17 +313,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv, return -EINVAL; } -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) { *i = 0; @@ -326,17 +321,22 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) { - if (i != 0) - return -EINVAL; + return i ? -EINVAL : 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; return 0; } static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) { - if (a->index != 0) - return -EINVAL; - return 0; + return a->index ? -EINVAL : 0; } enum { @@ -354,25 +354,10 @@ static struct pci_device_id gemtek_pci_id[] = { 0 } }; -MODULE_DEVICE_TABLE( pci, gemtek_pci_id ); - -static int mx = 1; - -static int gemtek_pci_exclusive_open(struct file *file) -{ - return test_and_set_bit(0, &in_use) ? -EBUSY : 0; -} - -static int gemtek_pci_exclusive_release(struct file *file) -{ - clear_bit(0, &in_use); - return 0; -} +MODULE_DEVICE_TABLE(pci, gemtek_pci_id); static const struct v4l2_file_operations gemtek_pci_fops = { .owner = THIS_MODULE, - .open = gemtek_pci_exclusive_open, - .release = gemtek_pci_exclusive_release, .ioctl = video_ioctl2, }; @@ -391,108 +376,100 @@ static const struct v4l2_ioctl_ops gemtek_pci_ioctl_ops = { .vidioc_s_ctrl = vidioc_s_ctrl, }; -static struct video_device vdev_template = { - .name = "Gemtek PCI Radio", - .fops = &gemtek_pci_fops, - .ioctl_ops = &gemtek_pci_ioctl_ops, - .release = video_device_release_empty, -}; - -static int __devinit gemtek_pci_probe( struct pci_dev *pci_dev, const struct pci_device_id *pci_id ) +static int __devinit gemtek_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id) { - struct gemtek_pci_card *card; - struct video_device *devradio; + struct gemtek_pci *card; + struct v4l2_device *v4l2_dev; + int res; - if ( (card = kzalloc( sizeof( struct gemtek_pci_card ), GFP_KERNEL )) == NULL ) { - printk( KERN_ERR "gemtek_pci: out of memory\n" ); + card = kzalloc(sizeof(struct gemtek_pci), GFP_KERNEL); + if (card == NULL) { + dev_err(&pdev->dev, "out of memory\n"); return -ENOMEM; } - if ( pci_enable_device( pci_dev ) ) - goto err_pci; + v4l2_dev = &card->v4l2_dev; + mutex_init(&card->lock); + card->pdev = pdev; - card->iobase = pci_resource_start( pci_dev, 0 ); - card->length = pci_resource_len( pci_dev, 0 ); + strlcpy(v4l2_dev->name, "gemtek_pci", sizeof(v4l2_dev->name)); - if ( request_region( card->iobase, card->length, card_names[pci_id->driver_data] ) == NULL ) { - printk( KERN_ERR "gemtek_pci: i/o port already in use\n" ); - goto err_pci; + res = v4l2_device_register(&pdev->dev, v4l2_dev); + if (res < 0) { + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + kfree(card); + return res; } - pci_set_drvdata( pci_dev, card ); + if (pci_enable_device(pdev)) + goto err_pci; - if ( (devradio = kmalloc( sizeof( struct video_device ), GFP_KERNEL )) == NULL ) { - printk( KERN_ERR "gemtek_pci: out of memory\n" ); - goto err_video; + card->iobase = pci_resource_start(pdev, 0); + card->length = pci_resource_len(pdev, 0); + + if (request_region(card->iobase, card->length, card_names[pci_id->driver_data]) == NULL) { + v4l2_err(v4l2_dev, "i/o port already in use\n"); + goto err_pci; } - *devradio = vdev_template; - if (video_register_device(devradio, VFL_TYPE_RADIO, nr_radio) < 0) { - kfree( devradio ); + strlcpy(card->vdev.name, v4l2_dev->name, sizeof(card->vdev.name)); + card->vdev.v4l2_dev = v4l2_dev; + card->vdev.fops = &gemtek_pci_fops; + card->vdev.ioctl_ops = &gemtek_pci_ioctl_ops; + card->vdev.release = video_device_release_empty; + video_set_drvdata(&card->vdev, card); + + if (video_register_device(&card->vdev, VFL_TYPE_RADIO, nr_radio) < 0) goto err_video; - } - card->videodev = devradio; - video_set_drvdata(devradio, card); - gemtek_pci_mute( card ); + gemtek_pci_mute(card); - printk( KERN_INFO "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n", - pci_dev->revision, card->iobase, card->iobase + card->length - 1 ); + v4l2_info(v4l2_dev, "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n", + pdev->revision, card->iobase, card->iobase + card->length - 1); return 0; err_video: - release_region( card->iobase, card->length ); + release_region(card->iobase, card->length); err_pci: - kfree( card ); + v4l2_device_unregister(v4l2_dev); + kfree(card); return -ENODEV; } -static void __devexit gemtek_pci_remove( struct pci_dev *pci_dev ) +static void __devexit gemtek_pci_remove(struct pci_dev *pdev) { - struct gemtek_pci_card *card = pci_get_drvdata( pci_dev ); + struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); + struct gemtek_pci *card = to_gemtek_pci(v4l2_dev); - video_unregister_device( card->videodev ); - kfree( card->videodev ); + video_unregister_device(&card->vdev); + v4l2_device_unregister(v4l2_dev); - release_region( card->iobase, card->length ); + release_region(card->iobase, card->length); - if ( mx ) - gemtek_pci_mute( card ); + if (mx) + gemtek_pci_mute(card); - kfree( card ); - - pci_set_drvdata( pci_dev, NULL ); + kfree(card); } -static struct pci_driver gemtek_pci_driver = -{ +static struct pci_driver gemtek_pci_driver = { .name = "gemtek_pci", .id_table = gemtek_pci_id, .probe = gemtek_pci_probe, .remove = __devexit_p(gemtek_pci_remove), }; -static int __init gemtek_pci_init_module( void ) +static int __init gemtek_pci_init(void) { - return pci_register_driver( &gemtek_pci_driver ); + return pci_register_driver(&gemtek_pci_driver); } -static void __exit gemtek_pci_cleanup_module( void ) +static void __exit gemtek_pci_exit(void) { pci_unregister_driver(&gemtek_pci_driver); } -MODULE_AUTHOR( "Vladimir Shebordaev <vshebordaev@mail.ru>" ); -MODULE_DESCRIPTION( "The video4linux driver for the Gemtek PCI Radio Card" ); -MODULE_LICENSE("GPL"); - -module_param(mx, bool, 0); -MODULE_PARM_DESC( mx, "single digit: 1 - turn off the turner upon module exit (default), 0 - do not" ); -module_param(nr_radio, int, 0); -MODULE_PARM_DESC( nr_radio, "video4linux device number to use"); - -module_init( gemtek_pci_init_module ); -module_exit( gemtek_pci_cleanup_module ); - +module_init(gemtek_pci_init); +module_exit(gemtek_pci_exit); diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c index 2b68be773f13..73985f641f07 100644 --- a/drivers/media/radio/radio-gemtek.c +++ b/drivers/media/radio/radio-gemtek.c @@ -20,16 +20,14 @@ #include <linux/init.h> /* Initdata */ #include <linux/ioport.h> /* request_region */ #include <linux/delay.h> /* udelay */ -#include <asm/io.h> /* outb, outb_p */ -#include <asm/uaccess.h> /* copy to/from user */ #include <linux/videodev2.h> /* kernel radio structs */ +#include <linux/version.h> /* for KERNEL_VERSION MACRO */ +#include <linux/mutex.h> +#include <linux/io.h> /* outb, outb_p */ #include <media/v4l2-ioctl.h> -#include <media/v4l2-common.h> -#include <linux/spinlock.h> +#include <media/v4l2-device.h> -#include <linux/version.h> /* for KERNEL_VERSION MACRO */ -#define RADIO_VERSION KERNEL_VERSION(0,0,3) -#define RADIO_BANNER "GemTek Radio card driver: v0.0.3" +#define RADIO_VERSION KERNEL_VERSION(0, 0, 3) /* * Module info. @@ -57,7 +55,6 @@ static int shutdown = 1; static int keepmuted = 1; static int initmute = 1; static int radio_nr = -1; -static unsigned long in_use; module_param(io, int, 0444); MODULE_PARM_DESC(io, "Force I/O port for the GemTek Radio card if automatic " @@ -112,12 +109,19 @@ module_param(radio_nr, int, 0444); #define SHORT_DELAY 5 /* usec */ #define LONG_DELAY 75 /* usec */ -struct gemtek_device { +struct gemtek { + struct v4l2_device v4l2_dev; + struct video_device vdev; + struct mutex lock; unsigned long lastfreq; int muted; + int verified; + int io; u32 bu2614data; }; +static struct gemtek gemtek_card; + #define BU2614_FREQ_BITS 16 /* D0..D15, Frequency data */ #define BU2614_PORT_BITS 3 /* P0..P2, Output port control data */ #define BU2614_VOID_BITS 4 /* unused */ @@ -153,10 +157,6 @@ struct gemtek_device { #define BU2614_FMUN_MASK MKMASK(FMUN) #define BU2614_TEST_MASK MKMASK(TEST) -static struct gemtek_device gemtek_unit; - -static spinlock_t lock; - /* * Set data which will be sent to BU2614FS. */ @@ -166,33 +166,33 @@ static spinlock_t lock; /* * Transmit settings to BU2614FS over GemTek IC. */ -static void gemtek_bu2614_transmit(struct gemtek_device *dev) +static void gemtek_bu2614_transmit(struct gemtek *gt) { int i, bit, q, mute; - spin_lock(&lock); + mutex_lock(>->lock); - mute = dev->muted ? GEMTEK_MT : 0x00; + mute = gt->muted ? GEMTEK_MT : 0x00; - outb_p(mute | GEMTEK_DA | GEMTEK_CK, io); + outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io); udelay(SHORT_DELAY); - outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io); + outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io); udelay(LONG_DELAY); - for (i = 0, q = dev->bu2614data; i < 32; i++, q >>= 1) { - bit = (q & 1) ? GEMTEK_DA : 0; - outb_p(mute | GEMTEK_CE | bit, io); - udelay(SHORT_DELAY); - outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, io); - udelay(SHORT_DELAY); + for (i = 0, q = gt->bu2614data; i < 32; i++, q >>= 1) { + bit = (q & 1) ? GEMTEK_DA : 0; + outb_p(mute | GEMTEK_CE | bit, gt->io); + udelay(SHORT_DELAY); + outb_p(mute | GEMTEK_CE | bit | GEMTEK_CK, gt->io); + udelay(SHORT_DELAY); } - outb_p(mute | GEMTEK_DA | GEMTEK_CK, io); + outb_p(mute | GEMTEK_DA | GEMTEK_CK, gt->io); udelay(SHORT_DELAY); - outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, io); + outb_p(mute | GEMTEK_CE | GEMTEK_DA | GEMTEK_CK, gt->io); udelay(LONG_DELAY); - spin_unlock(&lock); + mutex_unlock(>->lock); } /* @@ -206,107 +206,109 @@ static unsigned long gemtek_convfreq(unsigned long freq) /* * Set FM-frequency. */ -static void gemtek_setfreq(struct gemtek_device *dev, unsigned long freq) +static void gemtek_setfreq(struct gemtek *gt, unsigned long freq) { - - if (keepmuted && hardmute && dev->muted) + if (keepmuted && hardmute && gt->muted) return; - if (freq < GEMTEK_LOWFREQ) - freq = GEMTEK_LOWFREQ; - else if (freq > GEMTEK_HIGHFREQ) - freq = GEMTEK_HIGHFREQ; + freq = clamp_val(freq, GEMTEK_LOWFREQ, GEMTEK_HIGHFREQ); - dev->lastfreq = freq; - dev->muted = 0; + gt->lastfreq = freq; + gt->muted = 0; - gemtek_bu2614_set(dev, BU2614_PORT, 0); - gemtek_bu2614_set(dev, BU2614_FMES, 0); - gemtek_bu2614_set(dev, BU2614_SWIN, 0); /* FM-mode */ - gemtek_bu2614_set(dev, BU2614_SWAL, 0); - gemtek_bu2614_set(dev, BU2614_FMUN, 1); /* GT bit set */ - gemtek_bu2614_set(dev, BU2614_TEST, 0); + gemtek_bu2614_set(gt, BU2614_PORT, 0); + gemtek_bu2614_set(gt, BU2614_FMES, 0); + gemtek_bu2614_set(gt, BU2614_SWIN, 0); /* FM-mode */ + gemtek_bu2614_set(gt, BU2614_SWAL, 0); + gemtek_bu2614_set(gt, BU2614_FMUN, 1); /* GT bit set */ + gemtek_bu2614_set(gt, BU2614_TEST, 0); - gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_STDF_3_125_KHZ); - gemtek_bu2614_set(dev, BU2614_FREQ, gemtek_convfreq(freq)); + gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_STDF_3_125_KHZ); + gemtek_bu2614_set(gt, BU2614_FREQ, gemtek_convfreq(freq)); - gemtek_bu2614_transmit(dev); + gemtek_bu2614_transmit(gt); } /* * Set mute flag. */ -static void gemtek_mute(struct gemtek_device *dev) +static void gemtek_mute(struct gemtek *gt) { int i; - dev->muted = 1; + + gt->muted = 1; if (hardmute) { /* Turn off PLL, disable data output */ - gemtek_bu2614_set(dev, BU2614_PORT, 0); - gemtek_bu2614_set(dev, BU2614_FMES, 0); /* CT bit off */ - gemtek_bu2614_set(dev, BU2614_SWIN, 0); /* FM-mode */ - gemtek_bu2614_set(dev, BU2614_SWAL, 0); - gemtek_bu2614_set(dev, BU2614_FMUN, 0); /* GT bit off */ - gemtek_bu2614_set(dev, BU2614_TEST, 0); - gemtek_bu2614_set(dev, BU2614_STDF, GEMTEK_PLL_OFF); - gemtek_bu2614_set(dev, BU2614_FREQ, 0); - gemtek_bu2614_transmit(dev); - } else { - spin_lock(&lock); + gemtek_bu2614_set(gt, BU2614_PORT, 0); + gemtek_bu2614_set(gt, BU2614_FMES, 0); /* CT bit off */ + gemtek_bu2614_set(gt, BU2614_SWIN, 0); /* FM-mode */ + gemtek_bu2614_set(gt, BU2614_SWAL, 0); + gemtek_bu2614_set(gt, BU2614_FMUN, 0); /* GT bit off */ + gemtek_bu2614_set(gt, BU2614_TEST, 0); + gemtek_bu2614_set(gt, BU2614_STDF, GEMTEK_PLL_OFF); + gemtek_bu2614_set(gt, BU2614_FREQ, 0); + gemtek_bu2614_transmit(gt); + return; + } - /* Read bus contents (CE, CK and DA). */ - i = inb_p(io); - /* Write it back with mute flag set. */ - outb_p((i >> 5) | GEMTEK_MT, io); - udelay(SHORT_DELAY); + mutex_lock(>->lock); - spin_unlock(&lock); - } + /* Read bus contents (CE, CK and DA). */ + i = inb_p(gt->io); + /* Write it back with mute flag set. */ + outb_p((i >> 5) | GEMTEK_MT, gt->io); + udelay(SHORT_DELAY); + + mutex_unlock(>->lock); } /* * Unset mute flag. */ -static void gemtek_unmute(struct gemtek_device *dev) +static void gemtek_unmute(struct gemtek *gt) { int i; - dev->muted = 0; + gt->muted = 0; if (hardmute) { /* Turn PLL back on. */ - gemtek_setfreq(dev, dev->lastfreq); - } else { - spin_lock(&lock); + gemtek_setfreq(gt, gt->lastfreq); + return; + } + mutex_lock(>->lock); - i = inb_p(io); - outb_p(i >> 5, io); - udelay(SHORT_DELAY); + i = inb_p(gt->io); + outb_p(i >> 5, gt->io); + udelay(SHORT_DELAY); - spin_unlock(&lock); - } + mutex_unlock(>->lock); } /* * Get signal strength (= stereo status). */ -static inline int gemtek_getsigstr(void) +static inline int gemtek_getsigstr(struct gemtek *gt) { - return inb_p(io) & GEMTEK_NS ? 0 : 1; + int sig; + + mutex_lock(>->lock); + sig = inb_p(gt->io) & GEMTEK_NS ? 0 : 1; + mutex_unlock(>->lock); + return sig; } /* * Check if requested card acts like GemTek Radio card. */ -static int gemtek_verify(int port) +static int gemtek_verify(struct gemtek *gt, int port) { - static int verified = -1; int i, q; - if (verified == port) + if (gt->verified == port) return 1; - spin_lock(&lock); + mutex_lock(>->lock); q = inb_p(port); /* Read bus contents before probing. */ /* Try to turn on CE, CK and DA respectively and check if card responds @@ -316,15 +318,15 @@ static int gemtek_verify(int port) udelay(SHORT_DELAY); if ((inb_p(port) & (~GEMTEK_NS)) != (0x17 | (1 << (i + 5)))) { - spin_unlock(&lock); + mutex_unlock(>->lock); return 0; } } outb_p(q >> 5, port); /* Write bus contents back. */ udelay(SHORT_DELAY); - spin_unlock(&lock); - verified = port; + mutex_unlock(>->lock); + gt->verified = port; return 1; } @@ -332,42 +334,41 @@ static int gemtek_verify(int port) /* * Automatic probing for card. */ -static int gemtek_probe(void) +static int gemtek_probe(struct gemtek *gt) { + struct v4l2_device *v4l2_dev = >->v4l2_dev; int ioports[] = { 0x20c, 0x30c, 0x24c, 0x34c, 0x248, 0x28c }; int i; if (!probe) { - printk(KERN_INFO "Automatic device probing disabled.\n"); + v4l2_info(v4l2_dev, "Automatic device probing disabled.\n"); return -1; } - printk(KERN_INFO "Automatic device probing enabled.\n"); + v4l2_info(v4l2_dev, "Automatic device probing enabled.\n"); for (i = 0; i < ARRAY_SIZE(ioports); ++i) { - printk(KERN_INFO "Trying I/O port 0x%x...\n", ioports[i]); + v4l2_info(v4l2_dev, "Trying I/O port 0x%x...\n", ioports[i]); if (!request_region(ioports[i], 1, "gemtek-probe")) { - printk(KERN_WARNING "I/O port 0x%x busy!\n", + v4l2_warn(v4l2_dev, "I/O port 0x%x busy!\n", ioports[i]); continue; } - if (gemtek_verify(ioports[i])) { - printk(KERN_INFO "Card found from I/O port " + if (gemtek_verify(gt, ioports[i])) { + v4l2_info(v4l2_dev, "Card found from I/O port " "0x%x!\n", ioports[i]); release_region(ioports[i], 1); - - io = ioports[i]; - return io; + gt->io = ioports[i]; + return gt->io; } release_region(ioports[i], 1); } - printk(KERN_ERR "Automatic probing failed!\n"); - + v4l2_err(v4l2_dev, "Automatic probing failed!\n"); return -1; } @@ -375,40 +376,8 @@ static int gemtek_probe(void) * Video 4 Linux stuff. */ -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, { - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 65535, - .step = 65535, - .default_value = 0xff, - .type = V4L2_CTRL_TYPE_INTEGER, - } -}; - -static int gemtek_exclusive_open(struct file *file) -{ - return test_and_set_bit(0, &in_use) ? -EBUSY : 0; -} - -static int gemtek_exclusive_release(struct file *file) -{ - clear_bit(0, &in_use); - return 0; -} - static const struct v4l2_file_operations gemtek_fops = { .owner = THIS_MODULE, - .open = gemtek_exclusive_open, - .release = gemtek_exclusive_release, .ioctl = video_ioctl2, }; @@ -417,23 +386,25 @@ static int vidioc_querycap(struct file *file, void *priv, { strlcpy(v->driver, "radio-gemtek", sizeof(v->driver)); strlcpy(v->card, "GemTek", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { + struct gemtek *gt = video_drvdata(file); + if (v->index > 0) return -EINVAL; - strcpy(v->name, "FM"); + strlcpy(v->name, "FM", sizeof(v->name)); v->type = V4L2_TUNER_RADIO; v->rangelow = GEMTEK_LOWFREQ; v->rangehigh = GEMTEK_HIGHFREQ; v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO; - v->signal = 0xffff * gemtek_getsigstr(); + v->signal = 0xffff * gemtek_getsigstr(gt); if (v->signal) { v->audmode = V4L2_TUNER_MODE_STEREO; v->rxsubchans = V4L2_TUNER_SUB_STEREO; @@ -441,65 +412,56 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) v->audmode = V4L2_TUNER_MODE_MONO; v->rxsubchans = V4L2_TUNER_SUB_MONO; } - return 0; } static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - if (v->index > 0) - return -EINVAL; - return 0; + return (v->index != 0) ? -EINVAL : 0; } -static int vidioc_s_frequency(struct file *file, void *priv, +static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct gemtek_device *rt = video_drvdata(file); - - gemtek_setfreq(rt, f->frequency); + struct gemtek *gt = video_drvdata(file); + if (f->tuner != 0) + return -EINVAL; + f->type = V4L2_TUNER_RADIO; + f->frequency = gt->lastfreq; return 0; } -static int vidioc_g_frequency(struct file *file, void *priv, +static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct gemtek_device *rt = video_drvdata(file); + struct gemtek *gt = video_drvdata(file); - f->type = V4L2_TUNER_RADIO; - f->frequency = rt->lastfreq; + if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO) + return -EINVAL; + gemtek_setfreq(gt, f->frequency); return 0; } static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc) { - int i; - - for (i = 0; i < ARRAY_SIZE(radio_qctrl); ++i) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); - return 0; - } + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); + default: + return -EINVAL; } - return -EINVAL; } static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct gemtek_device *rt = video_drvdata(file); + struct gemtek *gt = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - ctrl->value = rt->muted; - return 0; - case V4L2_CID_AUDIO_VOLUME: - if (rt->muted) - ctrl->value = 0; - else - ctrl->value = 65535; + ctrl->value = gt->muted; return 0; } return -EINVAL; @@ -508,35 +470,19 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct gemtek_device *rt = video_drvdata(file); + struct gemtek *gt = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: if (ctrl->value) - gemtek_mute(rt); + gemtek_mute(gt); else - gemtek_unmute(rt); - return 0; - case V4L2_CID_AUDIO_VOLUME: - if (ctrl->value) - gemtek_unmute(rt); - else - gemtek_mute(rt); + gemtek_unmute(gt); return 0; } return -EINVAL; } -static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) { *i = 0; @@ -545,16 +491,20 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) { - if (i != 0) - return -EINVAL; + return (i != 0) ? -EINVAL : 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) +{ + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; return 0; } static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) { - if (a->index != 0) - return -EINVAL; - return 0; + return (a->index != 0) ? -EINVAL : 0; } static const struct v4l2_ioctl_ops gemtek_ioctl_ops = { @@ -572,62 +522,73 @@ static const struct v4l2_ioctl_ops gemtek_ioctl_ops = { .vidioc_s_ctrl = vidioc_s_ctrl }; -static struct video_device gemtek_radio = { - .name = "GemTek Radio card", - .fops = &gemtek_fops, - .ioctl_ops = &gemtek_ioctl_ops, - .release = video_device_release_empty, -}; - /* * Initialization / cleanup related stuff. */ -/* - * Initilize card. - */ static int __init gemtek_init(void) { - printk(KERN_INFO RADIO_BANNER "\n"); + struct gemtek *gt = &gemtek_card; + struct v4l2_device *v4l2_dev = >->v4l2_dev; + int res; - spin_lock_init(&lock); + strlcpy(v4l2_dev->name, "gemtek", sizeof(v4l2_dev->name)); - gemtek_probe(); - if (io) { - if (!request_region(io, 1, "gemtek")) { - printk(KERN_ERR "I/O port 0x%x already in use.\n", io); + v4l2_info(v4l2_dev, "GemTek Radio card driver: v0.0.3\n"); + + mutex_init(>->lock); + + gt->verified = -1; + gt->io = io; + gemtek_probe(gt); + if (gt->io) { + if (!request_region(gt->io, 1, "gemtek")) { + v4l2_err(v4l2_dev, "I/O port 0x%x already in use.\n", gt->io); return -EBUSY; } - if (!gemtek_verify(io)) - printk(KERN_WARNING "Card at I/O port 0x%x does not " + if (!gemtek_verify(gt, gt->io)) + v4l2_warn(v4l2_dev, "Card at I/O port 0x%x does not " "respond properly, check your " - "configuration.\n", io); + "configuration.\n", gt->io); else - printk(KERN_INFO "Using I/O port 0x%x.\n", io); + v4l2_info(v4l2_dev, "Using I/O port 0x%x.\n", gt->io); } else if (probe) { - printk(KERN_ERR "Automatic probing failed and no " + v4l2_err(v4l2_dev, "Automatic probing failed and no " "fixed I/O port defined.\n"); return -ENODEV; } else { - printk(KERN_ERR "Automatic probing disabled but no fixed " + v4l2_err(v4l2_dev, "Automatic probing disabled but no fixed " "I/O port defined."); return -EINVAL; } - video_set_drvdata(&gemtek_radio, &gemtek_unit); + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + release_region(gt->io, 1); + return res; + } - if (video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr) < 0) { - release_region(io, 1); + strlcpy(gt->vdev.name, v4l2_dev->name, sizeof(gt->vdev.name)); + gt->vdev.v4l2_dev = v4l2_dev; + gt->vdev.fops = &gemtek_fops; + gt->vdev.ioctl_ops = &gemtek_ioctl_ops; + gt->vdev.release = video_device_release_empty; + video_set_drvdata(>->vdev, gt); + + if (video_register_device(>->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(gt->io, 1); return -EBUSY; } /* Set defaults */ - gemtek_unit.lastfreq = GEMTEK_LOWFREQ; - gemtek_unit.bu2614data = 0; + gt->lastfreq = GEMTEK_LOWFREQ; + gt->bu2614data = 0; if (initmute) - gemtek_mute(&gemtek_unit); + gemtek_mute(gt); return 0; } @@ -637,15 +598,19 @@ static int __init gemtek_init(void) */ static void __exit gemtek_exit(void) { + struct gemtek *gt = &gemtek_card; + struct v4l2_device *v4l2_dev = >->v4l2_dev; + if (shutdown) { hardmute = 1; /* Turn off PLL */ - gemtek_mute(&gemtek_unit); + gemtek_mute(gt); } else { - printk(KERN_INFO "Module unloaded but card not muted!\n"); + v4l2_info(v4l2_dev, "Module unloaded but card not muted!\n"); } - video_unregister_device(&gemtek_radio); - release_region(io, 1); + video_unregister_device(>->vdev); + v4l2_device_unregister(>->v4l2_dev); + release_region(gt->io, 1); } module_init(gemtek_init); diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c index ba3a13a90013..64d737c35acf 100644 --- a/drivers/media/radio/radio-maestro.c +++ b/drivers/media/radio/radio-maestro.c @@ -22,27 +22,22 @@ #include <linux/init.h> #include <linux/ioport.h> #include <linux/delay.h> -#include <asm/io.h> -#include <asm/uaccess.h> +#include <linux/version.h> /* for KERNEL_VERSION MACRO */ #include <linux/pci.h> #include <linux/videodev2.h> -#include <media/v4l2-common.h> +#include <linux/io.h> +#include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> -#include <linux/version.h> /* for KERNEL_VERSION MACRO */ -#define RADIO_VERSION KERNEL_VERSION(0,0,6) -#define DRIVER_VERSION "0.06" +MODULE_AUTHOR("Adam Tlalka, atlka@pg.gda.pl"); +MODULE_DESCRIPTION("Radio driver for the Maestro PCI sound card radio."); +MODULE_LICENSE("GPL"); -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - } -}; +static int radio_nr = -1; +module_param(radio_nr, int, 0); + +#define RADIO_VERSION KERNEL_VERSION(0, 0, 6) +#define DRIVER_VERSION "0.06" #define GPIO_DATA 0x60 /* port offset from ESS_IO_BASE */ @@ -72,62 +67,27 @@ static struct v4l2_queryctrl radio_qctrl[] = { #define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF) -static int radio_nr = -1; -module_param(radio_nr, int, 0); - -static unsigned long in_use; +struct maestro { + struct v4l2_device v4l2_dev; + struct video_device vdev; + struct pci_dev *pdev; + struct mutex lock; -static int maestro_probe(struct pci_dev *pdev, const struct pci_device_id *ent); + u16 io; /* base of Maestro card radio io (GPIO_DATA)*/ + u16 muted; /* VIDEO_AUDIO_MUTE */ + u16 stereo; /* VIDEO_TUNER_STEREO_ON */ + u16 tuned; /* signal strength (0 or 0xffff) */ +}; -static int maestro_exclusive_open(struct file *file) +static inline struct maestro *to_maestro(struct v4l2_device *v4l2_dev) { - return test_and_set_bit(0, &in_use) ? -EBUSY : 0; + return container_of(v4l2_dev, struct maestro, v4l2_dev); } -static int maestro_exclusive_release(struct file *file) +static u32 radio_bits_get(struct maestro *dev) { - clear_bit(0, &in_use); - return 0; -} - -static void maestro_remove(struct pci_dev *pdev); - -static struct pci_device_id maestro_r_pci_tbl[] = { - { PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1968), - .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8, - .class_mask = 0xffff00 }, - { PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1978), - .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8, - .class_mask = 0xffff00 }, - { 0 } -}; -MODULE_DEVICE_TABLE(pci, maestro_r_pci_tbl); - -static struct pci_driver maestro_r_driver = { - .name = "maestro_radio", - .id_table = maestro_r_pci_tbl, - .probe = maestro_probe, - .remove = __devexit_p(maestro_remove), -}; - -static const struct v4l2_file_operations maestro_fops = { - .owner = THIS_MODULE, - .open = maestro_exclusive_open, - .release = maestro_exclusive_release, - .ioctl = video_ioctl2, -}; - -struct radio_device { - u16 io, /* base of Maestro card radio io (GPIO_DATA)*/ - muted, /* VIDEO_AUDIO_MUTE */ - stereo, /* VIDEO_TUNER_STEREO_ON */ - tuned; /* signal strength (0 or 0xffff) */ -}; - -static u32 radio_bits_get(struct radio_device *dev) -{ - register u16 io=dev->io, l, rdata; - register u32 data=0; + u16 io = dev->io, l, rdata; + u32 data = 0; u16 omask; omask = inw(io + IO_MASK); @@ -135,25 +95,23 @@ static u32 radio_bits_get(struct radio_device *dev) outw(0, io); udelay(16); - for (l=24;l--;) { + for (l = 24; l--;) { outw(STR_CLK, io); /* HI state */ udelay(2); - if(!l) + if (!l) dev->tuned = inw(io) & STR_MOST ? 0 : 0xffff; outw(0, io); /* LO state */ udelay(2); data <<= 1; /* shift data */ rdata = inw(io); - if(!l) - dev->stereo = rdata & STR_MOST ? - 0 : 1; - else - if(rdata & STR_DATA) - data++; + if (!l) + dev->stereo = (rdata & STR_MOST) ? 0 : 1; + else if (rdata & STR_DATA) + data++; udelay(2); } - if(dev->muted) + if (dev->muted) outw(STR_WREN, io); udelay(4); @@ -162,18 +120,18 @@ static u32 radio_bits_get(struct radio_device *dev) return data & 0x3ffe; } -static void radio_bits_set(struct radio_device *dev, u32 data) +static void radio_bits_set(struct maestro *dev, u32 data) { - register u16 io=dev->io, l, bits; + u16 io = dev->io, l, bits; u16 omask, odir; omask = inw(io + IO_MASK); - odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN); + odir = (inw(io + IO_DIR) & ~STR_DATA) | (STR_CLK | STR_WREN); outw(odir | STR_DATA, io + IO_DIR); outw(~(STR_DATA | STR_CLK | STR_WREN), io + IO_MASK); udelay(16); - for (l=25;l;l--) { - bits = ((data >> 18) & STR_DATA) | STR_WREN ; + for (l = 25; l; l--) { + bits = ((data >> 18) & STR_DATA) | STR_WREN; data <<= 1; /* shift data */ outw(bits, io); /* start strobe */ udelay(2); @@ -183,7 +141,7 @@ static void radio_bits_set(struct radio_device *dev, u32 data) udelay(4); } - if(!dev->muted) + if (!dev->muted) outw(0, io); udelay(4); @@ -195,78 +153,79 @@ static void radio_bits_set(struct radio_device *dev, u32 data) static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) { + struct maestro *dev = video_drvdata(file); + strlcpy(v->driver, "radio-maestro", sizeof(v->driver)); strlcpy(v->card, "Maestro Radio", sizeof(v->card)); - sprintf(v->bus_info, "PCI"); + snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev)); v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct radio_device *card = video_drvdata(file); + struct maestro *dev = video_drvdata(file); if (v->index > 0) return -EINVAL; - (void)radio_bits_get(card); + mutex_lock(&dev->lock); + radio_bits_get(dev); - strcpy(v->name, "FM"); + strlcpy(v->name, "FM", sizeof(v->name)); v->type = V4L2_TUNER_RADIO; v->rangelow = FREQ_LO; v->rangehigh = FREQ_HI; - v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; + v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; v->capability = V4L2_TUNER_CAP_LOW; - if(card->stereo) + if (dev->stereo) v->audmode = V4L2_TUNER_MODE_STEREO; else v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = card->tuned; + v->signal = dev->tuned; + mutex_unlock(&dev->lock); return 0; } static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - if (v->index > 0) - return -EINVAL; - return 0; + return v->index ? -EINVAL : 0; } static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct radio_device *card = video_drvdata(file); + struct maestro *dev = video_drvdata(file); if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) return -EINVAL; - radio_bits_set(card, FREQ2BITS(f->frequency)); + mutex_lock(&dev->lock); + radio_bits_set(dev, FREQ2BITS(f->frequency)); + mutex_unlock(&dev->lock); return 0; } static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct radio_device *card = video_drvdata(file); + struct maestro *dev = video_drvdata(file); f->type = V4L2_TUNER_RADIO; - f->frequency = BITS2FREQ(radio_bits_get(card)); + mutex_lock(&dev->lock); + f->frequency = BITS2FREQ(radio_bits_get(dev)); + mutex_unlock(&dev->lock); return 0; } static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc) { - int i; - - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); - return 0; - } + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); } return -EINVAL; } @@ -274,11 +233,11 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct radio_device *card = video_drvdata(file); + struct maestro *dev = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - ctrl->value = card->muted; + ctrl->value = dev->muted; return 0; } return -EINVAL; @@ -287,34 +246,26 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct radio_device *card = video_drvdata(file); - register u16 io = card->io; - register u16 omask = inw(io + IO_MASK); + struct maestro *dev = video_drvdata(file); + u16 io = dev->io; + u16 omask; switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: + mutex_lock(&dev->lock); + omask = inw(io + IO_MASK); outw(~STR_WREN, io + IO_MASK); - outw((card->muted = ctrl->value ) ? - STR_WREN : 0, io); + dev->muted = ctrl->value; + outw(dev->muted ? STR_WREN : 0, io); udelay(4); outw(omask, io + IO_MASK); msleep(125); + mutex_unlock(&dev->lock); return 0; } return -EINVAL; } -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) { *i = 0; @@ -323,20 +274,45 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) { - if (i != 0) - return -EINVAL; + return i ? -EINVAL : 0; +} + +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; return 0; } static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) { - if (a->index != 0) - return -EINVAL; - return 0; + return a->index ? -EINVAL : 0; } -static u16 __devinit radio_power_on(struct radio_device *dev) +static const struct v4l2_file_operations maestro_fops = { + .owner = THIS_MODULE, + .ioctl = video_ioctl2, +}; + +static const struct v4l2_ioctl_ops maestro_ioctl_ops = { + .vidioc_querycap = vidioc_querycap, + .vidioc_g_tuner = vidioc_g_tuner, + .vidioc_s_tuner = vidioc_s_tuner, + .vidioc_g_audio = vidioc_g_audio, + .vidioc_s_audio = vidioc_s_audio, + .vidioc_g_input = vidioc_g_input, + .vidioc_s_input = vidioc_s_input, + .vidioc_g_frequency = vidioc_g_frequency, + .vidioc_s_frequency = vidioc_s_frequency, + .vidioc_queryctrl = vidioc_queryctrl, + .vidioc_g_ctrl = vidioc_g_ctrl, + .vidioc_s_ctrl = vidioc_s_ctrl, +}; + +static u16 __devinit radio_power_on(struct maestro *dev) { register u16 io = dev->io; register u32 ofreq; @@ -360,33 +336,11 @@ static u16 __devinit radio_power_on(struct radio_device *dev) return (ofreq == radio_bits_get(dev)); } -static const struct v4l2_ioctl_ops maestro_ioctl_ops = { - .vidioc_querycap = vidioc_querycap, - .vidioc_g_tuner = vidioc_g_tuner, - .vidioc_s_tuner = vidioc_s_tuner, - .vidioc_g_audio = vidioc_g_audio, - .vidioc_s_audio = vidioc_s_audio, - .vidioc_g_input = vidioc_g_input, - .vidioc_s_input = vidioc_s_input, - .vidioc_g_frequency = vidioc_g_frequency, - .vidioc_s_frequency = vidioc_s_frequency, - .vidioc_queryctrl = vidioc_queryctrl, - .vidioc_g_ctrl = vidioc_g_ctrl, - .vidioc_s_ctrl = vidioc_s_ctrl, -}; - -static struct video_device maestro_radio = { - .name = "Maestro radio", - .fops = &maestro_fops, - .ioctl_ops = &maestro_ioctl_ops, - .release = video_device_release, -}; - static int __devinit maestro_probe(struct pci_dev *pdev, const struct pci_device_id *ent) { - struct radio_device *radio_unit; - struct video_device *maestro_radio_inst; + struct maestro *dev; + struct v4l2_device *v4l2_dev; int retval; retval = pci_enable_device(pdev); @@ -397,46 +351,53 @@ static int __devinit maestro_probe(struct pci_dev *pdev, retval = -ENOMEM; - radio_unit = kzalloc(sizeof(*radio_unit), GFP_KERNEL); - if (radio_unit == NULL) { + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { dev_err(&pdev->dev, "not enough memory\n"); goto err; } - radio_unit->io = pci_resource_start(pdev, 0) + GPIO_DATA; + v4l2_dev = &dev->v4l2_dev; + mutex_init(&dev->lock); + dev->pdev = pdev; - maestro_radio_inst = video_device_alloc(); - if (maestro_radio_inst == NULL) { - dev_err(&pdev->dev, "not enough memory\n"); + strlcpy(v4l2_dev->name, "maestro", sizeof(v4l2_dev->name)); + + retval = v4l2_device_register(&pdev->dev, v4l2_dev); + if (retval < 0) { + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); goto errfr; } - memcpy(maestro_radio_inst, &maestro_radio, sizeof(maestro_radio)); - video_set_drvdata(maestro_radio_inst, radio_unit); - pci_set_drvdata(pdev, maestro_radio_inst); + dev->io = pci_resource_start(pdev, 0) + GPIO_DATA; + + strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); + dev->vdev.v4l2_dev = v4l2_dev; + dev->vdev.fops = &maestro_fops; + dev->vdev.ioctl_ops = &maestro_ioctl_ops; + dev->vdev.release = video_device_release_empty; + video_set_drvdata(&dev->vdev, dev); - retval = video_register_device(maestro_radio_inst, VFL_TYPE_RADIO, radio_nr); + retval = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr); if (retval) { - printk(KERN_ERR "can't register video device!\n"); + v4l2_err(v4l2_dev, "can't register video device!\n"); goto errfr1; } - if (!radio_power_on(radio_unit)) { + if (!radio_power_on(dev)) { retval = -EIO; goto errunr; } - dev_info(&pdev->dev, "version " DRIVER_VERSION " time " __TIME__ " " - __DATE__ "\n"); - dev_info(&pdev->dev, "radio chip initialized\n"); + v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n"); return 0; errunr: - video_unregister_device(maestro_radio_inst); + video_unregister_device(&dev->vdev); errfr1: - video_device_release(maestro_radio_inst); + v4l2_device_unregister(v4l2_dev); errfr: - kfree(radio_unit); + kfree(dev); err: return retval; @@ -444,11 +405,31 @@ err: static void __devexit maestro_remove(struct pci_dev *pdev) { - struct video_device *vdev = pci_get_drvdata(pdev); + struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); + struct maestro *dev = to_maestro(v4l2_dev); - video_unregister_device(vdev); + video_unregister_device(&dev->vdev); + v4l2_device_unregister(&dev->v4l2_dev); } +static struct pci_device_id maestro_r_pci_tbl[] = { + { PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1968), + .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8, + .class_mask = 0xffff00 }, + { PCI_DEVICE(PCI_VENDOR_ID_ESS, PCI_DEVICE_ID_ESS_ESS1978), + .class = PCI_CLASS_MULTIMEDIA_AUDIO << 8, + .class_mask = 0xffff00 }, + { 0 } +}; +MODULE_DEVICE_TABLE(pci, maestro_r_pci_tbl); + +static struct pci_driver maestro_r_driver = { + .name = "maestro_radio", + .id_table = maestro_r_pci_tbl, + .probe = maestro_probe, + .remove = __devexit_p(maestro_remove), +}; + static int __init maestro_radio_init(void) { int retval = pci_register_driver(&maestro_r_driver); @@ -466,7 +447,3 @@ static void __exit maestro_radio_exit(void) module_init(maestro_radio_init); module_exit(maestro_radio_exit); - -MODULE_AUTHOR("Adam Tlalka, atlka@pg.gda.pl"); -MODULE_DESCRIPTION("Radio driver for the Maestro PCI sound card radio."); -MODULE_LICENSE("GPL"); diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c index c5dc00aa9c9f..3da51fe8fb93 100644 --- a/drivers/media/radio/radio-maxiradio.c +++ b/drivers/media/radio/radio-maxiradio.c @@ -37,38 +37,32 @@ #include <linux/init.h> #include <linux/ioport.h> #include <linux/delay.h> -#include <asm/io.h> -#include <asm/uaccess.h> #include <linux/mutex.h> - #include <linux/pci.h> #include <linux/videodev2.h> -#include <media/v4l2-common.h> +#include <linux/version.h> /* for KERNEL_VERSION MACRO */ +#include <linux/io.h> +#include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> +MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net"); +MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio."); +MODULE_LICENSE("GPL"); + +static int radio_nr = -1; +module_param(radio_nr, int, 0); + +static int debug; + +module_param(debug, int, 0644); +MODULE_PARM_DESC(debug, "activates debug info"); + #define DRIVER_VERSION "0.77" -#include <linux/version.h> /* for KERNEL_VERSION MACRO */ -#define RADIO_VERSION KERNEL_VERSION(0,7,7) - -static struct video_device maxiradio_radio; - -#define dprintk(num, fmt, arg...) \ - do { \ - if (maxiradio_radio.debug >= num) \ - printk(KERN_DEBUG "%s: " fmt, \ - maxiradio_radio.name, ## arg); } while (0) - -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - } -}; +#define RADIO_VERSION KERNEL_VERSION(0, 7, 7) + +#define dprintk(dev, num, fmt, arg...) \ + v4l2_dbg(num, debug, &dev->v4l2_dev, fmt, ## arg) #ifndef PCI_VENDOR_ID_GUILLEMOT #define PCI_VENDOR_ID_GUILLEMOT 0x5046 @@ -80,90 +74,70 @@ static struct v4l2_queryctrl radio_qctrl[] = { /* TEA5757 pin mappings */ -static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16 ; - -static int radio_nr = -1; -module_param(radio_nr, int, 0); - -static unsigned long in_use; +static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16; -#define FREQ_LO 50*16000 -#define FREQ_HI 150*16000 +#define FREQ_LO (50 * 16000) +#define FREQ_HI (150 * 16000) #define FREQ_IF 171200 /* 10.7*16000 */ #define FREQ_STEP 200 /* 12.5*16 */ /* (x==fmhz*16*1000) -> bits */ -#define FREQ2BITS(x) ((( (unsigned int)(x)+FREQ_IF+(FREQ_STEP<<1)) \ - /(FREQ_STEP<<2))<<2) +#define FREQ2BITS(x) \ + ((((unsigned int)(x) + FREQ_IF + (FREQ_STEP << 1)) / (FREQ_STEP << 2)) << 2) #define BITS2FREQ(x) ((x) * FREQ_STEP - FREQ_IF) -static int maxiradio_exclusive_open(struct file *file) -{ - return test_and_set_bit(0, &in_use) ? -EBUSY : 0; -} - -static int maxiradio_exclusive_release(struct file *file) +struct maxiradio { - clear_bit(0, &in_use); - return 0; -} + struct v4l2_device v4l2_dev; + struct video_device vdev; + struct pci_dev *pdev; -static const struct v4l2_file_operations maxiradio_fops = { - .owner = THIS_MODULE, - .open = maxiradio_exclusive_open, - .release = maxiradio_exclusive_release, - .ioctl = video_ioctl2, -}; - -static struct radio_device -{ - __u16 io, /* base of radio io */ - muted, /* VIDEO_AUDIO_MUTE */ - stereo, /* VIDEO_TUNER_STEREO_ON */ - tuned; /* signal strength (0 or 0xffff) */ + u16 io; /* base of radio io */ + u16 muted; /* VIDEO_AUDIO_MUTE */ + u16 stereo; /* VIDEO_TUNER_STEREO_ON */ + u16 tuned; /* signal strength (0 or 0xffff) */ unsigned long freq; struct mutex lock; -} radio_unit = { - .muted =1, - .freq = FREQ_LO, }; -static void outbit(unsigned long bit, __u16 io) +static inline struct maxiradio *to_maxiradio(struct v4l2_device *v4l2_dev) { - if (bit != 0) - { - outb( power|wren|data ,io); udelay(4); - outb( power|wren|data|clk ,io); udelay(4); - outb( power|wren|data ,io); udelay(4); - } - else - { - outb( power|wren ,io); udelay(4); - outb( power|wren|clk ,io); udelay(4); - outb( power|wren ,io); udelay(4); - } + return container_of(v4l2_dev, struct maxiradio, v4l2_dev); } -static void turn_power(__u16 io, int p) +static void outbit(unsigned long bit, u16 io) +{ + int val = power | wren | (bit ? data : 0); + + outb(val, io); + udelay(4); + outb(val | clk, io); + udelay(4); + outb(val, io); + udelay(4); +} + +static void turn_power(struct maxiradio *dev, int p) { if (p != 0) { - dprintk(1, "Radio powered on\n"); - outb(power, io); + dprintk(dev, 1, "Radio powered on\n"); + outb(power, dev->io); } else { - dprintk(1, "Radio powered off\n"); - outb(0,io); + dprintk(dev, 1, "Radio powered off\n"); + outb(0, dev->io); } } -static void set_freq(__u16 io, __u32 freq) +static void set_freq(struct maxiradio *dev, u32 freq) { unsigned long int si; int bl; + int io = dev->io; int val = FREQ2BITS(freq); /* TEA5757 shift register bits (see pdf) */ @@ -188,14 +162,14 @@ static void set_freq(__u16 io, __u32 freq) si >>= 1; } - dprintk(1, "Radio freq set to %d.%02d MHz\n", + dprintk(dev, 1, "Radio freq set to %d.%02d MHz\n", freq / 16000, freq % 16000 * 100 / 16000); - turn_power(io, 1); + turn_power(dev, 1); } -static int get_stereo(__u16 io) +static int get_stereo(u16 io) { outb(power,io); udelay(4); @@ -203,7 +177,7 @@ static int get_stereo(__u16 io) return !(inb(io) & mo_st); } -static int get_tune(__u16 io) +static int get_tune(u16 io) { outb(power+clk,io); udelay(4); @@ -212,95 +186,84 @@ static int get_tune(__u16 io) } -static int vidioc_querycap (struct file *file, void *priv, +static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) { - strlcpy(v->driver, "radio-maxiradio", sizeof (v->driver)); - strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof (v->card)); - sprintf(v->bus_info,"ISA"); - v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; + struct maxiradio *dev = video_drvdata(file); + strlcpy(v->driver, "radio-maxiradio", sizeof(v->driver)); + strlcpy(v->card, "Maxi Radio FM2000 radio", sizeof(v->card)); + snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(dev->pdev)); + v->version = RADIO_VERSION; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } -static int vidioc_g_tuner (struct file *file, void *priv, +static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct radio_device *card = video_drvdata(file); + struct maxiradio *dev = video_drvdata(file); if (v->index > 0) return -EINVAL; - memset(v,0,sizeof(*v)); - strcpy(v->name, "FM"); + mutex_lock(&dev->lock); + strlcpy(v->name, "FM", sizeof(v->name)); v->type = V4L2_TUNER_RADIO; - - v->rangelow=FREQ_LO; - v->rangehigh=FREQ_HI; - v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; - v->capability=V4L2_TUNER_CAP_LOW; - if(get_stereo(card->io)) + v->rangelow = FREQ_LO; + v->rangehigh = FREQ_HI; + v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; + v->capability = V4L2_TUNER_CAP_LOW; + if (get_stereo(dev->io)) v->audmode = V4L2_TUNER_MODE_STEREO; else v->audmode = V4L2_TUNER_MODE_MONO; - v->signal=0xffff*get_tune(card->io); + v->signal = 0xffff * get_tune(dev->io); + mutex_unlock(&dev->lock); return 0; } -static int vidioc_s_tuner (struct file *file, void *priv, +static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - if (v->index > 0) - return -EINVAL; - - return 0; -} - -static int vidioc_g_audio (struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "FM"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; + return v->index ? -EINVAL : 0; } static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) { *i = 0; - return 0; } static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) { - if (i != 0) - return -EINVAL; + return i ? -EINVAL : 0; +} +static int vidioc_g_audio(struct file *file, void *priv, + struct v4l2_audio *a) +{ + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; return 0; } -static int vidioc_s_audio (struct file *file, void *priv, +static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a) { - if (a->index != 0) - return -EINVAL; - - return 0; + return a->index ? -EINVAL : 0; } -static int vidioc_s_frequency (struct file *file, void *priv, +static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct radio_device *card = video_drvdata(file); + struct maxiradio *dev = video_drvdata(file); if (f->frequency < FREQ_LO || f->frequency > FREQ_HI) { - dprintk(1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n", + dprintk(dev, 1, "radio freq (%d.%02d MHz) out of range (%d-%d)\n", f->frequency / 16000, f->frequency % 16000 * 100 / 16000, FREQ_LO / 16000, FREQ_HI / 16000); @@ -308,75 +271,79 @@ static int vidioc_s_frequency (struct file *file, void *priv, return -EINVAL; } - card->freq = f->frequency; - set_freq(card->io, card->freq); + mutex_lock(&dev->lock); + dev->freq = f->frequency; + set_freq(dev, dev->freq); msleep(125); + mutex_unlock(&dev->lock); return 0; } -static int vidioc_g_frequency (struct file *file, void *priv, +static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct radio_device *card = video_drvdata(file); + struct maxiradio *dev = video_drvdata(file); f->type = V4L2_TUNER_RADIO; - f->frequency = card->freq; + f->frequency = dev->freq; - dprintk(4, "radio freq is %d.%02d MHz", + dprintk(dev, 4, "radio freq is %d.%02d MHz", f->frequency / 16000, f->frequency % 16000 * 100 / 16000); return 0; } -static int vidioc_queryctrl (struct file *file, void *priv, +static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc) { - int i; - - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); - return (0); - } + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); } - return -EINVAL; } -static int vidioc_g_ctrl (struct file *file, void *priv, - struct v4l2_control *ctrl) +static int vidioc_g_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) { - struct radio_device *card = video_drvdata(file); + struct maxiradio *dev = video_drvdata(file); switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - ctrl->value=card->muted; - return (0); + case V4L2_CID_AUDIO_MUTE: + ctrl->value = dev->muted; + return 0; } return -EINVAL; } -static int vidioc_s_ctrl (struct file *file, void *priv, - struct v4l2_control *ctrl) +static int vidioc_s_ctrl(struct file *file, void *priv, + struct v4l2_control *ctrl) { - struct radio_device *card = video_drvdata(file); + struct maxiradio *dev = video_drvdata(file); switch (ctrl->id) { - case V4L2_CID_AUDIO_MUTE: - card->muted = ctrl->value; - if(card->muted) - turn_power(card->io, 0); - else - set_freq(card->io, card->freq); - return 0; + case V4L2_CID_AUDIO_MUTE: + mutex_lock(&dev->lock); + dev->muted = ctrl->value; + if (dev->muted) + turn_power(dev, 0); + else + set_freq(dev, dev->freq); + mutex_unlock(&dev->lock); + return 0; } return -EINVAL; } +static const struct v4l2_file_operations maxiradio_fops = { + .owner = THIS_MODULE, + .ioctl = video_ioctl2, +}; + static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = { .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, @@ -392,60 +359,84 @@ static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = { .vidioc_s_ctrl = vidioc_s_ctrl, }; -static struct video_device maxiradio_radio = { - .name = "Maxi Radio FM2000 radio", - .fops = &maxiradio_fops, - .ioctl_ops = &maxiradio_ioctl_ops, - .release = video_device_release_empty, -}; - static int __devinit maxiradio_init_one(struct pci_dev *pdev, const struct pci_device_id *ent) { - if(!request_region(pci_resource_start(pdev, 0), + struct maxiradio *dev; + struct v4l2_device *v4l2_dev; + int retval = -ENOMEM; + + dev = kzalloc(sizeof(*dev), GFP_KERNEL); + if (dev == NULL) { + dev_err(&pdev->dev, "not enough memory\n"); + return -ENOMEM; + } + + v4l2_dev = &dev->v4l2_dev; + mutex_init(&dev->lock); + dev->pdev = pdev; + dev->muted = 1; + dev->freq = FREQ_LO; + + strlcpy(v4l2_dev->name, "maxiradio", sizeof(v4l2_dev->name)); + + retval = v4l2_device_register(&pdev->dev, v4l2_dev); + if (retval < 0) { + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + goto errfr; + } + + if (!request_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0), "Maxi Radio FM 2000")) { - printk(KERN_ERR "radio-maxiradio: can't reserve I/O ports\n"); + v4l2_err(v4l2_dev, "can't reserve I/O ports\n"); goto err_out; } if (pci_enable_device(pdev)) goto err_out_free_region; - radio_unit.io = pci_resource_start(pdev, 0); - mutex_init(&radio_unit.lock); - video_set_drvdata(&maxiradio_radio, &radio_unit); + dev->io = pci_resource_start(pdev, 0); + strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); + dev->vdev.v4l2_dev = v4l2_dev; + dev->vdev.fops = &maxiradio_fops; + dev->vdev.ioctl_ops = &maxiradio_ioctl_ops; + dev->vdev.release = video_device_release_empty; + video_set_drvdata(&dev->vdev, dev); - if (video_register_device(&maxiradio_radio, VFL_TYPE_RADIO, radio_nr) < 0) { - printk("radio-maxiradio: can't register device!"); + if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_err(v4l2_dev, "can't register device!"); goto err_out_free_region; } - printk(KERN_INFO "radio-maxiradio: version " - DRIVER_VERSION - " time " - __TIME__ " " - __DATE__ - "\n"); + v4l2_info(v4l2_dev, "version " DRIVER_VERSION + " time " __TIME__ " " __DATE__ "\n"); - printk(KERN_INFO "radio-maxiradio: found Guillemot MAXI Radio device (io = 0x%x)\n", - radio_unit.io); + v4l2_info(v4l2_dev, "found Guillemot MAXI Radio device (io = 0x%x)\n", + dev->io); return 0; err_out_free_region: release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); err_out: + v4l2_device_unregister(v4l2_dev); +errfr: + kfree(dev); return -ENODEV; } static void __devexit maxiradio_remove_one(struct pci_dev *pdev) { - video_unregister_device(&maxiradio_radio); + struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev); + struct maxiradio *dev = to_maxiradio(v4l2_dev); + + video_unregister_device(&dev->vdev); + v4l2_device_unregister(&dev->v4l2_dev); release_region(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0)); } static struct pci_device_id maxiradio_pci_tbl[] = { { PCI_VENDOR_ID_GUILLEMOT, PCI_DEVICE_ID_GUILLEMOT_MAXIRADIO, PCI_ANY_ID, PCI_ANY_ID, }, - { 0,} + { 0 } }; MODULE_DEVICE_TABLE(pci, maxiradio_pci_tbl); @@ -469,10 +460,3 @@ static void __exit maxiradio_radio_exit(void) module_init(maxiradio_radio_init); module_exit(maxiradio_radio_exit); - -MODULE_AUTHOR("Dimitromanolakis Apostolos, apdim@grecian.net"); -MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2000 radio."); -MODULE_LICENSE("GPL"); - -module_param_named(debug,maxiradio_radio.debug, int, 0644); -MODULE_PARM_DESC(debug,"activates debug info"); diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c index fdfc7bf86b9e..cab19d05e02f 100644 --- a/drivers/media/radio/radio-mr800.c +++ b/drivers/media/radio/radio-mr800.c @@ -22,7 +22,7 @@ */ /* - * Big thanks to authors of dsbr100.c and radio-si470x.c + * Big thanks to authors and contributors of dsbr100.c and radio-si470x.c * * When work was looked pretty good, i discover this: * http://av-usbradio.sourceforge.net/index.php @@ -30,18 +30,24 @@ * Latest release of theirs project was in 2005. * Probably, this driver could be improved trough using their * achievements (specifications given). - * So, we have smth to begin with. + * Also, Faidon Liambotis <paravoid@debian.org> wrote nice driver for this radio + * in 2007. He allowed to use his driver to improve current mr800 radio driver. + * http://kerneltrap.org/mailarchive/linux-usb-devel/2007/10/11/342492 * - * History: * Version 0.01: First working version. * It's required to blacklist AverMedia USB Radio * in usbhid/hid-quirks.c + * Version 0.10: A lot of cleanups and fixes: unpluging the device, + * few mutex locks were added, codinstyle issues, etc. + * Added stereo support. Thanks to + * Douglas Schilling Landgraf <dougsland@gmail.com> and + * David Ellingsworth <david@identd.dyndns.org> + * for discussion, help and support. + * Version 0.11: Converted to v4l2_device. * * Many things to do: * - Correct power managment of device (suspend & resume) - * - Make x86 independance (little-endian and big-endian stuff) * - Add code for scanning and smooth tuning - * - Checked and add stereo&mono stuff * - Add code for sensitivity value * - Correct mistakes * - In Japan another FREQ_MIN and FREQ_MAX @@ -54,7 +60,7 @@ #include <linux/slab.h> #include <linux/input.h> #include <linux/videodev2.h> -#include <media/v4l2-common.h> +#include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> #include <linux/usb.h> #include <linux/version.h> /* for KERNEL_VERSION MACRO */ @@ -62,8 +68,8 @@ /* driver and module definitions */ #define DRIVER_AUTHOR "Alexey Klimov <klimov.linux@gmail.com>" #define DRIVER_DESC "AverMedia MR 800 USB FM radio driver" -#define DRIVER_VERSION "0.01" -#define RADIO_VERSION KERNEL_VERSION(0, 0, 1) +#define DRIVER_VERSION "0.11" +#define RADIO_VERSION KERNEL_VERSION(0, 1, 1) MODULE_AUTHOR(DRIVER_AUTHOR); MODULE_DESCRIPTION(DRIVER_DESC); @@ -87,43 +93,27 @@ devices, that would be 76 and 91. */ #define FREQ_MAX 108.0 #define FREQ_MUL 16000 +/* + * Commands that device should understand + * List isnt full and will be updated with implementation of new functions + */ +#define AMRADIO_SET_FREQ 0xa4 +#define AMRADIO_SET_MUTE 0xab +#define AMRADIO_SET_MONO 0xae + +/* Comfortable defines for amradio_set_mute */ +#define AMRADIO_START 0x00 +#define AMRADIO_STOP 0x01 + +/* Comfortable defines for amradio_set_stereo */ +#define WANT_STEREO 0x00 +#define WANT_MONO 0x01 + /* module parameter */ static int radio_nr = -1; module_param(radio_nr, int, 0); MODULE_PARM_DESC(radio_nr, "Radio Nr"); -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .step = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, -/* HINT: the disabled controls are only here to satify kradio and such apps */ - { .id = V4L2_CID_AUDIO_VOLUME, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_BALANCE, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_BASS, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_TREBLE, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, - { - .id = V4L2_CID_AUDIO_LOUDNESS, - .flags = V4L2_CTRL_FLAG_DISABLED, - }, -}; - static int usb_amradio_probe(struct usb_interface *intf, const struct usb_device_id *id); static void usb_amradio_disconnect(struct usb_interface *intf); @@ -138,6 +128,7 @@ struct amradio_device { /* reference to USB and video device */ struct usb_device *usbdev; struct video_device *videodev; + struct v4l2_device v4l2_dev; unsigned char *buffer; struct mutex lock; /* buffer locking */ @@ -169,43 +160,48 @@ static struct usb_driver usb_amradio_driver = { .supports_autosuspend = 0, }; -/* switch on radio. Send 8 bytes to device. */ -static int amradio_start(struct amradio_device *radio) +/* switch on/off the radio. Send 8 bytes to device */ +static int amradio_set_mute(struct amradio_device *radio, char argument) { int retval; int size; + /* safety check */ + if (radio->removed) + return -EIO; + mutex_lock(&radio->lock); radio->buffer[0] = 0x00; radio->buffer[1] = 0x55; radio->buffer[2] = 0xaa; radio->buffer[3] = 0x00; - radio->buffer[4] = 0xab; - radio->buffer[5] = 0x00; + radio->buffer[4] = AMRADIO_SET_MUTE; + radio->buffer[5] = argument; radio->buffer[6] = 0x00; radio->buffer[7] = 0x00; retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); - if (retval) { + if (retval < 0 || size != BUFFER_LENGTH) { mutex_unlock(&radio->lock); return retval; } - radio->muted = 0; + radio->muted = argument; mutex_unlock(&radio->lock); return retval; } -/* switch off radio */ -static int amradio_stop(struct amradio_device *radio) +/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ +static int amradio_setfreq(struct amradio_device *radio, int freq) { int retval; int size; + unsigned short freq_send = 0x10 + (freq >> 3) / 25; /* safety check */ if (radio->removed) @@ -216,33 +212,46 @@ static int amradio_stop(struct amradio_device *radio) radio->buffer[0] = 0x00; radio->buffer[1] = 0x55; radio->buffer[2] = 0xaa; - radio->buffer[3] = 0x00; - radio->buffer[4] = 0xab; - radio->buffer[5] = 0x01; + radio->buffer[3] = 0x03; + radio->buffer[4] = AMRADIO_SET_FREQ; + radio->buffer[5] = 0x00; radio->buffer[6] = 0x00; - radio->buffer[7] = 0x00; + radio->buffer[7] = 0x08; retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); - if (retval) { + if (retval < 0 || size != BUFFER_LENGTH) { mutex_unlock(&radio->lock); return retval; } - radio->muted = 1; + /* frequency is calculated from freq_send and placed in first 2 bytes */ + radio->buffer[0] = (freq_send >> 8) & 0xff; + radio->buffer[1] = freq_send & 0xff; + radio->buffer[2] = 0x01; + radio->buffer[3] = 0x00; + radio->buffer[4] = 0x00; + /* 5 and 6 bytes of buffer already = 0x00 */ + radio->buffer[7] = 0x00; + + retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), + (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); + + if (retval < 0 || size != BUFFER_LENGTH) { + mutex_unlock(&radio->lock); + return retval; + } mutex_unlock(&radio->lock); return retval; } -/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */ -static int amradio_setfreq(struct amradio_device *radio, int freq) +static int amradio_set_stereo(struct amradio_device *radio, char argument) { int retval; int size; - unsigned short freq_send = 0x13 + (freq >> 3) / 25; /* safety check */ if (radio->removed) @@ -253,50 +262,33 @@ static int amradio_setfreq(struct amradio_device *radio, int freq) radio->buffer[0] = 0x00; radio->buffer[1] = 0x55; radio->buffer[2] = 0xaa; - radio->buffer[3] = 0x03; - radio->buffer[4] = 0xa4; - radio->buffer[5] = 0x00; - radio->buffer[6] = 0x00; - radio->buffer[7] = 0x08; - - retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), - (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); - - if (retval) { - mutex_unlock(&radio->lock); - return retval; - } - - /* frequency is calculated from freq_send and placed in first 2 bytes */ - radio->buffer[0] = (freq_send >> 8) & 0xff; - radio->buffer[1] = freq_send & 0xff; - radio->buffer[2] = 0x01; radio->buffer[3] = 0x00; - radio->buffer[4] = 0x00; - /* 5 and 6 bytes of buffer already = 0x00 */ + radio->buffer[4] = AMRADIO_SET_MONO; + radio->buffer[5] = argument; + radio->buffer[6] = 0x00; radio->buffer[7] = 0x00; retval = usb_bulk_msg(radio->usbdev, usb_sndintpipe(radio->usbdev, 2), (void *) (radio->buffer), BUFFER_LENGTH, &size, USB_TIMEOUT); - if (retval) { + if (retval < 0 || size != BUFFER_LENGTH) { + radio->stereo = -1; mutex_unlock(&radio->lock); return retval; } - radio->stereo = 0; + radio->stereo = 1; mutex_unlock(&radio->lock); return retval; } -/* USB subsystem interface begins here */ - -/* handle unplugging of the device, release data structures -if nothing keeps us from doing it. If something is still -keeping us busy, the release callback of v4l will take care -of releasing it. */ +/* Handle unplugging the device. + * We call video_unregister_device in any case. + * The last function called in this procedure is + * usb_amradio_device_release. + */ static void usb_amradio_disconnect(struct usb_interface *intf) { struct amradio_device *radio = usb_get_intfdata(intf); @@ -307,15 +299,18 @@ static void usb_amradio_disconnect(struct usb_interface *intf) usb_set_intfdata(intf, NULL); video_unregister_device(radio->videodev); + v4l2_device_disconnect(&radio->v4l2_dev); } /* vidioc_querycap - query device capabilities */ static int vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *v) { + struct amradio_device *radio = video_drvdata(file); + strlcpy(v->driver, "radio-mr800", sizeof(v->driver)); strlcpy(v->card, "AverMedia MR 800 USB FM Radio", sizeof(v->card)); - sprintf(v->bus_info, "USB"); + usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info)); v->version = RADIO_VERSION; v->capabilities = V4L2_CAP_TUNER; return 0; @@ -326,6 +321,7 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { struct amradio_device *radio = video_get_drvdata(video_devdata(file)); + int retval; /* safety check */ if (radio->removed) @@ -337,7 +333,16 @@ static int vidioc_g_tuner(struct file *file, void *priv, /* TODO: Add function which look is signal stereo or not * amradio_getstat(radio); */ - radio->stereo = -1; + +/* we call amradio_set_stereo to set radio->stereo + * Honestly, amradio_getstat should cover this in future and + * amradio_set_stereo shouldn't be here + */ + retval = amradio_set_stereo(radio, WANT_STEREO); + if (retval < 0) + amradio_dev_warn(&radio->videodev->dev, + "set stereo failed\n"); + strcpy(v->name, "FM"); v->type = V4L2_TUNER_RADIO; v->rangelow = FREQ_MIN * FREQ_MUL; @@ -358,6 +363,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { struct amradio_device *radio = video_get_drvdata(video_devdata(file)); + int retval; /* safety check */ if (radio->removed) @@ -365,6 +371,25 @@ static int vidioc_s_tuner(struct file *file, void *priv, if (v->index > 0) return -EINVAL; + + /* mono/stereo selector */ + switch (v->audmode) { + case V4L2_TUNER_MODE_MONO: + retval = amradio_set_stereo(radio, WANT_MONO); + if (retval < 0) + amradio_dev_warn(&radio->videodev->dev, + "set mono failed\n"); + break; + case V4L2_TUNER_MODE_STEREO: + retval = amradio_set_stereo(radio, WANT_STEREO); + if (retval < 0) + amradio_dev_warn(&radio->videodev->dev, + "set stereo failed\n"); + break; + default: + return -EINVAL; + } + return 0; } @@ -373,13 +398,18 @@ static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { struct amradio_device *radio = video_get_drvdata(video_devdata(file)); + int retval; /* safety check */ if (radio->removed) return -EIO; + mutex_lock(&radio->lock); radio->curfreq = f->frequency; - if (amradio_setfreq(radio, radio->curfreq) < 0) + mutex_unlock(&radio->lock); + + retval = amradio_setfreq(radio, radio->curfreq); + if (retval < 0) amradio_dev_warn(&radio->videodev->dev, "set frequency failed\n"); return 0; @@ -404,14 +434,11 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc) { - int i; - - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); - return 0; - } + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); } + return -EINVAL; } @@ -438,6 +465,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { struct amradio_device *radio = video_get_drvdata(video_devdata(file)); + int retval; /* safety check */ if (radio->removed) @@ -446,13 +474,15 @@ static int vidioc_s_ctrl(struct file *file, void *priv, switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: if (ctrl->value) { - if (amradio_stop(radio) < 0) { + retval = amradio_set_mute(radio, AMRADIO_STOP); + if (retval < 0) { amradio_dev_warn(&radio->videodev->dev, "amradio_stop failed\n"); return -1; } } else { - if (amradio_start(radio) < 0) { + retval = amradio_set_mute(radio, AMRADIO_START); + if (retval < 0) { amradio_dev_warn(&radio->videodev->dev, "amradio_start failed\n"); return -1; @@ -503,20 +533,29 @@ static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) static int usb_amradio_open(struct file *file) { struct amradio_device *radio = video_get_drvdata(video_devdata(file)); + int retval; lock_kernel(); radio->users = 1; radio->muted = 1; - if (amradio_start(radio) < 0) { + retval = amradio_set_mute(radio, AMRADIO_START); + if (retval < 0) { amradio_dev_warn(&radio->videodev->dev, "radio did not start up properly\n"); radio->users = 0; unlock_kernel(); return -EIO; } - if (amradio_setfreq(radio, radio->curfreq) < 0) + + retval = amradio_set_stereo(radio, WANT_STEREO); + if (retval < 0) + amradio_dev_warn(&radio->videodev->dev, + "set stereo failed\n"); + + retval = amradio_setfreq(radio, radio->curfreq); + if (retval < 0) amradio_dev_warn(&radio->videodev->dev, "set frequency failed\n"); @@ -533,10 +572,12 @@ static int usb_amradio_close(struct file *file) if (!radio) return -ENODEV; + mutex_lock(&radio->lock); radio->users = 0; + mutex_unlock(&radio->lock); if (!radio->removed) { - retval = amradio_stop(radio); + retval = amradio_set_mute(radio, AMRADIO_STOP); if (retval < 0) amradio_dev_warn(&radio->videodev->dev, "amradio_stop failed\n"); @@ -549,8 +590,10 @@ static int usb_amradio_close(struct file *file) static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message) { struct amradio_device *radio = usb_get_intfdata(intf); + int retval; - if (amradio_stop(radio) < 0) + retval = amradio_set_mute(radio, AMRADIO_STOP); + if (retval < 0) dev_warn(&intf->dev, "amradio_stop failed\n"); dev_info(&intf->dev, "going into suspend..\n"); @@ -562,8 +605,10 @@ static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message) static int usb_amradio_resume(struct usb_interface *intf) { struct amradio_device *radio = usb_get_intfdata(intf); + int retval; - if (amradio_start(radio) < 0) + retval = amradio_set_mute(radio, AMRADIO_START); + if (retval < 0) dev_warn(&intf->dev, "amradio_start failed\n"); dev_info(&intf->dev, "coming out of suspend..\n"); @@ -594,67 +639,82 @@ static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = { .vidioc_s_input = vidioc_s_input, }; -static void usb_amradio_device_release(struct video_device *videodev) +static void usb_amradio_video_device_release(struct video_device *videodev) { struct amradio_device *radio = video_get_drvdata(videodev); /* we call v4l to free radio->videodev */ video_device_release(videodev); + v4l2_device_unregister(&radio->v4l2_dev); + /* free rest memory */ kfree(radio->buffer); kfree(radio); } -/* V4L2 interface */ -static struct video_device amradio_videodev_template = { - .name = "AverMedia MR 800 USB FM Radio", - .fops = &usb_amradio_fops, - .ioctl_ops = &usb_amradio_ioctl_ops, - .release = usb_amradio_device_release, -}; - -/* check if the device is present and register with v4l and -usb if it is */ +/* check if the device is present and register with v4l and usb if it is */ static int usb_amradio_probe(struct usb_interface *intf, const struct usb_device_id *id) { struct amradio_device *radio; + struct v4l2_device *v4l2_dev; + int retval; - radio = kmalloc(sizeof(struct amradio_device), GFP_KERNEL); + radio = kzalloc(sizeof(struct amradio_device), GFP_KERNEL); - if (!(radio)) + if (!radio) { + dev_err(&intf->dev, "kmalloc for amradio_device failed\n"); return -ENOMEM; + } radio->buffer = kmalloc(BUFFER_LENGTH, GFP_KERNEL); - if (!(radio->buffer)) { + if (!radio->buffer) { + dev_err(&intf->dev, "kmalloc for radio->buffer failed\n"); kfree(radio); return -ENOMEM; } + v4l2_dev = &radio->v4l2_dev; + retval = v4l2_device_register(&intf->dev, v4l2_dev); + if (retval < 0) { + dev_err(&intf->dev, "couldn't register v4l2_device\n"); + kfree(radio->buffer); + kfree(radio); + return retval; + } + radio->videodev = video_device_alloc(); - if (!(radio->videodev)) { + if (!radio->videodev) { + dev_err(&intf->dev, "video_device_alloc failed\n"); kfree(radio->buffer); kfree(radio); return -ENOMEM; } - memcpy(radio->videodev, &amradio_videodev_template, - sizeof(amradio_videodev_template)); + strlcpy(radio->videodev->name, v4l2_dev->name, sizeof(radio->videodev->name)); + radio->videodev->v4l2_dev = v4l2_dev; + radio->videodev->fops = &usb_amradio_fops; + radio->videodev->ioctl_ops = &usb_amradio_ioctl_ops; + radio->videodev->release = usb_amradio_video_device_release; radio->removed = 0; radio->users = 0; radio->usbdev = interface_to_usbdev(intf); radio->curfreq = 95.16 * FREQ_MUL; + radio->stereo = -1; mutex_init(&radio->lock); video_set_drvdata(radio->videodev, radio); - if (video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr)) { - dev_warn(&intf->dev, "could not register video device\n"); + + retval = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr); + if (retval < 0) { + dev_err(&intf->dev, "could not register video device\n"); video_device_release(radio->videodev); + v4l2_device_unregister(v4l2_dev); kfree(radio->buffer); kfree(radio); return -EIO; diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c index 2587227214bf..9cb193fa6e33 100644 --- a/drivers/media/radio/radio-rtrack2.c +++ b/drivers/media/radio/radio-rtrack2.c @@ -13,34 +13,16 @@ #include <linux/init.h> /* Initdata */ #include <linux/ioport.h> /* request_region */ #include <linux/delay.h> /* udelay */ -#include <asm/io.h> /* outb, outb_p */ -#include <asm/uaccess.h> /* copy to/from user */ #include <linux/videodev2.h> /* kernel radio structs */ -#include <media/v4l2-common.h> +#include <linux/mutex.h> +#include <linux/version.h> /* for KERNEL_VERSION MACRO */ +#include <linux/io.h> /* outb, outb_p */ +#include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> -#include <linux/spinlock.h> -#include <linux/version.h> /* for KERNEL_VERSION MACRO */ -#define RADIO_VERSION KERNEL_VERSION(0,0,2) - -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 65535, - .step = 65535, - .default_value = 0xff, - .type = V4L2_CTRL_TYPE_INTEGER, - } -}; +MODULE_AUTHOR("Ben Pfaff"); +MODULE_DESCRIPTION("A driver for the RadioTrack II radio card."); +MODULE_LICENSE("GPL"); #ifndef CONFIG_RADIO_RTRACK2_PORT #define CONFIG_RADIO_RTRACK2_PORT -1 @@ -48,79 +30,88 @@ static struct v4l2_queryctrl radio_qctrl[] = { static int io = CONFIG_RADIO_RTRACK2_PORT; static int radio_nr = -1; -static spinlock_t lock; -struct rt_device +module_param(io, int, 0); +MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)"); +module_param(radio_nr, int, 0); + +#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) + +struct rtrack2 { - unsigned long in_use; - int port; + struct v4l2_device v4l2_dev; + struct video_device vdev; + int io; unsigned long curfreq; int muted; + struct mutex lock; }; +static struct rtrack2 rtrack2_card; + /* local things */ -static void rt_mute(struct rt_device *dev) +static void rt_mute(struct rtrack2 *dev) { - if(dev->muted) + if (dev->muted) return; - spin_lock(&lock); - outb(1, io); - spin_unlock(&lock); + mutex_lock(&dev->lock); + outb(1, dev->io); + mutex_unlock(&dev->lock); dev->muted = 1; } -static void rt_unmute(struct rt_device *dev) +static void rt_unmute(struct rtrack2 *dev) { if(dev->muted == 0) return; - spin_lock(&lock); - outb(0, io); - spin_unlock(&lock); + mutex_lock(&dev->lock); + outb(0, dev->io); + mutex_unlock(&dev->lock); dev->muted = 0; } -static void zero(void) +static void zero(struct rtrack2 *dev) { - outb_p(1, io); - outb_p(3, io); - outb_p(1, io); + outb_p(1, dev->io); + outb_p(3, dev->io); + outb_p(1, dev->io); } -static void one(void) +static void one(struct rtrack2 *dev) { - outb_p(5, io); - outb_p(7, io); - outb_p(5, io); + outb_p(5, dev->io); + outb_p(7, dev->io); + outb_p(5, dev->io); } -static int rt_setfreq(struct rt_device *dev, unsigned long freq) +static int rt_setfreq(struct rtrack2 *dev, unsigned long freq) { int i; + mutex_lock(&dev->lock); + dev->curfreq = freq; freq = freq / 200 + 856; - spin_lock(&lock); - - outb_p(0xc8, io); - outb_p(0xc9, io); - outb_p(0xc9, io); + outb_p(0xc8, dev->io); + outb_p(0xc9, dev->io); + outb_p(0xc9, dev->io); for (i = 0; i < 10; i++) - zero (); + zero(dev); for (i = 14; i >= 0; i--) if (freq & (1 << i)) - one (); + one(dev); else - zero (); + zero(dev); - outb_p(0xc8, io); + outb_p(0xc8, dev->io); if (!dev->muted) - outb_p(0, io); + outb_p(0, dev->io); - spin_unlock(&lock); + mutex_unlock(&dev->lock); return 0; } @@ -129,61 +120,61 @@ static int vidioc_querycap(struct file *file, void *priv, { strlcpy(v->driver, "radio-rtrack2", sizeof(v->driver)); strlcpy(v->card, "RadioTrack II", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - if (v->index > 0) - return -EINVAL; - - return 0; + return v->index ? -EINVAL : 0; } -static int rt_getsigstr(struct rt_device *dev) +static int rt_getsigstr(struct rtrack2 *dev) { - if (inb(io) & 2) /* bit set = no signal present */ - return 0; - return 1; /* signal present */ + int sig = 1; + + mutex_lock(&dev->lock); + if (inb(dev->io) & 2) /* bit set = no signal present */ + sig = 0; + mutex_unlock(&dev->lock); + return sig; } static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct rt_device *rt = video_drvdata(file); + struct rtrack2 *rt = video_drvdata(file); if (v->index > 0) return -EINVAL; - strcpy(v->name, "FM"); + strlcpy(v->name, "FM", sizeof(v->name)); v->type = V4L2_TUNER_RADIO; - v->rangelow = (88*16000); - v->rangehigh = (108*16000); + v->rangelow = 88 * 16000; + v->rangehigh = 108 * 16000; v->rxsubchans = V4L2_TUNER_SUB_MONO; v->capability = V4L2_TUNER_CAP_LOW; v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xFFFF*rt_getsigstr(rt); + v->signal = 0xFFFF * rt_getsigstr(rt); return 0; } static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct rt_device *rt = video_drvdata(file); + struct rtrack2 *rt = video_drvdata(file); - rt->curfreq = f->frequency; - rt_setfreq(rt, rt->curfreq); + rt_setfreq(rt, f->frequency); return 0; } static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct rt_device *rt = video_drvdata(file); + struct rtrack2 *rt = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = rt->curfreq; @@ -193,14 +184,11 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc) { - int i; - - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); - return 0; - } + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535); } return -EINVAL; } @@ -208,7 +196,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct rt_device *rt = video_drvdata(file); + struct rtrack2 *rt = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -227,7 +215,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct rt_device *rt = video_drvdata(file); + struct rtrack2 *rt = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -246,17 +234,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv, return -EINVAL; } -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) { *i = 0; @@ -265,36 +242,26 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) { - if (i != 0) - return -EINVAL; - return 0; + return i ? -EINVAL : 0; } -static int vidioc_s_audio(struct file *file, void *priv, +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) { - if (a->index != 0) - return -EINVAL; + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; return 0; } -static struct rt_device rtrack2_unit; - -static int rtrack2_exclusive_open(struct file *file) -{ - return test_and_set_bit(0, &rtrack2_unit.in_use) ? -EBUSY : 0; -} - -static int rtrack2_exclusive_release(struct file *file) +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) { - clear_bit(0, &rtrack2_unit.in_use); - return 0; + return a->index ? -EINVAL : 0; } static const struct v4l2_file_operations rtrack2_fops = { .owner = THIS_MODULE, - .open = rtrack2_exclusive_open, - .release = rtrack2_exclusive_release, .ioctl = video_ioctl2, }; @@ -313,62 +280,61 @@ static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = { .vidioc_s_input = vidioc_s_input, }; -static struct video_device rtrack2_radio = { - .name = "RadioTrack II radio", - .fops = &rtrack2_fops, - .ioctl_ops = &rtrack2_ioctl_ops, - .release = video_device_release_empty, -}; - static int __init rtrack2_init(void) { - if(io==-1) - { - printk(KERN_ERR "You must set an I/O address with io=0x20c or io=0x30c\n"); + struct rtrack2 *dev = &rtrack2_card; + struct v4l2_device *v4l2_dev = &dev->v4l2_dev; + int res; + + strlcpy(v4l2_dev->name, "rtrack2", sizeof(v4l2_dev->name)); + dev->io = io; + if (dev->io == -1) { + v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or io=0x30c\n"); return -EINVAL; } - if (!request_region(io, 4, "rtrack2")) - { - printk(KERN_ERR "rtrack2: port 0x%x already in use\n", io); + if (!request_region(dev->io, 4, "rtrack2")) { + v4l2_err(v4l2_dev, "port 0x%x already in use\n", dev->io); return -EBUSY; } - video_set_drvdata(&rtrack2_radio, &rtrack2_unit); + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + release_region(dev->io, 4); + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return res; + } - spin_lock_init(&lock); - if (video_register_device(&rtrack2_radio, VFL_TYPE_RADIO, radio_nr) < 0) { - release_region(io, 4); + strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); + dev->vdev.v4l2_dev = v4l2_dev; + dev->vdev.fops = &rtrack2_fops; + dev->vdev.ioctl_ops = &rtrack2_ioctl_ops; + dev->vdev.release = video_device_release_empty; + video_set_drvdata(&dev->vdev, dev); + + mutex_init(&dev->lock); + if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(dev->io, 4); return -EINVAL; } - printk(KERN_INFO "AIMSlab Radiotrack II card driver.\n"); + v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n"); /* mute card - prevents noisy bootups */ - outb(1, io); - rtrack2_unit.muted = 1; + outb(1, dev->io); + dev->muted = 1; return 0; } -MODULE_AUTHOR("Ben Pfaff"); -MODULE_DESCRIPTION("A driver for the RadioTrack II radio card."); -MODULE_LICENSE("GPL"); - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)"); -module_param(radio_nr, int, 0); - -static void __exit rtrack2_cleanup_module(void) +static void __exit rtrack2_exit(void) { - video_unregister_device(&rtrack2_radio); - release_region(io,4); + struct rtrack2 *dev = &rtrack2_card; + + video_unregister_device(&dev->vdev); + v4l2_device_unregister(&dev->v4l2_dev); + release_region(dev->io, 4); } module_init(rtrack2_init); -module_exit(rtrack2_cleanup_module); - -/* - Local variables: - compile-command: "mmake" - End: -*/ +module_exit(rtrack2_exit); diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c index d358e48c2422..1dba8f0832a0 100644 --- a/drivers/media/radio/radio-sf16fmi.c +++ b/drivers/media/radio/radio-sf16fmi.c @@ -22,113 +22,109 @@ #include <linux/init.h> /* Initdata */ #include <linux/ioport.h> /* request_region */ #include <linux/delay.h> /* udelay */ -#include <linux/videodev2.h> /* kernel radio structs */ -#include <media/v4l2-common.h> -#include <media/v4l2-ioctl.h> #include <linux/isapnp.h> -#include <asm/io.h> /* outb, outb_p */ -#include <asm/uaccess.h> /* copy to/from user */ #include <linux/mutex.h> +#include <linux/videodev2.h> /* kernel radio structs */ +#include <linux/io.h> /* outb, outb_p */ +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> -#define RADIO_VERSION KERNEL_VERSION(0,0,2) +MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood"); +MODULE_DESCRIPTION("A driver for the SF16MI radio."); +MODULE_LICENSE("GPL"); -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - } -}; +static int io = -1; +static int radio_nr = -1; + +module_param(io, int, 0); +MODULE_PARM_DESC(io, "I/O address of the SF16MI card (0x284 or 0x384)"); +module_param(radio_nr, int, 0); -struct fmi_device +#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) + +struct fmi { - unsigned long in_use; - int port; + struct v4l2_device v4l2_dev; + struct video_device vdev; + int io; int curvol; /* 1 or 0 */ unsigned long curfreq; /* freq in kHz */ __u32 flags; + struct mutex lock; }; -static int io = -1; -static int radio_nr = -1; -static struct pnp_dev *dev = NULL; -static struct mutex lock; +static struct fmi fmi_card; +static struct pnp_dev *dev; /* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */ /* It is only useful to give freq in intervall of 800 (=0.05Mhz), * other bits will be truncated, e.g 92.7400016 -> 92.7, but * 92.7400017 -> 92.75 */ -#define RSF16_ENCODE(x) ((x)/800+214) -#define RSF16_MINFREQ 87*16000 -#define RSF16_MAXFREQ 108*16000 +#define RSF16_ENCODE(x) ((x) / 800 + 214) +#define RSF16_MINFREQ (87 * 16000) +#define RSF16_MAXFREQ (108 * 16000) -static void outbits(int bits, unsigned int data, int port) +static void outbits(int bits, unsigned int data, int io) { - while(bits--) { - if(data & 1) { - outb(5, port); + while (bits--) { + if (data & 1) { + outb(5, io); udelay(6); - outb(7, port); + outb(7, io); udelay(6); } else { - outb(1, port); + outb(1, io); udelay(6); - outb(3, port); + outb(3, io); udelay(6); } - data>>=1; + data >>= 1; } } -static inline void fmi_mute(int port) +static inline void fmi_mute(struct fmi *fmi) { - mutex_lock(&lock); - outb(0x00, port); - mutex_unlock(&lock); + mutex_lock(&fmi->lock); + outb(0x00, fmi->io); + mutex_unlock(&fmi->lock); } -static inline void fmi_unmute(int port) +static inline void fmi_unmute(struct fmi *fmi) { - mutex_lock(&lock); - outb(0x08, port); - mutex_unlock(&lock); + mutex_lock(&fmi->lock); + outb(0x08, fmi->io); + mutex_unlock(&fmi->lock); } -static inline int fmi_setfreq(struct fmi_device *dev) +static inline int fmi_setfreq(struct fmi *fmi, unsigned long freq) { - int myport = dev->port; - unsigned long freq = dev->curfreq; - - mutex_lock(&lock); + mutex_lock(&fmi->lock); + fmi->curfreq = freq; - outbits(16, RSF16_ENCODE(freq), myport); - outbits(8, 0xC0, myport); + outbits(16, RSF16_ENCODE(freq), fmi->io); + outbits(8, 0xC0, fmi->io); msleep(143); /* was schedule_timeout(HZ/7) */ - mutex_unlock(&lock); - if (dev->curvol) fmi_unmute(myport); + mutex_unlock(&fmi->lock); + if (fmi->curvol) + fmi_unmute(fmi); return 0; } -static inline int fmi_getsigstr(struct fmi_device *dev) +static inline int fmi_getsigstr(struct fmi *fmi) { int val; int res; - int myport = dev->port; - - mutex_lock(&lock); - val = dev->curvol ? 0x08 : 0x00; /* unmute/mute */ - outb(val, myport); - outb(val | 0x10, myport); + mutex_lock(&fmi->lock); + val = fmi->curvol ? 0x08 : 0x00; /* unmute/mute */ + outb(val, fmi->io); + outb(val | 0x10, fmi->io); msleep(143); /* was schedule_timeout(HZ/7) */ - res = (int)inb(myport+1); - outb(val, myport); + res = (int)inb(fmi->io + 1); + outb(val, fmi->io); - mutex_unlock(&lock); + mutex_unlock(&fmi->lock); return (res & 2) ? 0 : 0xFFFF; } @@ -137,9 +133,9 @@ static int vidioc_querycap(struct file *file, void *priv, { strlcpy(v->driver, "radio-sf16fmi", sizeof(v->driver)); strlcpy(v->card, "SF16-FMx radio", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } @@ -147,18 +143,18 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { int mult; - struct fmi_device *fmi = video_drvdata(file); + struct fmi *fmi = video_drvdata(file); if (v->index > 0) return -EINVAL; - strcpy(v->name, "FM"); + strlcpy(v->name, "FM", sizeof(v->name)); v->type = V4L2_TUNER_RADIO; mult = (fmi->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000; - v->rangelow = RSF16_MINFREQ/mult; - v->rangehigh = RSF16_MAXFREQ/mult; + v->rangelow = RSF16_MINFREQ / mult; + v->rangehigh = RSF16_MAXFREQ / mult; v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO; - v->capability = fmi->flags&V4L2_TUNER_CAP_LOW; + v->capability = fmi->flags & V4L2_TUNER_CAP_LOW; v->audmode = V4L2_TUNER_MODE_STEREO; v->signal = fmi_getsigstr(fmi); return 0; @@ -167,32 +163,29 @@ static int vidioc_g_tuner(struct file *file, void *priv, static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - if (v->index > 0) - return -EINVAL; - return 0; + return v->index ? -EINVAL : 0; } static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct fmi_device *fmi = video_drvdata(file); + struct fmi *fmi = video_drvdata(file); if (!(fmi->flags & V4L2_TUNER_CAP_LOW)) f->frequency *= 1000; if (f->frequency < RSF16_MINFREQ || - f->frequency > RSF16_MAXFREQ ) + f->frequency > RSF16_MAXFREQ) return -EINVAL; - /*rounding in steps of 800 to match th freq - that will be used */ - fmi->curfreq = (f->frequency/800)*800; - fmi_setfreq(fmi); + /* rounding in steps of 800 to match the freq + that will be used */ + fmi_setfreq(fmi, (f->frequency / 800) * 800); return 0; } static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct fmi_device *fmi = video_drvdata(file); + struct fmi *fmi = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = fmi->curfreq; @@ -204,14 +197,9 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc) { - int i; - - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); - return 0; - } + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); } return -EINVAL; } @@ -219,7 +207,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct fmi_device *fmi = video_drvdata(file); + struct fmi *fmi = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -232,31 +220,20 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct fmi_device *fmi = video_drvdata(file); + struct fmi *fmi = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: if (ctrl->value) - fmi_mute(fmi->port); + fmi_mute(fmi); else - fmi_unmute(fmi->port); + fmi_unmute(fmi); fmi->curvol = ctrl->value; return 0; } return -EINVAL; } -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) { *i = 0; @@ -265,36 +242,26 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) { - if (i != 0) - return -EINVAL; - return 0; + return i ? -EINVAL : 0; } -static int vidioc_s_audio(struct file *file, void *priv, +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) { - if (a->index != 0) - return -EINVAL; + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; return 0; } -static struct fmi_device fmi_unit; - -static int fmi_exclusive_open(struct file *file) -{ - return test_and_set_bit(0, &fmi_unit.in_use) ? -EBUSY : 0; -} - -static int fmi_exclusive_release(struct file *file) +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) { - clear_bit(0, &fmi_unit.in_use); - return 0; + return a->index ? -EINVAL : 0; } static const struct v4l2_file_operations fmi_fops = { .owner = THIS_MODULE, - .open = fmi_exclusive_open, - .release = fmi_exclusive_release, .ioctl = video_ioctl2, }; @@ -313,13 +280,6 @@ static const struct v4l2_ioctl_ops fmi_ioctl_ops = { .vidioc_s_ctrl = vidioc_s_ctrl, }; -static struct video_device fmi_radio = { - .name = "SF16FMx radio", - .fops = &fmi_fops, - .ioctl_ops = &fmi_ioctl_ops, - .release = video_device_release_empty, -}; - /* ladis: this is my card. does any other types exist? */ static struct isapnp_device_id id_table[] __devinitdata = { { ISAPNP_ANY_ID, ISAPNP_ANY_ID, @@ -344,7 +304,7 @@ static int __init isapnp_fmi_probe(void) if (pnp_device_attach(dev) < 0) return -EAGAIN; if (pnp_activate_dev(dev) < 0) { - printk ("radio-sf16fmi: PnP configure failed (out of resources?)\n"); + printk(KERN_ERR "radio-sf16fmi: PnP configure failed (out of resources?)\n"); pnp_device_detach(dev); return -ENOMEM; } @@ -354,59 +314,72 @@ static int __init isapnp_fmi_probe(void) } i = pnp_port_start(dev, 0); - printk ("radio-sf16fmi: PnP reports card at %#x\n", i); + printk(KERN_INFO "radio-sf16fmi: PnP reports card at %#x\n", i); return i; } static int __init fmi_init(void) { + struct fmi *fmi = &fmi_card; + struct v4l2_device *v4l2_dev = &fmi->v4l2_dev; + int res; + if (io < 0) io = isapnp_fmi_probe(); - if (io < 0) { - printk(KERN_ERR "radio-sf16fmi: No PnP card found.\n"); - return io; + strlcpy(v4l2_dev->name, "sf16fmi", sizeof(v4l2_dev->name)); + fmi->io = io; + if (fmi->io < 0) { + v4l2_err(v4l2_dev, "No PnP card found.\n"); + return fmi->io; } if (!request_region(io, 2, "radio-sf16fmi")) { - printk(KERN_ERR "radio-sf16fmi: port 0x%x already in use\n", io); + v4l2_err(v4l2_dev, "port 0x%x already in use\n", fmi->io); pnp_device_detach(dev); return -EBUSY; } - fmi_unit.port = io; - fmi_unit.curvol = 0; - fmi_unit.curfreq = 0; - fmi_unit.flags = V4L2_TUNER_CAP_LOW; - video_set_drvdata(&fmi_radio, &fmi_unit); + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + release_region(fmi->io, 2); + pnp_device_detach(dev); + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return res; + } + + fmi->flags = V4L2_TUNER_CAP_LOW; + strlcpy(fmi->vdev.name, v4l2_dev->name, sizeof(fmi->vdev.name)); + fmi->vdev.v4l2_dev = v4l2_dev; + fmi->vdev.fops = &fmi_fops; + fmi->vdev.ioctl_ops = &fmi_ioctl_ops; + fmi->vdev.release = video_device_release_empty; + video_set_drvdata(&fmi->vdev, fmi); - mutex_init(&lock); + mutex_init(&fmi->lock); - if (video_register_device(&fmi_radio, VFL_TYPE_RADIO, radio_nr) < 0) { - release_region(io, 2); + if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(fmi->io, 2); + pnp_device_detach(dev); return -EINVAL; } - printk(KERN_INFO "SF16FMx radio card driver at 0x%x\n", io); + v4l2_info(v4l2_dev, "card driver at 0x%x\n", fmi->io); /* mute card - prevents noisy bootups */ - fmi_mute(io); + fmi_mute(fmi); return 0; } -MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood"); -MODULE_DESCRIPTION("A driver for the SF16MI radio."); -MODULE_LICENSE("GPL"); - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the SF16MI card (0x284 or 0x384)"); -module_param(radio_nr, int, 0); - -static void __exit fmi_cleanup_module(void) +static void __exit fmi_exit(void) { - video_unregister_device(&fmi_radio); - release_region(io, 2); + struct fmi *fmi = &fmi_card; + + video_unregister_device(&fmi->vdev); + v4l2_device_unregister(&fmi->v4l2_dev); + release_region(fmi->io, 2); if (dev) pnp_device_detach(dev); } module_init(fmi_init); -module_exit(fmi_cleanup_module); +module_exit(fmi_exit); diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c index 92f17a347fa7..c09ca8600ea1 100644 --- a/drivers/media/radio/radio-sf16fmr2.c +++ b/drivers/media/radio/radio-sf16fmr2.c @@ -18,40 +18,28 @@ #include <linux/init.h> /* Initdata */ #include <linux/ioport.h> /* request_region */ #include <linux/delay.h> /* udelay */ -#include <asm/io.h> /* outb, outb_p */ -#include <asm/uaccess.h> /* copy to/from user */ #include <linux/videodev2.h> /* kernel radio structs */ -#include <media/v4l2-common.h> -#include <media/v4l2-ioctl.h> #include <linux/mutex.h> +#include <linux/version.h> /* for KERNEL_VERSION MACRO */ +#include <linux/io.h> /* outb, outb_p */ +#include <media/v4l2-device.h> +#include <media/v4l2-ioctl.h> -static struct mutex lock; +MODULE_AUTHOR("Ziglio Frediano, freddy77@angelfire.com"); +MODULE_DESCRIPTION("A driver for the SF16FMR2 radio."); +MODULE_LICENSE("GPL"); + +static int io = 0x384; +static int radio_nr = -1; + +module_param(io, int, 0); +MODULE_PARM_DESC(io, "I/O address of the SF16FMR2 card (should be 0x384, if do not work try 0x284)"); +module_param(radio_nr, int, 0); -#include <linux/version.h> /* for KERNEL_VERSION MACRO */ #define RADIO_VERSION KERNEL_VERSION(0,0,2) #define AUD_VOL_INDEX 1 -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - }, - [AUD_VOL_INDEX] = { - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 15, - .step = 1, - .default_value = 0, - .type = V4L2_CTRL_TYPE_INTEGER, - } -}; - #undef DEBUG //#define DEBUG 1 @@ -62,156 +50,160 @@ static struct v4l2_queryctrl radio_qctrl[] = { #endif /* this should be static vars for module size */ -struct fmr2_device +struct fmr2 { - unsigned long in_use; - int port; + struct v4l2_device v4l2_dev; + struct video_device vdev; + struct mutex lock; + int io; int curvol; /* 0-15 */ int mute; int stereo; /* card is producing stereo audio */ unsigned long curfreq; /* freq in kHz */ int card_type; - __u32 flags; + u32 flags; }; -static int io = 0x384; -static int radio_nr = -1; +static struct fmr2 fmr2_card; /* hw precision is 12.5 kHz * It is only useful to give freq in intervall of 200 (=0.0125Mhz), * other bits will be truncated */ -#define RSF16_ENCODE(x) ((x)/200+856) -#define RSF16_MINFREQ 87*16000 -#define RSF16_MAXFREQ 108*16000 +#define RSF16_ENCODE(x) ((x) / 200 + 856) +#define RSF16_MINFREQ (87 * 16000) +#define RSF16_MAXFREQ (108 * 16000) -static inline void wait(int n,int port) +static inline void wait(int n, int io) { - for (;n;--n) inb(port); + for (; n; --n) + inb(io); } -static void outbits(int bits, unsigned int data, int nWait, int port) +static void outbits(int bits, unsigned int data, int nWait, int io) { int bit; - for(;--bits>=0;) { - bit = (data>>bits) & 1; - outb(bit,port); - wait(nWait,port); - outb(bit|2,port); - wait(nWait,port); - outb(bit,port); - wait(nWait,port); + + for (; --bits >= 0;) { + bit = (data >> bits) & 1; + outb(bit, io); + wait(nWait, io); + outb(bit | 2, io); + wait(nWait, io); + outb(bit, io); + wait(nWait, io); } } -static inline void fmr2_mute(int port) +static inline void fmr2_mute(int io) { - outb(0x00, port); - wait(4,port); + outb(0x00, io); + wait(4, io); } -static inline void fmr2_unmute(int port) +static inline void fmr2_unmute(int io) { - outb(0x04, port); - wait(4,port); + outb(0x04, io); + wait(4, io); } -static inline int fmr2_stereo_mode(int port) +static inline int fmr2_stereo_mode(int io) { - int n = inb(port); - outb(6,port); - inb(port); - n = ((n>>3)&1)^1; + int n = inb(io); + + outb(6, io); + inb(io); + n = ((n >> 3) & 1) ^ 1; debug_print((KERN_DEBUG "stereo: %d\n", n)); return n; } -static int fmr2_product_info(struct fmr2_device *dev) +static int fmr2_product_info(struct fmr2 *dev) { - int n = inb(dev->port); + int n = inb(dev->io); + n &= 0xC1; - if (n == 0) - { + if (n == 0) { /* this should support volume set */ dev->card_type = 12; return 0; } /* not volume (mine is 11) */ - dev->card_type = (n==128)?11:0; + dev->card_type = (n == 128) ? 11 : 0; return n; } -static inline int fmr2_getsigstr(struct fmr2_device *dev) +static inline int fmr2_getsigstr(struct fmr2 *dev) { - /* !!! work only if scanning freq */ - int port = dev->port, res = 0xffff; - outb(5,port); - wait(4,port); - if (!(inb(port)&1)) res = 0; + /* !!! works only if scanning freq */ + int res = 0xffff; + + outb(5, dev->io); + wait(4, dev->io); + if (!(inb(dev->io) & 1)) + res = 0; debug_print((KERN_DEBUG "signal: %d\n", res)); return res; } /* set frequency and unmute card */ -static int fmr2_setfreq(struct fmr2_device *dev) +static int fmr2_setfreq(struct fmr2 *dev) { - int port = dev->port; unsigned long freq = dev->curfreq; - fmr2_mute(port); + fmr2_mute(dev->io); /* 0x42 for mono output * 0x102 forward scanning * 0x182 scansione avanti */ - outbits(9,0x2,3,port); - outbits(16,RSF16_ENCODE(freq),2,port); + outbits(9, 0x2, 3, dev->io); + outbits(16, RSF16_ENCODE(freq), 2, dev->io); - fmr2_unmute(port); + fmr2_unmute(dev->io); /* wait 0.11 sec */ msleep(110); /* NOTE if mute this stop radio you must set freq on unmute */ - dev->stereo = fmr2_stereo_mode(port); + dev->stereo = fmr2_stereo_mode(dev->io); return 0; } /* !!! not tested, in my card this does't work !!! */ -static int fmr2_setvolume(struct fmr2_device *dev) +static int fmr2_setvolume(struct fmr2 *dev) { int vol[16] = { 0x021, 0x084, 0x090, 0x104, 0x110, 0x204, 0x210, 0x402, 0x404, 0x408, 0x410, 0x801, 0x802, 0x804, 0x808, 0x810 }; - int i, a, port = dev->port; + int i, a; int n = vol[dev->curvol & 0x0f]; if (dev->card_type != 11) return 1; for (i = 12; --i >= 0; ) { - a = ((n >> i) & 1) << 6; /* if (a=0) a= 0; else a= 0x40; */ - outb(a | 4, port); - wait(4, port); - outb(a | 0x24, port); - wait(4, port); - outb(a | 4, port); - wait(4, port); + a = ((n >> i) & 1) << 6; /* if (a==0) a = 0; else a = 0x40; */ + outb(a | 4, dev->io); + wait(4, dev->io); + outb(a | 0x24, dev->io); + wait(4, dev->io); + outb(a | 4, dev->io); + wait(4, dev->io); } for (i = 6; --i >= 0; ) { a = ((0x18 >> i) & 1) << 6; - outb(a | 4, port); - wait(4,port); - outb(a | 0x24, port); - wait(4,port); - outb(a|4, port); - wait(4,port); + outb(a | 4, dev->io); + wait(4, dev->io); + outb(a | 0x24, dev->io); + wait(4, dev->io); + outb(a | 4, dev->io); + wait(4, dev->io); } - wait(4, port); - outb(0x14, port); - + wait(4, dev->io); + outb(0x14, dev->io); return 0; } @@ -220,9 +212,9 @@ static int vidioc_querycap(struct file *file, void *priv, { strlcpy(v->driver, "radio-sf16fmr2", sizeof(v->driver)); strlcpy(v->card, "SF16-FMR2 radio", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } @@ -230,54 +222,52 @@ static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { int mult; - struct fmr2_device *fmr2 = video_drvdata(file); + struct fmr2 *fmr2 = video_drvdata(file); if (v->index > 0) return -EINVAL; - strcpy(v->name, "FM"); + strlcpy(v->name, "FM", sizeof(v->name)); v->type = V4L2_TUNER_RADIO; mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000; - v->rangelow = RSF16_MINFREQ/mult; - v->rangehigh = RSF16_MAXFREQ/mult; + v->rangelow = RSF16_MINFREQ / mult; + v->rangehigh = RSF16_MAXFREQ / mult; v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO; v->capability = fmr2->flags&V4L2_TUNER_CAP_LOW; v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO: V4L2_TUNER_MODE_MONO; - mutex_lock(&lock); + mutex_lock(&fmr2->lock); v->signal = fmr2_getsigstr(fmr2); - mutex_unlock(&lock); + mutex_unlock(&fmr2->lock); return 0; } static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - if (v->index > 0) - return -EINVAL; - return 0; + return v->index ? -EINVAL : 0; } static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct fmr2_device *fmr2 = video_drvdata(file); + struct fmr2 *fmr2 = video_drvdata(file); if (!(fmr2->flags & V4L2_TUNER_CAP_LOW)) f->frequency *= 1000; if (f->frequency < RSF16_MINFREQ || - f->frequency > RSF16_MAXFREQ ) + f->frequency > RSF16_MAXFREQ) return -EINVAL; - /*rounding in steps of 200 to match th freq - that will be used */ - fmr2->curfreq = (f->frequency/200)*200; + /* rounding in steps of 200 to match the freq + that will be used */ + fmr2->curfreq = (f->frequency / 200) * 200; /* set card freq (if not muted) */ if (fmr2->curvol && !fmr2->mute) { - mutex_lock(&lock); + mutex_lock(&fmr2->lock); fmr2_setfreq(fmr2); - mutex_unlock(&lock); + mutex_unlock(&fmr2->lock); } return 0; } @@ -285,7 +275,7 @@ static int vidioc_s_frequency(struct file *file, void *priv, static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct fmr2_device *fmr2 = video_drvdata(file); + struct fmr2 *fmr2 = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = fmr2->curfreq; @@ -297,13 +287,16 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc) { - int i; + struct fmr2 *fmr2 = video_drvdata(file); - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &radio_qctrl[i], sizeof(*qc)); - return 0; - } + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + case V4L2_CID_AUDIO_VOLUME: + /* Only card_type == 11 implements volume */ + if (fmr2->card_type == 11) + return v4l2_ctrl_query_fill(qc, 0, 15, 1, 0); + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0); } return -EINVAL; } @@ -311,7 +304,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct fmr2_device *fmr2 = video_drvdata(file); + struct fmr2 *fmr2 = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -327,18 +320,14 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct fmr2_device *fmr2 = video_drvdata(file); + struct fmr2 *fmr2 = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: fmr2->mute = ctrl->value; break; case V4L2_CID_AUDIO_VOLUME: - if (ctrl->value > radio_qctrl[AUD_VOL_INDEX].maximum) - fmr2->curvol = radio_qctrl[AUD_VOL_INDEX].maximum; - else - fmr2->curvol = ctrl->value; - + fmr2->curvol = ctrl->value; break; default: return -EINVAL; @@ -351,25 +340,14 @@ static int vidioc_s_ctrl(struct file *file, void *priv, printk(KERN_DEBUG "mute\n"); #endif - mutex_lock(&lock); + mutex_lock(&fmr2->lock); if (fmr2->curvol && !fmr2->mute) { fmr2_setvolume(fmr2); /* Set frequency and unmute card */ fmr2_setfreq(fmr2); } else - fmr2_mute(fmr2->port); - mutex_unlock(&lock); - return 0; -} - -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; + fmr2_mute(fmr2->io); + mutex_unlock(&fmr2->lock); return 0; } @@ -381,36 +359,26 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) { - if (i != 0) - return -EINVAL; - return 0; + return i ? -EINVAL : 0; } -static int vidioc_s_audio(struct file *file, void *priv, +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) { - if (a->index != 0) - return -EINVAL; + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; return 0; } -static struct fmr2_device fmr2_unit; - -static int fmr2_exclusive_open(struct file *file) -{ - return test_and_set_bit(0, &fmr2_unit.in_use) ? -EBUSY : 0; -} - -static int fmr2_exclusive_release(struct file *file) +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) { - clear_bit(0, &fmr2_unit.in_use); - return 0; + return a->index ? -EINVAL : 0; } static const struct v4l2_file_operations fmr2_fops = { .owner = THIS_MODULE, - .open = fmr2_exclusive_open, - .release = fmr2_exclusive_release, .ioctl = video_ioctl2, }; @@ -429,67 +397,64 @@ static const struct v4l2_ioctl_ops fmr2_ioctl_ops = { .vidioc_s_ctrl = vidioc_s_ctrl, }; -static struct video_device fmr2_radio = { - .name = "SF16FMR2 radio", - .fops = &fmr2_fops, - .ioctl_ops = &fmr2_ioctl_ops, - .release = video_device_release_empty, -}; - static int __init fmr2_init(void) { - fmr2_unit.port = io; - fmr2_unit.curvol = 0; - fmr2_unit.mute = 0; - fmr2_unit.curfreq = 0; - fmr2_unit.stereo = 1; - fmr2_unit.flags = V4L2_TUNER_CAP_LOW; - fmr2_unit.card_type = 0; - video_set_drvdata(&fmr2_radio, &fmr2_unit); - - mutex_init(&lock); - - if (!request_region(io, 2, "sf16fmr2")) { - printk(KERN_ERR "radio-sf16fmr2: request_region failed!\n"); + struct fmr2 *fmr2 = &fmr2_card; + struct v4l2_device *v4l2_dev = &fmr2->v4l2_dev; + int res; + + strlcpy(v4l2_dev->name, "sf16fmr2", sizeof(v4l2_dev->name)); + fmr2->io = io; + fmr2->stereo = 1; + fmr2->flags = V4L2_TUNER_CAP_LOW; + mutex_init(&fmr2->lock); + + if (!request_region(fmr2->io, 2, "sf16fmr2")) { + v4l2_err(v4l2_dev, "request_region failed!\n"); return -EBUSY; } - if (video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr) < 0) { - release_region(io, 2); - return -EINVAL; + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + release_region(fmr2->io, 2); + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return res; } - printk(KERN_INFO "SF16FMR2 radio card driver at 0x%x.\n", io); - /* mute card - prevents noisy bootups */ - mutex_lock(&lock); - fmr2_mute(io); - fmr2_product_info(&fmr2_unit); - mutex_unlock(&lock); - debug_print((KERN_DEBUG "card_type %d\n", fmr2_unit.card_type)); + strlcpy(fmr2->vdev.name, v4l2_dev->name, sizeof(fmr2->vdev.name)); + fmr2->vdev.v4l2_dev = v4l2_dev; + fmr2->vdev.fops = &fmr2_fops; + fmr2->vdev.ioctl_ops = &fmr2_ioctl_ops; + fmr2->vdev.release = video_device_release_empty; + video_set_drvdata(&fmr2->vdev, fmr2); - /* Only card_type == 11 implements volume */ - if (fmr2_unit.card_type != 11) - radio_qctrl[AUD_VOL_INDEX].maximum = 1; + if (video_register_device(&fmr2->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(fmr2->io, 2); + return -EINVAL; + } + v4l2_info(v4l2_dev, "SF16FMR2 radio card driver at 0x%x.\n", fmr2->io); + /* mute card - prevents noisy bootups */ + mutex_lock(&fmr2->lock); + fmr2_mute(fmr2->io); + fmr2_product_info(fmr2); + mutex_unlock(&fmr2->lock); + debug_print((KERN_DEBUG "card_type %d\n", fmr2->card_type)); return 0; } -MODULE_AUTHOR("Ziglio Frediano, freddy77@angelfire.com"); -MODULE_DESCRIPTION("A driver for the SF16FMR2 radio."); -MODULE_LICENSE("GPL"); - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the SF16FMR2 card (should be 0x384, if do not work try 0x284)"); -module_param(radio_nr, int, 0); - -static void __exit fmr2_cleanup_module(void) +static void __exit fmr2_exit(void) { - video_unregister_device(&fmr2_radio); - release_region(io,2); + struct fmr2 *fmr2 = &fmr2_card; + + video_unregister_device(&fmr2->vdev); + v4l2_device_unregister(&fmr2->v4l2_dev); + release_region(fmr2->io, 2); } module_init(fmr2_init); -module_exit(fmr2_cleanup_module); +module_exit(fmr2_exit); #ifndef MODULE diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c index 4dfed6aa2dbc..92c297796a9f 100644 --- a/drivers/media/radio/radio-si470x.c +++ b/drivers/media/radio/radio-si470x.c @@ -5,8 +5,9 @@ * - Silicon Labs USB FM Radio Reference Design * - ADS/Tech FM Radio Receiver (formerly Instant FM Music) (RDX-155-EF) * - KWorld USB FM Radio SnapMusic Mobile 700 (FM700) + * - Sanei Electric, Inc. FM USB Radio (sold as DealExtreme.com PCear) * - * Copyright (c) 2008 Tobias Lorenz <tobias.lorenz@gmx.net> + * Copyright (c) 2009 Tobias Lorenz <tobias.lorenz@gmx.net> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,7 +30,7 @@ * 2008-01-12 Tobias Lorenz <tobias.lorenz@gmx.net> * Version 1.0.0 * - First working version - * 2008-01-13 Tobias Lorenz <tobias.lorenz@gmx.net> + * 2008-01-13 Tobias Lorenz <tobias.lorenz@gmx.net> * Version 1.0.1 * - Improved error handling, every function now returns errno * - Improved multi user access (start/mute/stop) @@ -104,6 +105,7 @@ * 2009-01-31 Rick Bronson <rick@efn.org> * Tobias Lorenz <tobias.lorenz@gmx.net> * - add LED status output + * - get HW/SW version from scratchpad * * ToDo: * - add firmware download/update support @@ -114,10 +116,10 @@ /* driver definitions */ #define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>" #define DRIVER_NAME "radio-si470x" -#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 8) +#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 9) #define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver" #define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers" -#define DRIVER_VERSION "1.0.8" +#define DRIVER_VERSION "1.0.9" /* kernel includes */ @@ -145,7 +147,7 @@ static struct usb_device_id si470x_usb_driver_id_table[] = { { USB_DEVICE_AND_INTERFACE_INFO(0x06e1, 0xa155, USB_CLASS_HID, 0, 0) }, /* KWorld USB FM Radio SnapMusic Mobile 700 (FM700) */ { USB_DEVICE_AND_INTERFACE_INFO(0x1b80, 0xd700, USB_CLASS_HID, 0, 0) }, - /* DealExtreme USB Radio */ + /* Sanei Electric, Inc. FM USB Radio (sold as DealExtreme.com PCear) */ { USB_DEVICE_AND_INTERFACE_INFO(0x10c5, 0x819a, USB_CLASS_HID, 0, 0) }, /* Terminating entry */ { } @@ -345,7 +347,7 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); /* Report 19: stream */ #define STREAM_REPORT_SIZE 3 -#define STREAM_REPORT 19 +#define STREAM_REPORT 19 /* Report 20: scratch */ #define SCRATCH_PAGE_SIZE 63 @@ -353,9 +355,13 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); #define SCRATCH_REPORT 20 /* Reports 19-22: flash upgrade of the C8051F321 */ +#define WRITE_REPORT_SIZE 4 #define WRITE_REPORT 19 +#define FLASH_REPORT_SIZE 64 #define FLASH_REPORT 20 +#define CRC_REPORT_SIZE 3 #define CRC_REPORT 21 +#define RESPONSE_REPORT_SIZE 2 #define RESPONSE_REPORT 22 /* Report 23: currently unused, but can accept 60 byte reports on the HID */ @@ -414,7 +420,7 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); /* bootloader commands */ #define GET_SW_VERSION_COMMAND 0x00 -#define SET_PAGE_COMMAND 0x01 +#define SET_PAGE_COMMAND 0x01 #define ERASE_PAGE_COMMAND 0x02 #define WRITE_PAGE_COMMAND 0x03 #define CRC_ON_PAGE_COMMAND 0x04 @@ -428,12 +434,6 @@ MODULE_PARM_DESC(rds_poll_time, "RDS poll time (ms): *40*"); #define COMMAND_FAILED 0x02 #define COMMAND_PENDING 0x03 -/* buffer sizes */ -#define COMMAND_BUFFER_SIZE 4 -#define RESPONSE_BUFFER_SIZE 2 -#define FLASH_BUFFER_SIZE 64 -#define CRC_BUFFER_SIZE 3 - /************************************************************************** @@ -465,6 +465,10 @@ struct si470x_device { unsigned int buf_size; unsigned int rd_index; unsigned int wr_index; + + /* scratch page */ + unsigned char software_version; + unsigned char hardware_version; }; @@ -480,7 +484,7 @@ struct si470x_device { /************************************************************************** - * General Driver Functions + * General Driver Functions - REGISTER_REPORTs **************************************************************************/ /* @@ -566,60 +570,6 @@ static int si470x_set_register(struct si470x_device *radio, int regnr) /* - * si470x_get_all_registers - read entire registers - */ -static int si470x_get_all_registers(struct si470x_device *radio) -{ - unsigned char buf[ENTIRE_REPORT_SIZE]; - int retval; - unsigned char regnr; - - buf[0] = ENTIRE_REPORT; - - retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); - - if (retval >= 0) - for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++) - radio->registers[regnr] = get_unaligned_be16( - &buf[regnr * RADIO_REGISTER_SIZE + 1]); - - return (retval < 0) ? -EINVAL : 0; -} - - -/* - * si470x_get_rds_registers - read rds registers - */ -static int si470x_get_rds_registers(struct si470x_device *radio) -{ - unsigned char buf[RDS_REPORT_SIZE]; - int retval; - int size; - unsigned char regnr; - - buf[0] = RDS_REPORT; - - retval = usb_interrupt_msg(radio->usbdev, - usb_rcvintpipe(radio->usbdev, 1), - (void *) &buf, sizeof(buf), &size, usb_timeout); - if (size != sizeof(buf)) - printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: " - "return size differs: %d != %zu\n", size, sizeof(buf)); - if (retval < 0) - printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: " - "usb_interrupt_msg returned %d\n", retval); - - if (retval >= 0) - for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) - radio->registers[STATUSRSSI + regnr] = - get_unaligned_be16( - &buf[regnr * RADIO_REGISTER_SIZE + 1]); - - return (retval < 0) ? -EINVAL : 0; -} - - -/* * si470x_set_chan - set the channel */ static int si470x_set_chan(struct si470x_device *radio, unsigned short chan) @@ -887,6 +837,70 @@ static int si470x_rds_on(struct si470x_device *radio) /************************************************************************** + * General Driver Functions - ENTIRE_REPORT + **************************************************************************/ + +/* + * si470x_get_all_registers - read entire registers + */ +static int si470x_get_all_registers(struct si470x_device *radio) +{ + unsigned char buf[ENTIRE_REPORT_SIZE]; + int retval; + unsigned char regnr; + + buf[0] = ENTIRE_REPORT; + + retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); + + if (retval >= 0) + for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++) + radio->registers[regnr] = get_unaligned_be16( + &buf[regnr * RADIO_REGISTER_SIZE + 1]); + + return (retval < 0) ? -EINVAL : 0; +} + + + +/************************************************************************** + * General Driver Functions - RDS_REPORT + **************************************************************************/ + +/* + * si470x_get_rds_registers - read rds registers + */ +static int si470x_get_rds_registers(struct si470x_device *radio) +{ + unsigned char buf[RDS_REPORT_SIZE]; + int retval; + int size; + unsigned char regnr; + + buf[0] = RDS_REPORT; + + retval = usb_interrupt_msg(radio->usbdev, + usb_rcvintpipe(radio->usbdev, 1), + (void *) &buf, sizeof(buf), &size, usb_timeout); + if (size != sizeof(buf)) + printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: " + "return size differs: %d != %zu\n", size, sizeof(buf)); + if (retval < 0) + printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: " + "usb_interrupt_msg returned %d\n", retval); + + if (retval >= 0) + for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++) + radio->registers[STATUSRSSI + regnr] = + get_unaligned_be16( + &buf[regnr * RADIO_REGISTER_SIZE + 1]); + + return (retval < 0) ? -EINVAL : 0; +} + + + +/************************************************************************** * General Driver Functions - LED_REPORT **************************************************************************/ @@ -911,6 +925,35 @@ static int si470x_set_led_state(struct si470x_device *radio, /************************************************************************** + * General Driver Functions - SCRATCH_REPORT + **************************************************************************/ + +/* + * si470x_get_scratch_versions - gets the scratch page and version infos + */ +static int si470x_get_scratch_page_versions(struct si470x_device *radio) +{ + unsigned char buf[SCRATCH_REPORT_SIZE]; + int retval; + + buf[0] = SCRATCH_REPORT; + + retval = si470x_get_report(radio, (void *) &buf, sizeof(buf)); + + if (retval < 0) + printk(KERN_WARNING DRIVER_NAME ": si470x_get_scratch: " + "si470x_get_report returned %d\n", retval); + else { + radio->software_version = buf[1]; + radio->hardware_version = buf[2]; + } + + return (retval < 0) ? -EINVAL : 0; +} + + + +/************************************************************************** * RDS Driver Functions **************************************************************************/ @@ -1124,6 +1167,7 @@ static int si470x_fops_open(struct file *file) } if (radio->users == 1) { + /* start radio */ retval = si470x_start(radio); if (retval < 0) usb_autopm_put_interface(radio->intf); @@ -1165,6 +1209,7 @@ static int si470x_fops_release(struct file *file) /* cancel read processes */ wake_up_interruptible(&radio->read_queue); + /* stop radio */ retval = si470x_stop(radio); usb_autopm_put_interface(radio->intf); } @@ -1226,9 +1271,11 @@ static struct v4l2_queryctrl si470x_v4l2_queryctrl[] = { static int si470x_vidioc_querycap(struct file *file, void *priv, struct v4l2_capability *capability) { + struct si470x_device *radio = video_drvdata(file); + strlcpy(capability->driver, DRIVER_NAME, sizeof(capability->driver)); strlcpy(capability->card, DRIVER_CARD, sizeof(capability->card)); - sprintf(capability->bus_info, "USB"); + usb_make_path(radio->usbdev, capability->bus_info, sizeof(capability->bus_info)); capability->version = DRIVER_KERNEL_VERSION; capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER | V4L2_CAP_RADIO; @@ -1636,15 +1683,24 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, sizeof(si470x_viddev_template)); video_set_drvdata(radio->videodev, radio); - /* show some infos about the specific device */ + /* show some infos about the specific si470x device */ if (si470x_get_all_registers(radio) < 0) { retval = -EIO; - goto err_all; + goto err_video; } printk(KERN_INFO DRIVER_NAME ": DeviceID=0x%4.4hx ChipID=0x%4.4hx\n", radio->registers[DEVICEID], radio->registers[CHIPID]); - /* check if firmware is current */ + /* get software and hardware versions */ + if (si470x_get_scratch_page_versions(radio) < 0) { + retval = -EIO; + goto err_video; + } + printk(KERN_INFO DRIVER_NAME + ": software version %d, hardware version %d\n", + radio->software_version, radio->hardware_version); + + /* check if device and firmware is current */ if ((radio->registers[CHIPID] & CHIPID_FIRMWARE) < RADIO_SW_VERSION_CURRENT) { printk(KERN_WARNING DRIVER_NAME @@ -1657,7 +1713,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, ": If you have some trouble using this driver,\n"); printk(KERN_WARNING DRIVER_NAME ": please report to V4L ML at " - "video4linux-list@redhat.com\n"); + "linux-media@vger.kernel.org\n"); } /* set initial frequency */ @@ -1671,7 +1727,7 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL); if (!radio->buffer) { retval = -EIO; - goto err_all; + goto err_video; } /* rds buffer configuration */ @@ -1693,8 +1749,9 @@ static int si470x_usb_driver_probe(struct usb_interface *intf, return 0; err_all: - video_device_release(radio->videodev); kfree(radio->buffer); +err_video: + video_device_release(radio->videodev); err_radio: kfree(radio); err_initial: diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c index 0798d71abd00..699db9acaaf7 100644 --- a/drivers/media/radio/radio-terratec.c +++ b/drivers/media/radio/radio-terratec.c @@ -27,16 +27,29 @@ #include <linux/module.h> /* Modules */ #include <linux/init.h> /* Initdata */ #include <linux/ioport.h> /* request_region */ -#include <linux/delay.h> /* udelay */ -#include <asm/io.h> /* outb, outb_p */ -#include <asm/uaccess.h> /* copy to/from user */ #include <linux/videodev2.h> /* kernel radio structs */ -#include <media/v4l2-common.h> +#include <linux/mutex.h> +#include <linux/version.h> /* for KERNEL_VERSION MACRO */ +#include <linux/io.h> /* outb, outb_p */ +#include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> -#include <linux/spinlock.h> -#include <linux/version.h> /* for KERNEL_VERSION MACRO */ -#define RADIO_VERSION KERNEL_VERSION(0,0,2) +MODULE_AUTHOR("R.OFFERMANNS & others"); +MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card."); +MODULE_LICENSE("GPL"); + +#ifndef CONFIG_RADIO_TERRATEC_PORT +#define CONFIG_RADIO_TERRATEC_PORT 0x590 +#endif + +static int io = CONFIG_RADIO_TERRATEC_PORT; +static int radio_nr = -1; + +module_param(io, int, 0); +MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)"); +module_param(radio_nr, int, 0); + +#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) static struct v4l2_queryctrl radio_qctrl[] = { { @@ -57,13 +70,6 @@ static struct v4l2_queryctrl radio_qctrl[] = { } }; -#ifndef CONFIG_RADIO_TERRATEC_PORT -#define CONFIG_RADIO_TERRATEC_PORT 0x590 -#endif - -/**************** this ones are for the terratec *******************/ -#define BASEPORT 0x590 -#define VOLPORT 0x591 #define WRT_DIS 0x00 #define CLK_OFF 0x00 #define IIC_DATA 0x01 @@ -71,138 +77,124 @@ static struct v4l2_queryctrl radio_qctrl[] = { #define DATA 0x04 #define CLK_ON 0x08 #define WRT_EN 0x10 -/*******************************************************************/ -static int io = CONFIG_RADIO_TERRATEC_PORT; -static int radio_nr = -1; -static spinlock_t lock; - -struct tt_device +struct terratec { - unsigned long in_use; - int port; + struct v4l2_device v4l2_dev; + struct video_device vdev; + int io; int curvol; unsigned long curfreq; int muted; + struct mutex lock; }; +static struct terratec terratec_card; /* local things */ -static void cardWriteVol(int volume) +static void tt_write_vol(struct terratec *tt, int volume) { int i; - volume = volume+(volume * 32); // change both channels - spin_lock(&lock); - for (i=0;i<8;i++) - { - if (volume & (0x80>>i)) - outb(0x80, VOLPORT); - else outb(0x00, VOLPORT); + + volume = volume + (volume * 32); /* change both channels */ + mutex_lock(&tt->lock); + for (i = 0; i < 8; i++) { + if (volume & (0x80 >> i)) + outb(0x80, tt->io + 1); + else + outb(0x00, tt->io + 1); } - spin_unlock(&lock); + mutex_unlock(&tt->lock); } -static void tt_mute(struct tt_device *dev) +static void tt_mute(struct terratec *tt) { - dev->muted = 1; - cardWriteVol(0); + tt->muted = 1; + tt_write_vol(tt, 0); } -static int tt_setvol(struct tt_device *dev, int vol) +static int tt_setvol(struct terratec *tt, int vol) { - -// printk(KERN_ERR "setvol called, vol = %d\n", vol); - - if(vol == dev->curvol) { /* requested volume = current */ - if (dev->muted) { /* user is unmuting the card */ - dev->muted = 0; - cardWriteVol(vol); /* enable card */ + if (vol == tt->curvol) { /* requested volume = current */ + if (tt->muted) { /* user is unmuting the card */ + tt->muted = 0; + tt_write_vol(tt, vol); /* enable card */ } - return 0; } - if(vol == 0) { /* volume = 0 means mute the card */ - cardWriteVol(0); /* "turn off card" by setting vol to 0 */ - dev->curvol = vol; /* track the volume state! */ + if (vol == 0) { /* volume = 0 means mute the card */ + tt_write_vol(tt, 0); /* "turn off card" by setting vol to 0 */ + tt->curvol = vol; /* track the volume state! */ return 0; } - dev->muted = 0; - - cardWriteVol(vol); - - dev->curvol = vol; - + tt->muted = 0; + tt_write_vol(tt, vol); + tt->curvol = vol; return 0; - } /* this is the worst part in this driver */ /* many more or less strange things are going on here, but hey, it works :) */ -static int tt_setfreq(struct tt_device *dev, unsigned long freq1) +static int tt_setfreq(struct terratec *tt, unsigned long freq1) { int freq; int i; int p; int temp; long rest; - unsigned char buffer[25]; /* we have to bit shift 25 registers */ - freq = freq1/160; /* convert the freq. to a nice to handle value */ - for(i=24;i>-1;i--) - buffer[i]=0; - rest = freq*10+10700; /* i once had understood what is going on here */ + mutex_lock(&tt->lock); + + tt->curfreq = freq1; + + freq = freq1 / 160; /* convert the freq. to a nice to handle value */ + memset(buffer, 0, sizeof(buffer)); + + rest = freq * 10 + 10700; /* I once had understood what is going on here */ /* maybe some wise guy (friedhelm?) can comment this stuff */ - i=13; - p=10; - temp=102400; - while (rest!=0) - { - if (rest%temp == rest) + i = 13; + p = 10; + temp = 102400; + while (rest != 0) { + if (rest % temp == rest) buffer[i] = 0; - else - { + else { buffer[i] = 1; - rest = rest-temp; + rest = rest - temp; } i--; p--; - temp = temp/2; + temp = temp / 2; } - spin_lock(&lock); - - for (i=24;i>-1;i--) /* bit shift the values to the radiocard */ - { - if (buffer[i]==1) - { - outb(WRT_EN|DATA, BASEPORT); - outb(WRT_EN|DATA|CLK_ON , BASEPORT); - outb(WRT_EN|DATA, BASEPORT); - } - else - { - outb(WRT_EN|0x00, BASEPORT); - outb(WRT_EN|0x00|CLK_ON , BASEPORT); + for (i = 24; i > -1; i--) { /* bit shift the values to the radiocard */ + if (buffer[i] == 1) { + outb(WRT_EN | DATA, tt->io); + outb(WRT_EN | DATA | CLK_ON, tt->io); + outb(WRT_EN | DATA, tt->io); + } else { + outb(WRT_EN | 0x00, tt->io); + outb(WRT_EN | 0x00 | CLK_ON, tt->io); } } - outb(0x00, BASEPORT); + outb(0x00, tt->io); - spin_unlock(&lock); + mutex_unlock(&tt->lock); return 0; } -static int tt_getsigstr(struct tt_device *dev) /* TODO */ +static int tt_getsigstr(struct terratec *tt) { - if (inb(io) & 2) /* bit set = no signal present */ + if (inb(tt->io) & 2) /* bit set = no signal present */ return 0; return 1; /* signal present */ } @@ -212,53 +204,50 @@ static int vidioc_querycap(struct file *file, void *priv, { strlcpy(v->driver, "radio-terratec", sizeof(v->driver)); strlcpy(v->card, "ActiveRadio", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct tt_device *tt = video_drvdata(file); + struct terratec *tt = video_drvdata(file); if (v->index > 0) return -EINVAL; - strcpy(v->name, "FM"); + strlcpy(v->name, "FM", sizeof(v->name)); v->type = V4L2_TUNER_RADIO; - v->rangelow = (87*16000); - v->rangehigh = (108*16000); + v->rangelow = 87 * 16000; + v->rangehigh = 108 * 16000; v->rxsubchans = V4L2_TUNER_SUB_MONO; v->capability = V4L2_TUNER_CAP_LOW; v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xFFFF*tt_getsigstr(tt); + v->signal = 0xFFFF * tt_getsigstr(tt); return 0; } static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - if (v->index > 0) - return -EINVAL; - return 0; + return v->index ? -EINVAL : 0; } static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct tt_device *tt = video_drvdata(file); + struct terratec *tt = video_drvdata(file); - tt->curfreq = f->frequency; - tt_setfreq(tt, tt->curfreq); + tt_setfreq(tt, f->frequency); return 0; } static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct tt_device *tt = video_drvdata(file); + struct terratec *tt = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = tt->curfreq; @@ -272,8 +261,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); + memcpy(qc, &(radio_qctrl[i]), sizeof(*qc)); return 0; } } @@ -283,7 +271,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct tt_device *tt = video_drvdata(file); + struct terratec *tt = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -302,7 +290,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct tt_device *tt = video_drvdata(file); + struct terratec *tt = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -318,17 +306,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv, return -EINVAL; } -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) { *i = 0; @@ -337,36 +314,26 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) { - if (i != 0) - return -EINVAL; - return 0; + return i ? -EINVAL : 0; } -static int vidioc_s_audio(struct file *file, void *priv, +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) { - if (a->index != 0) - return -EINVAL; + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; return 0; } -static struct tt_device terratec_unit; - -static int terratec_exclusive_open(struct file *file) -{ - return test_and_set_bit(0, &terratec_unit.in_use) ? -EBUSY : 0; -} - -static int terratec_exclusive_release(struct file *file) +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) { - clear_bit(0, &terratec_unit.in_use); - return 0; + return a->index ? -EINVAL : 0; } static const struct v4l2_file_operations terratec_fops = { .owner = THIS_MODULE, - .open = terratec_exclusive_open, - .release = terratec_exclusive_release, .ioctl = video_ioctl2, }; @@ -385,60 +352,63 @@ static const struct v4l2_ioctl_ops terratec_ioctl_ops = { .vidioc_s_input = vidioc_s_input, }; -static struct video_device terratec_radio = { - .name = "TerraTec ActiveRadio", - .fops = &terratec_fops, - .ioctl_ops = &terratec_ioctl_ops, - .release = video_device_release_empty, -}; - static int __init terratec_init(void) { - if(io==-1) - { - printk(KERN_ERR "You must set an I/O address with io=0x???\n"); + struct terratec *tt = &terratec_card; + struct v4l2_device *v4l2_dev = &tt->v4l2_dev; + int res; + + strlcpy(v4l2_dev->name, "terratec", sizeof(v4l2_dev->name)); + tt->io = io; + if (tt->io == -1) { + v4l2_err(v4l2_dev, "you must set an I/O address with io=0x590 or 0x591\n"); return -EINVAL; } - if (!request_region(io, 2, "terratec")) - { - printk(KERN_ERR "TerraTec: port 0x%x already in use\n", io); + if (!request_region(tt->io, 2, "terratec")) { + v4l2_err(v4l2_dev, "port 0x%x already in use\n", io); return -EBUSY; } - video_set_drvdata(&terratec_radio, &terratec_unit); + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + release_region(tt->io, 2); + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return res; + } + + strlcpy(tt->vdev.name, v4l2_dev->name, sizeof(tt->vdev.name)); + tt->vdev.v4l2_dev = v4l2_dev; + tt->vdev.fops = &terratec_fops; + tt->vdev.ioctl_ops = &terratec_ioctl_ops; + tt->vdev.release = video_device_release_empty; + video_set_drvdata(&tt->vdev, tt); - spin_lock_init(&lock); + mutex_init(&tt->lock); - if (video_register_device(&terratec_radio, VFL_TYPE_RADIO, radio_nr) < 0) { - release_region(io,2); + if (video_register_device(&tt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(&tt->v4l2_dev); + release_region(tt->io, 2); return -EINVAL; } - printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver.\n"); + v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n"); /* mute card - prevents noisy bootups */ - - /* this ensures that the volume is all the way down */ - cardWriteVol(0); - terratec_unit.curvol = 0; - + tt_write_vol(tt, 0); return 0; } -MODULE_AUTHOR("R.OFFERMANNS & others"); -MODULE_DESCRIPTION("A driver for the TerraTec ActiveRadio Standalone radio card."); -MODULE_LICENSE("GPL"); -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the TerraTec ActiveRadio card (0x590 or 0x591)"); -module_param(radio_nr, int, 0); - -static void __exit terratec_cleanup_module(void) +static void __exit terratec_exit(void) { - video_unregister_device(&terratec_radio); - release_region(io,2); - printk(KERN_INFO "TERRATEC ActivRadio Standalone card driver unloaded.\n"); + struct terratec *tt = &terratec_card; + struct v4l2_device *v4l2_dev = &tt->v4l2_dev; + + video_unregister_device(&tt->vdev); + v4l2_device_unregister(&tt->v4l2_dev); + release_region(tt->io, 2); + v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver unloaded.\n"); } module_init(terratec_init); -module_exit(terratec_cleanup_module); +module_exit(terratec_exit); diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c index bdf9cb6a75f4..6f9ecc359356 100644 --- a/drivers/media/radio/radio-trust.c +++ b/drivers/media/radio/radio-trust.c @@ -19,49 +19,15 @@ #include <linux/module.h> #include <linux/init.h> #include <linux/ioport.h> -#include <asm/io.h> -#include <asm/uaccess.h> +#include <linux/version.h> /* for KERNEL_VERSION MACRO */ #include <linux/videodev2.h> -#include <media/v4l2-common.h> +#include <linux/io.h> +#include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> -#include <linux/version.h> /* for KERNEL_VERSION MACRO */ -#define RADIO_VERSION KERNEL_VERSION(0,0,2) - -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 65535, - .step = 2048, - .default_value = 65535, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_AUDIO_BASS, - .name = "Bass", - .minimum = 0, - .maximum = 65535, - .step = 4370, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - },{ - .id = V4L2_CID_AUDIO_TREBLE, - .name = "Treble", - .minimum = 0, - .maximum = 65535, - .step = 4370, - .default_value = 32768, - .type = V4L2_CTRL_TYPE_INTEGER, - }, -}; +MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); +MODULE_DESCRIPTION("A driver for the Trust FM Radio card."); +MODULE_LICENSE("GPL"); /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */ @@ -71,26 +37,41 @@ static struct v4l2_queryctrl radio_qctrl[] = { static int io = CONFIG_RADIO_TRUST_PORT; static int radio_nr = -1; -static int ioval = 0xf; -static __u16 curvol; -static __u16 curbass; -static __u16 curtreble; -static unsigned long curfreq; -static int curstereo; -static int curmute; -static unsigned long in_use; + +module_param(io, int, 0); +MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)"); +module_param(radio_nr, int, 0); + +#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) + +struct trust { + struct v4l2_device v4l2_dev; + struct video_device vdev; + int io; + int ioval; + __u16 curvol; + __u16 curbass; + __u16 curtreble; + int muted; + unsigned long curfreq; + int curstereo; + int curmute; + struct mutex lock; +}; + +static struct trust trust_card; /* i2c addresses */ #define TDA7318_ADDR 0x88 #define TSA6060T_ADDR 0xc4 -#define TR_DELAY do { inb(io); inb(io); inb(io); } while(0) -#define TR_SET_SCL outb(ioval |= 2, io) -#define TR_CLR_SCL outb(ioval &= 0xfd, io) -#define TR_SET_SDA outb(ioval |= 1, io) -#define TR_CLR_SDA outb(ioval &= 0xfe, io) +#define TR_DELAY do { inb(tr->io); inb(tr->io); inb(tr->io); } while (0) +#define TR_SET_SCL outb(tr->ioval |= 2, tr->io) +#define TR_CLR_SCL outb(tr->ioval &= 0xfd, tr->io) +#define TR_SET_SDA outb(tr->ioval |= 1, tr->io) +#define TR_CLR_SDA outb(tr->ioval &= 0xfe, tr->io) -static void write_i2c(int n, ...) +static void write_i2c(struct trust *tr, int n, ...) { unsigned char val, mask; va_list args; @@ -136,62 +117,77 @@ static void write_i2c(int n, ...) va_end(args); } -static void tr_setvol(__u16 vol) +static void tr_setvol(struct trust *tr, __u16 vol) { - curvol = vol / 2048; - write_i2c(2, TDA7318_ADDR, curvol ^ 0x1f); + mutex_lock(&tr->lock); + tr->curvol = vol / 2048; + write_i2c(tr, 2, TDA7318_ADDR, tr->curvol ^ 0x1f); + mutex_unlock(&tr->lock); } static int basstreble2chip[15] = { 0, 1, 2, 3, 4, 5, 6, 7, 14, 13, 12, 11, 10, 9, 8 }; -static void tr_setbass(__u16 bass) +static void tr_setbass(struct trust *tr, __u16 bass) { - curbass = bass / 4370; - write_i2c(2, TDA7318_ADDR, 0x60 | basstreble2chip[curbass]); + mutex_lock(&tr->lock); + tr->curbass = bass / 4370; + write_i2c(tr, 2, TDA7318_ADDR, 0x60 | basstreble2chip[tr->curbass]); + mutex_unlock(&tr->lock); } -static void tr_settreble(__u16 treble) +static void tr_settreble(struct trust *tr, __u16 treble) { - curtreble = treble / 4370; - write_i2c(2, TDA7318_ADDR, 0x70 | basstreble2chip[curtreble]); + mutex_lock(&tr->lock); + tr->curtreble = treble / 4370; + write_i2c(tr, 2, TDA7318_ADDR, 0x70 | basstreble2chip[tr->curtreble]); + mutex_unlock(&tr->lock); } -static void tr_setstereo(int stereo) +static void tr_setstereo(struct trust *tr, int stereo) { - curstereo = !!stereo; - ioval = (ioval & 0xfb) | (!curstereo << 2); - outb(ioval, io); + mutex_lock(&tr->lock); + tr->curstereo = !!stereo; + tr->ioval = (tr->ioval & 0xfb) | (!tr->curstereo << 2); + outb(tr->ioval, tr->io); + mutex_unlock(&tr->lock); } -static void tr_setmute(int mute) +static void tr_setmute(struct trust *tr, int mute) { - curmute = !!mute; - ioval = (ioval & 0xf7) | (curmute << 3); - outb(ioval, io); + mutex_lock(&tr->lock); + tr->curmute = !!mute; + tr->ioval = (tr->ioval & 0xf7) | (tr->curmute << 3); + outb(tr->ioval, tr->io); + mutex_unlock(&tr->lock); } -static int tr_getsigstr(void) +static int tr_getsigstr(struct trust *tr) { int i, v; - for(i = 0, v = 0; i < 100; i++) v |= inb(io); - return (v & 1)? 0 : 0xffff; + mutex_lock(&tr->lock); + for (i = 0, v = 0; i < 100; i++) + v |= inb(tr->io); + mutex_unlock(&tr->lock); + return (v & 1) ? 0 : 0xffff; } -static int tr_getstereo(void) +static int tr_getstereo(struct trust *tr) { /* don't know how to determine it, just return the setting */ - return curstereo; + return tr->curstereo; } -static void tr_setfreq(unsigned long f) +static void tr_setfreq(struct trust *tr, unsigned long f) { + mutex_lock(&tr->lock); + tr->curfreq = f; f /= 160; /* Convert to 10 kHz units */ - f += 1070; /* Add 10.7 MHz IF */ - - write_i2c(5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0); + f += 1070; /* Add 10.7 MHz IF */ + write_i2c(tr, 5, TSA6060T_ADDR, (f << 1) | 1, f >> 7, 0x60 | ((f >> 15) & 1), 0); + mutex_unlock(&tr->lock); } static int vidioc_querycap(struct file *file, void *priv, @@ -199,68 +195,75 @@ static int vidioc_querycap(struct file *file, void *priv, { strlcpy(v->driver, "radio-trust", sizeof(v->driver)); strlcpy(v->card, "Trust FM Radio", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { + struct trust *tr = video_drvdata(file); + if (v->index > 0) return -EINVAL; - strcpy(v->name, "FM"); + strlcpy(v->name, "FM", sizeof(v->name)); v->type = V4L2_TUNER_RADIO; - v->rangelow = (87.5*16000); - v->rangehigh = (108*16000); - v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; + v->rangelow = 87.5 * 16000; + v->rangehigh = 108 * 16000; + v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; v->capability = V4L2_TUNER_CAP_LOW; - if (tr_getstereo()) + if (tr_getstereo(tr)) v->audmode = V4L2_TUNER_MODE_STEREO; else v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = tr_getsigstr(); + v->signal = tr_getsigstr(tr); return 0; } static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - if (v->index > 0) - return -EINVAL; + struct trust *tr = video_drvdata(file); + if (v->index) + return -EINVAL; + tr_setstereo(tr, v->audmode == V4L2_TUNER_MODE_STEREO); return 0; } static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - curfreq = f->frequency; - tr_setfreq(curfreq); + struct trust *tr = video_drvdata(file); + + tr_setfreq(tr, f->frequency); return 0; } static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { + struct trust *tr = video_drvdata(file); + f->type = V4L2_TUNER_RADIO; - f->frequency = curfreq; + f->frequency = tr->curfreq; return 0; } static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc) { - int i; - - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); - return 0; - } + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 65535, 2048, 65535); + case V4L2_CID_AUDIO_BASS: + case V4L2_CID_AUDIO_TREBLE: + return v4l2_ctrl_query_fill(qc, 0, 65535, 4370, 32768); } return -EINVAL; } @@ -268,18 +271,20 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { + struct trust *tr = video_drvdata(file); + switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - ctrl->value = curmute; + ctrl->value = tr->curmute; return 0; case V4L2_CID_AUDIO_VOLUME: - ctrl->value = curvol * 2048; + ctrl->value = tr->curvol * 2048; return 0; case V4L2_CID_AUDIO_BASS: - ctrl->value = curbass * 4370; + ctrl->value = tr->curbass * 4370; return 0; case V4L2_CID_AUDIO_TREBLE: - ctrl->value = curtreble * 4370; + ctrl->value = tr->curtreble * 4370; return 0; } return -EINVAL; @@ -288,34 +293,25 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { + struct trust *tr = video_drvdata(file); + switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - tr_setmute(ctrl->value); + tr_setmute(tr, ctrl->value); return 0; case V4L2_CID_AUDIO_VOLUME: - tr_setvol(ctrl->value); + tr_setvol(tr, ctrl->value); return 0; case V4L2_CID_AUDIO_BASS: - tr_setbass(ctrl->value); + tr_setbass(tr, ctrl->value); return 0; case V4L2_CID_AUDIO_TREBLE: - tr_settreble(ctrl->value); + tr_settreble(tr, ctrl->value); return 0; } return -EINVAL; } -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) { *i = 0; @@ -324,34 +320,26 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) { - if (i != 0) - return -EINVAL; - return 0; + return i ? -EINVAL : 0; } -static int vidioc_s_audio(struct file *file, void *priv, +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) { - if (a->index != 0) - return -EINVAL; + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; return 0; } -static int trust_exclusive_open(struct file *file) -{ - return test_and_set_bit(0, &in_use) ? -EBUSY : 0; -} - -static int trust_exclusive_release(struct file *file) +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) { - clear_bit(0, &in_use); - return 0; + return a->index ? -EINVAL : 0; } static const struct v4l2_file_operations trust_fops = { .owner = THIS_MODULE, - .open = trust_exclusive_open, - .release = trust_exclusive_release, .ioctl = video_ioctl2, }; @@ -370,59 +358,72 @@ static const struct v4l2_ioctl_ops trust_ioctl_ops = { .vidioc_s_input = vidioc_s_input, }; -static struct video_device trust_radio = { - .name = "Trust FM Radio", - .fops = &trust_fops, - .ioctl_ops = &trust_ioctl_ops, - .release = video_device_release_empty, -}; - static int __init trust_init(void) { - if(io == -1) { - printk(KERN_ERR "You must set an I/O address with io=0x???\n"); + struct trust *tr = &trust_card; + struct v4l2_device *v4l2_dev = &tr->v4l2_dev; + int res; + + strlcpy(v4l2_dev->name, "trust", sizeof(v4l2_dev->name)); + tr->io = io; + tr->ioval = 0xf; + mutex_init(&tr->lock); + + if (tr->io == -1) { + v4l2_err(v4l2_dev, "You must set an I/O address with io=0x0x350 or 0x358\n"); return -EINVAL; } - if(!request_region(io, 2, "Trust FM Radio")) { - printk(KERN_ERR "trust: port 0x%x already in use\n", io); + if (!request_region(tr->io, 2, "Trust FM Radio")) { + v4l2_err(v4l2_dev, "port 0x%x already in use\n", tr->io); return -EBUSY; } - if (video_register_device(&trust_radio, VFL_TYPE_RADIO, radio_nr) < 0) { - release_region(io, 2); + + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + release_region(tr->io, 2); + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return res; + } + + strlcpy(tr->vdev.name, v4l2_dev->name, sizeof(tr->vdev.name)); + tr->vdev.v4l2_dev = v4l2_dev; + tr->vdev.fops = &trust_fops; + tr->vdev.ioctl_ops = &trust_ioctl_ops; + tr->vdev.release = video_device_release_empty; + video_set_drvdata(&tr->vdev, tr); + + if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(tr->io, 2); return -EINVAL; } - printk(KERN_INFO "Trust FM Radio card driver v1.0.\n"); + v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n"); - write_i2c(2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */ - write_i2c(2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */ - write_i2c(2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */ - write_i2c(2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */ - write_i2c(2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */ + write_i2c(tr, 2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */ + write_i2c(tr, 2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */ + write_i2c(tr, 2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */ + write_i2c(tr, 2, TDA7318_ADDR, 0xe0); /* speaker att. RR = 0 dB */ + write_i2c(tr, 2, TDA7318_ADDR, 0x40); /* stereo 1 input, gain = 18.75 dB */ - tr_setvol(0x8000); - tr_setbass(0x8000); - tr_settreble(0x8000); - tr_setstereo(1); + tr_setvol(tr, 0xffff); + tr_setbass(tr, 0x8000); + tr_settreble(tr, 0x8000); + tr_setstereo(tr, 1); /* mute card - prevents noisy bootups */ - tr_setmute(1); + tr_setmute(tr, 1); return 0; } -MODULE_AUTHOR("Eric Lammerts, Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath"); -MODULE_DESCRIPTION("A driver for the Trust FM Radio card."); -MODULE_LICENSE("GPL"); - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the Trust FM Radio card (0x350 or 0x358)"); -module_param(radio_nr, int, 0); - static void __exit cleanup_trust_module(void) { - video_unregister_device(&trust_radio); - release_region(io, 2); + struct trust *tr = &trust_card; + + video_unregister_device(&tr->vdev); + v4l2_device_unregister(&tr->v4l2_dev); + release_region(tr->io, 2); } module_init(trust_init); diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c index 5c3b319dab37..3a98f1399495 100644 --- a/drivers/media/radio/radio-typhoon.c +++ b/drivers/media/radio/radio-typhoon.c @@ -34,37 +34,15 @@ #include <linux/module.h> /* Modules */ #include <linux/init.h> /* Initdata */ #include <linux/ioport.h> /* request_region */ -#include <linux/proc_fs.h> /* radio card status report */ -#include <linux/seq_file.h> -#include <asm/io.h> /* outb, outb_p */ -#include <asm/uaccess.h> /* copy to/from user */ +#include <linux/version.h> /* for KERNEL_VERSION MACRO */ #include <linux/videodev2.h> /* kernel radio structs */ -#include <media/v4l2-common.h> +#include <linux/io.h> /* outb, outb_p */ +#include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> -#include <linux/version.h> /* for KERNEL_VERSION MACRO */ -#define RADIO_VERSION KERNEL_VERSION(0,1,1) -#define BANNER "Typhoon Radio Card driver v0.1.1\n" - -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 65535, - .step = 1<<14, - .default_value = 0xff, - .type = V4L2_CTRL_TYPE_INTEGER, - } -}; - +MODULE_AUTHOR("Dr. Henrik Seidel"); +MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio)."); +MODULE_LICENSE("GPL"); #ifndef CONFIG_RADIO_TYPHOON_PORT #define CONFIG_RADIO_TYPHOON_PORT -1 @@ -74,13 +52,26 @@ static struct v4l2_queryctrl radio_qctrl[] = { #define CONFIG_RADIO_TYPHOON_MUTEFREQ 0 #endif -#ifndef CONFIG_PROC_FS -#undef CONFIG_RADIO_TYPHOON_PROC_FS -#endif +static int io = CONFIG_RADIO_TYPHOON_PORT; +static int radio_nr = -1; -struct typhoon_device { - unsigned long in_use; - int iobase; +module_param(io, int, 0); +MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)"); + +module_param(radio_nr, int, 0); + +static unsigned long mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ; +module_param(mutefreq, ulong, 0); +MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)"); + +#define RADIO_VERSION KERNEL_VERSION(0, 1, 1) + +#define BANNER "Typhoon Radio Card driver v0.1.1\n" + +struct typhoon { + struct v4l2_device v4l2_dev; + struct video_device vdev; + int io; int curvol; int muted; unsigned long curfreq; @@ -88,25 +79,19 @@ struct typhoon_device { struct mutex lock; }; -static void typhoon_setvol_generic(struct typhoon_device *dev, int vol); -static int typhoon_setfreq_generic(struct typhoon_device *dev, - unsigned long frequency); -static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency); -static void typhoon_mute(struct typhoon_device *dev); -static void typhoon_unmute(struct typhoon_device *dev); -static int typhoon_setvol(struct typhoon_device *dev, int vol); +static struct typhoon typhoon_card; -static void typhoon_setvol_generic(struct typhoon_device *dev, int vol) +static void typhoon_setvol_generic(struct typhoon *dev, int vol) { mutex_lock(&dev->lock); vol >>= 14; /* Map 16 bit to 2 bit */ vol &= 3; - 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->io); /* Set the volume, high bit. */ + outb_p(vol % 2, dev->io + 2); /* Set the volume, low bit. */ mutex_unlock(&dev->lock); } -static int typhoon_setfreq_generic(struct typhoon_device *dev, +static int typhoon_setfreq_generic(struct typhoon *dev, unsigned long frequency) { unsigned long outval; @@ -130,22 +115,22 @@ static int typhoon_setfreq_generic(struct typhoon_device *dev, outval -= (10 * x * x + 10433) / 20866; outval += 4 * x - 11505; - outb_p((outval >> 8) & 0x01, dev->iobase + 4); - outb_p(outval >> 9, dev->iobase + 6); - outb_p(outval & 0xff, dev->iobase + 8); + outb_p((outval >> 8) & 0x01, dev->io + 4); + outb_p(outval >> 9, dev->io + 6); + outb_p(outval & 0xff, dev->io + 8); mutex_unlock(&dev->lock); return 0; } -static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency) +static int typhoon_setfreq(struct typhoon *dev, unsigned long frequency) { typhoon_setfreq_generic(dev, frequency); dev->curfreq = frequency; return 0; } -static void typhoon_mute(struct typhoon_device *dev) +static void typhoon_mute(struct typhoon *dev) { if (dev->muted == 1) return; @@ -154,7 +139,7 @@ static void typhoon_mute(struct typhoon_device *dev) dev->muted = 1; } -static void typhoon_unmute(struct typhoon_device *dev) +static void typhoon_unmute(struct typhoon *dev) { if (dev->muted == 0) return; @@ -163,7 +148,7 @@ static void typhoon_unmute(struct typhoon_device *dev) dev->muted = 0; } -static int typhoon_setvol(struct typhoon_device *dev, int vol) +static int typhoon_setvol(struct typhoon *dev, int vol) { if (dev->muted && vol != 0) { /* user is unmuting the card */ dev->curvol = vol; @@ -188,9 +173,9 @@ static int vidioc_querycap(struct file *file, void *priv, { strlcpy(v->driver, "radio-typhoon", sizeof(v->driver)); strlcpy(v->card, "Typhoon Radio", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } @@ -200,10 +185,10 @@ static int vidioc_g_tuner(struct file *file, void *priv, if (v->index > 0) return -EINVAL; - strcpy(v->name, "FM"); + strlcpy(v->name, "FM", sizeof(v->name)); v->type = V4L2_TUNER_RADIO; - v->rangelow = (87.5*16000); - v->rangehigh = (108*16000); + v->rangelow = 87.5 * 16000; + v->rangehigh = 108 * 16000; v->rxsubchans = V4L2_TUNER_SUB_MONO; v->capability = V4L2_TUNER_CAP_LOW; v->audmode = V4L2_TUNER_MODE_MONO; @@ -214,44 +199,37 @@ static int vidioc_g_tuner(struct file *file, void *priv, static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - if (v->index > 0) - return -EINVAL; - - return 0; + return v->index ? -EINVAL : 0; } -static int vidioc_s_frequency(struct file *file, void *priv, +static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct typhoon_device *typhoon = video_drvdata(file); + struct typhoon *dev = video_drvdata(file); - typhoon->curfreq = f->frequency; - typhoon_setfreq(typhoon, typhoon->curfreq); + f->type = V4L2_TUNER_RADIO; + f->frequency = dev->curfreq; return 0; } -static int vidioc_g_frequency(struct file *file, void *priv, +static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct typhoon_device *typhoon = video_drvdata(file); - - f->type = V4L2_TUNER_RADIO; - f->frequency = typhoon->curfreq; + struct typhoon *dev = video_drvdata(file); + dev->curfreq = f->frequency; + typhoon_setfreq(dev, dev->curfreq); return 0; } static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc) { - int i; - - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); - return 0; - } + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 65535, 16384, 65535); } return -EINVAL; } @@ -259,14 +237,14 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct typhoon_device *typhoon = video_drvdata(file); + struct typhoon *dev = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: - ctrl->value = typhoon->muted; + ctrl->value = dev->muted; return 0; case V4L2_CID_AUDIO_VOLUME: - ctrl->value = typhoon->curvol; + ctrl->value = dev->curvol; return 0; } return -EINVAL; @@ -275,33 +253,22 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl (struct file *file, void *priv, struct v4l2_control *ctrl) { - struct typhoon_device *typhoon = video_drvdata(file); + struct typhoon *dev = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: if (ctrl->value) - typhoon_mute(typhoon); + typhoon_mute(dev); else - typhoon_unmute(typhoon); + typhoon_unmute(dev); return 0; case V4L2_CID_AUDIO_VOLUME: - typhoon_setvol(typhoon, ctrl->value); + typhoon_setvol(dev, ctrl->value); return 0; } return -EINVAL; } -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) { *i = 0; @@ -310,45 +277,50 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) { - if (i != 0) - return -EINVAL; - return 0; + return i ? -EINVAL : 0; } -static int vidioc_s_audio(struct file *file, void *priv, +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) { - if (a->index != 0) - return -EINVAL; + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; return 0; } -static struct typhoon_device typhoon_unit = -{ - .iobase = CONFIG_RADIO_TYPHOON_PORT, - .curfreq = CONFIG_RADIO_TYPHOON_MUTEFREQ, - .mutefreq = CONFIG_RADIO_TYPHOON_MUTEFREQ, -}; - -static int typhoon_exclusive_open(struct file *file) +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) { - return test_and_set_bit(0, &typhoon_unit.in_use) ? -EBUSY : 0; + return a->index ? -EINVAL : 0; } -static int typhoon_exclusive_release(struct file *file) +static int vidioc_log_status(struct file *file, void *priv) { - clear_bit(0, &typhoon_unit.in_use); + struct typhoon *dev = video_drvdata(file); + struct v4l2_device *v4l2_dev = &dev->v4l2_dev; + + v4l2_info(v4l2_dev, BANNER); +#ifdef MODULE + v4l2_info(v4l2_dev, "Load type: Driver loaded as a module\n\n"); +#else + v4l2_info(v4l2_dev, "Load type: Driver compiled into kernel\n\n"); +#endif + v4l2_info(v4l2_dev, "frequency = %lu kHz\n", dev->curfreq >> 4); + v4l2_info(v4l2_dev, "volume = %d\n", dev->curvol); + v4l2_info(v4l2_dev, "mute = %s\n", dev->muted ? "on" : "off"); + v4l2_info(v4l2_dev, "io = 0x%x\n", dev->io); + v4l2_info(v4l2_dev, "mute frequency = %lu kHz\n", dev->mutefreq >> 4); return 0; } static const struct v4l2_file_operations typhoon_fops = { .owner = THIS_MODULE, - .open = typhoon_exclusive_open, - .release = typhoon_exclusive_release, .ioctl = video_ioctl2, }; static const struct v4l2_ioctl_ops typhoon_ioctl_ops = { + .vidioc_log_status = vidioc_log_status, .vidioc_querycap = vidioc_querycap, .vidioc_g_tuner = vidioc_g_tuner, .vidioc_s_tuner = vidioc_s_tuner, @@ -363,125 +335,72 @@ static const struct v4l2_ioctl_ops typhoon_ioctl_ops = { .vidioc_s_ctrl = vidioc_s_ctrl, }; -static struct video_device typhoon_radio = { - .name = "Typhoon Radio", - .fops = &typhoon_fops, - .ioctl_ops = &typhoon_ioctl_ops, - .release = video_device_release_empty, -}; - -#ifdef CONFIG_RADIO_TYPHOON_PROC_FS - -static int typhoon_proc_show(struct seq_file *m, void *v) -{ - #ifdef MODULE - #define MODULEPROCSTRING "Driver loaded as a module" - #else - #define MODULEPROCSTRING "Driver compiled into kernel" - #endif - - seq_puts(m, BANNER); - seq_puts(m, "Load type: " MODULEPROCSTRING "\n\n"); - seq_printf(m, "frequency = %lu kHz\n", - typhoon_unit.curfreq >> 4); - seq_printf(m, "volume = %d\n", typhoon_unit.curvol); - seq_printf(m, "mute = %s\n", typhoon_unit.muted ? - "on" : "off"); - seq_printf(m, "iobase = 0x%x\n", typhoon_unit.iobase); - seq_printf(m, "mute frequency = %lu kHz\n", - typhoon_unit.mutefreq >> 4); - return 0; -} - -static int typhoon_proc_open(struct inode *inode, struct file *file) +static int __init typhoon_init(void) { - return single_open(file, typhoon_proc_show, NULL); -} + struct typhoon *dev = &typhoon_card; + struct v4l2_device *v4l2_dev = &dev->v4l2_dev; + int res; -static const struct file_operations typhoon_proc_fops = { - .owner = THIS_MODULE, - .open = typhoon_proc_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; -#endif /* CONFIG_RADIO_TYPHOON_PROC_FS */ + strlcpy(v4l2_dev->name, "typhoon", sizeof(v4l2_dev->name)); + dev->io = io; + dev->curfreq = dev->mutefreq = mutefreq; -MODULE_AUTHOR("Dr. Henrik Seidel"); -MODULE_DESCRIPTION("A driver for the Typhoon radio card (a.k.a. EcoRadio)."); -MODULE_LICENSE("GPL"); - -static int io = -1; -static int radio_nr = -1; - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)"); -module_param(radio_nr, int, 0); - -#ifdef MODULE -static unsigned long mutefreq; -module_param(mutefreq, ulong, 0); -MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)"); -#endif - -static int __init typhoon_init(void) -{ -#ifdef MODULE - if (io == -1) { - printk(KERN_ERR "radio-typhoon: You must set an I/O address with io=0x316 or io=0x336\n"); + if (dev->io == -1) { + v4l2_err(v4l2_dev, "You must set an I/O address with io=0x316 or io=0x336\n"); return -EINVAL; } - typhoon_unit.iobase = io; - 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: e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n"); + if (dev->mutefreq < 87000 || dev->mutefreq > 108500) { + v4l2_err(v4l2_dev, "You must set a frequency (in kHz) used when muting the card,\n"); + v4l2_err(v4l2_dev, "e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n"); return -EINVAL; } - typhoon_unit.mutefreq = mutefreq; -#endif /* MODULE */ - - printk(KERN_INFO BANNER); - mutex_init(&typhoon_unit.lock); - io = typhoon_unit.iobase; - if (!request_region(io, 8, "typhoon")) { - printk(KERN_ERR "radio-typhoon: port 0x%x already in use\n", - typhoon_unit.iobase); + + mutex_init(&dev->lock); + if (!request_region(dev->io, 8, "typhoon")) { + v4l2_err(v4l2_dev, "port 0x%x already in use\n", + dev->io); return -EBUSY; } - video_set_drvdata(&typhoon_radio, &typhoon_unit); - if (video_register_device(&typhoon_radio, VFL_TYPE_RADIO, radio_nr) < 0) { - release_region(io, 8); + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + release_region(dev->io, 8); + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return res; + } + v4l2_info(v4l2_dev, BANNER); + + strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); + dev->vdev.v4l2_dev = v4l2_dev; + dev->vdev.fops = &typhoon_fops; + dev->vdev.ioctl_ops = &typhoon_ioctl_ops; + dev->vdev.release = video_device_release_empty; + video_set_drvdata(&dev->vdev, dev); + if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(&dev->v4l2_dev); + release_region(dev->io, 8); return -EINVAL; } - printk(KERN_INFO "radio-typhoon: port 0x%x.\n", typhoon_unit.iobase); - printk(KERN_INFO "radio-typhoon: mute frequency is %lu kHz.\n", - typhoon_unit.mutefreq); - typhoon_unit.mutefreq <<= 4; + v4l2_info(v4l2_dev, "port 0x%x.\n", dev->io); + v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", dev->mutefreq); + dev->mutefreq <<= 4; /* mute card - prevents noisy bootups */ - typhoon_mute(&typhoon_unit); - -#ifdef CONFIG_RADIO_TYPHOON_PROC_FS - if (!proc_create("driver/radio-typhoon", 0, NULL, &typhoon_proc_fops)) - printk(KERN_ERR "radio-typhoon: registering /proc/driver/radio-typhoon failed\n"); -#endif + typhoon_mute(dev); return 0; } -static void __exit typhoon_cleanup_module(void) +static void __exit typhoon_exit(void) { + struct typhoon *dev = &typhoon_card; -#ifdef CONFIG_RADIO_TYPHOON_PROC_FS - remove_proc_entry("driver/radio-typhoon", NULL); -#endif - - video_unregister_device(&typhoon_radio); - release_region(io, 8); + video_unregister_device(&dev->vdev); + v4l2_device_unregister(&dev->v4l2_dev); + release_region(dev->io, 8); } module_init(typhoon_init); -module_exit(typhoon_cleanup_module); +module_exit(typhoon_exit); diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c index d2ac17eeec5f..80e98b6422fe 100644 --- a/drivers/media/radio/radio-zoltrix.c +++ b/drivers/media/radio/radio-zoltrix.c @@ -33,33 +33,16 @@ #include <linux/init.h> /* Initdata */ #include <linux/ioport.h> /* request_region */ #include <linux/delay.h> /* udelay, msleep */ -#include <asm/io.h> /* outb, outb_p */ -#include <asm/uaccess.h> /* copy to/from user */ #include <linux/videodev2.h> /* kernel radio structs */ -#include <media/v4l2-common.h> +#include <linux/mutex.h> +#include <linux/version.h> /* for KERNEL_VERSION MACRO */ +#include <linux/io.h> /* outb, outb_p */ +#include <media/v4l2-device.h> #include <media/v4l2-ioctl.h> -#include <linux/version.h> /* for KERNEL_VERSION MACRO */ -#define RADIO_VERSION KERNEL_VERSION(0,0,2) - -static struct v4l2_queryctrl radio_qctrl[] = { - { - .id = V4L2_CID_AUDIO_MUTE, - .name = "Mute", - .minimum = 0, - .maximum = 1, - .default_value = 1, - .type = V4L2_CTRL_TYPE_BOOLEAN, - },{ - .id = V4L2_CID_AUDIO_VOLUME, - .name = "Volume", - .minimum = 0, - .maximum = 65535, - .step = 4096, - .default_value = 0xff, - .type = V4L2_CTRL_TYPE_INTEGER, - } -}; +MODULE_AUTHOR("C.van Schaik"); +MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus."); +MODULE_LICENSE("GPL"); #ifndef CONFIG_RADIO_ZOLTRIX_PORT #define CONFIG_RADIO_ZOLTRIX_PORT -1 @@ -68,9 +51,16 @@ static struct v4l2_queryctrl radio_qctrl[] = { static int io = CONFIG_RADIO_ZOLTRIX_PORT; static int radio_nr = -1; -struct zol_device { - unsigned long in_use; - int port; +module_param(io, int, 0); +MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)"); +module_param(radio_nr, int, 0); + +#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) + +struct zoltrix { + struct v4l2_device v4l2_dev; + struct video_device vdev; + int io; int curvol; unsigned long curfreq; int muted; @@ -78,161 +68,158 @@ struct zol_device { struct mutex lock; }; -static int zol_setvol(struct zol_device *dev, int vol) +static struct zoltrix zoltrix_card; + +static int zol_setvol(struct zoltrix *zol, int vol) { - dev->curvol = vol; - if (dev->muted) + zol->curvol = vol; + if (zol->muted) return 0; - mutex_lock(&dev->lock); + mutex_lock(&zol->lock); if (vol == 0) { - outb(0, io); - outb(0, io); - inb(io + 3); /* Zoltrix needs to be read to confirm */ - mutex_unlock(&dev->lock); + outb(0, zol->io); + outb(0, zol->io); + inb(zol->io + 3); /* Zoltrix needs to be read to confirm */ + mutex_unlock(&zol->lock); return 0; } - outb(dev->curvol-1, io); + outb(zol->curvol-1, zol->io); msleep(10); - inb(io + 2); - mutex_unlock(&dev->lock); + inb(zol->io + 2); + mutex_unlock(&zol->lock); return 0; } -static void zol_mute(struct zol_device *dev) +static void zol_mute(struct zoltrix *zol) { - dev->muted = 1; - mutex_lock(&dev->lock); - outb(0, io); - outb(0, io); - inb(io + 3); /* Zoltrix needs to be read to confirm */ - mutex_unlock(&dev->lock); + zol->muted = 1; + mutex_lock(&zol->lock); + outb(0, zol->io); + outb(0, zol->io); + inb(zol->io + 3); /* Zoltrix needs to be read to confirm */ + mutex_unlock(&zol->lock); } -static void zol_unmute(struct zol_device *dev) +static void zol_unmute(struct zoltrix *zol) { - dev->muted = 0; - zol_setvol(dev, dev->curvol); + zol->muted = 0; + zol_setvol(zol, zol->curvol); } -static int zol_setfreq(struct zol_device *dev, unsigned long freq) +static int zol_setfreq(struct zoltrix *zol, unsigned long freq) { /* tunes the radio to the desired frequency */ + struct v4l2_device *v4l2_dev = &zol->v4l2_dev; unsigned long long bitmask, f, m; - unsigned int stereo = dev->stereo; + unsigned int stereo = zol->stereo; int i; if (freq == 0) { - printk(KERN_WARNING "zoltrix: received zero freq. Failed to set.\n"); + v4l2_warn(v4l2_dev, "cannot set a frequency of 0.\n"); return -EINVAL; } m = (freq / 160 - 8800) * 2; - f = (unsigned long long) m + 0x4d1c; + f = (unsigned long long)m + 0x4d1c; bitmask = 0xc480402c10080000ull; i = 45; - mutex_lock(&dev->lock); + mutex_lock(&zol->lock); - outb(0, io); - outb(0, io); - inb(io + 3); /* Zoltrix needs to be read to confirm */ + zol->curfreq = freq; - outb(0x40, io); - outb(0xc0, io); + outb(0, zol->io); + outb(0, zol->io); + inb(zol->io + 3); /* Zoltrix needs to be read to confirm */ - bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ ( stereo << 31)); + outb(0x40, zol->io); + outb(0xc0, zol->io); + + bitmask = (bitmask ^ ((f & 0xff) << 47) ^ ((f & 0xff00) << 30) ^ (stereo << 31)); while (i--) { if ((bitmask & 0x8000000000000000ull) != 0) { - outb(0x80, io); + outb(0x80, zol->io); udelay(50); - outb(0x00, io); + outb(0x00, zol->io); udelay(50); - outb(0x80, io); + outb(0x80, zol->io); udelay(50); } else { - outb(0xc0, io); + outb(0xc0, zol->io); udelay(50); - outb(0x40, io); + outb(0x40, zol->io); udelay(50); - outb(0xc0, io); + outb(0xc0, zol->io); udelay(50); } bitmask *= 2; } /* termination sequence */ - outb(0x80, io); - outb(0xc0, io); - outb(0x40, io); + outb(0x80, zol->io); + outb(0xc0, zol->io); + outb(0x40, zol->io); udelay(1000); - inb(io+2); + inb(zol->io + 2); udelay(1000); - if (dev->muted) - { - outb(0, io); - outb(0, io); - inb(io + 3); + if (zol->muted) { + outb(0, zol->io); + outb(0, zol->io); + inb(zol->io + 3); udelay(1000); } - mutex_unlock(&dev->lock); + mutex_unlock(&zol->lock); - if(!dev->muted) - { - zol_setvol(dev, dev->curvol); - } + if (!zol->muted) + zol_setvol(zol, zol->curvol); return 0; } /* Get signal strength */ - -static int zol_getsigstr(struct zol_device *dev) +static int zol_getsigstr(struct zoltrix *zol) { int a, b; - mutex_lock(&dev->lock); - outb(0x00, io); /* This stuff I found to do nothing */ - outb(dev->curvol, io); + mutex_lock(&zol->lock); + outb(0x00, zol->io); /* This stuff I found to do nothing */ + outb(zol->curvol, zol->io); msleep(20); - a = inb(io); + a = inb(zol->io); msleep(10); - b = inb(io); + b = inb(zol->io); - mutex_unlock(&dev->lock); + mutex_unlock(&zol->lock); if (a != b) - return (0); + return 0; - if ((a == 0xcf) || (a == 0xdf) /* I found this out by playing */ - || (a == 0xef)) /* with a binary scanner on the card io */ - return (1); - return (0); + /* I found this out by playing with a binary scanner on the card io */ + return a == 0xcf || a == 0xdf || a == 0xef; } -static int zol_is_stereo (struct zol_device *dev) +static int zol_is_stereo(struct zoltrix *zol) { int x1, x2; - mutex_lock(&dev->lock); + mutex_lock(&zol->lock); - outb(0x00, io); - outb(dev->curvol, io); + outb(0x00, zol->io); + outb(zol->curvol, zol->io); msleep(20); - x1 = inb(io); + x1 = inb(zol->io); msleep(10); - x2 = inb(io); + x2 = inb(zol->io); - mutex_unlock(&dev->lock); + mutex_unlock(&zol->lock); - if ((x1 == x2) && (x1 == 0xcf)) - return 1; - return 0; + return x1 == x2 && x1 == 0xcf; } static int vidioc_querycap(struct file *file, void *priv, @@ -240,59 +227,54 @@ static int vidioc_querycap(struct file *file, void *priv, { strlcpy(v->driver, "radio-zoltrix", sizeof(v->driver)); strlcpy(v->card, "Zoltrix Radio", sizeof(v->card)); - sprintf(v->bus_info, "ISA"); + strlcpy(v->bus_info, "ISA", sizeof(v->bus_info)); v->version = RADIO_VERSION; - v->capabilities = V4L2_CAP_TUNER; + v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO; return 0; } static int vidioc_g_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - struct zol_device *zol = video_drvdata(file); + struct zoltrix *zol = video_drvdata(file); if (v->index > 0) return -EINVAL; - strcpy(v->name, "FM"); + strlcpy(v->name, "FM", sizeof(v->name)); v->type = V4L2_TUNER_RADIO; - v->rangelow = (88*16000); - v->rangehigh = (108*16000); - v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO; + v->rangelow = 88 * 16000; + v->rangehigh = 108 * 16000; + v->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO; v->capability = V4L2_TUNER_CAP_LOW; if (zol_is_stereo(zol)) v->audmode = V4L2_TUNER_MODE_STEREO; else v->audmode = V4L2_TUNER_MODE_MONO; - v->signal = 0xFFFF*zol_getsigstr(zol); + v->signal = 0xFFFF * zol_getsigstr(zol); return 0; } static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *v) { - if (v->index > 0) - return -EINVAL; - return 0; + return v->index ? -EINVAL : 0; } static int vidioc_s_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct zol_device *zol = video_drvdata(file); + struct zoltrix *zol = video_drvdata(file); - zol->curfreq = f->frequency; - if (zol_setfreq(zol, zol->curfreq) != 0) { - printk(KERN_WARNING "zoltrix: Set frequency failed.\n"); + if (zol_setfreq(zol, f->frequency) != 0) return -EINVAL; - } return 0; } static int vidioc_g_frequency(struct file *file, void *priv, struct v4l2_frequency *f) { - struct zol_device *zol = video_drvdata(file); + struct zoltrix *zol = video_drvdata(file); f->type = V4L2_TUNER_RADIO; f->frequency = zol->curfreq; @@ -302,14 +284,11 @@ static int vidioc_g_frequency(struct file *file, void *priv, static int vidioc_queryctrl(struct file *file, void *priv, struct v4l2_queryctrl *qc) { - int i; - - for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) { - if (qc->id && qc->id == radio_qctrl[i].id) { - memcpy(qc, &(radio_qctrl[i]), - sizeof(*qc)); - return 0; - } + switch (qc->id) { + case V4L2_CID_AUDIO_MUTE: + return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1); + case V4L2_CID_AUDIO_VOLUME: + return v4l2_ctrl_query_fill(qc, 0, 65535, 4096, 65535); } return -EINVAL; } @@ -317,7 +296,7 @@ static int vidioc_queryctrl(struct file *file, void *priv, static int vidioc_g_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct zol_device *zol = video_drvdata(file); + struct zoltrix *zol = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -333,7 +312,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv, static int vidioc_s_ctrl(struct file *file, void *priv, struct v4l2_control *ctrl) { - struct zol_device *zol = video_drvdata(file); + struct zoltrix *zol = video_drvdata(file); switch (ctrl->id) { case V4L2_CID_AUDIO_MUTE: @@ -341,43 +320,30 @@ static int vidioc_s_ctrl(struct file *file, void *priv, zol_mute(zol); else { zol_unmute(zol); - zol_setvol(zol,zol->curvol); + zol_setvol(zol, zol->curvol); } return 0; case V4L2_CID_AUDIO_VOLUME: - zol_setvol(zol,ctrl->value/4096); + zol_setvol(zol, ctrl->value / 4096); return 0; } zol->stereo = 1; - if (zol_setfreq(zol, zol->curfreq) != 0) { - printk(KERN_WARNING "zoltrix: Set frequency failed.\n"); + if (zol_setfreq(zol, zol->curfreq) != 0) return -EINVAL; - } #if 0 /* FIXME: Implement stereo/mono switch on V4L2 */ - if (v->mode & VIDEO_SOUND_STEREO) { - zol->stereo = 1; - zol_setfreq(zol, zol->curfreq); - } - if (v->mode & VIDEO_SOUND_MONO) { - zol->stereo = 0; - zol_setfreq(zol, zol->curfreq); - } + if (v->mode & VIDEO_SOUND_STEREO) { + zol->stereo = 1; + zol_setfreq(zol, zol->curfreq); + } + if (v->mode & VIDEO_SOUND_MONO) { + zol->stereo = 0; + zol_setfreq(zol, zol->curfreq); + } #endif return -EINVAL; } -static int vidioc_g_audio(struct file *file, void *priv, - struct v4l2_audio *a) -{ - if (a->index > 1) - return -EINVAL; - - strcpy(a->name, "Radio"); - a->capability = V4L2_AUDCAP_STEREO; - return 0; -} - static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) { *i = 0; @@ -386,37 +352,27 @@ static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i) static int vidioc_s_input(struct file *filp, void *priv, unsigned int i) { - if (i != 0) - return -EINVAL; - return 0; + return i ? -EINVAL : 0; } -static int vidioc_s_audio(struct file *file, void *priv, +static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a) { - if (a->index != 0) - return -EINVAL; + a->index = 0; + strlcpy(a->name, "Radio", sizeof(a->name)); + a->capability = V4L2_AUDCAP_STEREO; return 0; } -static struct zol_device zoltrix_unit; - -static int zoltrix_exclusive_open(struct file *file) +static int vidioc_s_audio(struct file *file, void *priv, + struct v4l2_audio *a) { - return test_and_set_bit(0, &zoltrix_unit.in_use) ? -EBUSY : 0; -} - -static int zoltrix_exclusive_release(struct file *file) -{ - clear_bit(0, &zoltrix_unit.in_use); - return 0; + return a->index ? -EINVAL : 0; } static const struct v4l2_file_operations zoltrix_fops = { .owner = THIS_MODULE, - .open = zoltrix_exclusive_open, - .release = zoltrix_exclusive_release, .ioctl = video_ioctl2, }; @@ -435,67 +391,75 @@ static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = { .vidioc_s_ctrl = vidioc_s_ctrl, }; -static struct video_device zoltrix_radio = { - .name = "Zoltrix Radio Plus", - .fops = &zoltrix_fops, - .ioctl_ops = &zoltrix_ioctl_ops, - .release = video_device_release_empty, -}; - static int __init zoltrix_init(void) { - if (io == -1) { - printk(KERN_ERR "You must set an I/O address with io=0x???\n"); + struct zoltrix *zol = &zoltrix_card; + struct v4l2_device *v4l2_dev = &zol->v4l2_dev; + int res; + + strlcpy(v4l2_dev->name, "zoltrix", sizeof(v4l2_dev->name)); + zol->io = io; + if (zol->io == -1) { + v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or 0x30c\n"); return -EINVAL; } - if ((io != 0x20c) && (io != 0x30c)) { - printk(KERN_ERR "zoltrix: invalid port, try 0x20c or 0x30c\n"); + if (zol->io != 0x20c && zol->io != 0x30c) { + v4l2_err(v4l2_dev, "invalid port, try 0x20c or 0x30c\n"); return -ENXIO; } - video_set_drvdata(&zoltrix_radio, &zoltrix_unit); - if (!request_region(io, 2, "zoltrix")) { - printk(KERN_ERR "zoltrix: port 0x%x already in use\n", io); + if (!request_region(zol->io, 2, "zoltrix")) { + v4l2_err(v4l2_dev, "port 0x%x already in use\n", zol->io); return -EBUSY; } - if (video_register_device(&zoltrix_radio, VFL_TYPE_RADIO, radio_nr) < 0) { - release_region(io, 2); + res = v4l2_device_register(NULL, v4l2_dev); + if (res < 0) { + release_region(zol->io, 2); + v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); + return res; + } + + strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name)); + zol->vdev.v4l2_dev = v4l2_dev; + zol->vdev.fops = &zoltrix_fops; + zol->vdev.ioctl_ops = &zoltrix_ioctl_ops; + zol->vdev.release = video_device_release_empty; + video_set_drvdata(&zol->vdev, zol); + + if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { + v4l2_device_unregister(v4l2_dev); + release_region(zol->io, 2); return -EINVAL; } - printk(KERN_INFO "Zoltrix Radio Plus card driver.\n"); + v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n"); - mutex_init(&zoltrix_unit.lock); + mutex_init(&zol->lock); /* mute card - prevents noisy bootups */ /* this ensures that the volume is all the way down */ - outb(0, io); - outb(0, io); + outb(0, zol->io); + outb(0, zol->io); msleep(20); - inb(io + 3); + inb(zol->io + 3); - zoltrix_unit.curvol = 0; - zoltrix_unit.stereo = 1; + zol->curvol = 0; + zol->stereo = 1; return 0; } -MODULE_AUTHOR("C.van Schaik"); -MODULE_DESCRIPTION("A driver for the Zoltrix Radio Plus."); -MODULE_LICENSE("GPL"); - -module_param(io, int, 0); -MODULE_PARM_DESC(io, "I/O address of the Zoltrix Radio Plus (0x20c or 0x30c)"); -module_param(radio_nr, int, 0); - -static void __exit zoltrix_cleanup_module(void) +static void __exit zoltrix_exit(void) { - video_unregister_device(&zoltrix_radio); - release_region(io, 2); + struct zoltrix *zol = &zoltrix_card; + + video_unregister_device(&zol->vdev); + v4l2_device_unregister(&zol->v4l2_dev); + release_region(zol->io, 2); } module_init(zoltrix_init); -module_exit(zoltrix_cleanup_module); +module_exit(zoltrix_exit); |