- pre5:
[davej-history.git] / drivers / usb / dsbr100.c
blobca1d8abba4b14a1c018ae5be7673cf31e22e2cc5
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
34 History:
36 Version 0.23:
37 Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
39 Version 0.22:
40 Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
41 thanks to Mike Cox for pointing the problem out.
43 Version 0.21:
44 Markus: Minor cleanup, warnings if something goes wrong, lame attempt
45 to adhere to Documentation/CodingStyle
47 Version 0.2:
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
67 #define TB_LEN 16
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,
72 void *arg);
73 static int usb_dsbr100_open(struct video_device *dev, int flags);
74 static void usb_dsbr100_close(struct video_device *dev);
77 typedef struct
78 { struct urb readurb,writeurb;
79 struct usb_device *dev;
80 unsigned char transfer_buffer[TB_LEN];
81 int curfreq;
82 int stereo;
83 int ifnum;
84 } usb_dsbr100;
87 static struct video_device usb_dsbr100_radio=
89 "D-Link DSB R-100 USB radio",
90 VID_TYPE_TUNER,
91 VID_HARDWARE_AZTECH,
92 usb_dsbr100_open,
93 usb_dsbr100_close,
94 NULL, /* Can't read (no capture ability) */
95 NULL, /* Can't write */
96 NULL, /* No poll */
97 usb_dsbr100_ioctl,
98 NULL,
99 NULL
102 static int users = 0;
104 static struct usb_driver usb_dsbr100_driver = {
105 name: "dsbr100",
106 probe: usb_dsbr100_probe,
107 disconnect: usb_dsbr100_disconnect,
108 driver_list: {NULL,NULL},
109 fops: NULL,
110 minor: 0
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)
120 return -1;
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)
131 return -1;
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) {
146 radio->stereo = -1;
147 return -1;
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)
157 radio->stereo = -1;
158 else
159 radio->stereo = ! (radio->transfer_buffer[0]&0x01);
163 static void *usb_dsbr100_probe(struct usb_device *dev, unsigned int ifnum)
165 usb_dsbr100 *radio;
167 if (dev->descriptor.idVendor!=DSB100_VENDOR ||
168 dev->descriptor.idProduct!=DSB100_PRODUCT)
169 return NULL;
170 if (!(radio = kmalloc(sizeof(usb_dsbr100),GFP_KERNEL)))
171 return NULL;
172 usb_dsbr100_radio.priv = radio;
173 radio->dev = dev;
174 radio->ifnum = ifnum;
175 radio->curfreq = 1454;
176 return (void*)radio;
179 static void usb_dsbr100_disconnect(struct usb_device *dev, void *ptr)
181 usb_dsbr100 *radio=ptr;
183 if (users)
184 return;
185 kfree(radio);
186 usb_dsbr100_radio.priv = NULL;
189 static int usb_dsbr100_ioctl(struct video_device *dev, unsigned int cmd,
190 void *arg)
192 usb_dsbr100 *radio=dev->priv;
194 if (!radio)
195 return -EINVAL;
197 switch(cmd)
199 case VIDIOCGCAP: {
200 struct video_capability v;
201 v.type=VID_TYPE_TUNER;
202 v.channels=1;
203 v.audios=1;
204 /* No we don't do pictures */
205 v.maxwidth=0;
206 v.maxheight=0;
207 v.minwidth=0;
208 v.minheight=0;
209 strcpy(v.name, "D-Link R-100 USB Radio");
210 if(copy_to_user(arg,&v,sizeof(v)))
211 return -EFAULT;
212 return 0;
214 case VIDIOCGTUNER: {
215 struct video_tuner v;
216 dsbr100_getstat(radio);
217 if(copy_from_user(&v, arg,sizeof(v))!=0)
218 return -EFAULT;
219 if(v.tuner) /* Only 1 tuner */
220 return -EINVAL;
221 v.rangelow = 87*16;
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)))
230 return -EFAULT;
231 return 0;
233 case VIDIOCSTUNER: {
234 struct video_tuner v;
235 if(copy_from_user(&v, arg, sizeof(v)))
236 return -EFAULT;
237 if(v.tuner!=0)
238 return -EINVAL;
239 /* Only 1 tuner so no setting needed ! */
240 return 0;
242 case VIDIOCGFREQ:
243 if (radio->curfreq==-1)
244 return -EINVAL;
245 if(copy_to_user(arg, &(radio->curfreq),
246 sizeof(radio->curfreq)))
247 return -EFAULT;
248 return 0;
250 case VIDIOCSFREQ:
251 if(copy_from_user(&(radio->curfreq), arg,
252 sizeof(radio->curfreq)))
253 return -EFAULT;
254 if (dsbr100_setfreq(radio, radio->curfreq)==-1)
255 warn("set frequency failed");
256 return 0;
258 case VIDIOCGAUDIO: {
259 struct video_audio v;
260 memset(&v,0, sizeof(v));
261 v.flags|=VIDEO_AUDIO_MUTABLE;
262 v.mode=VIDEO_SOUND_STEREO;
263 v.volume=1;
264 v.step=1;
265 strcpy(v.name, "Radio");
266 if(copy_to_user(arg,&v, sizeof(v)))
267 return -EFAULT;
268 return 0;
270 case VIDIOCSAUDIO: {
271 struct video_audio v;
272 if(copy_from_user(&v, arg, sizeof(v)))
273 return -EFAULT;
274 if(v.audio)
275 return -EINVAL;
277 if(v.flags&VIDEO_AUDIO_MUTE) {
278 if (dsbr100_stop(radio)==-1)
279 warn("radio did not respond properly");
281 else
282 if (dsbr100_start(radio)==-1)
283 warn("radio did not respond properly");
284 return 0;
286 default:
287 return -ENOIOCTLCMD;
292 static int usb_dsbr100_open(struct video_device *dev, int flags)
294 usb_dsbr100 *radio=dev->priv;
296 if (! radio) {
297 warn("radio not initialised");
298 return -EAGAIN;
300 if(users)
302 warn("radio in use");
303 return -EBUSY;
305 users++;
306 MOD_INC_USE_COUNT;
307 if (dsbr100_start(radio)<0)
308 warn("radio did not start up properly");
309 dsbr100_setfreq(radio,radio->curfreq);
310 return 0;
313 static void usb_dsbr100_close(struct video_device *dev)
315 usb_dsbr100 *radio=dev->priv;
317 if (!radio)
318 return;
319 users--;
320 dsbr100_stop(radio);
321 MOD_DEC_USE_COUNT;
324 static 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");
330 return -EINVAL;
332 return 0;
335 static void __exit dsbr100_exit(void)
337 usb_dsbr100 *radio=usb_dsbr100_radio.priv;
339 if (radio)
340 dsbr100_stop(radio);
341 video_unregister_device(&usb_dsbr100_radio);
342 usb_deregister(&usb_dsbr100_driver);
345 module_init (dsbr100_init);
346 module_exit (dsbr100_exit);
348 MODULE_AUTHOR("Markus Demleitner <msdemlei@tucana.harvard.edu>");
349 MODULE_DESCRIPTION("D-Link DSB-R100 USB radio driver");
352 vi: ts=8
353 Sigh. Of course, I am one of the ts=2 heretics, but Linus' wish is
354 my command.