Re: [PATCH- new driver] Maxi Radio FM 2 driver (GemTek) (3)

From: Fabien CHEVALIER (fabchev@free.fr)
Date: Sat Apr 14 2001 - 07:46:57 EST


I can't send any attachment to the list, what's wrong?

I got this mail :

/************************/
Norton AntiVirus quarantined an attachment in a message you sent.
De : NAV for Microsoft Exchange-EXCHANGE <NAVMSE-EXCHANGE@advent-comm.co.uk>
À : 'Fabien CHEVALIER' <fabchev2@free.fr>
Date : Sat, 14 Apr 2001 11:35:10 +0100

Recipient of the attachment: Jonathan Spillett\Personal\Linux Kernel
Subject of the message: [PATCH- new driver] Maxi Radio FM 2 driver (GemTek)
(2)
One or more attachments were quarantined.
  Attachment patch-maxifm2-v0.12-2.4.3.gz was Quarantined for the following
reasons:
        Scan Engine Failure (0x80004005)
        General Scan Engine error
/**************************/

Sorry, for now i will send the patch uncompressed...

diff -Nru linux/drivers/media/radio/Config.in
linuxm/drivers/media/radio/Config.in
--- linux/drivers/media/radio/Config.in Fri Apr 13 12:46:46 2001
+++ linuxm/drivers/media/radio/Config.in Fri Apr 13 12:24:24 2001
@@ -21,6 +21,10 @@
 if [ "$CONFIG_RADIO_GEMTEK" = "y" ]; then
    hex ' GemTek i/o port (0x20c, 0x30c, 0x24c or 0x34c)'
CONFIG_RADIO_GEMTEK_PORT 34c
 fi
+dep_tristate ' Guillemot MAXI Radio FM 2 card support' CONFIG_RADIO_MAXIFM2
$CONFIG_VIDEO_DEV
+if [ "$CONFIG_RADIO_MAXIFM2" = "y" ]; then
+ hex ' Maxi FM 2 i/o port (0x20c, 0x30c, 0x24c or 0x34c)'
CONFIG_RADIO_MAXIFM2_PORT 34c
+fi
 dep_tristate ' Guillemot MAXI Radio FM 2000 radio' CONFIG_RADIO_MAXIRADIO
$CONFIG_VIDEO_DEV
 dep_tristate ' Maestro on board radio' CONFIG_RADIO_MAESTRO
$CONFIG_VIDEO_DEV
 dep_tristate ' Miro PCM20 Radio' CONFIG_RADIO_MIROPCM20 $CONFIG_VIDEO_DEV
diff -Nru linux/drivers/media/radio/Makefile
linuxm/drivers/media/radio/Makefile
--- linux/drivers/media/radio/Makefile Fri Apr 13 12:46:46 2001
+++ linuxm/drivers/media/radio/Makefile Fri Apr 13 12:24:24 2001
@@ -31,6 +31,7 @@
 obj-$(CONFIG_RADIO_CADET) += radio-cadet.o
 obj-$(CONFIG_RADIO_TYPHOON) += radio-typhoon.o
 obj-$(CONFIG_RADIO_TERRATEC) += radio-terratec.o
+obj-$(CONFIG_RADIO_MAXIFM2) += radio-maxifm2.o
 obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o
 obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o
 obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o
diff -Nru linux/drivers/media/radio/radio-maxifm2.c
linuxm/drivers/media/radio/radio-maxifm2.c
--- linux/drivers/media/radio/radio-maxifm2.c Thu Jan 1 00:00:00 1970
+++ linuxm/drivers/media/radio/radio-maxifm2.c Fri Apr 13 12:48:46 2001
@@ -0,0 +1,347 @@
+/*
+ * Guillemot Maxi Radio FM 2 ISA radio card driver for Linux
+ * (C) 2001 Fabien Chevalier <fabchev@free.fr>
+ *
+ * contains code from Maxi Radio FM 2000 and GemTek drivers
+ *
+ * I reversed engineered the protocol from the win16 driver radio.exe
+ * with wine
+ * This driver contains as many features as the windows one : it
+ * even has card detection
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <asm/uaccess.h>
+#include <asm/semaphore.h>
+#include <asm/io.h>
+#include <linux/videodev.h>
+
+#define DRIVER_VERSION "0.12"
+
+#ifndef CONFIG_RADIO_MAXIFM2_PORT
+#define CONFIG_RADIO_MAXIFM2_PORT -1
+#endif
+
+static int io = CONFIG_RADIO_MAXIFM2_PORT;
+
+#define PORTWIDTH 4
+
+/* Maybe this is too small, but i had to choose one
+(works perfectly on my computer)*/
+#define IODELAY 10
+
+#define FREQ_LO 87*16000
+#define FREQ_HI 108*16000
+
+static __u8 powerbit = 16;
+static __u8 stereobit = 8;
+
+static int radio_open(struct video_device *, int);
+static int radio_ioctl(struct video_device *, unsigned int, void *);
+static void radio_close(struct video_device *);
+
+static struct video_device maxifm2_radio=
+{
+ owner: THIS_MODULE,
+ name: "Maxi Radio FM2 radio",
+ type: VID_TYPE_TUNER,
+ hardware: VID_HARDWARE_GEMTEK,
+ open: radio_open,
+ close: radio_close,
+ ioctl: radio_ioctl,
+};
+
+static struct radio_device
+{
+ __u16 muted, /* VIDEO_AUDIO_MUTE */
+ tuned; /* signal strength (0 or 0xffff) */
+
+ unsigned long freq;
+
+ struct semaphore lock;
+} card = {0, 0, 0, };
+
+
+/* to change the frequency, the card wants a 32 bit number : bits = a*f + b
+ * where f is the frequency in Mhz, where "a" is 78.12 and b is 1,107,297,092
+ *
+ * the final formula is :
+ * bits = ( 7812 * ( [video for linux value] / 16000 ) ) / 100 + 1107297092
+ * I had to arrange it because there are no floating points -- Anybody has
+ * a better idea?
+ */
+
+inline __u32 freq_2_bits(unsigned long v4lfreq)
+{
+ __u32 fm2freq;
+ v4lfreq /= 16;
+ v4lfreq *= 7812;
+ v4lfreq /= 100000;
+ fm2freq = v4lfreq + 1107297092;
+ return fm2freq;
+}
+
+int __init card_detect()
+{
+ __u8 read, count;
+ int anything = 0;
+
+ for(count=0; count <= 3; count++) {
+ read = inb(io);
+ if (read != 0xff)
+ anything = 1; //There is something on this io port
+ outb_p( (read & 0xfc) | count, io);
+ udelay(IODELAY);
+ }
+
+ /*When we read, we must have 0xff or 0xf7, otherwise there
+ is not any maxi radio fm 2 card here*/
+ read = inb(io);
+
+ if(anything)
+ if(read == 0xf7 || read == 0xff)
+ return 1;
+ else
+ printk(KERN_ERR "Maxi Radio FM2 driver: Card not found on I/O port
0x%x\n", io);
+ else
+ printk(KERN_ERR "Maxi Radio FM2 driver: Nothing on I/O port 0x%x\n", io);
+
+ return 0;
+}
+
+/*This function is the result of the reverse engineering */
+
+static void set_freq(unsigned long v4lfreq)
+{
+ __u32 fm2freq;
+ int i;
+
+ fm2freq = freq_2_bits(v4lfreq);
+
+ outb_p(0x03, io);
+ udelay(IODELAY);
+ outb_p(0x07, io);
+ udelay(IODELAY);
+
+ for(i=0; i<=31; i++)
+ if((fm2freq >> i) & 1) {
+ //we send a 1 bit
+ outb_p(0x06, io);
+ udelay(IODELAY);
+ outb_p(0x07, io);
+ udelay(IODELAY);
+ } else {
+ //we send a 0 bit
+ outb_p(0x04, io);
+ udelay(IODELAY);
+ outb_p(0x05, io);
+ udelay(IODELAY);
+ }
+
+ outb_p(0x03, io);
+ udelay(IODELAY);
+ outb_p(0x07, io);
+ udelay(IODELAY);
+}
+
+
+static int get_tuned()
+{
+ return (~inb(io)) & stereobit;
+}
+
+static void turn_power(int p)
+{
+ if(p != 0)
+ outb_p(~powerbit, io);
+ else
+ outb_p(0xff, io);
+ udelay(IODELAY);
+}
+
+inline static int radio_function(struct video_device *dev,
+ unsigned int cmd, void *arg)
+{
+ switch(cmd) {
+ case VIDIOCGCAP: {
+ struct video_capability v;
+
+ strcpy(v.name, "Maxi Radio FM2 radio");
+ v.type=VID_TYPE_TUNER;
+ v.channels=v.audios=1;
+ v.maxwidth=v.maxheight=v.minwidth=v.minheight=0;
+
+ if(copy_to_user(arg,&v,sizeof(v)))
+ return -EFAULT;
+
+ return 0;
+ }
+ case VIDIOCGTUNER: {
+ struct video_tuner v;
+
+ if(copy_from_user(&v, arg,sizeof(v))!=0)
+ return -EFAULT;
+
+ if(v.tuner)
+ return -EINVAL;
+
+ card.tuned = 0xffff * get_tuned();
+
+ v.flags = VIDEO_TUNER_LOW;
+ v.signal = card.tuned;
+
+ strcpy(v.name, "FM");
+
+ v.rangelow = FREQ_LO;
+ v.rangehigh = FREQ_HI;
+ v.mode = VIDEO_MODE_AUTO;
+
+ if(copy_to_user(arg,&v, sizeof(v)))
+ return -EFAULT;
+
+ return 0;
+ }
+ case VIDIOCSTUNER: {
+ struct video_tuner v;
+
+ if(copy_from_user(&v, arg, sizeof(v)))
+ return -EFAULT;
+
+ if(v.tuner!=0)
+ return -EINVAL;
+
+ return 0;
+ }
+ case VIDIOCGFREQ: {
+ unsigned long tmp=card.freq;
+
+ if(copy_to_user(arg, &tmp, sizeof(tmp)))
+ return -EFAULT;
+
+ return 0;
+ }
+
+ case VIDIOCSFREQ: {
+ unsigned long tmp;
+
+ if(copy_from_user(&tmp, arg, sizeof(tmp)))
+ return -EFAULT;
+
+ if ( tmp<FREQ_LO || tmp>FREQ_HI )
+ return -EINVAL;
+
+ card.freq = tmp;
+
+ set_freq(card.freq);
+
+ return 0;
+ }
+ case VIDIOCGAUDIO: {
+ struct video_audio v;
+
+ strcpy(v.name, "Radio");
+ v.audio=v.volume=v.bass=v.treble=v.balance=v.step=0;
+ v.flags=VIDEO_AUDIO_MUTABLE | card.muted;
+ v.mode=VIDEO_SOUND_MONO;
+ if(copy_to_user(arg,&v, sizeof(v)))
+ return -EFAULT;
+ return 0;
+ }
+
+ case VIDIOCSAUDIO: {
+ struct video_audio v;
+
+ if(copy_from_user(&v, arg, sizeof(v)))
+ return -EFAULT;
+
+ if(v.audio)
+ return -EINVAL;
+
+
+ card.muted = v.flags & VIDEO_AUDIO_MUTE;
+ turn_power(!card.muted);
+
+ return 0;
+ }
+
+ default: return -ENOIOCTLCMD;
+ }
+}
+
+static int radio_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+ int ret;
+ down(&card.lock);
+ ret = radio_function(dev, cmd, arg);
+ up(&card.lock);
+ return ret;
+}
+
+static int radio_open(struct video_device *dev, int flags)
+{
+ return 0;
+}
+
+static void radio_close(struct video_device *dev)
+{
+}
+
+int __init maxifm2_radio_init(void)
+{
+ if(io==-1) {
+ printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c,
io=0x24c or io=0x34c\n");
+ return -EINVAL;
+ }
+
+ if(!request_region(io, PORTWIDTH, "Maxi Radio FM2")) {
+ printk(KERN_ERR "Maxi Radio FM2 driver: can't reserve I/O port 0x%x\n",
io);
+ return -ENODEV;
+ }
+
+ if(!card_detect()) {
+ release_region(io, PORTWIDTH);
+ return -ENODEV;
+ }
+
+ if(video_register_device(&maxifm2_radio, VFL_TYPE_RADIO)==-1) {
+ printk(KERN_ERR "Maxi Radio FM2 driver: can't register video4linux
device!");
+ release_region(io, PORTWIDTH);
+ return -ENODEV;
+ }
+
+ printk(KERN_INFO "Maxi Radio FM2 : v"
+ DRIVER_VERSION
+ " driver loaded\n");
+
+ card.muted = 1;
+ turn_power(!card.muted);
+
+ init_MUTEX(&card.lock);
+
+ return 0;
+}
+
+void __exit maxifm2_radio_exit(void)
+{
+ video_unregister_device(&maxifm2_radio);
+ release_region(io, PORTWIDTH);
+ printk(KERN_INFO "Maxi Radio FM2 : driver unloaded\n");
+}
+
+MODULE_AUTHOR("Fabien Chevalier, fabchev@free.fr");
+MODULE_DESCRIPTION("Radio driver for the Guillemot Maxi Radio FM2 radio.");
+MODULE_PARM(io, "i");
+MODULE_PARM_DESC(io, "I/O address of the Maxi Radio card. \
+ If you don't know try 0x34c");
+
+EXPORT_NO_SYMBOLS;
+
+module_init(maxifm2_radio_init);
+module_exit(maxifm2_radio_exit);
+
+
+
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Sun Apr 15 2001 - 21:00:22 EST