radio-sf16fmr2.c (0a1340c185734a57fbf4775927966ad4a1347b02) radio-sf16fmr2.c (acda0e71857c8ec4e5348d08b53a52d35b92e6aa)
1/* SF16FMR2 radio driver for Linux radio support
2 * heavily based on fmi driver...
3 * (c) 2000-2002 Ziglio Frediano, freddy77@angelfire.com
4 *
5 * Notes on the hardware
6 *
7 * Frequency control is done digitally -- ie out(port,encodefreq(95.8));
8 * No volume control - only mute/unmute - you have to use line volume
9 *
10 * For read stereo/mono you must wait 0.1 sec after set frequency and
11 * card unmuted so I set frequency on unmute
12 * Signal handling seem to work only on autoscanning (not implemented)
1/* SF16FMR2 radio driver for Linux radio support
2 * heavily based on fmi driver...
3 * (c) 2000-2002 Ziglio Frediano, freddy77@angelfire.com
4 *
5 * Notes on the hardware
6 *
7 * Frequency control is done digitally -- ie out(port,encodefreq(95.8));
8 * No volume control - only mute/unmute - you have to use line volume
9 *
10 * For read stereo/mono you must wait 0.1 sec after set frequency and
11 * card unmuted so I set frequency on unmute
12 * Signal handling seem to work only on autoscanning (not implemented)
13 *
14 * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
13 */
14
15#include <linux/module.h> /* Modules */
16#include <linux/init.h> /* Initdata */
17#include <linux/ioport.h> /* request_region */
18#include <linux/delay.h> /* udelay */
19#include <asm/io.h> /* outb, outb_p */
20#include <asm/uaccess.h> /* copy to/from user */
15 */
16
17#include <linux/module.h> /* Modules */
18#include <linux/init.h> /* Initdata */
19#include <linux/ioport.h> /* request_region */
20#include <linux/delay.h> /* udelay */
21#include <asm/io.h> /* outb, outb_p */
22#include <asm/uaccess.h> /* copy to/from user */
21#include <linux/videodev.h> /* kernel radio structs */
23#include <linux/videodev2.h> /* kernel radio structs */
22#include <media/v4l2-common.h>
23#include <linux/mutex.h>
24
24#include <media/v4l2-common.h>
25#include <linux/mutex.h>
26
27#define RADIO_VERSION KERNEL_VERSION(0,0,2)
28
29static struct v4l2_queryctrl radio_qctrl[] = {
30 {
31 .id = V4L2_CID_AUDIO_MUTE,
32 .name = "Mute",
33 .minimum = 0,
34 .maximum = 1,
35 .default_value = 1,
36 .type = V4L2_CTRL_TYPE_BOOLEAN,
37 },{
38 .id = V4L2_CID_AUDIO_VOLUME,
39 .name = "Volume",
40 .minimum = 0,
41 .maximum = 65535,
42 .step = 1<<12,
43 .default_value = 0xff,
44 .type = V4L2_CTRL_TYPE_INTEGER,
45 }
46};
47
25static struct mutex lock;
26
27#undef DEBUG
28//#define DEBUG 1
29
30#ifdef DEBUG
31# define debug_print(s) printk s
32#else

--- 176 unchanged lines hidden (view full) ---

209 struct fmr2_device *fmr2 = dev->priv;
210 debug_print((KERN_DEBUG "freq %ld flags %d vol %d mute %d "
211 "stereo %d type %d\n",
212 fmr2->curfreq, fmr2->flags, fmr2->curvol, fmr2->mute,
213 fmr2->stereo, fmr2->card_type));
214
215 switch(cmd)
216 {
48static struct mutex lock;
49
50#undef DEBUG
51//#define DEBUG 1
52
53#ifdef DEBUG
54# define debug_print(s) printk s
55#else

--- 176 unchanged lines hidden (view full) ---

232 struct fmr2_device *fmr2 = dev->priv;
233 debug_print((KERN_DEBUG "freq %ld flags %d vol %d mute %d "
234 "stereo %d type %d\n",
235 fmr2->curfreq, fmr2->flags, fmr2->curvol, fmr2->mute,
236 fmr2->stereo, fmr2->card_type));
237
238 switch(cmd)
239 {
217 case VIDIOCGCAP:
240 case VIDIOC_QUERYCAP:
218 {
241 {
219 struct video_capability *v = arg;
242 struct v4l2_capability *v = arg;
220 memset(v,0,sizeof(*v));
243 memset(v,0,sizeof(*v));
221 strcpy(v->name, "SF16-FMR2 radio");
222 v->type=VID_TYPE_TUNER;
223 v->channels=1;
224 v->audios=1;
244 strlcpy(v->driver, "radio-sf16fmr2", sizeof (v->driver));
245 strlcpy(v->card, "SF16-FMR2 radio", sizeof (v->card));
246 sprintf(v->bus_info,"ISA");
247 v->version = RADIO_VERSION;
248 v->capabilities = V4L2_CAP_TUNER;
249
225 return 0;
226 }
250 return 0;
251 }
227 case VIDIOCGTUNER:
252 case VIDIOC_G_TUNER:
228 {
253 {
229 struct video_tuner *v = arg;
254 struct v4l2_tuner *v = arg;
230 int mult;
231
255 int mult;
256
232 if(v->tuner) /* Only 1 tuner */
257 if (v->index > 0)
233 return -EINVAL;
258 return -EINVAL;
259
260 memset(v,0,sizeof(*v));
234 strcpy(v->name, "FM");
261 strcpy(v->name, "FM");
235 mult = (fmr2->flags & VIDEO_TUNER_LOW) ? 1 : 1000;
262 v->type = V4L2_TUNER_RADIO;
263
264 mult = (fmr2->flags & V4L2_TUNER_CAP_LOW) ? 1 : 1000;
236 v->rangelow = RSF16_MINFREQ/mult;
237 v->rangehigh = RSF16_MAXFREQ/mult;
265 v->rangelow = RSF16_MINFREQ/mult;
266 v->rangehigh = RSF16_MAXFREQ/mult;
238 v->flags = fmr2->flags | VIDEO_AUDIO_MUTABLE;
239 if (fmr2->mute)
240 v->flags |= VIDEO_AUDIO_MUTE;
241 v->mode=VIDEO_MODE_AUTO;
267 v->rxsubchans =V4L2_TUNER_SUB_MONO | V4L2_TUNER_MODE_STEREO;
268 v->capability=fmr2->flags&V4L2_TUNER_CAP_LOW;
269
270 v->audmode = fmr2->stereo ? V4L2_TUNER_MODE_STEREO:
271 V4L2_TUNER_MODE_MONO;
242 mutex_lock(&lock);
243 v->signal = fmr2_getsigstr(fmr2);
244 mutex_unlock(&lock);
272 mutex_lock(&lock);
273 v->signal = fmr2_getsigstr(fmr2);
274 mutex_unlock(&lock);
275
245 return 0;
246 }
276 return 0;
277 }
247 case VIDIOCSTUNER:
278 case VIDIOC_S_TUNER:
248 {
279 {
249 struct video_tuner *v = arg;
250 if (v->tuner!=0)
280 struct v4l2_tuner *v = arg;
281
282 if (v->index > 0)
251 return -EINVAL;
283 return -EINVAL;
252 fmr2->flags = v->flags & VIDEO_TUNER_LOW;
284
253 return 0;
254 }
285 return 0;
286 }
255 case VIDIOCGFREQ:
287 case VIDIOC_S_FREQUENCY:
256 {
288 {
257 unsigned long *freq = arg;
258 *freq = fmr2->curfreq;
259 if (!(fmr2->flags & VIDEO_TUNER_LOW))
260 *freq /= 1000;
261 return 0;
262 }
263 case VIDIOCSFREQ:
264 {
265 unsigned long *freq = arg;
266 if (!(fmr2->flags & VIDEO_TUNER_LOW))
267 *freq *= 1000;
268 if ( *freq < RSF16_MINFREQ || *freq > RSF16_MAXFREQ )
289 struct v4l2_frequency *f = arg;
290
291 if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
292 f->frequency *= 1000;
293 if (f->frequency < RSF16_MINFREQ ||
294 f->frequency > RSF16_MAXFREQ )
269 return -EINVAL;
295 return -EINVAL;
270 /* rounding in steps of 200 to match th freq
271 * that will be used
272 */
273 fmr2->curfreq = (*freq/200)*200;
296 /*rounding in steps of 200 to match th freq
297 that will be used */
298 fmr2->curfreq = (f->frequency/200)*200;
274
275 /* set card freq (if not muted) */
276 if (fmr2->curvol && !fmr2->mute)
277 {
278 mutex_lock(&lock);
279 fmr2_setfreq(fmr2);
280 mutex_unlock(&lock);
281 }
299
300 /* set card freq (if not muted) */
301 if (fmr2->curvol && !fmr2->mute)
302 {
303 mutex_lock(&lock);
304 fmr2_setfreq(fmr2);
305 mutex_unlock(&lock);
306 }
307
282 return 0;
283 }
308 return 0;
309 }
284 case VIDIOCGAUDIO:
310 case VIDIOC_G_FREQUENCY:
285 {
311 {
286 struct video_audio *v = arg;
287 memset(v,0,sizeof(*v));
288 /* !!! do not return VIDEO_AUDIO_MUTE */
289 v->flags = VIDEO_AUDIO_MUTABLE;
290 strcpy(v->name, "Radio");
291 /* get current stereo mode */
292 v->mode = fmr2->stereo ? VIDEO_SOUND_STEREO: VIDEO_SOUND_MONO;
293 /* volume supported ? */
294 if (fmr2->card_type == 11)
295 {
296 v->flags |= VIDEO_AUDIO_VOLUME;
297 v->step = 1 << 12;
298 v->volume = fmr2->curvol;
299 }
300 debug_print((KERN_DEBUG "Get flags %d vol %d\n", v->flags, v->volume));
312 struct v4l2_frequency *f = arg;
313
314 f->type = V4L2_TUNER_RADIO;
315 f->frequency = fmr2->curfreq;
316 if (!(fmr2->flags & V4L2_TUNER_CAP_LOW))
317 f->frequency /= 1000;
318
301 return 0;
302 }
319 return 0;
320 }
303 case VIDIOCSAUDIO:
321 case VIDIOC_QUERYCTRL:
304 {
322 {
305 struct video_audio *v = arg;
306 if(v->audio)
307 return -EINVAL;
308 debug_print((KERN_DEBUG "Set flags %d vol %d\n", v->flags, v->volume));
309 /* set volume */
310 if (v->flags & VIDEO_AUDIO_VOLUME)
311 fmr2->curvol = v->volume; /* !!! set with precision */
312 if (fmr2->card_type != 11) fmr2->curvol = 65535;
313 fmr2->mute = 0;
314 if (v->flags & VIDEO_AUDIO_MUTE)
315 fmr2->mute = 1;
323 struct v4l2_queryctrl *qc = arg;
324 int i;
325
326 for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
327 if ((fmr2->card_type != 11)
328 && V4L2_CID_AUDIO_VOLUME)
329 radio_qctrl[i].step=65535;
330 if (qc->id && qc->id == radio_qctrl[i].id) {
331 memcpy(qc, &(radio_qctrl[i]),
332 sizeof(*qc));
333 return (0);
334 }
335 }
336 return -EINVAL;
337 }
338 case VIDIOC_G_CTRL:
339 {
340 struct v4l2_control *ctrl= arg;
341
342 switch (ctrl->id) {
343 case V4L2_CID_AUDIO_MUTE:
344 ctrl->value=fmr2->mute;
345 return (0);
346 case V4L2_CID_AUDIO_VOLUME:
347 ctrl->value=fmr2->curvol;
348 return (0);
349 }
350 return -EINVAL;
351 }
352 case VIDIOC_S_CTRL:
353 {
354 struct v4l2_control *ctrl= arg;
355
356 switch (ctrl->id) {
357 case V4L2_CID_AUDIO_MUTE:
358 fmr2->mute=ctrl->value;
359 if (fmr2->card_type != 11) {
360 if (!fmr2->mute) {
361 fmr2->curvol = 65535;
362 } else {
363 fmr2->curvol = 0;
364 }
365 }
366 break;
367 case V4L2_CID_AUDIO_VOLUME:
368 fmr2->curvol = ctrl->value;
369 if (fmr2->card_type != 11) {
370 if (fmr2->curvol) {
371 fmr2->curvol = 65535;
372 fmr2->mute = 0;
373 } else {
374 fmr2->curvol = 0;
375 fmr2->mute = 1;
376 }
377 }
378 break;
379 default:
380 return -EINVAL;
381 }
316#ifdef DEBUG
317 if (fmr2->curvol && !fmr2->mute)
318 printk(KERN_DEBUG "unmute\n");
319 else
320 printk(KERN_DEBUG "mute\n");
321#endif
322 mutex_lock(&lock);
382#ifdef DEBUG
383 if (fmr2->curvol && !fmr2->mute)
384 printk(KERN_DEBUG "unmute\n");
385 else
386 printk(KERN_DEBUG "mute\n");
387#endif
388 mutex_lock(&lock);
323 if (fmr2->curvol && !fmr2->mute)
324 {
389 if (fmr2->curvol && !fmr2->mute) {
325 fmr2_setvolume(fmr2);
326 fmr2_setfreq(fmr2);
390 fmr2_setvolume(fmr2);
391 fmr2_setfreq(fmr2);
327 }
328 else fmr2_mute(fmr2->port);
392 } else
393 fmr2_mute(fmr2->port);
329 mutex_unlock(&lock);
394 mutex_unlock(&lock);
330 return 0;
395 return (0);
331 }
396 }
332 case VIDIOCGUNIT:
333 {
334 struct video_unit *v = arg;
335 v->video=VIDEO_NO_UNIT;
336 v->vbi=VIDEO_NO_UNIT;
337 v->radio=dev->minor;
338 v->audio=0; /* How do we find out this??? */
339 v->teletext=VIDEO_NO_UNIT;
340 return 0;
341 }
342 default:
397 default:
343 return -ENOIOCTLCMD;
398 return v4l_compat_translate_ioctl(inode,file,cmd,arg,
399 az_do_ioctl);
400
344 }
345}
346
347static int fmr2_ioctl(struct inode *inode, struct file *file,
348 unsigned int cmd, unsigned long arg)
349 {
350 return video_usercopy(inode, file, cmd, arg, fmr2_do_ioctl);
351}

--- 9 unchanged lines hidden (view full) ---

361 .llseek = no_llseek,
362};
363
364static struct video_device fmr2_radio=
365{
366 .owner = THIS_MODULE,
367 .name = "SF16FMR2 radio",
368 . type = VID_TYPE_TUNER,
401 }
402}
403
404static int fmr2_ioctl(struct inode *inode, struct file *file,
405 unsigned int cmd, unsigned long arg)
406 {
407 return video_usercopy(inode, file, cmd, arg, fmr2_do_ioctl);
408}

--- 9 unchanged lines hidden (view full) ---

418 .llseek = no_llseek,
419};
420
421static struct video_device fmr2_radio=
422{
423 .owner = THIS_MODULE,
424 .name = "SF16FMR2 radio",
425 . type = VID_TYPE_TUNER,
369 .hardware = VID_HARDWARE_SF16FMR2,
426 .hardware = 0,
370 .fops = &fmr2_fops,
371};
372
373static int __init fmr2_init(void)
374{
375 fmr2_unit.port = io;
376 fmr2_unit.curvol = 0;
377 fmr2_unit.mute = 0;
378 fmr2_unit.curfreq = 0;
379 fmr2_unit.stereo = 1;
427 .fops = &fmr2_fops,
428};
429
430static int __init fmr2_init(void)
431{
432 fmr2_unit.port = io;
433 fmr2_unit.curvol = 0;
434 fmr2_unit.mute = 0;
435 fmr2_unit.curfreq = 0;
436 fmr2_unit.stereo = 1;
380 fmr2_unit.flags = VIDEO_TUNER_LOW;
437 fmr2_unit.flags = V4L2_TUNER_CAP_LOW;
381 fmr2_unit.card_type = 0;
382 fmr2_radio.priv = &fmr2_unit;
383
384 mutex_init(&lock);
385
386 if (request_region(io, 2, "sf16fmr2"))
387 {
388 printk(KERN_ERR "fmr2: port 0x%x already in use\n", io);
389 return -EBUSY;
390 }
391
392 if(video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr)==-1)
393 {
394 release_region(io, 2);
395 return -EINVAL;
396 }
397
398 printk(KERN_INFO "SF16FMR2 radio card driver at 0x%x.\n", io);
438 fmr2_unit.card_type = 0;
439 fmr2_radio.priv = &fmr2_unit;
440
441 mutex_init(&lock);
442
443 if (request_region(io, 2, "sf16fmr2"))
444 {
445 printk(KERN_ERR "fmr2: port 0x%x already in use\n", io);
446 return -EBUSY;
447 }
448
449 if(video_register_device(&fmr2_radio, VFL_TYPE_RADIO, radio_nr)==-1)
450 {
451 release_region(io, 2);
452 return -EINVAL;
453 }
454
455 printk(KERN_INFO "SF16FMR2 radio card driver at 0x%x.\n", io);
399 debug_print((KERN_DEBUG "Mute %d Low %d\n",VIDEO_AUDIO_MUTE,VIDEO_TUNER_LOW));
400 /* mute card - prevents noisy bootups */
401 mutex_lock(&lock);
402 fmr2_mute(io);
403 fmr2_product_info(&fmr2_unit);
404 mutex_unlock(&lock);
405 debug_print((KERN_DEBUG "card_type %d\n", fmr2_unit.card_type));
406 return 0;
407}

--- 29 unchanged lines hidden ---
456 /* mute card - prevents noisy bootups */
457 mutex_lock(&lock);
458 fmr2_mute(io);
459 fmr2_product_info(&fmr2_unit);
460 mutex_unlock(&lock);
461 debug_print((KERN_DEBUG "card_type %d\n", fmr2_unit.card_type));
462 return 0;
463}

--- 29 unchanged lines hidden ---