OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [drivers/] [usb/] [dsbr100.c] - Blame information for rev 1780

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/* 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.25:
37
        PSL and Markus: Cleanup, radio now doesn't stop on device close
38
 
39
 Version 0.24:
40
        Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
41
        right.  Some minor cleanup, improved standalone compilation
42
 
43
 Version 0.23:
44
        Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
45
 
46
 Version 0.22:
47
        Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
48
        thanks to Mike Cox for pointing the problem out.
49
 
50
 Version 0.21:
51
        Markus: Minor cleanup, warnings if something goes wrong, lame attempt
52
        to adhere to Documentation/CodingStyle
53
 
54
 Version 0.2:
55
        Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
56
        Markus: Copyright clarification
57
 
58
 Version 0.01: Markus: initial release
59
 
60
*/
61
 
62
 
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>
71
 
72
/*
73
 * Version Information
74
 */
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"
78
 
79
#define DSB100_VENDOR 0x04b4
80
#define DSB100_PRODUCT 0x1002
81
 
82
#define TB_LEN 16
83
 
84
/* Frequency limits in MHz -- these are European values.  For Japanese
85
devices, that would be 76 and 91 */
86
#define FREQ_MIN  87.5
87
#define FREQ_MAX 108.0
88
#define FREQ_MUL 16000
89
 
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,
94
        void *arg);
95
static int usb_dsbr100_open(struct video_device *dev, int flags);
96
static void usb_dsbr100_close(struct video_device *dev);
97
 
98
static int radio_nr = -1;
99
MODULE_PARM(radio_nr, "i");
100
 
101
typedef struct
102
{       struct urb readurb, writeurb;
103
        struct usb_device *dev;
104
        unsigned char transfer_buffer[TB_LEN];
105
        int curfreq;
106
        int stereo;
107
        int ifnum;
108
} usb_dsbr100;
109
 
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.
112
 * */
113
 
114
static struct video_device usb_dsbr100_radio =
115
{
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,
122
};
123
 
124
static int users = 0;
125
 
126
static struct usb_device_id usb_dsbr100_table [] = {
127
        { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
128
        { }                                             /* Terminating entry */
129
};
130
 
131
MODULE_DEVICE_TABLE (usb, usb_dsbr100_table);
132
 
133
static struct usb_driver usb_dsbr100_driver = {
134
        name:           "dsbr100",
135
        probe:          usb_dsbr100_probe,
136
        disconnect:     usb_dsbr100_disconnect,
137
        fops:           NULL,
138
        minor:          0,
139
        id_table:       usb_dsbr100_table,
140
};
141
 
142
 
143
static int dsbr100_start(usb_dsbr100 *radio)
144
{
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)
149
                return -1;
150
        return (radio->transfer_buffer)[0];
151
}
152
 
153
 
154
static int dsbr100_stop(usb_dsbr100 *radio)
155
{
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)
160
                return -1;
161
        return (radio->transfer_buffer)[0];
162
}
163
 
164
 
165
static int dsbr100_setfreq(usb_dsbr100 *radio, int freq)
166
{
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) {
175
                radio->stereo = -1;
176
                return -1;
177
        }
178
        radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
179
        return (radio->transfer_buffer)[0];
180
}
181
 
182
static void dsbr100_getstat(usb_dsbr100 *radio)
183
{
184
        if (usb_control_msg(radio->dev, usb_rcvctrlpipe(radio->dev, 0),
185
                0x00, 0xC0, 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
186
                radio->stereo = -1;
187
        else
188
                radio->stereo = ! (radio->transfer_buffer[0]&0x01);
189
}
190
 
191
 
192
static void *usb_dsbr100_probe(struct usb_device *dev, unsigned int ifnum,
193
                         const struct usb_device_id *id)
194
{
195
        usb_dsbr100 *radio;
196
 
197
        if (!(radio = kmalloc(sizeof(usb_dsbr100), GFP_KERNEL)))
198
                return NULL;
199
        usb_dsbr100_radio.priv = radio;
200
        radio->dev = dev;
201
        radio->ifnum = ifnum;
202
        radio->curfreq = FREQ_MIN*FREQ_MUL;
203
        return (void*)radio;
204
}
205
 
206
static void usb_dsbr100_disconnect(struct usb_device *dev, void *ptr)
207
{
208
        usb_dsbr100 *radio=ptr;
209
 
210
        lock_kernel();
211
        if (users) {
212
                unlock_kernel();
213
                return;
214
        }
215
        kfree(radio);
216
        usb_dsbr100_radio.priv = NULL;
217
        unlock_kernel();
218
}
219
 
220
static int usb_dsbr100_ioctl(struct video_device *dev, unsigned int cmd,
221
        void *arg)
222
{
223
        usb_dsbr100 *radio=dev->priv;
224
 
225
        if (!radio)
226
                return -EINVAL;
227
 
228
        switch(cmd)
229
        {
230
                case VIDIOCGCAP: {
231
                        struct video_capability v;
232
                        v.type=VID_TYPE_TUNER;
233
                        v.channels=1;
234
                        v.audios=1;
235
                        v.maxwidth=0;
236
                        v.maxheight=0;
237
                        v.minwidth=0;
238
                        v.minheight=0;
239
                        strcpy(v.name, "D-Link R-100 USB FM Radio");
240
                        if(copy_to_user(arg, &v, sizeof(v)))
241
                                return -EFAULT;
242
                        return 0;
243
                }
244
                case VIDIOCGTUNER: {
245
                        struct video_tuner v;
246
                        dsbr100_getstat(radio);
247
                        if(copy_from_user(&v, arg, sizeof(v))!=0)
248
                                return -EFAULT;
249
                        if(v.tuner)     /* Only 1 tuner */
250
                                return -EINVAL;
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)))
260
                                return -EFAULT;
261
                        return 0;
262
                }
263
                case VIDIOCSTUNER: {
264
                        struct video_tuner v;
265
                        if(copy_from_user(&v, arg, sizeof(v)))
266
                                return -EFAULT;
267
                        if(v.tuner!=0)
268
                                return -EINVAL;
269
                        /* Only 1 tuner so no setting needed ! */
270
                        return 0;
271
                }
272
                case VIDIOCGFREQ:
273
                        if (radio->curfreq==-1)
274
                                return -EINVAL;
275
                        if(copy_to_user(arg, &(radio->curfreq),
276
                                sizeof(radio->curfreq)))
277
                                return -EFAULT;
278
                        return 0;
279
 
280
                case VIDIOCSFREQ:
281
                        if(copy_from_user(&(radio->curfreq), arg,
282
                                sizeof(radio->curfreq)))
283
                                return -EFAULT;
284
                        if (dsbr100_setfreq(radio, radio->curfreq)==-1)
285
                                warn("set frequency failed");
286
                        return 0;
287
 
288
                case VIDIOCGAUDIO: {
289
                        struct video_audio v;
290
                        memset(&v, 0, sizeof(v));
291
                        v.flags|=VIDEO_AUDIO_MUTABLE;
292
                        v.mode=VIDEO_SOUND_STEREO;
293
                        v.volume=1;
294
                        v.step=1;
295
                        strcpy(v.name, "Radio");
296
                        if(copy_to_user(arg, &v, sizeof(v)))
297
                                return -EFAULT;
298
                        return 0;
299
                }
300
                case VIDIOCSAUDIO: {
301
                        struct video_audio v;
302
                        if(copy_from_user(&v, arg, sizeof(v)))
303
                                return -EFAULT;
304
                        if(v.audio)
305
                                return -EINVAL;
306
 
307
                        if(v.flags&VIDEO_AUDIO_MUTE) {
308
                                if (dsbr100_stop(radio)==-1)
309
                                        warn("radio did not respond properly");
310
                        }
311
                        else
312
                                if (dsbr100_start(radio)==-1)
313
                                        warn("radio did not respond properly");
314
                        return 0;
315
                }
316
                default:
317
                        return -ENOIOCTLCMD;
318
        }
319
}
320
 
321
 
322
static int usb_dsbr100_open(struct video_device *dev, int flags)
323
{
324
        usb_dsbr100 *radio=dev->priv;
325
 
326
        if (! radio) {
327
                warn("radio not initialised");
328
                return -EAGAIN;
329
        }
330
        if(users)
331
        {
332
                warn("radio in use");
333
                return -EBUSY;
334
        }
335
        users++;
336
        MOD_INC_USE_COUNT;
337
        if (dsbr100_start(radio)<0)
338
                warn("radio did not start up properly");
339
        dsbr100_setfreq(radio, radio->curfreq);
340
        return 0;
341
}
342
 
343
static void usb_dsbr100_close(struct video_device *dev)
344
{
345
        usb_dsbr100 *radio=dev->priv;
346
 
347
        if (!radio)
348
                return;
349
        users--;
350
        MOD_DEC_USE_COUNT;
351
}
352
 
353
static int __init dsbr100_init(void)
354
{
355
        usb_dsbr100_radio.priv = NULL;
356
        usb_register(&usb_dsbr100_driver);
357
        if (video_register_device(&usb_dsbr100_radio, VFL_TYPE_RADIO,
358
                radio_nr)==-1) {
359
                warn("couldn't register video device");
360
                return -EINVAL;
361
        }
362
        info(DRIVER_VERSION ":" DRIVER_DESC);
363
        return 0;
364
}
365
 
366
static void __exit dsbr100_exit(void)
367
{
368
        usb_dsbr100 *radio=usb_dsbr100_radio.priv;
369
 
370
        if (radio)
371
                dsbr100_stop(radio);
372
        video_unregister_device(&usb_dsbr100_radio);
373
        usb_deregister(&usb_dsbr100_driver);
374
}
375
 
376
module_init (dsbr100_init);
377
module_exit (dsbr100_exit);
378
 
379
MODULE_AUTHOR( DRIVER_AUTHOR );
380
MODULE_DESCRIPTION( DRIVER_DESC );
381
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.