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