Lines Matching +full:switch +full:- +full:freq +full:- +full:select
1 // SPDX-License-Identifier: GPL-2.0-only
2 /* radio-cadet.c - A video4linux driver for the ADS Cadet AM/FM Radio Card
17 * 2000-04-29 Russell Kroll <rkroll@exploits.org>
20 * 2001-01-10 Russell Kroll <rkroll@exploits.org>
24 * 2002-01-17 Adam Belay <ambx1@neo.rr.com>
27 * 2003-01-31 Alan Cox <alan@lxorguk.ukuu.org.uk>
30 * 2006-07-30 Hans J. Koch <koch@hjk-az.de>
43 #include <media/v4l2-device.h>
44 #include <media/v4l2-ioctl.h>
45 #include <media/v4l2-ctrls.h>
46 #include <media/v4l2-fh.h>
47 #include <media/v4l2-event.h>
54 static int io = -1; /* default to isapnp activation */
55 static int radio_nr = -1;
119 if (!dev->is_fm_band) /* Only FM has stereo capability! */ in cadet_getstereo()
122 outb(7, dev->io); /* Select tuner control */ in cadet_getstereo()
123 if ((inb(dev->io + 1) & 0x40) == 0) in cadet_getstereo()
137 outb(7, dev->io); /* Select tuner control */ in cadet_gettune()
138 curvol = inb(dev->io + 1); /* Save current volume/mute setting */ in cadet_gettune()
139 outb(0x00, dev->io + 1); /* Ensure WRITE-ENABLE is LOW */ in cadet_gettune()
140 dev->tunestat = 0xffff; in cadet_gettune()
146 fifo = (fifo << 1) | ((inb(dev->io + 1) >> 7) & 0x01); in cadet_gettune()
148 outb(0x01, dev->io + 1); in cadet_gettune()
149 dev->tunestat &= inb(dev->io + 1); in cadet_gettune()
150 outb(0x00, dev->io + 1); in cadet_gettune()
157 outb(curvol, dev->io + 1); in cadet_gettune()
164 unsigned freq = 0, test, fifo = 0; in cadet_getfreq() local
174 if (!dev->is_fm_band) /* AM */ in cadet_getfreq()
175 return ((fifo & 0x7fff) - 450) * 16; in cadet_getfreq()
180 freq += test; in cadet_getfreq()
184 freq -= 10700000; /* IF frequency is 10.7 MHz */ in cadet_getfreq()
185 freq = (freq * 16) / 1000; /* Make it 1/16 kHz */ in cadet_getfreq()
186 return freq; in cadet_getfreq()
194 outb(7, dev->io); /* Select tuner control */ in cadet_settune()
201 outb(7, dev->io); /* Select tuner control */ in cadet_settune()
202 outb(test, dev->io + 1); /* Initialize for write */ in cadet_settune()
205 outb(test, dev->io + 1); in cadet_settune()
207 outb(test, dev->io + 1); in cadet_settune()
210 outb(test, dev->io + 1); in cadet_settune()
214 static void cadet_setfreq(struct cadet *dev, unsigned freq) in cadet_setfreq() argument
220 freq = clamp(freq, bands[dev->is_fm_band].rangelow, in cadet_setfreq()
221 bands[dev->is_fm_band].rangehigh); in cadet_setfreq()
222 dev->curfreq = freq; in cadet_setfreq()
227 if (dev->is_fm_band) { /* FM */ in cadet_setfreq()
229 freq = freq / 16; /* Make it kHz */ in cadet_setfreq()
230 freq += 10700; /* IF is 10700 kHz */ in cadet_setfreq()
233 if (freq >= test) { in cadet_setfreq()
235 freq -= test; in cadet_setfreq()
240 fifo = (freq / 16) + 450; /* Make it kHz */ in cadet_setfreq()
241 fifo |= 0x100000; /* Select AM Band */ in cadet_setfreq()
248 outb(7, dev->io); /* Select tuner control */ in cadet_setfreq()
249 curvol = inb(dev->io + 1); in cadet_setfreq()
254 for (j = 3; j > -1; j--) { in cadet_setfreq()
257 outb(7, dev->io); /* Select tuner control */ in cadet_setfreq()
258 outb(curvol, dev->io + 1); in cadet_setfreq()
263 if ((dev->tunestat & 0x40) == 0) { /* Tuned */ in cadet_setfreq()
264 dev->sigstrength = sigtable[dev->is_fm_band][j]; in cadet_setfreq()
268 dev->sigstrength = 0; in cadet_setfreq()
270 outb(3, dev->io); in cadet_setfreq()
271 outb(inb(dev->io + 1) & 0x7f, dev->io + 1); in cadet_setfreq()
278 mutex_lock(&dev->lock); in cadet_has_rds_data()
279 result = dev->rdsin != dev->rdsout; in cadet_has_rds_data()
280 mutex_unlock(&dev->lock); in cadet_has_rds_data()
290 if (mutex_trylock(&dev->lock)) { in cadet_handler()
291 outb(0x3, dev->io); /* Select RDS Decoder Control */ in cadet_handler()
292 if ((inb(dev->io + 1) & 0x20) != 0) in cadet_handler()
294 outb(0x80, dev->io); /* Select RDS fifo */ in cadet_handler()
296 while ((inb(dev->io) & 0x80) != 0) { in cadet_handler()
297 dev->rdsbuf[dev->rdsin] = inb(dev->io + 1); in cadet_handler()
298 if (dev->rdsin + 1 != dev->rdsout) in cadet_handler()
299 dev->rdsin++; in cadet_handler()
301 mutex_unlock(&dev->lock); in cadet_handler()
308 wake_up_interruptible(&dev->read_queue); in cadet_handler()
313 dev->readtimer.expires = jiffies + msecs_to_jiffies(50); in cadet_handler()
314 add_timer(&dev->readtimer); in cadet_handler()
319 dev->rdsstat = 1; in cadet_start_rds()
320 outb(0x80, dev->io); /* Select RDS fifo */ in cadet_start_rds()
321 timer_setup(&dev->readtimer, cadet_handler, 0); in cadet_start_rds()
322 dev->readtimer.expires = jiffies + msecs_to_jiffies(50); in cadet_start_rds()
323 add_timer(&dev->readtimer); in cadet_start_rds()
332 mutex_lock(&dev->lock); in cadet_read()
333 if (dev->rdsstat == 0) in cadet_read()
335 mutex_unlock(&dev->lock); in cadet_read()
337 if (!cadet_has_rds_data(dev) && (file->f_flags & O_NONBLOCK)) in cadet_read()
338 return -EWOULDBLOCK; in cadet_read()
339 i = wait_event_interruptible(dev->read_queue, cadet_has_rds_data(dev)); in cadet_read()
343 mutex_lock(&dev->lock); in cadet_read()
344 while (i < count && dev->rdsin != dev->rdsout) in cadet_read()
345 readbuf[i++] = dev->rdsbuf[dev->rdsout++]; in cadet_read()
346 mutex_unlock(&dev->lock); in cadet_read()
349 return -EFAULT; in cadet_read()
357 strscpy(v->driver, "ADS Cadet", sizeof(v->driver)); in vidioc_querycap()
358 strscpy(v->card, "ADS Cadet", sizeof(v->card)); in vidioc_querycap()
359 strscpy(v->bus_info, "ISA:radio-cadet", sizeof(v->bus_info)); in vidioc_querycap()
368 if (v->index) in vidioc_g_tuner()
369 return -EINVAL; in vidioc_g_tuner()
370 v->type = V4L2_TUNER_RADIO; in vidioc_g_tuner()
371 strscpy(v->name, "Radio", sizeof(v->name)); in vidioc_g_tuner()
372 v->capability = bands[0].capability | bands[1].capability; in vidioc_g_tuner()
373 v->rangelow = bands[0].rangelow; /* 520 kHz (start of AM band) */ in vidioc_g_tuner()
374 v->rangehigh = bands[1].rangehigh; /* 108.0 MHz (end of FM band) */ in vidioc_g_tuner()
375 if (dev->is_fm_band) { in vidioc_g_tuner()
376 v->rxsubchans = cadet_getstereo(dev); in vidioc_g_tuner()
377 outb(3, dev->io); in vidioc_g_tuner()
378 outb(inb(dev->io + 1) & 0x7f, dev->io + 1); in vidioc_g_tuner()
380 outb(3, dev->io); in vidioc_g_tuner()
381 if (inb(dev->io + 1) & 0x80) in vidioc_g_tuner()
382 v->rxsubchans |= V4L2_TUNER_SUB_RDS; in vidioc_g_tuner()
384 v->rangelow = 8320; /* 520 kHz */ in vidioc_g_tuner()
385 v->rangehigh = 26400; /* 1650 kHz */ in vidioc_g_tuner()
386 v->rxsubchans = V4L2_TUNER_SUB_MONO; in vidioc_g_tuner()
388 v->audmode = V4L2_TUNER_MODE_STEREO; in vidioc_g_tuner()
389 v->signal = dev->sigstrength; /* We might need to modify scaling of this */ in vidioc_g_tuner()
396 return v->index ? -EINVAL : 0; in vidioc_s_tuner()
402 if (band->tuner) in vidioc_enum_freq_bands()
403 return -EINVAL; in vidioc_enum_freq_bands()
404 if (band->index >= ARRAY_SIZE(bands)) in vidioc_enum_freq_bands()
405 return -EINVAL; in vidioc_enum_freq_bands()
406 *band = bands[band->index]; in vidioc_enum_freq_bands()
415 if (f->tuner) in vidioc_g_frequency()
416 return -EINVAL; in vidioc_g_frequency()
417 f->type = V4L2_TUNER_RADIO; in vidioc_g_frequency()
418 f->frequency = dev->curfreq; in vidioc_g_frequency()
428 if (f->tuner) in vidioc_s_frequency()
429 return -EINVAL; in vidioc_s_frequency()
430 dev->is_fm_band = in vidioc_s_frequency()
431 f->frequency >= (bands[0].rangehigh + bands[1].rangelow) / 2; in vidioc_s_frequency()
432 cadet_setfreq(dev, f->frequency); in vidioc_s_frequency()
438 struct cadet *dev = container_of(ctrl->handler, struct cadet, ctrl_handler); in cadet_s_ctrl()
440 switch (ctrl->id) { in cadet_s_ctrl()
442 outb(7, dev->io); /* Select tuner control */ in cadet_s_ctrl()
443 if (ctrl->val) in cadet_s_ctrl()
444 outb(0x00, dev->io + 1); in cadet_s_ctrl()
446 outb(0x20, dev->io + 1); in cadet_s_ctrl()
449 return -EINVAL; in cadet_s_ctrl()
457 mutex_lock(&dev->lock); in cadet_open()
462 init_waitqueue_head(&dev->read_queue); in cadet_open()
464 mutex_unlock(&dev->lock); in cadet_open()
472 mutex_lock(&dev->lock); in cadet_release()
473 if (v4l2_fh_is_singular_file(file) && dev->rdsstat) { in cadet_release()
474 del_timer_sync(&dev->readtimer); in cadet_release()
475 dev->rdsstat = 0; in cadet_release()
478 mutex_unlock(&dev->lock); in cadet_release()
488 poll_wait(file, &dev->read_queue, wait); in cadet_poll()
489 if (dev->rdsstat == 0 && (req_events & (EPOLLIN | EPOLLRDNORM))) { in cadet_poll()
490 mutex_lock(&dev->lock); in cadet_poll()
491 if (dev->rdsstat == 0) in cadet_poll()
493 mutex_unlock(&dev->lock); in cadet_poll()
539 return -ENODEV; in cadet_pnp_probe()
542 return -EBUSY; in cadet_pnp_probe()
545 return -ENODEV; in cadet_pnp_probe()
549 printk(KERN_INFO "radio-cadet: PnP reports device at %#x\n", io); in cadet_pnp_probe()
555 .name = "radio-cadet",
571 dev->io = iovals[i]; in cadet_probe()
572 if (request_region(dev->io, 2, "cadet-probe")) { in cadet_probe()
575 release_region(dev->io, 2); in cadet_probe()
578 release_region(dev->io, 2); in cadet_probe()
581 dev->io = -1; in cadet_probe()
592 struct v4l2_device *v4l2_dev = &dev->v4l2_dev; in cadet_init()
594 int res = -ENODEV; in cadet_init()
596 strscpy(v4l2_dev->name, "cadet", sizeof(v4l2_dev->name)); in cadet_init()
597 mutex_init(&dev->lock); in cadet_init()
602 dev->io = io; in cadet_init()
605 if (dev->io < 0) in cadet_init()
609 if (dev->io < 0) { in cadet_init()
616 if (!request_region(dev->io, 2, "cadet")) in cadet_init()
621 release_region(dev->io, 2); in cadet_init()
626 hdl = &dev->ctrl_handler; in cadet_init()
630 v4l2_dev->ctrl_handler = hdl; in cadet_init()
631 if (hdl->error) { in cadet_init()
632 res = hdl->error; in cadet_init()
637 dev->is_fm_band = true; in cadet_init()
638 dev->curfreq = bands[dev->is_fm_band].rangelow; in cadet_init()
639 cadet_setfreq(dev, dev->curfreq); in cadet_init()
640 strscpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name)); in cadet_init()
641 dev->vdev.v4l2_dev = v4l2_dev; in cadet_init()
642 dev->vdev.fops = &cadet_fops; in cadet_init()
643 dev->vdev.ioctl_ops = &cadet_ioctl_ops; in cadet_init()
644 dev->vdev.release = video_device_release_empty; in cadet_init()
645 dev->vdev.lock = &dev->lock; in cadet_init()
646 dev->vdev.device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO | in cadet_init()
648 video_set_drvdata(&dev->vdev, dev); in cadet_init()
650 res = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr); in cadet_init()
653 v4l2_info(v4l2_dev, "ADS Cadet Radio Card at 0x%x\n", dev->io); in cadet_init()
658 release_region(dev->io, 2); in cadet_init()
668 video_unregister_device(&dev->vdev); in cadet_exit()
669 v4l2_ctrl_handler_free(&dev->ctrl_handler); in cadet_exit()
670 v4l2_device_unregister(&dev->v4l2_dev); in cadet_exit()
671 outb(7, dev->io); /* Mute */ in cadet_exit()
672 outb(0x00, dev->io + 1); in cadet_exit()
673 release_region(dev->io, 2); in cadet_exit()