]> nv-tegra.nvidia Code Review - linux-3.10.git/blob - drivers/media/video/dsbr100.c
[PATCH] ieee1394: fix kerneldoc of hpsb_alloc_host
[linux-3.10.git] / drivers / media / video / 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.40:
37   Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
38
39  Version 0.30:
40         Markus: Updates for 2.5.x kernel and more ISO compliant source
41
42  Version 0.25:
43         PSL and Markus: Cleanup, radio now doesn't stop on device close
44
45  Version 0.24:
46         Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
47         right.  Some minor cleanup, improved standalone compilation
48
49  Version 0.23:
50         Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
51
52  Version 0.22:
53         Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
54         thanks to Mike Cox for pointing the problem out.
55
56  Version 0.21:
57         Markus: Minor cleanup, warnings if something goes wrong, lame attempt
58         to adhere to Documentation/CodingStyle
59
60  Version 0.2:
61         Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
62         Markus: Copyright clarification
63
64  Version 0.01: Markus: initial release
65
66 */
67
68
69 #include <linux/kernel.h>
70 #include <linux/module.h>
71 #include <linux/init.h>
72 #include <linux/slab.h>
73 #include <linux/input.h>
74 #include <linux/videodev.h>
75 #include <media/v4l2-common.h>
76 #include <linux/usb.h>
77 #include <linux/smp_lock.h>
78
79 /*
80  * Version Information
81  */
82 #define DRIVER_VERSION "v0.40"
83 #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
84 #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
85
86 #define DSB100_VENDOR 0x04b4
87 #define DSB100_PRODUCT 0x1002
88
89 /* Commands the device appears to understand */
90 #define DSB100_TUNE 1
91 #define DSB100_ONOFF 2
92
93 #define TB_LEN 16
94
95 /* Frequency limits in MHz -- these are European values.  For Japanese
96 devices, that would be 76 and 91.  */
97 #define FREQ_MIN  87.5
98 #define FREQ_MAX 108.0
99 #define FREQ_MUL 16000
100
101
102 static int usb_dsbr100_probe(struct usb_interface *intf,
103                              const struct usb_device_id *id);
104 static void usb_dsbr100_disconnect(struct usb_interface *intf);
105 static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
106                              unsigned int cmd, unsigned long arg);
107 static int usb_dsbr100_open(struct inode *inode, struct file *file);
108 static int usb_dsbr100_close(struct inode *inode, struct file *file);
109
110 static int radio_nr = -1;
111 module_param(radio_nr, int, 0);
112
113 /* Data for one (physical) device */
114 typedef struct {
115         struct usb_device *usbdev;
116         struct video_device *videodev;
117         unsigned char transfer_buffer[TB_LEN];
118         int curfreq;
119         int stereo;
120         int users;
121         int removed;
122 } dsbr100_device;
123
124
125 /* File system interface */
126 static struct file_operations usb_dsbr100_fops = {
127         .owner =        THIS_MODULE,
128         .open =         usb_dsbr100_open,
129         .release =      usb_dsbr100_close,
130         .ioctl =        usb_dsbr100_ioctl,
131         .compat_ioctl = v4l_compat_ioctl32,
132         .llseek =       no_llseek,
133 };
134
135 /* V4L interface */
136 static struct video_device dsbr100_videodev_template=
137 {
138         .owner =        THIS_MODULE,
139         .name =         "D-Link DSB-R 100",
140         .type =         VID_TYPE_TUNER,
141         .hardware =     VID_HARDWARE_AZTECH,
142         .fops =         &usb_dsbr100_fops,
143         .release = video_device_release,
144 };
145
146 static struct usb_device_id usb_dsbr100_device_table [] = {
147         { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
148         { }                                             /* Terminating entry */
149 };
150
151 MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
152
153 /* USB subsystem interface */
154 static struct usb_driver usb_dsbr100_driver = {
155         .name =         "dsbr100",
156         .probe =        usb_dsbr100_probe,
157         .disconnect =   usb_dsbr100_disconnect,
158         .id_table =     usb_dsbr100_device_table,
159 };
160
161 /* Low-level device interface begins here */
162
163 /* switch on radio */
164 static int dsbr100_start(dsbr100_device *radio)
165 {
166         if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
167                         USB_REQ_GET_STATUS,
168                         USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
169                         0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 ||
170         usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
171                         DSB100_ONOFF,
172                         USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
173                         0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
174                 return -1;
175         return (radio->transfer_buffer)[0];
176 }
177
178
179 /* switch off radio */
180 static int dsbr100_stop(dsbr100_device *radio)
181 {
182         if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
183                         USB_REQ_GET_STATUS,
184                         USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
185                         0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 ||
186         usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
187                         DSB100_ONOFF,
188                         USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
189                         0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
190                 return -1;
191         return (radio->transfer_buffer)[0];
192 }
193
194 /* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
195 static int dsbr100_setfreq(dsbr100_device *radio, int freq)
196 {
197         freq = (freq/16*80)/1000+856;
198         if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
199                         DSB100_TUNE,
200                         USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
201                         (freq>>8)&0x00ff, freq&0xff,
202                         radio->transfer_buffer, 8, 300)<0 ||
203            usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
204                         USB_REQ_GET_STATUS,
205                         USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
206                         0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
207         usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
208                         USB_REQ_GET_STATUS,
209                         USB_TYPE_VENDOR | USB_RECIP_DEVICE |  USB_DIR_IN,
210                         0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
211                 radio->stereo = -1;
212                 return -1;
213         }
214         radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
215         return (radio->transfer_buffer)[0];
216 }
217
218 /* return the device status.  This is, in effect, just whether it
219 sees a stereo signal or not.  Pity. */
220 static void dsbr100_getstat(dsbr100_device *radio)
221 {
222         if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
223                 USB_REQ_GET_STATUS,
224                 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
225                 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
226                 radio->stereo = -1;
227         else
228                 radio->stereo = ! (radio->transfer_buffer[0]&0x01);
229 }
230
231
232 /* USB subsystem interface begins here */
233
234 /* check if the device is present and register with v4l and
235 usb if it is */
236 static int usb_dsbr100_probe(struct usb_interface *intf,
237                          const struct usb_device_id *id)
238 {
239         dsbr100_device *radio;
240
241         if (!(radio = kmalloc(sizeof(dsbr100_device), GFP_KERNEL)))
242                 return -ENOMEM;
243         if (!(radio->videodev = video_device_alloc())) {
244                 kfree(radio);
245                 return -ENOMEM;
246         }
247         memcpy(radio->videodev, &dsbr100_videodev_template,
248                 sizeof(dsbr100_videodev_template));
249         radio->removed = 0;
250         radio->users = 0;
251         radio->usbdev = interface_to_usbdev(intf);
252         radio->curfreq = FREQ_MIN*FREQ_MUL;
253         video_set_drvdata(radio->videodev, radio);
254         if (video_register_device(radio->videodev, VFL_TYPE_RADIO,
255                 radio_nr)) {
256                 warn("Could not register video device");
257                 video_device_release(radio->videodev);
258                 kfree(radio);
259                 return -EIO;
260         }
261         usb_set_intfdata(intf, radio);
262         return 0;
263 }
264
265 /* handle unplugging of the device, release data structures
266 if nothing keeps us from doing it.  If something is still
267 keeping us busy, the release callback of v4l will take care
268 of releasing it.  stv680.c does not relase its private
269 data, so I don't do this here either.  Checking out the
270 code I'd expect I better did that, but if there's a memory
271 leak here it's tiny (~50 bytes per disconnect) */
272 static void usb_dsbr100_disconnect(struct usb_interface *intf)
273 {
274         dsbr100_device *radio = usb_get_intfdata(intf);
275
276         usb_set_intfdata (intf, NULL);
277         if (radio) {
278                 video_unregister_device(radio->videodev);
279                 radio->videodev = NULL;
280                 if (radio->users) {
281                         kfree(radio);
282                 } else {
283                         radio->removed = 1;
284                 }
285         }
286 }
287
288
289 /* Video for Linux interface */
290
291 static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file,
292                                 unsigned int cmd, void *arg)
293 {
294         dsbr100_device *radio=video_get_drvdata(video_devdata(file));
295
296         if (!radio)
297                 return -EIO;
298
299         switch(cmd) {
300                 case VIDIOCGCAP: {
301                         struct video_capability *v = arg;
302
303                         memset(v, 0, sizeof(*v));
304                         v->type = VID_TYPE_TUNER;
305                         v->channels = 1;
306                         v->audios = 1;
307                         strcpy(v->name, "D-Link R-100 USB FM Radio");
308                         return 0;
309                 }
310                 case VIDIOCGTUNER: {
311                         struct video_tuner *v = arg;
312
313                         dsbr100_getstat(radio);
314                         if(v->tuner)    /* Only 1 tuner */
315                                 return -EINVAL;
316                         v->rangelow = FREQ_MIN*FREQ_MUL;
317                         v->rangehigh = FREQ_MAX*FREQ_MUL;
318                         v->flags = VIDEO_TUNER_LOW;
319                         v->mode = VIDEO_MODE_AUTO;
320                         v->signal = radio->stereo*0x7000;
321                                 /* Don't know how to get signal strength */
322                         v->flags |= VIDEO_TUNER_STEREO_ON*radio->stereo;
323                         strcpy(v->name, "DSB R-100");
324                         return 0;
325                 }
326                 case VIDIOCSTUNER: {
327                         struct video_tuner *v = arg;
328
329                         if(v->tuner!=0)
330                                 return -EINVAL;
331                         /* Only 1 tuner so no setting needed ! */
332                         return 0;
333                 }
334                 case VIDIOCGFREQ: {
335                         int *freq = arg;
336
337                         if (radio->curfreq==-1)
338                                 return -EINVAL;
339                         *freq = radio->curfreq;
340                         return 0;
341                 }
342                 case VIDIOCSFREQ: {
343                         int *freq = arg;
344
345                         radio->curfreq = *freq;
346                         if (dsbr100_setfreq(radio, radio->curfreq)==-1)
347                                 warn("Set frequency failed");
348                         return 0;
349                 }
350                 case VIDIOCGAUDIO: {
351                         struct video_audio *v = arg;
352
353                         memset(v, 0, sizeof(*v));
354                         v->flags |= VIDEO_AUDIO_MUTABLE;
355                         v->mode = VIDEO_SOUND_STEREO;
356                         v->volume = 1;
357                         v->step = 1;
358                         strcpy(v->name, "Radio");
359                         return 0;
360                 }
361                 case VIDIOCSAUDIO: {
362                         struct video_audio *v = arg;
363
364                         if (v->audio)
365                                 return -EINVAL;
366                         if (v->flags&VIDEO_AUDIO_MUTE) {
367                                 if (dsbr100_stop(radio)==-1)
368                                         warn("Radio did not respond properly");
369                         }
370                         else
371                                 if (dsbr100_start(radio)==-1)
372                                         warn("Radio did not respond properly");
373                         return 0;
374                 }
375                 default:
376                         return -ENOIOCTLCMD;
377         }
378 }
379
380 static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
381                              unsigned int cmd, unsigned long arg)
382 {
383         return video_usercopy(inode, file, cmd, arg, usb_dsbr100_do_ioctl);
384 }
385
386 static int usb_dsbr100_open(struct inode *inode, struct file *file)
387 {
388         dsbr100_device *radio=video_get_drvdata(video_devdata(file));
389
390         radio->users = 1;
391         if (dsbr100_start(radio)<0) {
392                 warn("Radio did not start up properly");
393                 radio->users = 0;
394                 return -EIO;
395         }
396         dsbr100_setfreq(radio, radio->curfreq);
397         return 0;
398 }
399
400 static int usb_dsbr100_close(struct inode *inode, struct file *file)
401 {
402         dsbr100_device *radio=video_get_drvdata(video_devdata(file));
403
404         if (!radio)
405                 return -ENODEV;
406         radio->users = 0;
407         if (radio->removed) {
408                 kfree(radio);
409         }
410         return 0;
411 }
412
413 static int __init dsbr100_init(void)
414 {
415         int retval = usb_register(&usb_dsbr100_driver);
416         info(DRIVER_VERSION ":" DRIVER_DESC);
417         return retval;
418 }
419
420 static void __exit dsbr100_exit(void)
421 {
422         usb_deregister(&usb_dsbr100_driver);
423 }
424
425 module_init (dsbr100_init);
426 module_exit (dsbr100_exit);
427
428 MODULE_AUTHOR( DRIVER_AUTHOR );
429 MODULE_DESCRIPTION( DRIVER_DESC );
430 MODULE_LICENSE("GPL");