5dd5e349ef47c22696b0fea79c72c5de5880d9ce
[linux-2.6.git] / drivers / media / radio / radio-aztech.c
1 /* radio-aztech.c - Aztech radio card driver for Linux 2.2
2  *
3  * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
4  * Adapted to support the Video for Linux API by
5  * Russell Kroll <rkroll@exploits.org>.  Based on original tuner code by:
6  *
7  * Quay Ly
8  * Donald Song
9  * Jason Lewis      (jlewis@twilight.vtc.vsc.edu)
10  * Scott McGrath    (smcgrath@twilight.vtc.vsc.edu)
11  * William McGrath  (wmcgrath@twilight.vtc.vsc.edu)
12  *
13  * The basis for this code may be found at http://bigbang.vtc.vsc.edu/fmradio/
14  * along with more information on the card itself.
15  *
16  * History:
17  * 1999-02-24   Russell Kroll <rkroll@exploits.org>
18  *              Fine tuning/VIDEO_TUNER_LOW
19  *              Range expanded to 87-108 MHz (from 87.9-107.8)
20  *
21  * Notable changes from the original source:
22  * - includes stripped down to the essentials
23  * - for loops used as delays replaced with udelay()
24  * - #defines removed, changed to static values
25  * - tuning structure changed - no more character arrays, other changes
26 */
27
28 #include <linux/module.h>       /* Modules                      */
29 #include <linux/init.h>         /* Initdata                     */
30 #include <linux/ioport.h>       /* request_region               */
31 #include <linux/delay.h>        /* udelay                       */
32 #include <asm/io.h>             /* outb, outb_p                 */
33 #include <asm/uaccess.h>        /* copy to/from user            */
34 #include <linux/videodev2.h>    /* kernel radio structs         */
35 #include <media/v4l2-common.h>
36 #include <media/v4l2-ioctl.h>
37
38 #include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
39 #define RADIO_VERSION KERNEL_VERSION(0,0,2)
40
41 static struct v4l2_queryctrl radio_qctrl[] = {
42         {
43                 .id            = V4L2_CID_AUDIO_MUTE,
44                 .name          = "Mute",
45                 .minimum       = 0,
46                 .maximum       = 1,
47                 .default_value = 1,
48                 .type          = V4L2_CTRL_TYPE_BOOLEAN,
49         },{
50                 .id            = V4L2_CID_AUDIO_VOLUME,
51                 .name          = "Volume",
52                 .minimum       = 0,
53                 .maximum       = 0xff,
54                 .step          = 1,
55                 .default_value = 0xff,
56                 .type          = V4L2_CTRL_TYPE_INTEGER,
57         }
58 };
59
60 /* acceptable ports: 0x350 (JP3 shorted), 0x358 (JP3 open) */
61
62 #ifndef CONFIG_RADIO_AZTECH_PORT
63 #define CONFIG_RADIO_AZTECH_PORT -1
64 #endif
65
66 static int io = CONFIG_RADIO_AZTECH_PORT;
67 static int radio_nr = -1;
68 static int radio_wait_time = 1000;
69 static struct mutex lock;
70
71 struct az_device
72 {
73         unsigned long in_use;
74         int curvol;
75         unsigned long curfreq;
76         int stereo;
77 };
78
79 static int volconvert(int level)
80 {
81         level>>=14;             /* Map 16bits down to 2 bit */
82         level&=3;
83
84         /* convert to card-friendly values */
85         switch (level)
86         {
87                 case 0:
88                         return 0;
89                 case 1:
90                         return 1;
91                 case 2:
92                         return 4;
93                 case 3:
94                         return 5;
95         }
96         return 0;       /* Quieten gcc */
97 }
98
99 static void send_0_byte (struct az_device *dev)
100 {
101         udelay(radio_wait_time);
102         outb_p(2+volconvert(dev->curvol), io);
103         outb_p(64+2+volconvert(dev->curvol), io);
104 }
105
106 static void send_1_byte (struct az_device *dev)
107 {
108         udelay (radio_wait_time);
109         outb_p(128+2+volconvert(dev->curvol), io);
110         outb_p(128+64+2+volconvert(dev->curvol), io);
111 }
112
113 static int az_setvol(struct az_device *dev, int vol)
114 {
115         mutex_lock(&lock);
116         outb (volconvert(vol), io);
117         mutex_unlock(&lock);
118         return 0;
119 }
120
121 /* thanks to Michael Dwyer for giving me a dose of clues in
122  * the signal strength department..
123  *
124  * This card has a stereo bit - bit 0 set = mono, not set = stereo
125  * It also has a "signal" bit - bit 1 set = bad signal, not set = good
126  *
127  */
128
129 static int az_getsigstr(struct az_device *dev)
130 {
131         if (inb(io) & 2)        /* bit set = no signal present */
132                 return 0;
133         return 1;               /* signal present */
134 }
135
136 static int az_getstereo(struct az_device *dev)
137 {
138         if (inb(io) & 1)        /* bit set = mono */
139                 return 0;
140         return 1;               /* stereo */
141 }
142
143 static int az_setfreq(struct az_device *dev, unsigned long frequency)
144 {
145         int  i;
146
147         frequency += 171200;            /* Add 10.7 MHz IF              */
148         frequency /= 800;               /* Convert to 50 kHz units      */
149
150         mutex_lock(&lock);
151
152         send_0_byte (dev);              /*  0: LSB of frequency       */
153
154         for (i = 0; i < 13; i++)        /*   : frequency bits (1-13)  */
155                 if (frequency & (1 << i))
156                         send_1_byte (dev);
157                 else
158                         send_0_byte (dev);
159
160         send_0_byte (dev);              /* 14: test bit - always 0    */
161         send_0_byte (dev);              /* 15: test bit - always 0    */
162         send_0_byte (dev);              /* 16: band data 0 - always 0 */
163         if (dev->stereo)                /* 17: stereo (1 to enable)   */
164                 send_1_byte (dev);
165         else
166                 send_0_byte (dev);
167
168         send_1_byte (dev);              /* 18: band data 1 - unknown  */
169         send_0_byte (dev);              /* 19: time base - always 0   */
170         send_0_byte (dev);              /* 20: spacing (0 = 25 kHz)   */
171         send_1_byte (dev);              /* 21: spacing (1 = 25 kHz)   */
172         send_0_byte (dev);              /* 22: spacing (0 = 25 kHz)   */
173         send_1_byte (dev);              /* 23: AM/FM (FM = 1, always) */
174
175         /* latch frequency */
176
177         udelay (radio_wait_time);
178         outb_p(128+64+volconvert(dev->curvol), io);
179
180         mutex_unlock(&lock);
181
182         return 0;
183 }
184
185 static int vidioc_querycap (struct file *file, void  *priv,
186                                         struct v4l2_capability *v)
187 {
188         strlcpy(v->driver, "radio-aztech", sizeof (v->driver));
189         strlcpy(v->card, "Aztech Radio", sizeof (v->card));
190         sprintf(v->bus_info,"ISA");
191         v->version = RADIO_VERSION;
192         v->capabilities = V4L2_CAP_TUNER;
193         return 0;
194 }
195
196 static int vidioc_g_tuner (struct file *file, void *priv,
197                                 struct v4l2_tuner *v)
198 {
199         struct video_device *dev = video_devdata(file);
200         struct az_device *az = video_get_drvdata(dev);
201
202         if (v->index > 0)
203                 return -EINVAL;
204
205         strcpy(v->name, "FM");
206         v->type = V4L2_TUNER_RADIO;
207
208         v->rangelow=(87*16000);
209         v->rangehigh=(108*16000);
210         v->rxsubchans =V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
211         v->capability=V4L2_TUNER_CAP_LOW;
212         if(az_getstereo(az))
213                 v->audmode = V4L2_TUNER_MODE_STEREO;
214         else
215                 v->audmode = V4L2_TUNER_MODE_MONO;
216         v->signal=0xFFFF*az_getsigstr(az);
217
218         return 0;
219 }
220
221
222 static int vidioc_s_tuner (struct file *file, void *priv,
223                                 struct v4l2_tuner *v)
224 {
225         if (v->index > 0)
226                 return -EINVAL;
227
228         return 0;
229 }
230
231 static int vidioc_g_audio (struct file *file, void *priv,
232                            struct v4l2_audio *a)
233 {
234         if (a->index > 1)
235                 return -EINVAL;
236
237         strcpy(a->name, "Radio");
238         a->capability = V4L2_AUDCAP_STEREO;
239         return 0;
240 }
241
242 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
243 {
244         *i = 0;
245         return 0;
246 }
247
248 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
249 {
250         if (i != 0)
251                 return -EINVAL;
252         return 0;
253 }
254
255
256 static int vidioc_s_audio (struct file *file, void *priv,
257                            struct v4l2_audio *a)
258 {
259         if (a->index != 0)
260                 return -EINVAL;
261
262         return 0;
263 }
264
265 static int vidioc_s_frequency (struct file *file, void *priv,
266                                 struct v4l2_frequency *f)
267 {
268         struct video_device *dev = video_devdata(file);
269         struct az_device *az = video_get_drvdata(dev);
270
271         az->curfreq = f->frequency;
272         az_setfreq(az, az->curfreq);
273         return 0;
274 }
275
276 static int vidioc_g_frequency (struct file *file, void *priv,
277                                 struct v4l2_frequency *f)
278 {
279         struct video_device *dev = video_devdata(file);
280         struct az_device *az = video_get_drvdata(dev);
281
282         f->type = V4L2_TUNER_RADIO;
283         f->frequency = az->curfreq;
284
285         return 0;
286 }
287
288 static int vidioc_queryctrl (struct file *file, void *priv,
289                             struct v4l2_queryctrl *qc)
290 {
291         int i;
292
293         for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
294                 if (qc->id && qc->id == radio_qctrl[i].id) {
295                         memcpy(qc, &(radio_qctrl[i]),
296                                                 sizeof(*qc));
297                         return (0);
298                 }
299         }
300         return -EINVAL;
301 }
302
303 static int vidioc_g_ctrl (struct file *file, void *priv,
304                             struct v4l2_control *ctrl)
305 {
306         struct video_device *dev = video_devdata(file);
307         struct az_device *az = video_get_drvdata(dev);
308
309         switch (ctrl->id) {
310                 case V4L2_CID_AUDIO_MUTE:
311                         if (az->curvol==0)
312                                 ctrl->value=1;
313                         else
314                                 ctrl->value=0;
315                         return (0);
316                 case V4L2_CID_AUDIO_VOLUME:
317                         ctrl->value=az->curvol * 6554;
318                         return (0);
319         }
320         return -EINVAL;
321 }
322
323 static int vidioc_s_ctrl (struct file *file, void *priv,
324                             struct v4l2_control *ctrl)
325 {
326         struct video_device *dev = video_devdata(file);
327         struct az_device *az = video_get_drvdata(dev);
328
329         switch (ctrl->id) {
330                 case V4L2_CID_AUDIO_MUTE:
331                         if (ctrl->value) {
332                                 az_setvol(az,0);
333                         } else {
334                                 az_setvol(az,az->curvol);
335                         }
336                         return (0);
337                 case V4L2_CID_AUDIO_VOLUME:
338                         az_setvol(az,ctrl->value);
339                         return (0);
340         }
341         return -EINVAL;
342 }
343
344 static struct az_device aztech_unit;
345
346 static int aztech_exclusive_open(struct inode *inode, struct file *file)
347 {
348         return test_and_set_bit(0, &aztech_unit.in_use) ? -EBUSY : 0;
349 }
350
351 static int aztech_exclusive_release(struct inode *inode, struct file *file)
352 {
353         clear_bit(0, &aztech_unit.in_use);
354         return 0;
355 }
356
357 static const struct file_operations aztech_fops = {
358         .owner          = THIS_MODULE,
359         .open           = aztech_exclusive_open,
360         .release        = aztech_exclusive_release,
361         .ioctl          = video_ioctl2,
362 #ifdef CONFIG_COMPAT
363         .compat_ioctl   = v4l_compat_ioctl32,
364 #endif
365         .llseek         = no_llseek,
366 };
367
368 static const struct v4l2_ioctl_ops aztech_ioctl_ops = {
369         .vidioc_querycap    = vidioc_querycap,
370         .vidioc_g_tuner     = vidioc_g_tuner,
371         .vidioc_s_tuner     = vidioc_s_tuner,
372         .vidioc_g_audio     = vidioc_g_audio,
373         .vidioc_s_audio     = vidioc_s_audio,
374         .vidioc_g_input     = vidioc_g_input,
375         .vidioc_s_input     = vidioc_s_input,
376         .vidioc_g_frequency = vidioc_g_frequency,
377         .vidioc_s_frequency = vidioc_s_frequency,
378         .vidioc_queryctrl   = vidioc_queryctrl,
379         .vidioc_g_ctrl      = vidioc_g_ctrl,
380         .vidioc_s_ctrl      = vidioc_s_ctrl,
381 };
382
383 static struct video_device aztech_radio = {
384         .name           = "Aztech radio",
385         .fops           = &aztech_fops,
386         .ioctl_ops      = &aztech_ioctl_ops,
387         .release        = video_device_release_empty,
388 };
389
390 module_param_named(debug,aztech_radio.debug, int, 0644);
391 MODULE_PARM_DESC(debug,"activates debug info");
392
393 static int __init aztech_init(void)
394 {
395         if(io==-1)
396         {
397                 printk(KERN_ERR "You must set an I/O address with io=0x???\n");
398                 return -EINVAL;
399         }
400
401         if (!request_region(io, 2, "aztech"))
402         {
403                 printk(KERN_ERR "aztech: port 0x%x already in use\n", io);
404                 return -EBUSY;
405         }
406
407         mutex_init(&lock);
408         video_set_drvdata(&aztech_radio, &aztech_unit);
409
410         if (video_register_device(&aztech_radio, VFL_TYPE_RADIO, radio_nr) < 0) {
411                 release_region(io,2);
412                 return -EINVAL;
413         }
414
415         printk(KERN_INFO "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n");
416         /* mute card - prevents noisy bootups */
417         outb (0, io);
418         return 0;
419 }
420
421 MODULE_AUTHOR("Russell Kroll, Quay Lu, Donald Song, Jason Lewis, Scott McGrath, William McGrath");
422 MODULE_DESCRIPTION("A driver for the Aztech radio card.");
423 MODULE_LICENSE("GPL");
424
425 module_param(io, int, 0);
426 module_param(radio_nr, int, 0);
427 MODULE_PARM_DESC(io, "I/O address of the Aztech card (0x350 or 0x358)");
428
429 static void __exit aztech_cleanup(void)
430 {
431         video_unregister_device(&aztech_radio);
432         release_region(io,2);
433 }
434
435 module_init(aztech_init);
436 module_exit(aztech_cleanup);