]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/media/radio/radio-gemtek.c
V4L/DVB (5705): Removed unnecessary .hardware from video_device struct.
[linux-2.6-omap-h63xx.git] / drivers / media / radio / radio-gemtek.c
1 /* GemTek radio card driver for Linux (C) 1998 Jonas Munsin <jmunsin@iki.fi>
2  *
3  * GemTek hasn't released any specs on the card, so the protocol had to
4  * be reverse engineered with dosemu.
5  *
6  * Besides the protocol changes, this is mostly a copy of:
7  *
8  *    RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
9  *
10  *    Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
11  *    Converted to new API by Alan Cox <Alan.Cox@linux.org>
12  *    Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
13  *
14  * TODO: Allow for more than one of these foolish entities :-)
15  *
16  * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
17  */
18
19 #include <linux/module.h>       /* Modules                      */
20 #include <linux/init.h>         /* Initdata                     */
21 #include <linux/ioport.h>       /* request_region               */
22 #include <linux/delay.h>        /* udelay                       */
23 #include <asm/io.h>             /* outb, outb_p                 */
24 #include <asm/uaccess.h>        /* copy to/from user            */
25 #include <linux/videodev2.h>    /* kernel radio structs         */
26 #include <media/v4l2-common.h>
27 #include <linux/spinlock.h>
28
29 #include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
30 #define RADIO_VERSION KERNEL_VERSION(0,0,2)
31
32 static struct v4l2_queryctrl radio_qctrl[] = {
33         {
34                 .id            = V4L2_CID_AUDIO_MUTE,
35                 .name          = "Mute",
36                 .minimum       = 0,
37                 .maximum       = 1,
38                 .default_value = 1,
39                 .type          = V4L2_CTRL_TYPE_BOOLEAN,
40         },{
41                 .id            = V4L2_CID_AUDIO_VOLUME,
42                 .name          = "Volume",
43                 .minimum       = 0,
44                 .maximum       = 65535,
45                 .step          = 65535,
46                 .default_value = 0xff,
47                 .type          = V4L2_CTRL_TYPE_INTEGER,
48         }
49 };
50
51 #ifndef CONFIG_RADIO_GEMTEK_PORT
52 #define CONFIG_RADIO_GEMTEK_PORT -1
53 #endif
54
55 static int io = CONFIG_RADIO_GEMTEK_PORT;
56 static int radio_nr = -1;
57 static spinlock_t lock;
58
59 struct gemtek_device
60 {
61         int port;
62         unsigned long curfreq;
63         int muted;
64 };
65
66
67 /* local things */
68
69 /* the correct way to mute the gemtek may be to write the last written
70  * frequency || 0x10, but just writing 0x10 once seems to do it as well
71  */
72 static void gemtek_mute(struct gemtek_device *dev)
73 {
74         if(dev->muted)
75                 return;
76         spin_lock(&lock);
77         outb(0x10, io);
78         spin_unlock(&lock);
79         dev->muted = 1;
80 }
81
82 static void gemtek_unmute(struct gemtek_device *dev)
83 {
84         if(dev->muted == 0)
85                 return;
86         spin_lock(&lock);
87         outb(0x20, io);
88         spin_unlock(&lock);
89         dev->muted = 0;
90 }
91
92 static void zero(void)
93 {
94         outb_p(0x04, io);
95         udelay(5);
96         outb_p(0x05, io);
97         udelay(5);
98 }
99
100 static void one(void)
101 {
102         outb_p(0x06, io);
103         udelay(5);
104         outb_p(0x07, io);
105         udelay(5);
106 }
107
108 static int gemtek_setfreq(struct gemtek_device *dev, unsigned long freq)
109 {
110         int i;
111
112 /*        freq = 78.25*((float)freq/16000.0 + 10.52); */
113
114         freq /= 16;
115         freq += 10520;
116         freq *= 7825;
117         freq /= 100000;
118
119         spin_lock(&lock);
120
121         /* 2 start bits */
122         outb_p(0x03, io);
123         udelay(5);
124         outb_p(0x07, io);
125         udelay(5);
126
127         /* 28 frequency bits (lsb first) */
128         for (i = 0; i < 14; i++)
129                 if (freq & (1 << i))
130                         one();
131                 else
132                         zero();
133         /* 36 unknown bits */
134         for (i = 0; i < 11; i++)
135                 zero();
136         one();
137         for (i = 0; i < 4; i++)
138                 zero();
139         one();
140         zero();
141
142         /* 2 end bits */
143         outb_p(0x03, io);
144         udelay(5);
145         outb_p(0x07, io);
146         udelay(5);
147
148         spin_unlock(&lock);
149
150         return 0;
151 }
152
153 static int gemtek_getsigstr(struct gemtek_device *dev)
154 {
155         spin_lock(&lock);
156         inb(io);
157         udelay(5);
158         spin_unlock(&lock);
159         if (inb(io) & 8)                /* bit set = no signal present */
160                 return 0;
161         return 1;               /* signal present */
162 }
163
164 static int vidioc_querycap(struct file *file, void  *priv,
165                                         struct v4l2_capability *v)
166 {
167         strlcpy(v->driver, "radio-gemtek", sizeof(v->driver));
168         strlcpy(v->card, "GemTek", sizeof(v->card));
169         sprintf(v->bus_info, "ISA");
170         v->version = RADIO_VERSION;
171         v->capabilities = V4L2_CAP_TUNER;
172         return 0;
173 }
174
175 static int vidioc_g_tuner(struct file *file, void *priv,
176                                         struct v4l2_tuner *v)
177 {
178         struct video_device *dev = video_devdata(file);
179         struct gemtek_device *rt = dev->priv;
180
181         if (v->index > 0)
182                 return -EINVAL;
183
184         strcpy(v->name, "FM");
185         v->type = V4L2_TUNER_RADIO;
186         v->rangelow = (87*16000);
187         v->rangehigh = (108*16000);
188         v->rxsubchans = V4L2_TUNER_SUB_MONO;
189         v->capability = V4L2_TUNER_CAP_LOW;
190         v->audmode = V4L2_TUNER_MODE_MONO;
191         v->signal = 0xffff*gemtek_getsigstr(rt);
192         return 0;
193 }
194
195 static int vidioc_s_tuner(struct file *file, void *priv,
196                                         struct v4l2_tuner *v)
197 {
198         if (v->index > 0)
199                 return -EINVAL;
200         return 0;
201 }
202
203 static int vidioc_s_frequency(struct file *file, void *priv,
204                                         struct v4l2_frequency *f)
205 {
206         struct video_device *dev = video_devdata(file);
207         struct gemtek_device *rt = dev->priv;
208
209         rt->curfreq = f->frequency;
210         /* needs to be called twice in order for getsigstr to work */
211         gemtek_setfreq(rt, rt->curfreq);
212         gemtek_setfreq(rt, rt->curfreq);
213         return 0;
214 }
215
216 static int vidioc_g_frequency(struct file *file, void *priv,
217                                         struct v4l2_frequency *f)
218 {
219         struct video_device *dev = video_devdata(file);
220         struct gemtek_device *rt = dev->priv;
221
222         f->type = V4L2_TUNER_RADIO;
223         f->frequency = rt->curfreq;
224         return 0;
225 }
226
227 static int vidioc_queryctrl(struct file *file, void *priv,
228                                         struct v4l2_queryctrl *qc)
229 {
230         int i;
231
232         for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
233                 if (qc->id && qc->id == radio_qctrl[i].id) {
234                         memcpy(qc, &(radio_qctrl[i]),
235                                                 sizeof(*qc));
236                         return 0;
237                 }
238         }
239         return -EINVAL;
240 }
241
242 static int vidioc_g_ctrl(struct file *file, void *priv,
243                                         struct v4l2_control *ctrl)
244 {
245         struct video_device *dev = video_devdata(file);
246         struct gemtek_device *rt = dev->priv;
247
248         switch (ctrl->id) {
249         case V4L2_CID_AUDIO_MUTE:
250                 ctrl->value = rt->muted;
251                 return 0;
252         case V4L2_CID_AUDIO_VOLUME:
253                 if (rt->muted)
254                         ctrl->value = 0;
255                 else
256                         ctrl->value = 65535;
257                 return 0;
258         }
259         return -EINVAL;
260 }
261
262 static int vidioc_s_ctrl(struct file *file, void *priv,
263                                         struct v4l2_control *ctrl)
264 {
265         struct video_device *dev = video_devdata(file);
266         struct gemtek_device *rt = dev->priv;
267
268         switch (ctrl->id) {
269         case V4L2_CID_AUDIO_MUTE:
270                 if (ctrl->value)
271                         gemtek_mute(rt);
272                 else
273                         gemtek_unmute(rt);
274                 return 0;
275         case V4L2_CID_AUDIO_VOLUME:
276                 if (ctrl->value)
277                         gemtek_unmute(rt);
278                 else
279                         gemtek_mute(rt);
280                 return 0;
281         }
282         return -EINVAL;
283 }
284
285 static int vidioc_g_audio (struct file *file, void *priv,
286                                         struct v4l2_audio *a)
287 {
288         if (a->index > 1)
289                 return -EINVAL;
290
291         strcpy(a->name, "Radio");
292         a->capability = V4L2_AUDCAP_STEREO;
293         return 0;
294 }
295
296 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
297 {
298         *i = 0;
299         return 0;
300 }
301
302 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
303 {
304         if (i != 0)
305                 return -EINVAL;
306         return 0;
307 }
308
309 static int vidioc_s_audio(struct file *file, void *priv,
310                                         struct v4l2_audio *a)
311 {
312         if (a->index != 0)
313                 return -EINVAL;
314         return 0;
315 }
316
317 static struct gemtek_device gemtek_unit;
318
319 static const struct file_operations gemtek_fops = {
320         .owner          = THIS_MODULE,
321         .open           = video_exclusive_open,
322         .release        = video_exclusive_release,
323         .ioctl          = video_ioctl2,
324         .compat_ioctl   = v4l_compat_ioctl32,
325         .llseek         = no_llseek,
326 };
327
328 static struct video_device gemtek_radio=
329 {
330         .owner          = THIS_MODULE,
331         .name           = "GemTek radio",
332         .type           = VID_TYPE_TUNER,
333         .fops           = &gemtek_fops,
334         .vidioc_querycap    = vidioc_querycap,
335         .vidioc_g_tuner     = vidioc_g_tuner,
336         .vidioc_s_tuner     = vidioc_s_tuner,
337         .vidioc_g_audio     = vidioc_g_audio,
338         .vidioc_s_audio     = vidioc_s_audio,
339         .vidioc_g_input     = vidioc_g_input,
340         .vidioc_s_input     = vidioc_s_input,
341         .vidioc_g_frequency = vidioc_g_frequency,
342         .vidioc_s_frequency = vidioc_s_frequency,
343         .vidioc_queryctrl   = vidioc_queryctrl,
344         .vidioc_g_ctrl      = vidioc_g_ctrl,
345         .vidioc_s_ctrl      = vidioc_s_ctrl,
346 };
347
348 static int __init gemtek_init(void)
349 {
350         if(io==-1)
351         {
352                 printk(KERN_ERR "You must set an I/O address with io=0x20c, io=0x30c, io=0x24c or io=0x34c (io=0x020c or io=0x248 for the combined sound/radiocard)\n");
353                 return -EINVAL;
354         }
355
356         if (!request_region(io, 4, "gemtek"))
357         {
358                 printk(KERN_ERR "gemtek: port 0x%x already in use\n", io);
359                 return -EBUSY;
360         }
361
362         gemtek_radio.priv=&gemtek_unit;
363
364         if(video_register_device(&gemtek_radio, VFL_TYPE_RADIO, radio_nr)==-1)
365         {
366                 release_region(io, 4);
367                 return -EINVAL;
368         }
369         printk(KERN_INFO "GemTek Radio Card driver.\n");
370
371         spin_lock_init(&lock);
372
373         /* this is _maybe_ unnecessary */
374         outb(0x01, io);
375
376         /* mute card - prevents noisy bootups */
377         gemtek_unit.muted = 0;
378         gemtek_mute(&gemtek_unit);
379
380         return 0;
381 }
382
383 MODULE_AUTHOR("Jonas Munsin");
384 MODULE_DESCRIPTION("A driver for the GemTek Radio Card");
385 MODULE_LICENSE("GPL");
386
387 module_param(io, int, 0);
388 MODULE_PARM_DESC(io, "I/O address of the GemTek card (0x20c, 0x30c, 0x24c or 0x34c (0x20c or 0x248 have been reported to work for the combined sound/radiocard)).");
389 module_param(radio_nr, int, 0);
390
391 static void __exit gemtek_cleanup(void)
392 {
393         video_unregister_device(&gemtek_radio);
394         release_region(io,4);
395 }
396
397 module_init(gemtek_init);
398 module_exit(gemtek_cleanup);
399
400 /*
401   Local variables:
402   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"
403   End:
404 */