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.
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.
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:-)
15 You might find some interesting stuff about this module at
16 http://unimut.fsk.uni-heidelberg.de/unimut/demi/dsbr
18 Copyright (c) 2000 Markus Demleitner <msdemlei@cl.uni-heidelberg.de>
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.
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.
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
37 Markus: Updates for 2.5.x kernel and more ISO compliant source
40 PSL and Markus: Cleanup, radio now doesn't stop on device close
43 Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
44 right. Some minor cleanup, improved standalone compilation
47 Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
50 Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
51 thanks to Mike Cox for pointing the problem out.
54 Markus: Minor cleanup, warnings if something goes wrong, lame attempt
55 to adhere to Documentation/CodingStyle
58 Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
59 Markus: Copyright clarification
61 Version 0.01: Markus: initial release
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>
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"
82 #define DSB100_VENDOR 0x04b4
83 #define DSB100_PRODUCT 0x1002
87 /* Frequency limits in MHz -- these are European values. For Japanese
88 devices, that would be 76 and 91. */
90 #define FREQ_MAX 108.0
91 #define FREQ_MUL 16000
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);
102 static int radio_nr = -1;
103 MODULE_PARM(radio_nr, "i");
107 struct usb_device *dev;
108 unsigned char transfer_buffer[TB_LEN];
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,
121 static struct video_device usb_dsbr100_radio=
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,
130 static int users = 0;
132 static struct usb_device_id usb_dsbr100_table [] = {
133 { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
134 { } /* Terminating entry */
137 MODULE_DEVICE_TABLE (usb, usb_dsbr100_table);
139 static struct usb_driver usb_dsbr100_driver = {
140 .owner = THIS_MODULE,
142 .probe = usb_dsbr100_probe,
143 .disconnect = usb_dsbr100_disconnect,
144 .id_table = usb_dsbr100_table,
148 static int dsbr100_start(usb_dsbr100 *radio)
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)
155 return (radio->transfer_buffer)[0];
159 static int dsbr100_stop(usb_dsbr100 *radio)
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)
166 return (radio->transfer_buffer)[0];
170 static int dsbr100_setfreq(usb_dsbr100 *radio, int freq)
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) {
183 radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
184 return (radio->transfer_buffer)[0];
187 static void dsbr100_getstat(usb_dsbr100 *radio)
189 if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
190 0x00, 0xC0, 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
193 radio->stereo = ! (radio->transfer_buffer[0]&0x01);
197 static int usb_dsbr100_probe(struct usb_interface *intf,
198 const struct usb_device_id *id)
202 if (!(radio = kmalloc(sizeof(usb_dsbr100),GFP_KERNEL)))
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);
211 static void usb_dsbr100_disconnect(struct usb_interface *intf)
213 usb_dsbr100 *radio = usb_get_intfdata (intf);
215 usb_set_intfdata (intf, NULL);
224 usb_dsbr100_radio.priv = NULL;
229 static int usb_dsbr100_do_ioctl(struct inode *inode, struct file *file,
230 unsigned int cmd, void *arg)
232 struct video_device *dev = video_devdata(file);
233 usb_dsbr100 *radio=dev->priv;
241 struct video_capability *v = arg;
242 memset(v, 0, sizeof(*v));
243 v->type = VID_TYPE_TUNER;
246 strcpy(v->name, "D-Link R-100 USB FM Radio");
250 struct video_tuner *v = arg;
251 dsbr100_getstat(radio);
252 if(v->tuner) /* Only 1 tuner */
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");
265 struct video_tuner *v = arg;
268 /* Only 1 tuner so no setting needed ! */
274 if (radio->curfreq==-1)
276 *freq = radio->curfreq;
283 radio->curfreq = *freq;
284 if (dsbr100_setfreq(radio, radio->curfreq)==-1)
285 warn("Set frequency failed");
289 struct video_audio *v = arg;
290 memset(v, 0, sizeof(*v));
291 v->flags |= VIDEO_AUDIO_MUTABLE;
292 v->mode = VIDEO_SOUND_STEREO;
295 strcpy(v->name, "Radio");
299 struct video_audio *v = arg;
303 if (v->flags&VIDEO_AUDIO_MUTE) {
304 if (dsbr100_stop(radio)==-1)
305 warn("Radio did not respond properly");
308 if (dsbr100_start(radio)==-1)
309 warn("Radio did not respond properly");
317 static int usb_dsbr100_ioctl(struct inode *inode, struct file *file,
318 unsigned int cmd, unsigned long arg)
320 return video_usercopy(inode, file, cmd, arg, usb_dsbr100_do_ioctl);
323 static int usb_dsbr100_open(struct inode *inode, struct file *file)
325 struct video_device *dev = video_devdata(file);
326 usb_dsbr100 *radio=dev->priv;
329 warn("Radio not initialised");
334 warn("Radio in use");
338 if (dsbr100_start(radio)<0)
339 warn("Radio did not start up properly");
340 dsbr100_setfreq(radio, radio->curfreq);
344 static int usb_dsbr100_close(struct inode *inode, struct file *file)
346 struct video_device *dev = video_devdata(file);
347 usb_dsbr100 *radio=dev->priv;
355 static int __init dsbr100_init(void)
358 usb_dsbr100_radio.priv = NULL;
359 retval = usb_register(&usb_dsbr100_driver);
361 goto failed_usb_register;
362 retval = video_register_device(&usb_dsbr100_radio, VFL_TYPE_RADIO,
365 warn("Couldn't register video device");
366 goto failed_video_register;
368 info(DRIVER_VERSION ":" DRIVER_DESC);
370 failed_video_register:
371 usb_deregister(&usb_dsbr100_driver);
376 static void __exit dsbr100_exit(void)
378 usb_dsbr100 *radio=usb_dsbr100_radio.priv;
382 video_unregister_device(&usb_dsbr100_radio);
383 usb_deregister(&usb_dsbr100_driver);
386 module_init (dsbr100_init);
387 module_exit (dsbr100_exit);
389 MODULE_AUTHOR( DRIVER_AUTHOR );
390 MODULE_DESCRIPTION( DRIVER_DESC );
391 MODULE_LICENSE("GPL");