Import 2.3.99pre2-1
[davej-history.git] / drivers / usb / dsbr100.c
blob22c21bb339f79cab74eb2f2faab2ec918e4debd7
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
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.21:
37 Markus Demleitner <msdemlei@tucana.harvard.edu>:
38 Minor cleanup, warnings if something goes wrong, lame attempt
39 to adhere to Documentation/CodingStyle
41 Version 0.2:
42 Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
43 Markus: Copyright clarification
45 Version 0.01: Markus: initial release
50 #include <linux/kernel.h>
51 #include <linux/module.h>
52 #include <linux/init.h>
53 #include <linux/malloc.h>
54 #include <linux/input.h>
55 #include <linux/videodev.h>
56 #include <linux/usb.h>
58 #define DSB100_VENDOR 0x04b4
59 #define DSB100_PRODUCT 0x1002
61 #define TB_LEN 16
63 static void *usb_dsbr100_probe(struct usb_device *dev, unsigned int ifnum);
64 static void usb_dsbr100_disconnect(struct usb_device *dev, void *ptr);
65 static int usb_dsbr100_ioctl(struct video_device *dev, unsigned int cmd,
66 void *arg);
67 static int usb_dsbr100_open(struct video_device *dev, int flags);
68 static void usb_dsbr100_close(struct video_device *dev);
71 typedef struct
72 { struct urb readurb,writeurb;
73 struct usb_device *dev;
74 char transfer_buffer[TB_LEN];
75 int curfreq;
76 int stereo;
77 int ifnum;
78 } usb_dsbr100;
81 static struct video_device usb_dsbr100_radio=
83 "D-Link DSB R-100 USB radio",
84 VID_TYPE_TUNER,
85 VID_HARDWARE_AZTECH,
86 usb_dsbr100_open,
87 usb_dsbr100_close,
88 NULL, /* Can't read (no capture ability) */
89 NULL, /* Can't write */
90 NULL, /* No poll */
91 usb_dsbr100_ioctl,
92 NULL,
93 NULL
96 static int users = 0;
98 static struct usb_driver usb_dsbr100_driver = {
99 name: "dsbr100",
100 probe: usb_dsbr100_probe,
101 disconnect: usb_dsbr100_disconnect,
102 driver_list: {NULL,NULL},
103 fops: NULL,
104 minor: 0
108 static int dsbr100_start(usb_dsbr100 *radio)
110 if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
111 0x00, 0xC0, 0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 ||
112 usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
113 0x02, 0xC0, 0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
114 return -1;
115 return (radio->transfer_buffer)[0];
119 static int dsbr100_stop(usb_dsbr100 *radio)
121 if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
122 0x00, 0xC0, 0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 ||
123 usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
124 0x02, 0xC0, 0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
125 return -1;
126 return (radio->transfer_buffer)[0];
130 static int dsbr100_setfreq(usb_dsbr100 *radio, int freq)
132 freq = (freq*80)/16+856;
133 if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
134 0x01, 0xC0, (freq&0xff00)>>8, freq&0xff,
135 radio->transfer_buffer, 8, 300)<0
136 || usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
137 0x00, 0xC0, 0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
138 usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
139 0x00, 0xC0, 0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
140 radio->stereo = -1;
141 return -1;
143 radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
144 return (radio->transfer_buffer)[0];
147 static void dsbr100_getstat(usb_dsbr100 *radio)
149 if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
150 0x00, 0xC0, 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
151 radio->stereo = -1;
152 else
153 radio->stereo = ! (radio->transfer_buffer[0]&0x01);
157 static void *usb_dsbr100_probe(struct usb_device *dev, unsigned int ifnum)
159 usb_dsbr100 *radio;
161 if (dev->descriptor.idVendor!=DSB100_VENDOR ||
162 dev->descriptor.idProduct!=DSB100_PRODUCT)
163 return NULL;
164 if (!(radio = kmalloc(sizeof(usb_dsbr100),GFP_KERNEL)))
165 return NULL;
166 usb_dsbr100_radio.priv = radio;
167 radio->dev = dev;
168 radio->ifnum = ifnum;
169 radio->curfreq = 1454;
170 return (void*)radio;
173 static void usb_dsbr100_disconnect(struct usb_device *dev, void *ptr)
175 usb_dsbr100 *radio=ptr;
177 if (users)
178 return;
179 kfree(radio);
180 usb_dsbr100_radio.priv = NULL;
183 static int usb_dsbr100_ioctl(struct video_device *dev, unsigned int cmd,
184 void *arg)
186 usb_dsbr100 *radio=dev->priv;
188 if (!radio)
189 return -EINVAL;
191 switch(cmd)
193 case VIDIOCGCAP: {
194 struct video_capability v;
195 v.type=VID_TYPE_TUNER;
196 v.channels=1;
197 v.audios=1;
198 /* No we don't do pictures */
199 v.maxwidth=0;
200 v.maxheight=0;
201 v.minwidth=0;
202 v.minheight=0;
203 strcpy(v.name, "D-Link R-100 USB Radio");
204 if(copy_to_user(arg,&v,sizeof(v)))
205 return -EFAULT;
206 return 0;
208 case VIDIOCGTUNER: {
209 struct video_tuner v;
210 dsbr100_getstat(radio);
211 if(copy_from_user(&v, arg,sizeof(v))!=0)
212 return -EFAULT;
213 if(v.tuner) /* Only 1 tuner */
214 return -EINVAL;
215 v.rangelow=(87*16000);
216 v.rangehigh=(108*16000);
217 /*v.flags=VIDEO_TUNER_LOW;*/
218 v.mode=VIDEO_MODE_AUTO;
219 v.signal=radio->stereo;
220 v.flags|=VIDEO_TUNER_STEREO_ON;
221 strcpy(v.name, "FM");
222 if(copy_to_user(arg,&v, sizeof(v)))
223 return -EFAULT;
224 return 0;
226 case VIDIOCSTUNER: {
227 struct video_tuner v;
228 if(copy_from_user(&v, arg, sizeof(v)))
229 return -EFAULT;
230 if(v.tuner!=0)
231 return -EINVAL;
232 /* Only 1 tuner so no setting needed ! */
233 return 0;
235 case VIDIOCGFREQ:
236 if (radio->curfreq==-1)
237 return -EINVAL;
238 if(copy_to_user(arg, &(radio->curfreq),
239 sizeof(radio->curfreq)))
240 return -EFAULT;
241 return 0;
243 case VIDIOCSFREQ:
244 if(copy_from_user(&(radio->curfreq), arg,
245 sizeof(radio->curfreq)))
246 return -EFAULT;
247 if (dsbr100_setfreq(radio, radio->curfreq)==-1)
248 warn("set frequency failed");
249 return 0;
251 case VIDIOCGAUDIO: {
252 struct video_audio v;
253 memset(&v,0, sizeof(v));
254 v.flags|=VIDEO_AUDIO_MUTABLE;
255 v.mode=VIDEO_SOUND_STEREO;
256 v.volume=1;
257 v.step=1;
258 strcpy(v.name, "Radio");
259 if(copy_to_user(arg,&v, sizeof(v)))
260 return -EFAULT;
261 return 0;
263 case VIDIOCSAUDIO: {
264 struct video_audio v;
265 if(copy_from_user(&v, arg, sizeof(v)))
266 return -EFAULT;
267 if(v.audio)
268 return -EINVAL;
270 if(v.flags&VIDEO_AUDIO_MUTE) {
271 if (dsbr100_stop(radio)==-1)
272 warn("radio did not respond properly");
274 else
275 if (dsbr100_start(radio)==-1)
276 warn("radio did not respond properly");
277 return 0;
279 default:
280 return -ENOIOCTLCMD;
285 static int usb_dsbr100_open(struct video_device *dev, int flags)
287 usb_dsbr100 *radio=dev->priv;
289 if (! radio) {
290 warn("radio not initialised");
291 return -EAGAIN;
293 if(users)
295 warn("radio in use");
296 return -EBUSY;
298 users++;
299 MOD_INC_USE_COUNT;
300 if (dsbr100_start(radio)<0)
301 warn("radio did not start up properly");
302 dsbr100_setfreq(radio,radio->curfreq);
303 return 0;
306 static void usb_dsbr100_close(struct video_device *dev)
308 usb_dsbr100 *radio=dev->priv;
310 if (!radio)
311 return;
312 users--;
313 dsbr100_stop(radio);
314 MOD_DEC_USE_COUNT;
317 int __init dsbr100_init(void)
319 usb_dsbr100_radio.priv = NULL;
320 usb_register(&usb_dsbr100_driver);
321 if (video_register_device(&usb_dsbr100_radio,VFL_TYPE_RADIO)==-1) {
322 warn("couldn't register video device");
323 return -EINVAL;
325 return 0;
328 int __init init_module(void)
330 return dsbr100_init();
333 void cleanup_module(void)
335 usb_dsbr100 *radio=usb_dsbr100_radio.priv;
337 if (radio)
338 dsbr100_stop(radio);
339 video_unregister_device(&usb_dsbr100_radio);
340 usb_deregister(&usb_dsbr100_driver);
344 vi: ts=8
345 Sigh. Of course, I am one of the ts=2 heretics, but Linus' wish is
346 my command.