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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [drivers/] [media/] [radio/] [dsbr100.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/* 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@cl.uni-heidelberg.de>
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.42:
37
        Converted dsbr100 to use video_ioctl2
38
        by Douglas Landgraf <dougsland@gmail.com>
39
 
40
 Version 0.41-ac1:
41
        Alan Cox: Some cleanups and fixes
42
 
43
 Version 0.41:
44
        Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
45
 
46
 Version 0.40:
47
        Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
48
 
49
 Version 0.30:
50
        Markus: Updates for 2.5.x kernel and more ISO compliant source
51
 
52
 Version 0.25:
53
        PSL and Markus: Cleanup, radio now doesn't stop on device close
54
 
55
 Version 0.24:
56
        Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
57
        right.  Some minor cleanup, improved standalone compilation
58
 
59
 Version 0.23:
60
        Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
61
 
62
 Version 0.22:
63
        Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
64
        thanks to Mike Cox for pointing the problem out.
65
 
66
 Version 0.21:
67
        Markus: Minor cleanup, warnings if something goes wrong, lame attempt
68
        to adhere to Documentation/CodingStyle
69
 
70
 Version 0.2:
71
        Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
72
        Markus: Copyright clarification
73
 
74
 Version 0.01: Markus: initial release
75
 
76
*/
77
 
78
#include <linux/kernel.h>
79
#include <linux/module.h>
80
#include <linux/init.h>
81
#include <linux/slab.h>
82
#include <linux/input.h>
83
#include <linux/videodev2.h>
84
#include <media/v4l2-common.h>
85
#include <linux/usb.h>
86
 
87
/*
88
 * Version Information
89
 */
90
#include <linux/version.h>      /* for KERNEL_VERSION MACRO     */
91
 
92
#define DRIVER_VERSION "v0.41"
93
#define RADIO_VERSION KERNEL_VERSION(0,4,1)
94
 
95
static struct v4l2_queryctrl radio_qctrl[] = {
96
        {
97
                .id            = V4L2_CID_AUDIO_MUTE,
98
                .name          = "Mute",
99
                .minimum       = 0,
100
                .maximum       = 1,
101
                .default_value = 1,
102
                .type          = V4L2_CTRL_TYPE_BOOLEAN,
103
        }
104
};
105
 
106
#define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
107
#define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
108
 
109
#define DSB100_VENDOR 0x04b4
110
#define DSB100_PRODUCT 0x1002
111
 
112
/* Commands the device appears to understand */
113
#define DSB100_TUNE 1
114
#define DSB100_ONOFF 2
115
 
116
#define TB_LEN 16
117
 
118
/* Frequency limits in MHz -- these are European values.  For Japanese
119
devices, that would be 76 and 91.  */
120
#define FREQ_MIN  87.5
121
#define FREQ_MAX 108.0
122
#define FREQ_MUL 16000
123
 
124
 
125
static int usb_dsbr100_probe(struct usb_interface *intf,
126
                             const struct usb_device_id *id);
127
static void usb_dsbr100_disconnect(struct usb_interface *intf);
128
static int usb_dsbr100_open(struct inode *inode, struct file *file);
129
static int usb_dsbr100_close(struct inode *inode, struct file *file);
130
 
131
static int radio_nr = -1;
132
module_param(radio_nr, int, 0);
133
 
134
/* Data for one (physical) device */
135
struct dsbr100_device {
136
        struct usb_device *usbdev;
137
        struct video_device *videodev;
138
        unsigned char transfer_buffer[TB_LEN];
139
        int curfreq;
140
        int stereo;
141
        int users;
142
        int removed;
143
        int muted;
144
};
145
 
146
 
147
static struct usb_device_id usb_dsbr100_device_table [] = {
148
        { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
149
        { }                                             /* Terminating entry */
150
};
151
 
152
MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
153
 
154
/* USB subsystem interface */
155
static struct usb_driver usb_dsbr100_driver = {
156
        .name =         "dsbr100",
157
        .probe =        usb_dsbr100_probe,
158
        .disconnect =   usb_dsbr100_disconnect,
159
        .id_table =     usb_dsbr100_device_table,
160
};
161
 
162
/* Low-level device interface begins here */
163
 
164
/* switch on radio */
165
static int dsbr100_start(struct dsbr100_device *radio)
166
{
167
        if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
168
                        USB_REQ_GET_STATUS,
169
                        USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
170
                        0x00, 0xC7, radio->transfer_buffer, 8, 300)<0 ||
171
        usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
172
                        DSB100_ONOFF,
173
                        USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
174
                        0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
175
                return -1;
176
        radio->muted=0;
177
        return (radio->transfer_buffer)[0];
178
}
179
 
180
 
181
/* switch off radio */
182
static int dsbr100_stop(struct dsbr100_device *radio)
183
{
184
        if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
185
                        USB_REQ_GET_STATUS,
186
                        USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
187
                        0x16, 0x1C, radio->transfer_buffer, 8, 300)<0 ||
188
        usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
189
                        DSB100_ONOFF,
190
                        USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
191
                        0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
192
                return -1;
193
        radio->muted=1;
194
        return (radio->transfer_buffer)[0];
195
}
196
 
197
/* set a frequency, freq is defined by v4l's TUNER_LOW, i.e. 1/16th kHz */
198
static int dsbr100_setfreq(struct dsbr100_device *radio, int freq)
199
{
200
        freq = (freq/16*80)/1000+856;
201
        if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
202
                        DSB100_TUNE,
203
                        USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
204
                        (freq>>8)&0x00ff, freq&0xff,
205
                        radio->transfer_buffer, 8, 300)<0 ||
206
           usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
207
                        USB_REQ_GET_STATUS,
208
                        USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
209
                        0x96, 0xB7, radio->transfer_buffer, 8, 300)<0 ||
210
        usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
211
                        USB_REQ_GET_STATUS,
212
                        USB_TYPE_VENDOR | USB_RECIP_DEVICE |  USB_DIR_IN,
213
                        0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
214
                radio->stereo = -1;
215
                return -1;
216
        }
217
        radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
218
        return (radio->transfer_buffer)[0];
219
}
220
 
221
/* return the device status.  This is, in effect, just whether it
222
sees a stereo signal or not.  Pity. */
223
static void dsbr100_getstat(struct dsbr100_device *radio)
224
{
225
        if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
226
                USB_REQ_GET_STATUS,
227
                USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
228
                0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
229
                radio->stereo = -1;
230
        else
231
                radio->stereo = ! (radio->transfer_buffer[0]&0x01);
232
}
233
 
234
 
235
/* USB subsystem interface begins here */
236
 
237
/* handle unplugging of the device, release data structures
238
if nothing keeps us from doing it.  If something is still
239
keeping us busy, the release callback of v4l will take care
240
of releasing it.  stv680.c does not relase its private
241
data, so I don't do this here either.  Checking out the
242
code I'd expect I better did that, but if there's a memory
243
leak here it's tiny (~50 bytes per disconnect) */
244
static void usb_dsbr100_disconnect(struct usb_interface *intf)
245
{
246
        struct dsbr100_device *radio = usb_get_intfdata(intf);
247
 
248
        usb_set_intfdata (intf, NULL);
249
        if (radio) {
250
                video_unregister_device(radio->videodev);
251
                radio->videodev = NULL;
252
                if (radio->users) {
253
                        kfree(radio);
254
                } else {
255
                        radio->removed = 1;
256
                }
257
        }
258
}
259
 
260
 
261
static int vidioc_querycap(struct file *file, void *priv,
262
                                        struct v4l2_capability *v)
263
{
264
        strlcpy(v->driver, "dsbr100", sizeof(v->driver));
265
        strlcpy(v->card, "D-Link R-100 USB FM Radio", sizeof(v->card));
266
        sprintf(v->bus_info, "ISA");
267
        v->version = RADIO_VERSION;
268
        v->capabilities = V4L2_CAP_TUNER;
269
        return 0;
270
}
271
 
272
static int vidioc_g_tuner(struct file *file, void *priv,
273
                                struct v4l2_tuner *v)
274
{
275
        struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
276
 
277
        if (v->index > 0)
278
                return -EINVAL;
279
 
280
        dsbr100_getstat(radio);
281
        strcpy(v->name, "FM");
282
        v->type = V4L2_TUNER_RADIO;
283
        v->rangelow = FREQ_MIN*FREQ_MUL;
284
        v->rangehigh = FREQ_MAX*FREQ_MUL;
285
        v->rxsubchans = V4L2_TUNER_SUB_MONO|V4L2_TUNER_SUB_STEREO;
286
        v->capability = V4L2_TUNER_CAP_LOW;
287
        if(radio->stereo)
288
                v->audmode = V4L2_TUNER_MODE_STEREO;
289
        else
290
                v->audmode = V4L2_TUNER_MODE_MONO;
291
        v->signal = 0xffff;     /* We can't get the signal strength */
292
        return 0;
293
}
294
 
295
static int vidioc_s_tuner(struct file *file, void *priv,
296
                                struct v4l2_tuner *v)
297
{
298
        if (v->index > 0)
299
                return -EINVAL;
300
 
301
        return 0;
302
}
303
 
304
static int vidioc_s_frequency(struct file *file, void *priv,
305
                                struct v4l2_frequency *f)
306
{
307
        struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
308
 
309
        radio->curfreq = f->frequency;
310
        if (dsbr100_setfreq(radio, radio->curfreq)==-1)
311
                warn("Set frequency failed");
312
        return 0;
313
}
314
 
315
static int vidioc_g_frequency(struct file *file, void *priv,
316
                                struct v4l2_frequency *f)
317
{
318
        struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
319
 
320
        f->type = V4L2_TUNER_RADIO;
321
        f->frequency = radio->curfreq;
322
        return 0;
323
}
324
 
325
static int vidioc_queryctrl(struct file *file, void *priv,
326
                                struct v4l2_queryctrl *qc)
327
{
328
        int i;
329
 
330
        for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
331
                if (qc->id && qc->id == radio_qctrl[i].id) {
332
                        memcpy(qc, &(radio_qctrl[i]),
333
                                                sizeof(*qc));
334
                        return 0;
335
                }
336
        }
337
        return -EINVAL;
338
}
339
 
340
static int vidioc_g_ctrl(struct file *file, void *priv,
341
                                struct v4l2_control *ctrl)
342
{
343
        struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
344
 
345
        switch (ctrl->id) {
346
        case V4L2_CID_AUDIO_MUTE:
347
                ctrl->value = radio->muted;
348
                return 0;
349
        }
350
        return -EINVAL;
351
}
352
 
353
static int vidioc_s_ctrl(struct file *file, void *priv,
354
                                struct v4l2_control *ctrl)
355
{
356
        struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
357
 
358
        switch (ctrl->id) {
359
        case V4L2_CID_AUDIO_MUTE:
360
                if (ctrl->value) {
361
                        if (dsbr100_stop(radio)==-1)
362
                                warn("Radio did not respond properly");
363
                } else {
364
                        if (dsbr100_start(radio)==-1)
365
                                warn("Radio did not respond properly");
366
                }
367
                return 0;
368
        }
369
        return -EINVAL;
370
}
371
 
372
static int vidioc_g_audio(struct file *file, void *priv,
373
                                struct v4l2_audio *a)
374
{
375
        if (a->index > 1)
376
                return -EINVAL;
377
 
378
        strcpy(a->name, "Radio");
379
        a->capability = V4L2_AUDCAP_STEREO;
380
        return 0;
381
}
382
 
383
static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
384
{
385
        *i = 0;
386
        return 0;
387
}
388
 
389
static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
390
{
391
        if (i != 0)
392
                return -EINVAL;
393
        return 0;
394
}
395
 
396
static int vidioc_s_audio(struct file *file, void *priv,
397
                                        struct v4l2_audio *a)
398
{
399
        if (a->index != 0)
400
                return -EINVAL;
401
        return 0;
402
}
403
 
404
static int usb_dsbr100_open(struct inode *inode, struct file *file)
405
{
406
        struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
407
 
408
        radio->users = 1;
409
        radio->muted = 1;
410
 
411
        if (dsbr100_start(radio)<0) {
412
                warn("Radio did not start up properly");
413
                radio->users = 0;
414
                return -EIO;
415
        }
416
        dsbr100_setfreq(radio, radio->curfreq);
417
        return 0;
418
}
419
 
420
static int usb_dsbr100_close(struct inode *inode, struct file *file)
421
{
422
        struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
423
 
424
        if (!radio)
425
                return -ENODEV;
426
        radio->users = 0;
427
        if (radio->removed) {
428
                kfree(radio);
429
        }
430
        return 0;
431
}
432
 
433
/* File system interface */
434
static const struct file_operations usb_dsbr100_fops = {
435
        .owner          = THIS_MODULE,
436
        .open           = usb_dsbr100_open,
437
        .release        = usb_dsbr100_close,
438
        .ioctl          = video_ioctl2,
439
        .compat_ioctl   = v4l_compat_ioctl32,
440
        .llseek         = no_llseek,
441
};
442
 
443
/* V4L2 interface */
444
static struct video_device dsbr100_videodev_template =
445
{
446
        .owner          = THIS_MODULE,
447
        .name           = "D-Link DSB-R 100",
448
        .type           = VID_TYPE_TUNER,
449
        .fops           = &usb_dsbr100_fops,
450
        .release        = video_device_release,
451
        .vidioc_querycap    = vidioc_querycap,
452
        .vidioc_g_tuner     = vidioc_g_tuner,
453
        .vidioc_s_tuner     = vidioc_s_tuner,
454
        .vidioc_g_frequency = vidioc_g_frequency,
455
        .vidioc_s_frequency = vidioc_s_frequency,
456
        .vidioc_queryctrl   = vidioc_queryctrl,
457
        .vidioc_g_ctrl      = vidioc_g_ctrl,
458
        .vidioc_s_ctrl      = vidioc_s_ctrl,
459
        .vidioc_g_audio     = vidioc_g_audio,
460
        .vidioc_s_audio     = vidioc_s_audio,
461
        .vidioc_g_input     = vidioc_g_input,
462
        .vidioc_s_input     = vidioc_s_input,
463
};
464
 
465
/* check if the device is present and register with v4l and
466
usb if it is */
467
static int usb_dsbr100_probe(struct usb_interface *intf,
468
                                const struct usb_device_id *id)
469
{
470
        struct dsbr100_device *radio;
471
 
472
        if (!(radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL)))
473
                return -ENOMEM;
474
        if (!(radio->videodev = video_device_alloc())) {
475
                kfree(radio);
476
                return -ENOMEM;
477
        }
478
        memcpy(radio->videodev, &dsbr100_videodev_template,
479
                sizeof(dsbr100_videodev_template));
480
        radio->removed = 0;
481
        radio->users = 0;
482
        radio->usbdev = interface_to_usbdev(intf);
483
        radio->curfreq = FREQ_MIN*FREQ_MUL;
484
        video_set_drvdata(radio->videodev, radio);
485
        if (video_register_device(radio->videodev, VFL_TYPE_RADIO,radio_nr)) {
486
                warn("Could not register video device");
487
                video_device_release(radio->videodev);
488
                kfree(radio);
489
                return -EIO;
490
        }
491
        usb_set_intfdata(intf, radio);
492
        return 0;
493
}
494
 
495
static int __init dsbr100_init(void)
496
{
497
        int retval = usb_register(&usb_dsbr100_driver);
498
        info(DRIVER_VERSION ":" DRIVER_DESC);
499
        return retval;
500
}
501
 
502
static void __exit dsbr100_exit(void)
503
{
504
        usb_deregister(&usb_dsbr100_driver);
505
}
506
 
507
module_init (dsbr100_init);
508
module_exit (dsbr100_exit);
509
 
510
MODULE_AUTHOR( DRIVER_AUTHOR );
511
MODULE_DESCRIPTION( DRIVER_DESC );
512
MODULE_LICENSE("GPL");

powered by: WebSVN 2.1.0

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