diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 15:20:36 -0700 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /drivers/media/radio |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'drivers/media/radio')
-rw-r--r-- | drivers/media/radio/Kconfig | 354 | ||||
-rw-r--r-- | drivers/media/radio/Makefile | 22 | ||||
-rw-r--r-- | drivers/media/radio/miropcm20-radio.c | 264 | ||||
-rw-r--r-- | drivers/media/radio/miropcm20-rds-core.c | 210 | ||||
-rw-r--r-- | drivers/media/radio/miropcm20-rds-core.h | 19 | ||||
-rw-r--r-- | drivers/media/radio/miropcm20-rds.c | 133 | ||||
-rw-r--r-- | drivers/media/radio/radio-aimslab.c | 368 | ||||
-rw-r--r-- | drivers/media/radio/radio-aztech.c | 315 | ||||
-rw-r--r-- | drivers/media/radio/radio-cadet.c | 620 | ||||
-rw-r--r-- | drivers/media/radio/radio-gemtek-pci.c | 416 | ||||
-rw-r--r-- | drivers/media/radio/radio-gemtek.c | 304 | ||||
-rw-r--r-- | drivers/media/radio/radio-maestro.c | 332 | ||||
-rw-r--r-- | drivers/media/radio/radio-maxiradio.c | 349 | ||||
-rw-r--r-- | drivers/media/radio/radio-rtrack2.c | 266 | ||||
-rw-r--r-- | drivers/media/radio/radio-sf16fmi.c | 328 | ||||
-rw-r--r-- | drivers/media/radio/radio-sf16fmr2.c | 434 | ||||
-rw-r--r-- | drivers/media/radio/radio-terratec.c | 341 | ||||
-rw-r--r-- | drivers/media/radio/radio-trust.c | 320 | ||||
-rw-r--r-- | drivers/media/radio/radio-typhoon.c | 383 | ||||
-rw-r--r-- | drivers/media/radio/radio-zoltrix.c | 385 |
20 files changed, 6163 insertions, 0 deletions
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig new file mode 100644 index 00000000000..d318be383de --- /dev/null +++ b/drivers/media/radio/Kconfig @@ -0,0 +1,354 @@ +# +# Multimedia Video device configuration +# + +menu "Radio Adapters" + depends on VIDEO_DEV!=n + +config RADIO_CADET + tristate "ADS Cadet AM/FM Tuner" + depends on ISA && VIDEO_DEV + ---help--- + Choose Y here if you have one of these AM/FM radio cards, and then + fill in the port address below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + <file:Documentation/video4linux/API.html>. + + Further documentation on this driver can be found on the WWW at + <http://linux.blackhawke.net/cadet/>. + + To compile this driver as a module, choose M here: the + module will be called radio-cadet. + +config RADIO_RTRACK + tristate "AIMSlab RadioTrack (aka RadioReveal) support" + depends on ISA && VIDEO_DEV + ---help--- + Choose Y here if you have one of these FM radio cards, and then fill + in the port address below. + + Note that newer AIMSlab RadioTrack cards have a different chipset + and are not supported by this driver. For these cards, use the + RadioTrack II driver below. + + If you have a GemTeks combined (PnP) sound- and radio card you must + use this driver as a module and setup the card with isapnptools. + You must also pass the module a suitable io parameter, 0x248 has + been reported to be used by these cards. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + <file:Documentation/video4linux/API.html>. More information is + contained in the file + <file:Documentation/video4linux/radiotrack.txt>. + + To compile this driver as a module, choose M here: the + module will be called radio-aimslab. + +config RADIO_RTRACK_PORT + hex "RadioTrack i/o port (0x20f or 0x30f)" + depends on RADIO_RTRACK=y + default "20f" + help + Enter either 0x30f or 0x20f here. The card default is 0x30f, if you + haven't changed the jumper setting on the card. + +config RADIO_RTRACK2 + tristate "AIMSlab RadioTrack II support" + depends on ISA && VIDEO_DEV + ---help--- + Choose Y here if you have this FM radio card, and then fill in the + port address below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + <file:Documentation/video4linux/API.html>. + + To compile this driver as a module, choose M here: the + module will be called radio-rtrack2. + +config RADIO_RTRACK2_PORT + hex "RadioTrack II i/o port (0x20c or 0x30c)" + depends on RADIO_RTRACK2=y + default "30c" + help + Enter either 0x30c or 0x20c here. The card default is 0x30c, if you + haven't changed the jumper setting on the card. + +config RADIO_AZTECH + tristate "Aztech/Packard Bell Radio" + depends on ISA && VIDEO_DEV + ---help--- + Choose Y here if you have one of these FM radio cards, and then fill + in the port address below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + <file:Documentation/video4linux/API.html>. + + To compile this driver as a module, choose M here: the + module will be called radio-aztech. + +config RADIO_AZTECH_PORT + hex "Aztech/Packard Bell I/O port (0x350 or 0x358)" + depends on RADIO_AZTECH=y + default "350" + help + Enter either 0x350 or 0x358 here. The card default is 0x350, if you + haven't changed the setting of jumper JP3 on the card. Removing the + jumper sets the card to 0x358. + +config RADIO_GEMTEK + tristate "GemTek Radio Card support" + depends on ISA && VIDEO_DEV + ---help--- + Choose Y here if you have this FM radio card, and then fill in the + port address below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + <file:Documentation/video4linux/API.html>. + + To compile this driver as a module, choose M here: the + module will be called radio-gemtek. + +config RADIO_GEMTEK_PORT + hex "GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)" + depends on RADIO_GEMTEK=y + default "34c" + help + Enter either 0x20c, 0x30c, 0x24c or 0x34c here. The card default is + 0x34c, if you haven't changed the jumper setting on the card. On + Sound Vision 16 Gold PnP with FM Radio (ESS1869+FM Gemtek), the I/O + port is 0x28c. + +config RADIO_GEMTEK_PCI + tristate "GemTek PCI Radio Card support" + depends on VIDEO_DEV && PCI + ---help--- + Choose Y here if you have this PCI FM radio card. + + In order to control your radio card, you will need to use programs + that are compatible with the Video for Linux API. Information on + this API and pointers to "v4l" programs may be found at + <file:Documentation/video4linux/API.html>. + + To compile this driver as a module, choose M here: the + module will be called radio-gemtek-pci. + +config RADIO_MAXIRADIO + tristate "Guillemot MAXI Radio FM 2000 radio" + depends on VIDEO_DEV && PCI + ---help--- + Choose Y here if you have this radio card. This card may also be + found as Gemtek PCI FM. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + <file:Documentation/video4linux/API.html>. + + To compile this driver as a module, choose M here: the + module will be called radio-maxiradio. + +config RADIO_MAESTRO + tristate "Maestro on board radio" + depends on VIDEO_DEV + ---help--- + Say Y here to directly support the on-board radio tuner on the + Maestro 2 or 2E sound card. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + <file:Documentation/video4linux/API.html>. + + To compile this driver as a module, choose M here: the + module will be called radio-maestro. + +config RADIO_MIROPCM20 + tristate "miroSOUND PCM20 radio" + depends on ISA && VIDEO_DEV && SOUND_ACI_MIXER + ---help--- + Choose Y here if you have this FM radio card. You also need to say Y + to "ACI mixer (miroSOUND PCM1-pro/PCM12/PCM20 radio)" (in "Sound") + for this to work. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + <file:Documentation/video4linux/API.html>. + + To compile this driver as a module, choose M here: the + module will be called miropcm20. + +config RADIO_MIROPCM20_RDS + tristate "miroSOUND PCM20 radio RDS user interface (EXPERIMENTAL)" + depends on RADIO_MIROPCM20 && EXPERIMENTAL + ---help--- + Choose Y here if you want to see RDS/RBDS information like + RadioText, Programme Service name, Clock Time and date, Programme + TYpe and Traffic Announcement/Programme identification. You also + need to say Y to "miroSOUND PCM20 radio" and devfs! + + It's not possible to read the raw RDS packets from the device, so + the driver cant provide an V4L interface for this. But the + availability of RDS is reported over V4L by the basic driver + already. Here RDS can be read from files in /dev/v4l/rds. + + To compile this driver as a module, choose M here: the + module will be called miropcm20-rds. + +config RADIO_SF16FMI + tristate "SF16FMI Radio" + depends on ISA && VIDEO_DEV + ---help--- + Choose Y here if you have one of these FM radio cards. If you + compile the driver into the kernel and your card is not PnP one, you + have to add "sf16fm=<io>" to the kernel command line (I/O address is + 0x284 or 0x384). + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + <file:Documentation/video4linux/API.html>. + + To compile this driver as a module, choose M here: the + module will be called radio-sf16fmi. + +config RADIO_SF16FMR2 + tristate "SF16FMR2 Radio" + depends on ISA && VIDEO_DEV + ---help--- + Choose Y here if you have one of these FM radio cards. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found on the WWW at + <http://roadrunner.swansea.uk.linux.org/v4l.shtml>. + + To compile this driver as a module, choose M here: the + module will be called radio-sf16fmr2. + +config RADIO_TERRATEC + tristate "TerraTec ActiveRadio ISA Standalone" + depends on ISA && VIDEO_DEV + ---help--- + Choose Y here if you have this FM radio card, and then fill in the + port address below. (TODO) + + Note: This driver is in its early stages. Right now volume and + frequency control and muting works at least for me, but + unfortunately I have not found anybody who wants to use this card + with Linux. So if it is this what YOU are trying to do right now, + PLEASE DROP ME A NOTE!! Rolf Offermanns <rolf@offermanns.de>. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + <file:Documentation/video4linux/API.html>. + + To compile this driver as a module, choose M here: the + module will be called radio-terratec. + +config RADIO_TERRATEC_PORT + hex "Terratec i/o port (normally 0x590)" + depends on RADIO_TERRATEC=y + default "590" + help + Fill in the I/O port of your TerraTec FM radio card. If unsure, go + with the default. + +config RADIO_TRUST + tristate "Trust FM radio card" + depends on ISA && VIDEO_DEV + help + This is a driver for the Trust FM radio cards. Say Y if you have + such a card and want to use it under Linux. + + To compile this driver as a module, choose M here: the + module will be called radio-trust. + +config RADIO_TRUST_PORT + hex "Trust i/o port (usually 0x350 or 0x358)" + depends on RADIO_TRUST=y + default "350" + help + Enter the I/O port of your Trust FM radio card. If unsure, try the + values "0x350" or "0x358". + +config RADIO_TYPHOON + tristate "Typhoon Radio (a.k.a. EcoRadio)" + depends on ISA && VIDEO_DEV + ---help--- + Choose Y here if you have one of these FM radio cards, and then fill + in the port address and the frequency used for muting below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + <file:Documentation/video4linux/API.html>. + + To compile this driver as a module, choose M here: the + module will be called radio-typhoon. + +config RADIO_TYPHOON_PROC_FS + bool "Support for /proc/radio-typhoon" + depends on PROC_FS && RADIO_TYPHOON + help + Say Y here if you want the typhoon radio card driver to write + status information (frequency, volume, muted, mute frequency, + base address) to /proc/radio-typhoon. The file can be viewed with + your favorite pager (i.e. use "more /proc/radio-typhoon" or "less + /proc/radio-typhoon" or simply "cat /proc/radio-typhoon"). + +config RADIO_TYPHOON_PORT + hex "Typhoon I/O port (0x316 or 0x336)" + depends on RADIO_TYPHOON=y + default "316" + help + Enter the I/O port of your Typhoon or EcoRadio radio card. + +config RADIO_TYPHOON_MUTEFREQ + int "Typhoon frequency set when muting the device (kHz)" + depends on RADIO_TYPHOON=y + default "87500" + help + Enter the frequency used for muting the radio. The device is never + completely silent. If the volume is just turned down, you can still + hear silent voices and music. For that reason, the frequency of the + radio device is set to the frequency you can enter here whenever + the device is muted. There should be no local radio station at that + frequency. + +config RADIO_ZOLTRIX + tristate "Zoltrix Radio" + depends on ISA && VIDEO_DEV + ---help--- + Choose Y here if you have one of these FM radio cards, and then fill + in the port address below. + + In order to control your radio card, you will need to use programs + that are compatible with the Video For Linux API. Information on + this API and pointers to "v4l" programs may be found at + <file:Documentation/video4linux/API.html>. + + To compile this driver as a module, choose M here: the + module will be called radio-zoltrix. + +config RADIO_ZOLTRIX_PORT + hex "ZOLTRIX I/O port (0x20c or 0x30c)" + depends on RADIO_ZOLTRIX=y + default "20c" + help + Enter the I/O port of your Zoltrix radio card. + +endmenu + diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile new file mode 100644 index 00000000000..8b351945d06 --- /dev/null +++ b/drivers/media/radio/Makefile @@ -0,0 +1,22 @@ +# +# Makefile for the kernel character device drivers. +# + +miropcm20-objs := miropcm20-rds-core.o miropcm20-radio.o + +obj-$(CONFIG_RADIO_AZTECH) += radio-aztech.o +obj-$(CONFIG_RADIO_RTRACK2) += radio-rtrack2.o +obj-$(CONFIG_RADIO_SF16FMI) += radio-sf16fmi.o +obj-$(CONFIG_RADIO_SF16FMR2) += radio-sf16fmr2.o +obj-$(CONFIG_RADIO_CADET) += radio-cadet.o +obj-$(CONFIG_RADIO_TYPHOON) += radio-typhoon.o +obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o +obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o +obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o +obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o +obj-$(CONFIG_RADIO_MIROPCM20) += miropcm20.o +obj-$(CONFIG_RADIO_MIROPCM20_RDS) += miropcm20-rds.o +obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o +obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o +obj-$(CONFIG_RADIO_TRUST) += radio-trust.o +obj-$(CONFIG_RADIO_MAESTRO) += radio-maestro.o diff --git a/drivers/media/radio/miropcm20-radio.c b/drivers/media/radio/miropcm20-radio.c new file mode 100644 index 00000000000..c2ebe8754a9 --- /dev/null +++ b/drivers/media/radio/miropcm20-radio.c @@ -0,0 +1,264 @@ +/* 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 "../../../sound/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 struct file_operations pcm20_fops = { + .owner = THIS_MODULE, + .open = video_exclusive_open, + .release = video_exclusive_release, + .ioctl = pcm20_ioctl, + .llseek = no_llseek, +}; + +static struct video_device pcm20_radio = { + .owner = THIS_MODULE, + .name = "Miro PCM 20 radio", + .type = VID_TYPE_TUNER, + .hardware = VID_HARDWARE_RTRACK, + .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); diff --git a/drivers/media/radio/miropcm20-rds-core.c b/drivers/media/radio/miropcm20-rds-core.c new file mode 100644 index 00000000000..a917a90cb5d --- /dev/null +++ b/drivers/media/radio/miropcm20-rds-core.c @@ -0,0 +1,210 @@ +/* + * Many thanks to Fred Seidel <seidel@metabox.de>, the + * designer of the RDS decoder hardware. With his help + * I was able to code this driver. + * Thanks also to Norberto Pellicci, Dominic Mounteney + * <DMounteney@pinnaclesys.com> and www.teleauskunft.de + * for good hints on finding Fred. It was somewhat hard + * to locate him here in Germany... [: + * + * Revision history: + * + * 2000-08-09 Robert Siemer <Robert.Siemer@gmx.de> + * RDS support for MiroSound PCM20 radio + */ + +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/string.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <asm/semaphore.h> +#include <asm/io.h> +#include "../../../sound/oss/aci.h" +#include "miropcm20-rds-core.h" + +#define DEBUG 0 + +static struct semaphore aci_rds_sem; + +#define RDS_DATASHIFT 2 /* Bit 2 */ +#define RDS_DATAMASK (1 << RDS_DATASHIFT) +#define RDS_BUSYMASK 0x10 /* Bit 4 */ +#define RDS_CLOCKMASK 0x08 /* Bit 3 */ + +#define RDS_DATA(x) (((x) >> RDS_DATASHIFT) & 1) + + +#if DEBUG +static void print_matrix(char array[], unsigned int length) +{ + int i, j; + + for (i=0; i<length; i++) { + printk(KERN_DEBUG "aci-rds: "); + for (j=7; j>=0; j--) { + printk("%d", (array[i] >> j) & 0x1); + } + if (i%8 == 0) + printk(" byte-border\n"); + else + printk("\n"); + } +} +#endif /* DEBUG */ + +static int byte2trans(unsigned char byte, unsigned char sendbuffer[], int size) +{ + int i; + + if (size != 8) + return -1; + for (i = 7; i >= 0; i--) + sendbuffer[7-i] = (byte & (1 << i)) ? RDS_DATAMASK : 0; + sendbuffer[0] |= RDS_CLOCKMASK; + + return 0; +} + +static int rds_waitread(void) +{ + unsigned char byte; + int i=2000; + + do { + byte=inb(RDS_REGISTER); + i--; + } + while ((byte & RDS_BUSYMASK) && i); + + if (i) { + #if DEBUG + printk(KERN_DEBUG "rds_waitread()"); + print_matrix(&byte, 1); + #endif + return (byte); + } else { + printk(KERN_WARNING "aci-rds: rds_waitread() timeout...\n"); + return -1; + } +} + +/* don't use any ..._nowait() function if you are not sure what you do... */ + +static inline void rds_rawwrite_nowait(unsigned char byte) +{ + #if DEBUG + printk(KERN_DEBUG "rds_rawwrite()"); + print_matrix(&byte, 1); + #endif + outb(byte, RDS_REGISTER); +} + +static int rds_rawwrite(unsigned char byte) +{ + if (rds_waitread() >= 0) { + rds_rawwrite_nowait(byte); + return 0; + } else + return -1; +} + +static int rds_write(unsigned char cmd) +{ + unsigned char sendbuffer[8]; + int i; + + if (byte2trans(cmd, sendbuffer, 8) != 0){ + return -1; + } else { + for (i=0; i<8; i++) { + rds_rawwrite(sendbuffer[i]); + } + } + return 0; +} + +static int rds_readcycle_nowait(void) +{ + rds_rawwrite_nowait(0); + return rds_waitread(); +} + +static int rds_readcycle(void) +{ + if (rds_rawwrite(0) < 0) + return -1; + return rds_waitread(); +} + +static int rds_read(unsigned char databuffer[], int datasize) +{ + #define READSIZE (8*datasize) + + int i,j; + + if (datasize < 1) /* nothing to read */ + return 0; + + /* to be able to use rds_readcycle_nowait() + I have to waitread() here */ + if (rds_waitread() < 0) + return -1; + + memset(databuffer, 0, datasize); + + for (i=0; i< READSIZE; i++) + if((j=rds_readcycle_nowait()) < 0) { + return -1; + } else { + databuffer[i/8]|=(RDS_DATA(j) << (7-(i%8))); + } + + return 0; +} + +static int rds_ack(void) +{ + int i=rds_readcycle(); + + if (i < 0) + return -1; + if (i & RDS_DATAMASK) { + return 0; /* ACK */ + } else { + printk(KERN_DEBUG "aci-rds: NACK\n"); + return 1; /* NACK */ + } +} + +int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize) +{ + int ret; + + if (down_interruptible(&aci_rds_sem)) + return -EINTR; + + rds_write(cmd); + + /* RDS_RESET doesn't need further processing */ + if (cmd!=RDS_RESET && (rds_ack() || rds_read(databuffer, datasize))) + ret = -1; + else + ret = 0; + + up(&aci_rds_sem); + + return ret; +} +EXPORT_SYMBOL(aci_rds_cmd); + +int __init attach_aci_rds(void) +{ + init_MUTEX(&aci_rds_sem); + return 0; +} + +void __exit unload_aci_rds(void) +{ +} +MODULE_LICENSE("GPL"); diff --git a/drivers/media/radio/miropcm20-rds-core.h b/drivers/media/radio/miropcm20-rds-core.h new file mode 100644 index 00000000000..aeb5761f046 --- /dev/null +++ b/drivers/media/radio/miropcm20-rds-core.h @@ -0,0 +1,19 @@ +#ifndef _MIROPCM20_RDS_CORE_H_ +#define _MIROPCM20_RDS_CORE_H_ + +extern int aci_rds_cmd(unsigned char cmd, unsigned char databuffer[], int datasize); + +#define RDS_STATUS 0x01 +#define RDS_STATIONNAME 0x02 +#define RDS_TEXT 0x03 +#define RDS_ALTFREQ 0x04 +#define RDS_TIMEDATE 0x05 +#define RDS_PI_CODE 0x06 +#define RDS_PTYTATP 0x07 +#define RDS_RESET 0x08 +#define RDS_RXVALUE 0x09 + +extern void __exit unload_aci_rds(void); +extern int __init attach_aci_rds(void); + +#endif /* _MIROPCM20_RDS_CORE_H_ */ diff --git a/drivers/media/radio/miropcm20-rds.c b/drivers/media/radio/miropcm20-rds.c new file mode 100644 index 00000000000..df79d5e0aae --- /dev/null +++ b/drivers/media/radio/miropcm20-rds.c @@ -0,0 +1,133 @@ +/* MiroSOUND PCM20 radio rds interface driver + * (c) 2001 Robert Siemer <Robert.Siemer@gmx.de> + * Thanks to Fred Seidel. See miropcm20-rds-core.c for further information. + */ + +/* Revision history: + * + * 2001-04-18 Robert Siemer <Robert.Siemer@gmx.de> + * separate file for user interface driver + */ + +#include <linux/module.h> +#include <linux/init.h> +#include <linux/slab.h> +#include <linux/fs.h> +#include <linux/miscdevice.h> +#include <linux/delay.h> +#include <asm/uaccess.h> +#include "miropcm20-rds-core.h" + +static char * text_buffer; +static int rds_users = 0; + + +static int rds_f_open(struct inode *in, struct file *fi) +{ + if (rds_users) + return -EBUSY; + + rds_users++; + if ((text_buffer=kmalloc(66, GFP_KERNEL)) == 0) { + rds_users--; + printk(KERN_NOTICE "aci-rds: Out of memory by open()...\n"); + return -ENOMEM; + } + + return 0; +} + +static int rds_f_release(struct inode *in, struct file *fi) +{ + kfree(text_buffer); + + rds_users--; + return 0; +} + +static void print_matrix(char *ch, char out[]) +{ + int j; + + for (j=7; j>=0; j--) { + out[7-j] = ((*ch >> j) & 0x1) + '0'; + } +} + +static ssize_t rds_f_read(struct file *file, char __user *buffer, size_t length, loff_t *offset) +{ +// i = sprintf(text_buffer, "length: %d, offset: %d\n", length, *offset); + + char c; + char bits[8]; + + msleep(2000); + aci_rds_cmd(RDS_STATUS, &c, 1); + print_matrix(&c, bits); |