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@tucana.harvard.edu>
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 PSL and Markus: Cleanup, radio now doesn't stop on device close
40 Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
41 right. Some minor cleanup, improved standalone compilation
44 Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
47 Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
48 thanks to Mike Cox for pointing the problem out.
51 Markus: Minor cleanup, warnings if something goes wrong, lame attempt
52 to adhere to Documentation/CodingStyle
55 Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
56 Markus: Copyright clarification
58 Version 0.01: Markus: initial release
63 #include <linux/kernel.h>
64 #include <linux/module.h>
65 #include <linux/init.h>
66 #include <linux/slab.h>
67 #include <linux/input.h>
68 #include <linux/videodev.h>
69 #include <linux/usb.h>
70 #include <linux/smp_lock.h>
75 #define DRIVER_VERSION "v0.25"
76 #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
77 #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
79 #define DSB100_VENDOR 0x04b4
80 #define DSB100_PRODUCT 0x1002
84 /* Frequency limits in MHz -- these are European values. For Japanese
85 devices, that would be 76 and 91 */
87 #define FREQ_MAX 108.0
88 #define FREQ_MUL 16000
90 static void *usb_dsbr100_probe(struct usb_device *dev, unsigned int ifnum,
91 const struct usb_device_id *id);
92 static void usb_dsbr100_disconnect(struct usb_device *dev, void *ptr);
93 static int usb_dsbr100_ioctl(struct video_device *dev, unsigned int cmd,
95 static int usb_dsbr100_open(struct video_device *dev, int flags);
96 static void usb_dsbr100_close(struct video_device *dev);
98 static int radio_nr = -1;
99 MODULE_PARM(radio_nr, "i");
102 { struct urb readurb, writeurb;
103 struct usb_device *dev;
104 unsigned char transfer_buffer[TB_LEN];
110 /* D-Link DSB-R100 and D-Link DRU-R100 are very similar products,
111 * both works with this driver. I don't know about any difference.
114 static struct video_device usb_dsbr100_radio =
116 name: "D-Link DSB R-100 USB FM radio",
117 type: VID_TYPE_TUNER,
118 hardware: VID_HARDWARE_AZTECH,
119 open: usb_dsbr100_open,
120 close: usb_dsbr100_close,
121 ioctl: usb_dsbr100_ioctl,
124 static int users = 0;
126 static struct usb_device_id usb_dsbr100_table [] = {
127 { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
128 { } /* Terminating entry */
131 MODULE_DEVICE_TABLE (usb, usb_dsbr100_table);
133 static struct usb_driver usb_dsbr100_driver = {
135 probe: usb_dsbr100_probe,
136 disconnect: usb_dsbr100_disconnect,
139 id_table: usb_dsbr100_table,
143 static int dsbr100_start(usb_dsbr100 *radio)
145 if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
146 0x00, 0xC0, 0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 ||
147 usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
148 0x02, 0xC0, 0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
150 return (radio->transfer_buffer)[0];
154 static int dsbr100_stop(usb_dsbr100 *radio)
156 if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
157 0x00, 0xC0, 0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 ||
158 usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
159 0x02, 0xC0, 0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
161 return (radio->transfer_buffer)[0];
165 static int dsbr100_setfreq(usb_dsbr100 *radio, int freq)
167 int rfreq = (freq/16*80)/1000+856;
168 if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
169 0x01, 0xC0, (rfreq>>8)&0x00ff, rfreq&0xff,
170 radio->transfer_buffer, 8, 300)<0 ||
171 usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
172 0x00, 0xC0, 0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
173 usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
174 0x00, 0xC0, 0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
178 radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
179 return (radio->transfer_buffer)[0];
182 static void dsbr100_getstat(usb_dsbr100 *radio)
184 if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
185 0x00, 0xC0, 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
188 radio->stereo = ! (radio->transfer_buffer[0]&0x01);
192 static void *usb_dsbr100_probe(struct usb_device *dev, unsigned int ifnum,
193 const struct usb_device_id *id)
197 if (!(radio = kmalloc(sizeof(usb_dsbr100), GFP_KERNEL)))
199 usb_dsbr100_radio.priv = radio;
201 radio->ifnum = ifnum;
202 radio->curfreq = FREQ_MIN*FREQ_MUL;
206 static void usb_dsbr100_disconnect(struct usb_device *dev, void *ptr)
208 usb_dsbr100 *radio=ptr;
216 usb_dsbr100_radio.priv = NULL;
220 static int usb_dsbr100_ioctl(struct video_device *dev, unsigned int cmd,
223 usb_dsbr100 *radio=dev->priv;
231 struct video_capability v;
232 v.type=VID_TYPE_TUNER;
239 strcpy(v.name, "D-Link R-100 USB FM Radio");
240 if(copy_to_user(arg, &v, sizeof(v)))
245 struct video_tuner v;
246 dsbr100_getstat(radio);
247 if(copy_from_user(&v, arg, sizeof(v))!=0)
249 if(v.tuner) /* Only 1 tuner */
251 v.rangelow = FREQ_MIN*FREQ_MUL;
252 v.rangehigh = FREQ_MAX*FREQ_MUL;
253 v.flags = VIDEO_TUNER_LOW;
254 v.mode = VIDEO_MODE_AUTO;
255 v.signal = radio->stereo*0x7000;
256 /* Don't know how to get signal strength */
257 v.flags |= VIDEO_TUNER_STEREO_ON*radio->stereo;
258 strcpy(v.name, "DSB R-100");
259 if(copy_to_user(arg, &v, sizeof(v)))
264 struct video_tuner v;
265 if(copy_from_user(&v, arg, sizeof(v)))
269 /* Only 1 tuner so no setting needed ! */
273 if (radio->curfreq==-1)
275 if(copy_to_user(arg, &(radio->curfreq),
276 sizeof(radio->curfreq)))
281 if(copy_from_user(&(radio->curfreq), arg,
282 sizeof(radio->curfreq)))
284 if (dsbr100_setfreq(radio, radio->curfreq)==-1)
285 warn("set frequency failed");
289 struct video_audio v;
290 memset(&v, 0, sizeof(v));
291 v.flags|=VIDEO_AUDIO_MUTABLE;
292 v.mode=VIDEO_SOUND_STEREO;
295 strcpy(v.name, "Radio");
296 if(copy_to_user(arg, &v, sizeof(v)))
301 struct video_audio v;
302 if(copy_from_user(&v, arg, sizeof(v)))
307 if(v.flags&VIDEO_AUDIO_MUTE) {
308 if (dsbr100_stop(radio)==-1)
309 warn("radio did not respond properly");
312 if (dsbr100_start(radio)==-1)
313 warn("radio did not respond properly");
322 static int usb_dsbr100_open(struct video_device *dev, int flags)
324 usb_dsbr100 *radio=dev->priv;
327 warn("radio not initialised");
332 warn("radio in use");
337 if (dsbr100_start(radio)<0)
338 warn("radio did not start up properly");
339 dsbr100_setfreq(radio, radio->curfreq);
343 static void usb_dsbr100_close(struct video_device *dev)
345 usb_dsbr100 *radio=dev->priv;
353 static int __init dsbr100_init(void)
355 usb_dsbr100_radio.priv = NULL;
356 usb_register(&usb_dsbr100_driver);
357 if (video_register_device(&usb_dsbr100_radio, VFL_TYPE_RADIO,
359 warn("couldn't register video device");
362 info(DRIVER_VERSION ":" DRIVER_DESC);
366 static void __exit dsbr100_exit(void)
368 usb_dsbr100 *radio=usb_dsbr100_radio.priv;
372 video_unregister_device(&usb_dsbr100_radio);
373 usb_deregister(&usb_dsbr100_driver);
376 module_init (dsbr100_init);
377 module_exit (dsbr100_exit);
379 MODULE_AUTHOR( DRIVER_AUTHOR );
380 MODULE_DESCRIPTION( DRIVER_DESC );
381 MODULE_LICENSE("GPL");