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 Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
40 Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
41 thanks to Mike Cox for pointing the problem out.
44 Markus: Minor cleanup, warnings if something goes wrong, lame attempt
45 to adhere to Documentation/CodingStyle
48 Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
49 Markus: Copyright clarification
51 Version 0.01: Markus: initial release
56 #include <linux/kernel.h>
57 #include <linux/module.h>
58 #include <linux/init.h>
59 #include <linux/malloc.h>
60 #include <linux/input.h>
61 #include <linux/videodev.h>
62 #include <linux/usb.h>
64 #define DSB100_VENDOR 0x04b4
65 #define DSB100_PRODUCT 0x1002
69 static void *usb_dsbr100_probe(struct usb_device
*dev
, unsigned int ifnum
);
70 static void usb_dsbr100_disconnect(struct usb_device
*dev
, void *ptr
);
71 static int usb_dsbr100_ioctl(struct video_device
*dev
, unsigned int cmd
,
73 static int usb_dsbr100_open(struct video_device
*dev
, int flags
);
74 static void usb_dsbr100_close(struct video_device
*dev
);
78 { struct urb readurb
,writeurb
;
79 struct usb_device
*dev
;
80 unsigned char transfer_buffer
[TB_LEN
];
87 static struct video_device usb_dsbr100_radio
=
89 "D-Link DSB R-100 USB radio",
94 NULL
, /* Can't read (no capture ability) */
95 NULL
, /* Can't write */
102 static int users
= 0;
104 static struct usb_driver usb_dsbr100_driver
= {
106 probe
: usb_dsbr100_probe
,
107 disconnect
: usb_dsbr100_disconnect
,
108 driver_list
: {NULL
,NULL
},
114 static int dsbr100_start(usb_dsbr100
*radio
)
116 if (usb_control_msg(radio
->dev
, usb_rcvctrlpipe(radio
->dev
, 0),
117 0x00, 0xC0, 0x00, 0xC7, radio
->transfer_buffer
, 8, 300)<0 ||
118 usb_control_msg(radio
->dev
, usb_rcvctrlpipe(radio
->dev
, 0),
119 0x02, 0xC0, 0x01, 0x00, radio
->transfer_buffer
, 8, 300)<0)
121 return (radio
->transfer_buffer
)[0];
125 static int dsbr100_stop(usb_dsbr100
*radio
)
127 if (usb_control_msg(radio
->dev
, usb_rcvctrlpipe(radio
->dev
, 0),
128 0x00, 0xC0, 0x16, 0x1C, radio
->transfer_buffer
, 8, 300)<0 ||
129 usb_control_msg(radio
->dev
, usb_rcvctrlpipe(radio
->dev
, 0),
130 0x02, 0xC0, 0x00, 0x00, radio
->transfer_buffer
, 8, 300)<0)
132 return (radio
->transfer_buffer
)[0];
136 static int dsbr100_setfreq(usb_dsbr100
*radio
, int freq
)
138 freq
= (freq
*80)/16+856;
139 if (usb_control_msg(radio
->dev
, usb_rcvctrlpipe(radio
->dev
, 0),
140 0x01, 0xC0, (freq
&0xff00)>>8, freq
&0xff,
141 radio
->transfer_buffer
, 8, 300)<0
142 || usb_control_msg(radio
->dev
, usb_rcvctrlpipe(radio
->dev
, 0),
143 0x00, 0xC0, 0x96, 0xB7, radio
->transfer_buffer
, 8, 300)<0 ||
144 usb_control_msg(radio
->dev
, usb_rcvctrlpipe(radio
->dev
, 0),
145 0x00, 0xC0, 0x00, 0x24, radio
->transfer_buffer
, 8, 300)<0) {
149 radio
->stereo
= ! ((radio
->transfer_buffer
)[0]&0x01);
150 return (radio
->transfer_buffer
)[0];
153 static void dsbr100_getstat(usb_dsbr100
*radio
)
155 if (usb_control_msg(radio
->dev
, usb_rcvctrlpipe(radio
->dev
, 0),
156 0x00, 0xC0, 0x00 , 0x24, radio
->transfer_buffer
, 8, 300)<0)
159 radio
->stereo
= ! (radio
->transfer_buffer
[0]&0x01);
163 static void *usb_dsbr100_probe(struct usb_device
*dev
, unsigned int ifnum
)
167 if (dev
->descriptor
.idVendor
!=DSB100_VENDOR
||
168 dev
->descriptor
.idProduct
!=DSB100_PRODUCT
)
170 if (!(radio
= kmalloc(sizeof(usb_dsbr100
),GFP_KERNEL
)))
172 usb_dsbr100_radio
.priv
= radio
;
174 radio
->ifnum
= ifnum
;
175 radio
->curfreq
= 1454;
179 static void usb_dsbr100_disconnect(struct usb_device
*dev
, void *ptr
)
181 usb_dsbr100
*radio
=ptr
;
186 usb_dsbr100_radio
.priv
= NULL
;
189 static int usb_dsbr100_ioctl(struct video_device
*dev
, unsigned int cmd
,
192 usb_dsbr100
*radio
=dev
->priv
;
200 struct video_capability v
;
201 v
.type
=VID_TYPE_TUNER
;
204 /* No we don't do pictures */
209 strcpy(v
.name
, "D-Link R-100 USB Radio");
210 if(copy_to_user(arg
,&v
,sizeof(v
)))
215 struct video_tuner v
;
216 dsbr100_getstat(radio
);
217 if(copy_from_user(&v
, arg
,sizeof(v
))!=0)
219 if(v
.tuner
) /* Only 1 tuner */
222 v
.rangehigh
= 108*16;
223 v
.flags
= VIDEO_TUNER_LOW
;
224 v
.mode
= VIDEO_MODE_AUTO
;
225 v
.signal
= radio
->stereo
*0x7000;
226 /* Don't know how to get signal strength */
227 v
.flags
|= VIDEO_TUNER_STEREO_ON
*radio
->stereo
;
228 strcpy(v
.name
, "DSB R-100");
229 if(copy_to_user(arg
,&v
, sizeof(v
)))
234 struct video_tuner v
;
235 if(copy_from_user(&v
, arg
, sizeof(v
)))
239 /* Only 1 tuner so no setting needed ! */
243 if (radio
->curfreq
==-1)
245 if(copy_to_user(arg
, &(radio
->curfreq
),
246 sizeof(radio
->curfreq
)))
251 if(copy_from_user(&(radio
->curfreq
), arg
,
252 sizeof(radio
->curfreq
)))
254 if (dsbr100_setfreq(radio
, radio
->curfreq
)==-1)
255 warn("set frequency failed");
259 struct video_audio v
;
260 memset(&v
,0, sizeof(v
));
261 v
.flags
|=VIDEO_AUDIO_MUTABLE
;
262 v
.mode
=VIDEO_SOUND_STEREO
;
265 strcpy(v
.name
, "Radio");
266 if(copy_to_user(arg
,&v
, sizeof(v
)))
271 struct video_audio v
;
272 if(copy_from_user(&v
, arg
, sizeof(v
)))
277 if(v
.flags
&VIDEO_AUDIO_MUTE
) {
278 if (dsbr100_stop(radio
)==-1)
279 warn("radio did not respond properly");
282 if (dsbr100_start(radio
)==-1)
283 warn("radio did not respond properly");
292 static int usb_dsbr100_open(struct video_device
*dev
, int flags
)
294 usb_dsbr100
*radio
=dev
->priv
;
297 warn("radio not initialised");
302 warn("radio in use");
307 if (dsbr100_start(radio
)<0)
308 warn("radio did not start up properly");
309 dsbr100_setfreq(radio
,radio
->curfreq
);
313 static void usb_dsbr100_close(struct video_device
*dev
)
315 usb_dsbr100
*radio
=dev
->priv
;
324 int __init
dsbr100_init(void)
326 usb_dsbr100_radio
.priv
= NULL
;
327 usb_register(&usb_dsbr100_driver
);
328 if (video_register_device(&usb_dsbr100_radio
,VFL_TYPE_RADIO
)==-1) {
329 warn("couldn't register video device");
335 int __init
init_module(void)
337 return dsbr100_init();
340 void cleanup_module(void)
342 usb_dsbr100
*radio
=usb_dsbr100_radio
.priv
;
346 video_unregister_device(&usb_dsbr100_radio
);
347 usb_deregister(&usb_dsbr100_driver
);
352 Sigh. Of course, I am one of the ts=2 heretics, but Linus' wish is