08bd8d9dc4f1576cd7e3afe0a9450ed6af0d7d67
[safe/jmp/linux-2.6] / drivers / media / radio / radio-rtrack2.c
1 /* RadioTrack II driver for Linux radio support (C) 1998 Ben Pfaff
2  *
3  * Based on RadioTrack I/RadioReveal (C) 1997 M. Kirkwood
4  * Converted to new API by Alan Cox <alan@lxorguk.ukuu.org.uk>
5  * Various bugfixes and enhancements by Russell Kroll <rkroll@exploits.org>
6  *
7  * TODO: Allow for more than one of these foolish entities :-)
8  *
9  * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
10  */
11
12 #include <linux/module.h>       /* Modules                      */
13 #include <linux/init.h>         /* Initdata                     */
14 #include <linux/ioport.h>       /* request_region               */
15 #include <linux/delay.h>        /* udelay                       */
16 #include <linux/videodev2.h>    /* kernel radio structs         */
17 #include <linux/mutex.h>
18 #include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
19 #include <linux/io.h>           /* outb, outb_p                 */
20 #include <linux/uaccess.h>      /* copy to/from user            */
21 #include <media/v4l2-device.h>
22 #include <media/v4l2-ioctl.h>
23
24 MODULE_AUTHOR("Ben Pfaff");
25 MODULE_DESCRIPTION("A driver for the RadioTrack II radio card.");
26 MODULE_LICENSE("GPL");
27
28 #ifndef CONFIG_RADIO_RTRACK2_PORT
29 #define CONFIG_RADIO_RTRACK2_PORT -1
30 #endif
31
32 static int io = CONFIG_RADIO_RTRACK2_PORT;
33 static int radio_nr = -1;
34
35 module_param(io, int, 0);
36 MODULE_PARM_DESC(io, "I/O address of the RadioTrack card (0x20c or 0x30c)");
37 module_param(radio_nr, int, 0);
38
39 #define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
40
41 struct rtrack2
42 {
43         struct v4l2_device v4l2_dev;
44         struct video_device vdev;
45         int io;
46         unsigned long curfreq;
47         int muted;
48         struct mutex lock;
49 };
50
51 static struct rtrack2 rtrack2_card;
52
53
54 /* local things */
55
56 static void rt_mute(struct rtrack2 *dev)
57 {
58         if (dev->muted)
59                 return;
60         mutex_lock(&dev->lock);
61         outb(1, dev->io);
62         mutex_unlock(&dev->lock);
63         mutex_unlock(&dev->lock);
64         dev->muted = 1;
65 }
66
67 static void rt_unmute(struct rtrack2 *dev)
68 {
69         if(dev->muted == 0)
70                 return;
71         mutex_lock(&dev->lock);
72         outb(0, dev->io);
73         mutex_unlock(&dev->lock);
74         dev->muted = 0;
75 }
76
77 static void zero(struct rtrack2 *dev)
78 {
79         outb_p(1, dev->io);
80         outb_p(3, dev->io);
81         outb_p(1, dev->io);
82 }
83
84 static void one(struct rtrack2 *dev)
85 {
86         outb_p(5, dev->io);
87         outb_p(7, dev->io);
88         outb_p(5, dev->io);
89 }
90
91 static int rt_setfreq(struct rtrack2 *dev, unsigned long freq)
92 {
93         int i;
94
95         mutex_lock(&dev->lock);
96         dev->curfreq = freq;
97         freq = freq / 200 + 856;
98
99         outb_p(0xc8, dev->io);
100         outb_p(0xc9, dev->io);
101         outb_p(0xc9, dev->io);
102
103         for (i = 0; i < 10; i++)
104                 zero(dev);
105
106         for (i = 14; i >= 0; i--)
107                 if (freq & (1 << i))
108                         one(dev);
109                 else
110                         zero(dev);
111
112         outb_p(0xc8, dev->io);
113         if (!dev->muted)
114                 outb_p(0, dev->io);
115
116         mutex_unlock(&dev->lock);
117         return 0;
118 }
119
120 static int vidioc_querycap(struct file *file, void *priv,
121                                 struct v4l2_capability *v)
122 {
123         strlcpy(v->driver, "radio-rtrack2", sizeof(v->driver));
124         strlcpy(v->card, "RadioTrack II", sizeof(v->card));
125         strlcpy(v->bus_info, "ISA", sizeof(v->bus_info));
126         v->version = RADIO_VERSION;
127         v->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
128         return 0;
129 }
130
131 static int vidioc_s_tuner(struct file *file, void *priv,
132                                 struct v4l2_tuner *v)
133 {
134         return v->index ? -EINVAL : 0;
135 }
136
137 static int rt_getsigstr(struct rtrack2 *dev)
138 {
139         int sig = 1;
140
141         mutex_lock(&dev->lock);
142         if (inb(dev->io) & 2)   /* bit set = no signal present  */
143                 sig = 0;
144         mutex_unlock(&dev->lock);
145         return sig;
146 }
147
148 static int vidioc_g_tuner(struct file *file, void *priv,
149                                 struct v4l2_tuner *v)
150 {
151         struct rtrack2 *rt = video_drvdata(file);
152
153         if (v->index > 0)
154                 return -EINVAL;
155
156         strlcpy(v->name, "FM", sizeof(v->name));
157         v->type = V4L2_TUNER_RADIO;
158         v->rangelow = 88 * 16000;
159         v->rangehigh = 108 * 16000;
160         v->rxsubchans = V4L2_TUNER_SUB_MONO;
161         v->capability = V4L2_TUNER_CAP_LOW;
162         v->audmode = V4L2_TUNER_MODE_MONO;
163         v->signal = 0xFFFF * rt_getsigstr(rt);
164         return 0;
165 }
166
167 static int vidioc_s_frequency(struct file *file, void *priv,
168                                 struct v4l2_frequency *f)
169 {
170         struct rtrack2 *rt = video_drvdata(file);
171
172         rt_setfreq(rt, f->frequency);
173         return 0;
174 }
175
176 static int vidioc_g_frequency(struct file *file, void *priv,
177                                 struct v4l2_frequency *f)
178 {
179         struct rtrack2 *rt = video_drvdata(file);
180
181         f->type = V4L2_TUNER_RADIO;
182         f->frequency = rt->curfreq;
183         return 0;
184 }
185
186 static int vidioc_queryctrl(struct file *file, void *priv,
187                                 struct v4l2_queryctrl *qc)
188 {
189         switch (qc->id) {
190         case V4L2_CID_AUDIO_MUTE:
191                 return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
192         case V4L2_CID_AUDIO_VOLUME:
193                 return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535);
194         }
195         return -EINVAL;
196 }
197
198 static int vidioc_g_ctrl(struct file *file, void *priv,
199                                 struct v4l2_control *ctrl)
200 {
201         struct rtrack2 *rt = video_drvdata(file);
202
203         switch (ctrl->id) {
204         case V4L2_CID_AUDIO_MUTE:
205                 ctrl->value = rt->muted;
206                 return 0;
207         case V4L2_CID_AUDIO_VOLUME:
208                 if (rt->muted)
209                         ctrl->value = 0;
210                 else
211                         ctrl->value = 65535;
212                 return 0;
213         }
214         return -EINVAL;
215 }
216
217 static int vidioc_s_ctrl(struct file *file, void *priv,
218                                 struct v4l2_control *ctrl)
219 {
220         struct rtrack2 *rt = video_drvdata(file);
221
222         switch (ctrl->id) {
223         case V4L2_CID_AUDIO_MUTE:
224                 if (ctrl->value)
225                         rt_mute(rt);
226                 else
227                         rt_unmute(rt);
228                 return 0;
229         case V4L2_CID_AUDIO_VOLUME:
230                 if (ctrl->value)
231                         rt_unmute(rt);
232                 else
233                         rt_mute(rt);
234                 return 0;
235         }
236         return -EINVAL;
237 }
238
239 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
240 {
241         *i = 0;
242         return 0;
243 }
244
245 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
246 {
247         return i ? -EINVAL : 0;
248 }
249
250 static int vidioc_g_audio(struct file *file, void *priv,
251                                 struct v4l2_audio *a)
252 {
253         a->index = 0;
254         strlcpy(a->name, "Radio", sizeof(a->name));
255         a->capability = V4L2_AUDCAP_STEREO;
256         return 0;
257 }
258
259 static int vidioc_s_audio(struct file *file, void *priv,
260                                 struct v4l2_audio *a)
261 {
262         return a->index ? -EINVAL : 0;
263 }
264
265 static int rtrack2_open(struct file *file)
266 {
267         return 0;
268 }
269
270 static int rtrack2_release(struct file *file)
271 {
272         return 0;
273 }
274
275 static const struct v4l2_file_operations rtrack2_fops = {
276         .owner          = THIS_MODULE,
277         .open           = rtrack2_open,
278         .release        = rtrack2_release,
279         .ioctl          = video_ioctl2,
280 };
281
282 static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = {
283         .vidioc_querycap    = vidioc_querycap,
284         .vidioc_g_tuner     = vidioc_g_tuner,
285         .vidioc_s_tuner     = vidioc_s_tuner,
286         .vidioc_g_frequency = vidioc_g_frequency,
287         .vidioc_s_frequency = vidioc_s_frequency,
288         .vidioc_queryctrl   = vidioc_queryctrl,
289         .vidioc_g_ctrl      = vidioc_g_ctrl,
290         .vidioc_s_ctrl      = vidioc_s_ctrl,
291         .vidioc_g_audio     = vidioc_g_audio,
292         .vidioc_s_audio     = vidioc_s_audio,
293         .vidioc_g_input     = vidioc_g_input,
294         .vidioc_s_input     = vidioc_s_input,
295 };
296
297 static int __init rtrack2_init(void)
298 {
299         struct rtrack2 *dev = &rtrack2_card;
300         struct v4l2_device *v4l2_dev = &dev->v4l2_dev;
301         int res;
302
303         strlcpy(v4l2_dev->name, "rtrack2", sizeof(v4l2_dev->name));
304         dev->io = io;
305         if (dev->io == -1) {
306                 v4l2_err(v4l2_dev, "You must set an I/O address with io=0x20c or io=0x30c\n");
307                 return -EINVAL;
308         }
309         if (!request_region(dev->io, 4, "rtrack2")) {
310                 v4l2_err(v4l2_dev, "port 0x%x already in use\n", dev->io);
311                 return -EBUSY;
312         }
313
314         res = v4l2_device_register(NULL, v4l2_dev);
315         if (res < 0) {
316                 release_region(dev->io, 4);
317                 v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
318                 return res;
319         }
320
321         strlcpy(dev->vdev.name, v4l2_dev->name, sizeof(dev->vdev.name));
322         dev->vdev.v4l2_dev = v4l2_dev;
323         dev->vdev.fops = &rtrack2_fops;
324         dev->vdev.ioctl_ops = &rtrack2_ioctl_ops;
325         dev->vdev.release = video_device_release_empty;
326         video_set_drvdata(&dev->vdev, dev);
327
328         mutex_init(&dev->lock);
329         if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
330                 v4l2_device_unregister(v4l2_dev);
331                 release_region(dev->io, 4);
332                 return -EINVAL;
333         }
334
335         v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n");
336
337         /* mute card - prevents noisy bootups */
338         outb(1, dev->io);
339         dev->muted = 1;
340
341         return 0;
342 }
343
344 static void __exit rtrack2_exit(void)
345 {
346         struct rtrack2 *dev = &rtrack2_card;
347
348         video_unregister_device(&dev->vdev);
349         v4l2_device_unregister(&dev->v4l2_dev);
350         release_region(dev->io, 4);
351 }
352
353 module_init(rtrack2_init);
354 module_exit(rtrack2_exit);