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@tucana.harvard.edu>
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.24:
37 Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
38 right. Some minor cleanup, improved standalone compilation
39
40 Version 0.23:
41 Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
42
43 Version 0.22:
44 Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
45 thanks to Mike Cox for pointing the problem out.
46
47 Version 0.21:
48 Markus: Minor cleanup, warnings if something goes wrong, lame attempt
49 to adhere to Documentation/CodingStyle
50
51 Version 0.2:
52 Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
53 Markus: Copyright clarification
54
55 Version 0.01: Markus: initial release
56
57 */
58
59
60 #include <linux/kernel.h>
61 #include <linux/module.h>
62 #include <linux/init.h>
63 #include <linux/malloc.h>
64 #include <linux/input.h>
65 #include <linux/videodev.h>
66 #include <linux/usb.h>
67
68 #define DSB100_VENDOR 0x04b4
69 #define DSB100_PRODUCT 0x1002
70
71 #define TB_LEN 16
72
73 static void *usb_dsbr100_probe(struct usb_device *dev, unsigned int ifnum,
74 const struct usb_device_id *id);
75 static void usb_dsbr100_disconnect(struct usb_device *dev, void *ptr);
76 static int usb_dsbr100_ioctl(struct video_device *dev, unsigned int cmd,
77 void *arg);
78 static int usb_dsbr100_open(struct video_device *dev, int flags);
79 static void usb_dsbr100_close(struct video_device *dev);
80
81
82 typedef struct
83 { struct urb readurb,writeurb;
84 struct usb_device *dev;
85 unsigned char transfer_buffer[TB_LEN];
86 int curfreq;
87 int stereo;
88 int ifnum;
89 } usb_dsbr100;
90
91
92 static struct video_device usb_dsbr100_radio=
93 {
94 name: "D-Link DSB R-100 USB radio",
95 type: VID_TYPE_TUNER,
96 hardware: VID_HARDWARE_AZTECH,
97 open: usb_dsbr100_open,
98 close: usb_dsbr100_close,
99 ioctl: usb_dsbr100_ioctl,
100 };
101
102 static int users = 0;
103
104 static struct usb_device_id usb_dsbr100_table [] = {
105 { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
106 { } /* Terminating entry */
107 };
108
109 MODULE_DEVICE_TABLE (usb, usb_dsbr100_table);
110
111 static struct usb_driver usb_dsbr100_driver = {
112 name: "dsbr100",
113 probe: usb_dsbr100_probe,
114 disconnect: usb_dsbr100_disconnect,
115 fops: NULL,
116 minor: 0,
117 id_table: usb_dsbr100_table,
118 };
119
120
121 static int dsbr100_start(usb_dsbr100 *radio)
122 {
123 if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
124 0x00, 0xC0, 0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 ||
125 usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
126 0x02, 0xC0, 0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
127 return -1;
128 return (radio->transfer_buffer)[0];
129 }
130
131
132 static int dsbr100_stop(usb_dsbr100 *radio)
133 {
134 if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
135 0x00, 0xC0, 0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 ||
136 usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
137 0x02, 0xC0, 0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
138 return -1;
139 return (radio->transfer_buffer)[0];
140 }
141
142
143 static int dsbr100_setfreq(usb_dsbr100 *radio, int freq)
144 {
145 freq = (freq/16*80)/1000+856;
146 if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
147 0x01, 0xC0, (freq>>8)&0x00ff, freq&0xff,
148 radio->transfer_buffer, 8, 300)<0 ||
149 usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
150 0x00, 0xC0, 0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
151 usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
152 0x00, 0xC0, 0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
153 radio->stereo = -1;
154 return -1;
155 }
156 radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
157 return (radio->transfer_buffer)[0];
158 }
159
160 static void dsbr100_getstat(usb_dsbr100 *radio)
161 {
162 if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
163 0x00, 0xC0, 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
164 radio->stereo = -1;
165 else
166 radio->stereo = ! (radio->transfer_buffer[0]&0x01);
167 }
168
169
170 static void *usb_dsbr100_probe(struct usb_device *dev, unsigned int ifnum,
171 const struct usb_device_id *id)
172 {
173 usb_dsbr100 *radio;
174
175 if (!(radio = kmalloc(sizeof(usb_dsbr100),GFP_KERNEL)))
176 return NULL;
177 usb_dsbr100_radio.priv = radio;
178 radio->dev = dev;
179 radio->ifnum = ifnum;
180 radio->curfreq = 1454000;
181 return (void*)radio;
182 }
183
184 static void usb_dsbr100_disconnect(struct usb_device *dev, void *ptr)
185 {
186 usb_dsbr100 *radio=ptr;
187
188 if (users)
189 return;
190 kfree(radio);
191 usb_dsbr100_radio.priv = NULL;
192 }
193
194 static int usb_dsbr100_ioctl(struct video_device *dev, unsigned int cmd,
195 void *arg)
196 {
197 usb_dsbr100 *radio=dev->priv;
198
199 if (!radio)
200 return -EINVAL;
201
202 switch(cmd)
203 {
204 case VIDIOCGCAP: {
205 struct video_capability v;
206 v.type=VID_TYPE_TUNER;
207 v.channels=1;
208 v.audios=1;
209 /* No we don't do pictures */
210 v.maxwidth=0;
211 v.maxheight=0;
212 v.minwidth=0;
213 v.minheight=0;
214 strcpy(v.name, "D-Link R-100 USB Radio");
215 if(copy_to_user(arg,&v,sizeof(v)))
216 return -EFAULT;
217 return 0;
218 }
219 case VIDIOCGTUNER: {
220 struct video_tuner v;
221 dsbr100_getstat(radio);
222 if(copy_from_user(&v, arg,sizeof(v))!=0)
223 return -EFAULT;
224 if(v.tuner) /* Only 1 tuner */
225 return -EINVAL;
226 v.rangelow = 87*16000;
227 v.rangehigh = 108*16000;
228 v.flags = VIDEO_TUNER_LOW;
229 v.mode = VIDEO_MODE_AUTO;
230 v.signal = radio->stereo*0x7000;
231 /* Don't know how to get signal strength */
232 v.flags |= VIDEO_TUNER_STEREO_ON*radio->stereo;
233 strcpy(v.name, "DSB R-100");
234 if(copy_to_user(arg,&v, sizeof(v)))
235 return -EFAULT;
236 return 0;
237 }
238 case VIDIOCSTUNER: {
239 struct video_tuner v;
240 if(copy_from_user(&v, arg, sizeof(v)))
241 return -EFAULT;
242 if(v.tuner!=0)
243 return -EINVAL;
244 /* Only 1 tuner so no setting needed ! */
245 return 0;
246 }
247 case VIDIOCGFREQ:
248 if (radio->curfreq==-1)
249 return -EINVAL;
250 if(copy_to_user(arg, &(radio->curfreq),
251 sizeof(radio->curfreq)))
252 return -EFAULT;
253 return 0;
254
255 case VIDIOCSFREQ:
256 if(copy_from_user(&(radio->curfreq), arg,
257 sizeof(radio->curfreq)))
258 return -EFAULT;
259 if (dsbr100_setfreq(radio, radio->curfreq)==-1)
260 warn("set frequency failed");
261 return 0;
262
263 case VIDIOCGAUDIO: {
264 struct video_audio v;
265 memset(&v,0, sizeof(v));
266 v.flags|=VIDEO_AUDIO_MUTABLE;
267 v.mode=VIDEO_SOUND_STEREO;
268 v.volume=1;
269 v.step=1;
270 strcpy(v.name, "Radio");
271 if(copy_to_user(arg,&v, sizeof(v)))
272 return -EFAULT;
273 return 0;
274 }
275 case VIDIOCSAUDIO: {
276 struct video_audio v;
277 if(copy_from_user(&v, arg, sizeof(v)))
278 return -EFAULT;
279 if(v.audio)
280 return -EINVAL;
281
282 if(v.flags&VIDEO_AUDIO_MUTE) {
283 if (dsbr100_stop(radio)==-1)
284 warn("radio did not respond properly");
285 }
286 else
287 if (dsbr100_start(radio)==-1)
288 warn("radio did not respond properly");
289 return 0;
290 }
291 default:
292 return -ENOIOCTLCMD;
293 }
294 }
295
296
297 static int usb_dsbr100_open(struct video_device *dev, int flags)
298 {
299 usb_dsbr100 *radio=dev->priv;
300
301 if (! radio) {
302 warn("radio not initialised");
303 return -EAGAIN;
304 }
305 if(users)
306 {
307 warn("radio in use");
308 return -EBUSY;
309 }
310 users++;
311 MOD_INC_USE_COUNT;
312 if (dsbr100_start(radio)<0)
313 warn("radio did not start up properly");
314 dsbr100_setfreq(radio,radio->curfreq);
315 return 0;
316 }
317
318 static void usb_dsbr100_close(struct video_device *dev)
319 {
320 usb_dsbr100 *radio=dev->priv;
321
322 if (!radio)
323 return;
324 users--;
325 dsbr100_stop(radio);
326 MOD_DEC_USE_COUNT;
327 }
328
329 static int __init dsbr100_init(void)
330 {
331 usb_dsbr100_radio.priv = NULL;
332 usb_register(&usb_dsbr100_driver);
333 if (video_register_device(&usb_dsbr100_radio,VFL_TYPE_RADIO)==-1) {
334 warn("couldn't register video device");
335 return -EINVAL;
336 }
337 return 0;
338 }
339
340 static void __exit dsbr100_exit(void)
341 {
342 usb_dsbr100 *radio=usb_dsbr100_radio.priv;
343
344 if (radio)
345 dsbr100_stop(radio);
346 video_unregister_device(&usb_dsbr100_radio);
347 usb_deregister(&usb_dsbr100_driver);
348 }
349
350 module_init (dsbr100_init);
351 module_exit (dsbr100_exit);
352
353 MODULE_AUTHOR("Markus Demleitner <msdemlei@tucana.harvard.edu>");
354 MODULE_DESCRIPTION("D-Link DSB-R100 USB radio driver");
355
356 /*
357 vi: ts=8
358 Sigh. Of course, I am one of the ts=2 heretics, but Linus' wish is
359 my command.
360 */
361
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.