|
@@ -1,266 +0,0 @@
|
|
|
-/* Miro PCM20 radio driver for Linux radio support
|
|
|
- * (c) 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
|
|
|
- * Thanks to Norberto Pellici for the ACI device interface specification
|
|
|
- * The API part is based on the radiotrack driver by M. Kirkwood
|
|
|
- * This driver relies on the aci mixer (drivers/sound/aci.c)
|
|
|
- * Look there for further info...
|
|
|
- */
|
|
|
-
|
|
|
-/* Revision history:
|
|
|
- *
|
|
|
- * 1998 Ruurd Reitsma <R.A.Reitsma@wbmt.tudelft.nl>
|
|
|
- * 2000-09-05 Robert Siemer <Robert.Siemer@gmx.de>
|
|
|
- * removed unfinished volume control (maybe adding it later again)
|
|
|
- * use OSS-mixer; added stereo control
|
|
|
- */
|
|
|
-
|
|
|
-/* What ever you think about the ACI, version 0x07 is not very well!
|
|
|
- * I can't get frequency, 'tuner status', 'tuner flags' or mute/mono
|
|
|
- * conditions... Robert
|
|
|
- */
|
|
|
-
|
|
|
-#include <linux/module.h>
|
|
|
-#include <linux/init.h>
|
|
|
-#include <linux/videodev.h>
|
|
|
-#include <media/v4l2-common.h>
|
|
|
-#include <media/v4l2-ioctl.h>
|
|
|
-#include "oss/aci.h"
|
|
|
-#include "miropcm20-rds-core.h"
|
|
|
-
|
|
|
-static int radio_nr = -1;
|
|
|
-module_param(radio_nr, int, 0);
|
|
|
-
|
|
|
-struct pcm20_device {
|
|
|
- unsigned long freq;
|
|
|
- int muted;
|
|
|
- int stereo;
|
|
|
-};
|
|
|
-
|
|
|
-
|
|
|
-static int pcm20_mute(struct pcm20_device *dev, unsigned char mute)
|
|
|
-{
|
|
|
- dev->muted = mute;
|
|
|
- return aci_write_cmd(ACI_SET_TUNERMUTE, mute);
|
|
|
-}
|
|
|
-
|
|
|
-static int pcm20_stereo(struct pcm20_device *dev, unsigned char stereo)
|
|
|
-{
|
|
|
- dev->stereo = stereo;
|
|
|
- return aci_write_cmd(ACI_SET_TUNERMONO, !stereo);
|
|
|
-}
|
|
|
-
|
|
|
-static int pcm20_setfreq(struct pcm20_device *dev, unsigned long freq)
|
|
|
-{
|
|
|
- unsigned char freql;
|
|
|
- unsigned char freqh;
|
|
|
-
|
|
|
- dev->freq=freq;
|
|
|
-
|
|
|
- freq /= 160;
|
|
|
- if (!(aci_version==0x07 || aci_version>=0xb0))
|
|
|
- freq /= 10; /* I don't know exactly which version
|
|
|
- * needs this hack */
|
|
|
- freql = freq & 0xff;
|
|
|
- freqh = freq >> 8;
|
|
|
-
|
|
|
- aci_rds_cmd(RDS_RESET, NULL, 0);
|
|
|
- pcm20_stereo(dev, 1);
|
|
|
-
|
|
|
- return aci_rw_cmd(ACI_WRITE_TUNE, freql, freqh);
|
|
|
-}
|
|
|
-
|
|
|
-static int pcm20_getflags(struct pcm20_device *dev, __u32 *flags, __u16 *signal)
|
|
|
-{
|
|
|
- /* okay, check for signal, stereo and rds here... */
|
|
|
- int i;
|
|
|
- unsigned char buf;
|
|
|
-
|
|
|
- if ((i=aci_rw_cmd(ACI_READ_TUNERSTATION, -1, -1))<0)
|
|
|
- return i;
|
|
|
- pr_debug("check_sig: 0x%x\n", i);
|
|
|
- if (i & 0x80) {
|
|
|
- /* no signal from tuner */
|
|
|
- *flags=0;
|
|
|
- *signal=0;
|
|
|
- return 0;
|
|
|
- } else
|
|
|
- *signal=0xffff;
|
|
|
-
|
|
|
- if ((i=aci_rw_cmd(ACI_READ_TUNERSTEREO, -1, -1))<0)
|
|
|
- return i;
|
|
|
- if (i & 0x40) {
|
|
|
- *flags=0;
|
|
|
- } else {
|
|
|
- /* stereo */
|
|
|
- *flags=VIDEO_TUNER_STEREO_ON;
|
|
|
- /* I can't see stereo, when forced to mono */
|
|
|
- dev->stereo=1;
|
|
|
- }
|
|
|
-
|
|
|
- if ((i=aci_rds_cmd(RDS_STATUS, &buf, 1))<0)
|
|
|
- return i;
|
|
|
- if (buf & 1)
|
|
|
- /* RDS available */
|
|
|
- *flags|=VIDEO_TUNER_RDS_ON;
|
|
|
- else
|
|
|
- return 0;
|
|
|
-
|
|
|
- if ((i=aci_rds_cmd(RDS_RXVALUE, &buf, 1))<0)
|
|
|
- return i;
|
|
|
- pr_debug("rds-signal: %d\n", buf);
|
|
|
- if (buf > 15) {
|
|
|
- printk("miropcm20-radio: RX strengths unexpected high...\n");
|
|
|
- buf=15;
|
|
|
- }
|
|
|
- /* refine signal */
|
|
|
- if ((*signal=SCALE(15, 0xffff, buf))==0)
|
|
|
- *signal = 1;
|
|
|
-
|
|
|
- return 0;
|
|
|
-}
|
|
|
-
|
|
|
-static int pcm20_do_ioctl(struct inode *inode, struct file *file,
|
|
|
- unsigned int cmd, void *arg)
|
|
|
-{
|
|
|
- struct video_device *dev = video_devdata(file);
|
|
|
- struct pcm20_device *pcm20 = dev->priv;
|
|
|
- int i;
|
|
|
-
|
|
|
- switch(cmd)
|
|
|
- {
|
|
|
- case VIDIOCGCAP:
|
|
|
- {
|
|
|
- struct video_capability *v = arg;
|
|
|
- memset(v,0,sizeof(*v));
|
|
|
- v->type=VID_TYPE_TUNER;
|
|
|
- strcpy(v->name, "Miro PCM20");
|
|
|
- v->channels=1;
|
|
|
- v->audios=1;
|
|
|
- return 0;
|
|
|
- }
|
|
|
- case VIDIOCGTUNER:
|
|
|
- {
|
|
|
- struct video_tuner *v = arg;
|
|
|
- if(v->tuner) /* Only 1 tuner */
|
|
|
- return -EINVAL;
|
|
|
- v->rangelow=87*16000;
|
|
|
- v->rangehigh=108*16000;
|
|
|
- pcm20_getflags(pcm20, &v->flags, &v->signal);
|
|
|
- v->flags|=VIDEO_TUNER_LOW;
|
|
|
- v->mode=VIDEO_MODE_AUTO;
|
|
|
- strcpy(v->name, "FM");
|
|
|
- return 0;
|
|
|
- }
|
|
|
- case VIDIOCSTUNER:
|
|
|
- {
|
|
|
- struct video_tuner *v = arg;
|
|
|
- if(v->tuner!=0)
|
|
|
- return -EINVAL;
|
|
|
- /* Only 1 tuner so no setting needed ! */
|
|
|
- return 0;
|
|
|
- }
|
|
|
- case VIDIOCGFREQ:
|
|
|
- {
|
|
|
- unsigned long *freq = arg;
|
|
|
- *freq = pcm20->freq;
|
|
|
- return 0;
|
|
|
- }
|
|
|
- case VIDIOCSFREQ:
|
|
|
- {
|
|
|
- unsigned long *freq = arg;
|
|
|
- pcm20->freq = *freq;
|
|
|
- i=pcm20_setfreq(pcm20, pcm20->freq);
|
|
|
- pr_debug("First view (setfreq): 0x%x\n", i);
|
|
|
- return i;
|
|
|
- }
|
|
|
- case VIDIOCGAUDIO:
|
|
|
- {
|
|
|
- struct video_audio *v = arg;
|
|
|
- memset(v,0, sizeof(*v));
|
|
|
- v->flags=VIDEO_AUDIO_MUTABLE;
|
|
|
- if (pcm20->muted)
|
|
|
- v->flags|=VIDEO_AUDIO_MUTE;
|
|
|
- v->mode=VIDEO_SOUND_STEREO;
|
|
|
- if (pcm20->stereo)
|
|
|
- v->mode|=VIDEO_SOUND_MONO;
|
|
|
- /* v->step=2048; */
|
|
|
- strcpy(v->name, "Radio");
|
|
|
- return 0;
|
|
|
- }
|
|
|
- case VIDIOCSAUDIO:
|
|
|
- {
|
|
|
- struct video_audio *v = arg;
|
|
|
- if(v->audio)
|
|
|
- return -EINVAL;
|
|
|
-
|
|
|
- pcm20_mute(pcm20, !!(v->flags&VIDEO_AUDIO_MUTE));
|
|
|
- if(v->flags&VIDEO_SOUND_MONO)
|
|
|
- pcm20_stereo(pcm20, 0);
|
|
|
- if(v->flags&VIDEO_SOUND_STEREO)
|
|
|
- pcm20_stereo(pcm20, 1);
|
|
|
-
|
|
|
- return 0;
|
|
|
- }
|
|
|
- default:
|
|
|
- return -ENOIOCTLCMD;
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
-static int pcm20_ioctl(struct inode *inode, struct file *file,
|
|
|
- unsigned int cmd, unsigned long arg)
|
|
|
-{
|
|
|
- return video_usercopy(inode, file, cmd, arg, pcm20_do_ioctl);
|
|
|
-}
|
|
|
-
|
|
|
-static struct pcm20_device pcm20_unit = {
|
|
|
- .freq = 87*16000,
|
|
|
- .muted = 1,
|
|
|
-};
|
|
|
-
|
|
|
-static const struct file_operations pcm20_fops = {
|
|
|
- .owner = THIS_MODULE,
|
|
|
- .open = video_exclusive_open,
|
|
|
- .release = video_exclusive_release,
|
|
|
- .ioctl = pcm20_ioctl,
|
|
|
-#ifdef CONFIG_COMPAT
|
|
|
- .compat_ioctl = v4l_compat_ioctl32,
|
|
|
-#endif
|
|
|
- .llseek = no_llseek,
|
|
|
-};
|
|
|
-
|
|
|
-static struct video_device pcm20_radio = {
|
|
|
- .name = "Miro PCM 20 radio",
|
|
|
- .fops = &pcm20_fops,
|
|
|
- .priv = &pcm20_unit
|
|
|
-};
|
|
|
-
|
|
|
-static int __init pcm20_init(void)
|
|
|
-{
|
|
|
- if(video_register_device(&pcm20_radio, VFL_TYPE_RADIO, radio_nr)==-1)
|
|
|
- goto video_register_device;
|
|
|
-
|
|
|
- if(attach_aci_rds()<0)
|
|
|
- goto attach_aci_rds;
|
|
|
-
|
|
|
- printk(KERN_INFO "Miro PCM20 radio card driver.\n");
|
|
|
-
|
|
|
- return 0;
|
|
|
-
|
|
|
- attach_aci_rds:
|
|
|
- video_unregister_device(&pcm20_radio);
|
|
|
- video_register_device:
|
|
|
- return -EINVAL;
|
|
|
-}
|
|
|
-
|
|
|
-MODULE_AUTHOR("Ruurd Reitsma");
|
|
|
-MODULE_DESCRIPTION("A driver for the Miro PCM20 radio card.");
|
|
|
-MODULE_LICENSE("GPL");
|
|
|
-
|
|
|
-static void __exit pcm20_cleanup(void)
|
|
|
-{
|
|
|
- unload_aci_rds();
|
|
|
- video_unregister_device(&pcm20_radio);
|
|
|
-}
|
|
|
-
|
|
|
-module_init(pcm20_init);
|
|
|
-module_exit(pcm20_cleanup);
|