aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/media/radio/radio-sf16fmi.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/radio/radio-sf16fmi.c')
-rw-r--r--drivers/media/radio/radio-sf16fmi.c82
1 files changed, 58 insertions, 24 deletions
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 49c4aab95dab..985359d18aa5 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -1,4 +1,4 @@
1/* SF16FMI radio driver for Linux radio support 1/* SF16-FMI and SF16-FMP radio driver for Linux radio support
2 * heavily based on rtrack driver... 2 * heavily based on rtrack driver...
3 * (c) 1997 M. Kirkwood 3 * (c) 1997 M. Kirkwood
4 * (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz 4 * (c) 1998 Petr Vandrovec, vandrove@vc.cvut.cz
@@ -11,7 +11,7 @@
11 * 11 *
12 * Frequency control is done digitally -- ie out(port,encodefreq(95.8)); 12 * Frequency control is done digitally -- ie out(port,encodefreq(95.8));
13 * No volume control - only mute/unmute - you have to use line volume 13 * No volume control - only mute/unmute - you have to use line volume
14 * control on SB-part of SF16FMI 14 * control on SB-part of SF16-FMI/SF16-FMP
15 * 15 *
16 * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org> 16 * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
17 */ 17 */
@@ -30,14 +30,14 @@
30#include <media/v4l2-ioctl.h> 30#include <media/v4l2-ioctl.h>
31 31
32MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood"); 32MODULE_AUTHOR("Petr Vandrovec, vandrove@vc.cvut.cz and M. Kirkwood");
33MODULE_DESCRIPTION("A driver for the SF16MI radio."); 33MODULE_DESCRIPTION("A driver for the SF16-FMI and SF16-FMP radio.");
34MODULE_LICENSE("GPL"); 34MODULE_LICENSE("GPL");
35 35
36static int io = -1; 36static int io = -1;
37static int radio_nr = -1; 37static int radio_nr = -1;
38 38
39module_param(io, int, 0); 39module_param(io, int, 0);
40MODULE_PARM_DESC(io, "I/O address of the SF16MI card (0x284 or 0x384)"); 40MODULE_PARM_DESC(io, "I/O address of the SF16-FMI or SF16-FMP card (0x284 or 0x384)");
41module_param(radio_nr, int, 0); 41module_param(radio_nr, int, 0);
42 42
43#define RADIO_VERSION KERNEL_VERSION(0, 0, 2) 43#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
@@ -47,13 +47,14 @@ struct fmi
47 struct v4l2_device v4l2_dev; 47 struct v4l2_device v4l2_dev;
48 struct video_device vdev; 48 struct video_device vdev;
49 int io; 49 int io;
50 int curvol; /* 1 or 0 */ 50 bool mute;
51 unsigned long curfreq; /* freq in kHz */ 51 unsigned long curfreq; /* freq in kHz */
52 struct mutex lock; 52 struct mutex lock;
53}; 53};
54 54
55static struct fmi fmi_card; 55static struct fmi fmi_card;
56static struct pnp_dev *dev; 56static struct pnp_dev *dev;
57bool pnp_attached;
57 58
58/* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */ 59/* freq is in 1/16 kHz to internal number, hw precision is 50 kHz */
59/* It is only useful to give freq in interval of 800 (=0.05Mhz), 60/* It is only useful to give freq in interval of 800 (=0.05Mhz),
@@ -105,7 +106,7 @@ static inline int fmi_setfreq(struct fmi *fmi, unsigned long freq)
105 outbits(8, 0xC0, fmi->io); 106 outbits(8, 0xC0, fmi->io);
106 msleep(143); /* was schedule_timeout(HZ/7) */ 107 msleep(143); /* was schedule_timeout(HZ/7) */
107 mutex_unlock(&fmi->lock); 108 mutex_unlock(&fmi->lock);
108 if (fmi->curvol) 109 if (!fmi->mute)
109 fmi_unmute(fmi); 110 fmi_unmute(fmi);
110 return 0; 111 return 0;
111} 112}
@@ -116,7 +117,7 @@ static inline int fmi_getsigstr(struct fmi *fmi)
116 int res; 117 int res;
117 118
118 mutex_lock(&fmi->lock); 119 mutex_lock(&fmi->lock);
119 val = fmi->curvol ? 0x08 : 0x00; /* unmute/mute */ 120 val = fmi->mute ? 0x00 : 0x08; /* mute/unmute */
120 outb(val, fmi->io); 121 outb(val, fmi->io);
121 outb(val | 0x10, fmi->io); 122 outb(val | 0x10, fmi->io);
122 msleep(143); /* was schedule_timeout(HZ/7) */ 123 msleep(143); /* was schedule_timeout(HZ/7) */
@@ -168,6 +169,8 @@ static int vidioc_s_frequency(struct file *file, void *priv,
168{ 169{
169 struct fmi *fmi = video_drvdata(file); 170 struct fmi *fmi = video_drvdata(file);
170 171
172 if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
173 return -EINVAL;
171 if (f->frequency < RSF16_MINFREQ || 174 if (f->frequency < RSF16_MINFREQ ||
172 f->frequency > RSF16_MAXFREQ) 175 f->frequency > RSF16_MAXFREQ)
173 return -EINVAL; 176 return -EINVAL;
@@ -182,6 +185,8 @@ static int vidioc_g_frequency(struct file *file, void *priv,
182{ 185{
183 struct fmi *fmi = video_drvdata(file); 186 struct fmi *fmi = video_drvdata(file);
184 187
188 if (f->tuner != 0)
189 return -EINVAL;
185 f->type = V4L2_TUNER_RADIO; 190 f->type = V4L2_TUNER_RADIO;
186 f->frequency = fmi->curfreq; 191 f->frequency = fmi->curfreq;
187 return 0; 192 return 0;
@@ -204,7 +209,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
204 209
205 switch (ctrl->id) { 210 switch (ctrl->id) {
206 case V4L2_CID_AUDIO_MUTE: 211 case V4L2_CID_AUDIO_MUTE:
207 ctrl->value = fmi->curvol; 212 ctrl->value = fmi->mute;
208 return 0; 213 return 0;
209 } 214 }
210 return -EINVAL; 215 return -EINVAL;
@@ -221,7 +226,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
221 fmi_mute(fmi); 226 fmi_mute(fmi);
222 else 227 else
223 fmi_unmute(fmi); 228 fmi_unmute(fmi);
224 fmi->curvol = ctrl->value; 229 fmi->mute = ctrl->value;
225 return 0; 230 return 0;
226 } 231 }
227 return -EINVAL; 232 return -EINVAL;
@@ -316,26 +321,54 @@ static int __init fmi_init(void)
316{ 321{
317 struct fmi *fmi = &fmi_card; 322 struct fmi *fmi = &fmi_card;
318 struct v4l2_device *v4l2_dev = &fmi->v4l2_dev; 323 struct v4l2_device *v4l2_dev = &fmi->v4l2_dev;
319 int res; 324 int res, i;
325 int probe_ports[] = { 0, 0x284, 0x384 };
326
327 if (io < 0) {
328 for (i = 0; i < ARRAY_SIZE(probe_ports); i++) {
329 io = probe_ports[i];
330 if (io == 0) {
331 io = isapnp_fmi_probe();
332 if (io < 0)
333 continue;
334 pnp_attached = 1;
335 }
336 if (!request_region(io, 2, "radio-sf16fmi")) {
337 if (pnp_attached)
338 pnp_device_detach(dev);
339 io = -1;
340 continue;
341 }
342 if (pnp_attached ||
343 ((inb(io) & 0xf9) == 0xf9 && (inb(io) & 0x4) == 0))
344 break;
345 release_region(io, 2);
346 io = -1;
347 }
348 } else {
349 if (!request_region(io, 2, "radio-sf16fmi")) {
350 printk(KERN_ERR "radio-sf16fmi: port %#x already in use\n", io);
351 return -EBUSY;
352 }
353 if (inb(io) == 0xff) {
354 printk(KERN_ERR "radio-sf16fmi: card not present at %#x\n", io);
355 release_region(io, 2);
356 return -ENODEV;
357 }
358 }
359 if (io < 0) {
360 printk(KERN_ERR "radio-sf16fmi: no cards found\n");
361 return -ENODEV;
362 }
320 363
321 if (io < 0)
322 io = isapnp_fmi_probe();
323 strlcpy(v4l2_dev->name, "sf16fmi", sizeof(v4l2_dev->name)); 364 strlcpy(v4l2_dev->name, "sf16fmi", sizeof(v4l2_dev->name));
324 fmi->io = io; 365 fmi->io = io;
325 if (fmi->io < 0) {
326 v4l2_err(v4l2_dev, "No PnP card found.\n");
327 return fmi->io;
328 }
329 if (!request_region(io, 2, "radio-sf16fmi")) {
330 v4l2_err(v4l2_dev, "port 0x%x already in use\n", fmi->io);
331 pnp_device_detach(dev);
332 return -EBUSY;
333 }
334 366
335 res = v4l2_device_register(NULL, v4l2_dev); 367 res = v4l2_device_register(NULL, v4l2_dev);
336 if (res < 0) { 368 if (res < 0) {
337 release_region(fmi->io, 2); 369 release_region(fmi->io, 2);
338 pnp_device_detach(dev); 370 if (pnp_attached)
371 pnp_device_detach(dev);
339 v4l2_err(v4l2_dev, "Could not register v4l2_device\n"); 372 v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
340 return res; 373 return res;
341 } 374 }
@@ -352,7 +385,8 @@ static int __init fmi_init(void)
352 if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) { 385 if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
353 v4l2_device_unregister(v4l2_dev); 386 v4l2_device_unregister(v4l2_dev);
354 release_region(fmi->io, 2); 387 release_region(fmi->io, 2);
355 pnp_device_detach(dev); 388 if (pnp_attached)
389 pnp_device_detach(dev);
356 return -EINVAL; 390 return -EINVAL;
357 } 391 }
358 392
@@ -369,7 +403,7 @@ static void __exit fmi_exit(void)
369 video_unregister_device(&fmi->vdev); 403 video_unregister_device(&fmi->vdev);
370 v4l2_device_unregister(&fmi->v4l2_dev); 404 v4l2_device_unregister(&fmi->v4l2_dev);
371 release_region(fmi->io, 2); 405 release_region(fmi->io, 2);
372 if (dev) 406 if (dev && pnp_attached)
373 pnp_device_detach(dev); 407 pnp_device_detach(dev);
374} 408}
375 409