ftp://ftp.kernel.org/pub/linux/kernel/v2.6/linux-2.6.6.tar.bz2
[linux-2.6.git] / drivers / usb / media / dsbr100.c
1 /* A driver for the D-Link DSB-R100 USB radio.  The R100 plugs
2  into both the USB and an analog audio input, so this thing
3  only deals with initialisation and frequency setting, the
4  audio data has to be handled by a sound driver.
5
6  Major issue: I can't find out where the device reports the signal
7  strength, and indeed the windows software appearantly just looks
8  at the stereo indicator as well.  So, scanning will only find
9  stereo stations.  Sad, but I can't help it.
10
11  Also, the windows program sends oodles of messages over to the
12  device, and I couldn't figure out their meaning.  My suspicion
13  is that they don't have any:-)
14
15  You might find some interesting stuff about this module at
16  http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
17
18  Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
19
20  This program is free software; you can redistribute it and/or modify
21  it under the terms of the GNU General Public License as published by
22  the Free Software Foundation; either version 2 of the License, or
23  (at your option) any later version.
24
25  This program is distributed in the hope that it will be useful,
26  but WITHOUT ANY WARRANTY; without even the implied warranty of
27  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28  GNU General Public License for more details.
29
30  You should have received a copy of the GNU General Public License
31  along with this program; if not, write to the Free Software
32  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
33
34  History:
35
36  Version 0.30:
37         Markus: Updates for 2.5.x kernel and more ISO compliant source
38
39  Version 0.25:
40         PSL and Markus: Cleanup, radio now doesn't stop on device close
41
42  Version 0.24:
43         Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
44         right.  Some minor cleanup, improved standalone compilation
45
46  Version 0.23:
47         Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
48
49  Version 0.22:
50         Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns, 
51         thanks to Mike Cox for pointing the problem out.
52
53  Version 0.21:
54         Markus: Minor cleanup, warnings if something goes wrong, lame attempt
55         to adhere to Documentation/CodingStyle
56
57  Version 0.2: 
58         Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
59         Markus: Copyright clarification
60
61  Version 0.01: Markus: initial release
62
63 */
64
65
66 #include <linux/kernel.h>
67 #include <linux/module.h>
68 #include <linux/init.h>
69 #include <linux/slab.h>
70 #include <linux/input.h>
71 #include <linux/videodev.h>
72 #include <linux/usb.h>
73 #include <linux/smp_lock.h>
74
75 /*
76  * Version Information
77  */
78 #define DRIVER_VERSION "v0.30"
79 #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
80 #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
81
82 #define DSB100_VENDOR 0x04b4
83 #define DSB100_PRODUCT 0x1002
84
85 #define TB_LEN 16
86
87 /* Frequency limits in MHz -- these are European values.  For Japanese
88 devices, that would be 76 and 91.  */
89 #define FREQ_MIN  87.5
90 #define FREQ_MAX 108.0
91 #define FREQ_MUL 16000
92
93
94 static int usb_dsbr100_probe(struct usb_interface *intf,
95                              const struct usb_device_id *id);
96 static void usb_dsbr100_disconnect(struct usb_interface *intf);
97 static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
98                              unsigned int cmd, unsigned long arg);
99 static int usb_dsbr100_open(struct inode *inode, struct file *file);
100 static int usb_dsbr100_close(struct inode *inode, struct file *file);
101
102 static int radio_nr = -1;
103 MODULE_PARM(radio_nr, "i");
104
105 typedef struct
106 {
107         struct usb_device *dev;
108         unsigned char transfer_buffer[TB_LEN];
109         int curfreq;
110         int stereo;
111 } usb_dsbr100;
112
113
114 static struct file_operations usb_dsbr100_fops = {
115         .owner =        THIS_MODULE,
116         .open =         usb_dsbr100_open,
117         .release =      usb_dsbr100_close,
118         .ioctl =        usb_dsbr100_ioctl,
119         .llseek =       no_llseek,
120 };
121 static struct video_device usb_dsbr100_radio=
122 {
123         .owner =        THIS_MODULE,
124         .name =         "D-Link DSB-R 100",
125         .type =         VID_TYPE_TUNER,
126         .hardware =     VID_HARDWARE_AZTECH,
127         .fops =         &usb_dsbr100_fops,
128 };
129
130 static int users = 0;
131
132 static struct usb_device_id usb_dsbr100_table [] = {
133         { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
134         { }                                             /* Terminating entry */
135 };
136
137 MODULE_DEVICE_TABLE (usb, usb_dsbr100_table);
138
139 static struct usb_driver usb_dsbr100_driver = {
140         .owner =        THIS_MODULE,
141         .name =         "dsbr100",
142         .probe =        usb_dsbr100_probe,
143         .disconnect =   usb_dsbr100_disconnect,
144         .id_table =     usb_dsbr100_table,
145 };
146
147
148 static int dsbr100_start(usb_dsbr100 *radio)
149 {
150         if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
151                 0x00, 0xC0, 0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 ||
152             usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
153                 0x02, 0xC0, 0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
154                 return -1;
155         return (radio->transfer_buffer)[0];
156 }
157
158
159 static int dsbr100_stop(usb_dsbr100 *radio)
160 {
161         if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
162                 0x00, 0xC0, 0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 ||
163             usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
164                 0x02, 0xC0, 0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
165                 return -1;
166         return (radio->transfer_buffer)[0];
167 }
168
169
170 static int dsbr100_setfreq(usb_dsbr100 *radio, int freq)
171 {
172         freq = (freq/16*80)/1000+856;
173         if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
174                 0x01, 0xC0, (freq>>8)&0x00ff, freq&0xff, 
175                 radio->transfer_buffer, 8, 300)<0 ||
176             usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
177                 0x00, 0xC0, 0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
178             usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
179                 0x00, 0xC0, 0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
180                 radio->stereo = -1;
181                 return -1;
182         }
183         radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
184         return (radio->transfer_buffer)[0];
185 }
186
187 static void dsbr100_getstat(usb_dsbr100 *radio)
188 {
189         if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
190                 0x00, 0xC0, 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
191                 radio->stereo = -1;
192         else
193                 radio->stereo = ! (radio->transfer_buffer[0]&0x01);
194 }
195
196
197 static int usb_dsbr100_probe(struct usb_interface *intf, 
198                          const struct usb_device_id *id)
199 {
200         usb_dsbr100 *radio;
201
202         if (!(radio = kmalloc(sizeof(usb_dsbr100),GFP_KERNEL)))
203                 return -ENOMEM;
204         usb_dsbr100_radio.priv = radio;
205         radio->dev = interface_to_usbdev (intf);
206         radio->curfreq = FREQ_MIN*FREQ_MUL;
207         usb_set_intfdata (intf, radio);
208         return 0;
209 }
210
211 static void usb_dsbr100_disconnect(struct usb_interface *intf)
212 {
213         usb_dsbr100 *radio = usb_get_intfdata (intf);
214
215         usb_set_intfdata (intf, NULL);
216
217         if (radio) {
218                 lock_kernel();
219                 if (users) {
220                         unlock_kernel();
221                         return;
222                 }
223                 kfree(radio);
224                 usb_dsbr100_radio.priv = NULL;
225                 unlock_kernel();
226         }
227 }
228
229 static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file,
230                                 unsigned int cmd, void *arg)
231 {
232         struct video_device *dev = video_devdata(file);
233         usb_dsbr100 *radio=dev->priv;
234
235         if (!radio)
236                 return -EINVAL;
237
238         switch(cmd)
239         {
240                 case VIDIOCGCAP: {
241                         struct video_capability *v = arg;
242                         memset(v, 0, sizeof(*v));
243                         v->type = VID_TYPE_TUNER;
244                         v->channels = 1;
245                         v->audios = 1;
246                         strcpy(v->name, "D-Link R-100 USB FM Radio");
247                         return 0;
248                 }
249                 case VIDIOCGTUNER: {
250                         struct video_tuner *v = arg;
251                         dsbr100_getstat(radio);
252                         if(v->tuner)    /* Only 1 tuner */ 
253                                 return -EINVAL;
254                         v->rangelow = FREQ_MIN*FREQ_MUL;
255                         v->rangehigh = FREQ_MAX*FREQ_MUL;
256                         v->flags = VIDEO_TUNER_LOW;
257                         v->mode = VIDEO_MODE_AUTO;
258                         v->signal = radio->stereo*0x7000;
259                                 /* Don't know how to get signal strength */
260                         v->flags |= VIDEO_TUNER_STEREO_ON*radio->stereo;
261                         strcpy(v->name, "DSB R-100");
262                         return 0;
263                 }
264                 case VIDIOCSTUNER: {
265                         struct video_tuner *v = arg;
266                         if(v->tuner!=0)
267                                 return -EINVAL;
268                         /* Only 1 tuner so no setting needed ! */
269                         return 0;
270                 }
271                 case VIDIOCGFREQ:
272                 {
273                         int *freq = arg;
274                         if (radio->curfreq==-1)
275                                 return -EINVAL;
276                         *freq = radio->curfreq;
277                         return 0;
278                 }
279                 case VIDIOCSFREQ:
280                 {
281                         int *freq = arg;
282
283                         radio->curfreq = *freq;
284                         if (dsbr100_setfreq(radio, radio->curfreq)==-1)
285                                 warn("Set frequency failed");
286                         return 0;
287                 }
288                 case VIDIOCGAUDIO: {
289                         struct video_audio *v = arg;
290                         memset(v, 0, sizeof(*v));
291                         v->flags |= VIDEO_AUDIO_MUTABLE;
292                         v->mode = VIDEO_SOUND_STEREO;
293                         v->volume = 1;
294                         v->step = 1;
295                         strcpy(v->name, "Radio");
296                         return 0;                       
297                 }
298                 case VIDIOCSAUDIO: {
299                         struct video_audio *v = arg;
300                         if (v->audio) 
301                                 return -EINVAL;
302
303                         if (v->flags&VIDEO_AUDIO_MUTE) {
304                                 if (dsbr100_stop(radio)==-1)
305                                         warn("Radio did not respond properly");
306                         }
307                         else
308                                 if (dsbr100_start(radio)==-1)
309                                         warn("Radio did not respond properly");
310                         return 0;
311                 }
312                 default:
313                         return -ENOIOCTLCMD;
314         }
315 }
316
317 static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
318                              unsigned int cmd, unsigned long arg)
319 {
320         return video_usercopy(inode, file, cmd, arg, usb_dsbr100_do_ioctl);
321 }
322
323 static int usb_dsbr100_open(struct inode *inode, struct file *file)
324 {
325         struct video_device *dev = video_devdata(file);
326         usb_dsbr100 *radio=dev->priv;
327
328         if (! radio) {
329                 warn("Radio not initialised");
330                 return -EAGAIN;
331         }
332         if(users)
333         {
334                 warn("Radio in use");
335                 return -EBUSY;
336         }
337         users++;
338         if (dsbr100_start(radio)<0)
339                 warn("Radio did not start up properly");
340         dsbr100_setfreq(radio, radio->curfreq);
341         return 0;
342 }
343
344 static int usb_dsbr100_close(struct inode *inode, struct file *file)
345 {
346         struct video_device *dev = video_devdata(file);
347         usb_dsbr100 *radio=dev->priv;
348
349         if (!radio)
350                 return -ENODEV;
351         users--;
352         return 0;
353 }
354
355 static int __init dsbr100_init(void)
356 {
357         int retval;
358         usb_dsbr100_radio.priv = NULL;
359         retval = usb_register(&usb_dsbr100_driver);
360         if (retval)
361                 goto failed_usb_register;
362         retval = video_register_device(&usb_dsbr100_radio, VFL_TYPE_RADIO,
363                                        radio_nr);
364         if (retval) {   
365                 warn("Couldn't register video device");
366                 goto failed_video_register;
367         }
368         info(DRIVER_VERSION ":" DRIVER_DESC);
369         return 0;
370 failed_video_register:
371         usb_deregister(&usb_dsbr100_driver);
372 failed_usb_register:
373         return retval;
374 }
375
376 static void __exit dsbr100_exit(void)
377 {
378         usb_dsbr100 *radio=usb_dsbr100_radio.priv;
379
380         if (radio)
381                 dsbr100_stop(radio);
382         video_unregister_device(&usb_dsbr100_radio);
383         usb_deregister(&usb_dsbr100_driver);
384 }
385
386 module_init (dsbr100_init);
387 module_exit (dsbr100_exit);
388
389 MODULE_AUTHOR( DRIVER_AUTHOR );
390 MODULE_DESCRIPTION( DRIVER_DESC );
391 MODULE_LICENSE("GPL");