Linux 2.3.7pre1
[davej-history.git] / drivers / char / radio-gemtek.c
blob46d41f423912736aeeaf7837119da3a550db911a
1 /* GemTek radio card driver for Linux (C) 1998 Jonas Munsin <jmunsin@iki.fi>
3 * GemTek hasn't released any specs on the card, so the protocol had to
4 * be reverse engineered with dosemu.
6 * Besides the protocol changes, this is mostly a copy of:
8 * RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
9 *
10 * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
11 * Coverted to new API by Alan Cox <Alan.Cox@linux.org>
12 * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
14 * TODO: Allow for more than one of these foolish entities :-)
18 #include <linux/module.h> /* Modules */
19 #include <linux/init.h> /* Initdata */
20 #include <linux/ioport.h> /* check_region, request_region */
21 #include <linux/delay.h> /* udelay */
22 #include <asm/io.h> /* outb, outb_p */
23 #include <asm/uaccess.h> /* copy to/from user */
24 #include <linux/videodev.h> /* kernel radio structs */
25 #include <linux/config.h> /* CONFIG_RADIO_GEMTEK_PORT */
27 #ifndef CONFIG_RADIO_GEMTEK_PORT
28 #define CONFIG_RADIO_GEMTEK_PORT -1
29 #endif
31 static int io = CONFIG_RADIO_GEMTEK_PORT;
32 static int users = 0;
34 struct gemtek_device
36 int port;
37 unsigned long curfreq;
38 int muted;
42 /* local things */
44 /* the correct way to mute the gemtek may be to write the last written
45 * frequency || 0x10, but just writing 0x10 once seems to do it as well
47 static void gemtek_mute(struct gemtek_device *dev)
49 if(dev->muted)
50 return;
51 outb(0x10, io);
52 dev->muted = 1;
55 static void gemtek_unmute(struct gemtek_device *dev)
57 if(dev->muted == 0)
58 return;
59 outb(0x20, io);
60 dev->muted = 0;
63 static void zero(void)
65 outb_p(0x04, io);
66 udelay(5);
67 outb_p(0x05, io);
68 udelay(5);
71 static void one(void)
73 outb_p(0x06, io);
74 udelay(5);
75 outb_p(0x07, io);
76 udelay(5);
79 static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
81 int i;
83 /* freq = 78.25*((float)freq/16000.0 + 10.52); */
85 freq /= 16;
86 freq += 10520;
87 freq *= 7825;
88 freq /= 100000;
90 /* 2 start bits */
91 outb_p(0x03, io);
92 udelay(5);
93 outb_p(0x07, io);
94 udelay(5);
96 /* 28 frequency bits (lsb first) */
97 for (i = 0; i < 14; i++)
98 if (freq & (1 << i))
99 one();
100 else
101 zero();
102 /* 36 unknown bits */
103 for (i = 0; i < 11; i++)
104 zero();
105 one();
106 for (i = 0; i < 4; i++)
107 zero();
108 one();
109 zero();
111 /* 2 end bits */
112 outb_p(0x03, io);
113 udelay(5);
114 outb_p(0x07, io);
115 udelay(5);
117 return 0;
120 int gemtek_getsigstr(struct gemtek_device *dev)
122 inb(io);
123 udelay(5);
124 if (inb(io) & 8) /* bit set = no signal present */
125 return 0;
126 return 1; /* signal present */
129 static int gemtek_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
131 struct gemtek_device *rt=dev->priv;
133 switch(cmd)
135 case VIDIOCGCAP:
137 struct video_capability v;
138 v.type=VID_TYPE_TUNER;
139 v.channels=1;
140 v.audios=1;
141 /* No we don't do pictures */
142 v.maxwidth=0;
143 v.maxheight=0;
144 v.minwidth=0;
145 v.minheight=0;
146 strcpy(v.name, "GemTek");
147 if(copy_to_user(arg,&v,sizeof(v)))
148 return -EFAULT;
149 return 0;
151 case VIDIOCGTUNER:
153 struct video_tuner v;
154 if(copy_from_user(&v, arg,sizeof(v))!=0)
155 return -EFAULT;
156 if(v.tuner) /* Only 1 tuner */
157 return -EINVAL;
158 v.rangelow=87*16000;
159 v.rangehigh=108*16000;
160 v.flags=VIDEO_TUNER_LOW;
161 v.mode=VIDEO_MODE_AUTO;
162 v.signal=0xFFFF*gemtek_getsigstr(rt);
163 strcpy(v.name, "FM");
164 if(copy_to_user(arg,&v, sizeof(v)))
165 return -EFAULT;
166 return 0;
168 case VIDIOCSTUNER:
170 struct video_tuner v;
171 if(copy_from_user(&v, arg, sizeof(v)))
172 return -EFAULT;
173 if(v.tuner!=0)
174 return -EINVAL;
175 /* Only 1 tuner so no setting needed ! */
176 return 0;
178 case VIDIOCGFREQ:
179 if(copy_to_user(arg, &rt->curfreq, sizeof(rt->curfreq)))
180 return -EFAULT;
181 return 0;
182 case VIDIOCSFREQ:
183 if(copy_from_user(&rt->curfreq, arg,sizeof(rt->curfreq)))
184 return -EFAULT;
185 /* needs to be called twice in order for getsigstr to work */
186 gemtek_setfreq(rt, rt->curfreq);
187 gemtek_setfreq(rt, rt->curfreq);
188 return 0;
189 case VIDIOCGAUDIO:
191 struct video_audio v;
192 memset(&v,0, sizeof(v));
193 v.flags|=VIDEO_AUDIO_MUTABLE;
194 v.volume=1;
195 v.step=65535;
196 strcpy(v.name, "Radio");
197 if(copy_to_user(arg,&v, sizeof(v)))
198 return -EFAULT;
199 return 0;
201 case VIDIOCSAUDIO:
203 struct video_audio v;
204 if(copy_from_user(&v, arg, sizeof(v)))
205 return -EFAULT;
206 if(v.audio)
207 return -EINVAL;
209 if(v.flags&VIDEO_AUDIO_MUTE)
210 gemtek_mute(rt);
211 else
212 gemtek_unmute(rt);
214 return 0;
216 default:
217 return -ENOIOCTLCMD;
221 static int gemtek_open(struct video_device *dev, int flags)
223 if(users)
224 return -EBUSY;
225 users++;
226 MOD_INC_USE_COUNT;
227 return 0;
230 static void gemtek_close(struct video_device *dev)
232 users--;
233 MOD_DEC_USE_COUNT;
236 static struct gemtek_device gemtek_unit;
238 static struct video_device gemtek_radio=
240 "GemTek radio",
241 VID_TYPE_TUNER,
242 VID_HARDWARE_GEMTEK,
243 gemtek_open,
244 gemtek_close,
245 NULL, /* Can't read (no capture ability) */
246 NULL, /* Can't write */
247 NULL, /* Can't poll */
248 gemtek_ioctl,
249 NULL,
250 NULL
253 __initfunc(int gemtek_init(struct video_init *v))
255 if (check_region(io, 4))
257 printk(KERN_ERR "gemtek: port 0x%x already in use\n", io);
258 return -EBUSY;
261 gemtek_radio.priv=&gemtek_unit;
263 if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO)==-1)
264 return -EINVAL;
266 request_region(io, 4, "gemtek");
267 printk(KERN_INFO "GemTek Radio Card driver.\n");
269 /* mute card - prevents noisy bootups */
270 outb(0x10, io);
271 udelay(5);
272 gemtek_unit.muted = 1;
274 /* this is _maybe_ unnecessary */
275 outb(0x01, io);
277 return 0;
280 #ifdef MODULE
282 MODULE_AUTHOR("Jonas Munsin");
283 MODULE_DESCRIPTION("A driver for the GemTek Radio Card");
284 MODULE_PARM(io, "i");
285 MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c)");
287 EXPORT_NO_SYMBOLS;
289 int init_module(void)
291 if(io==-1)
293 printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c\n");
294 return -EINVAL;
296 return gemtek_init(NULL);
299 void cleanup_module(void)
301 video_unregister_device(&gemtek_radio);
302 release_region(io,4);
305 #endif
308 Local variables:
309 compile-command: "gcc -c -DMODVERSIONS -D__KERNEL__ -DMODULE -O6 -Wall -Wstrict-prototypes -I /home/blp/tmp/linux-2.1.111-rtrack/include radio-rtrack2.c"
310 End: