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@cl.uni-heidelberg.de>
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
37 Converted dsbr100 to use video_ioctl2
38 by Douglas Landgraf <dougsland@gmail.com>
41 Alan Cox: Some cleanups and fixes
44 Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
47 Markus: Updates for 2.6.x kernels, code layout changes, name sanitizing
50 Markus: Updates for 2.5.x kernel and more ISO compliant source
53 PSL and Markus: Cleanup, radio now doesn't stop on device close
56 Markus: Hope I got these silly VIDEO_TUNER_LOW issues finally
57 right. Some minor cleanup, improved standalone compilation
60 Markus: Sign extension bug fixed by declaring transfer_buffer unsigned
63 Markus: Some (brown bag) cleanup in what VIDIOCSTUNER returns,
64 thanks to Mike Cox for pointing the problem out.
67 Markus: Minor cleanup, warnings if something goes wrong, lame attempt
68 to adhere to Documentation/CodingStyle
71 Brad Hards <bradh@dynamite.com.au>: Fixes to make it work as non-module
72 Markus: Copyright clarification
74 Version 0.01: Markus: initial release
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>
90 #include <linux/version.h> /* for KERNEL_VERSION MACRO */
92 #define DRIVER_VERSION "v0.41"
93 #define RADIO_VERSION KERNEL_VERSION(0,4,1)
95 static struct v4l2_queryctrl radio_qctrl[] = {
97 .id = V4L2_CID_AUDIO_MUTE,
102 .type = V4L2_CTRL_TYPE_BOOLEAN,
106 #define DRIVER_AUTHOR "Markus Demleitner <msdemlei@tucana.harvard.edu>"
107 #define DRIVER_DESC "D-Link DSB-R100 USB FM radio driver"
109 #define DSB100_VENDOR 0x04b4
110 #define DSB100_PRODUCT 0x1002
112 /* Commands the device appears to understand */
113 #define DSB100_TUNE 1
114 #define DSB100_ONOFF 2
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
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);
131 static int radio_nr = -1;
132 module_param(radio_nr, int, 0);
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];
147 static struct usb_device_id usb_dsbr100_device_table [] = {
148 { USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
149 { } /* Terminating entry */
152 MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
154 /* USB subsystem interface */
155 static struct usb_driver usb_dsbr100_driver = {
157 .probe = usb_dsbr100_probe,
158 .disconnect = usb_dsbr100_disconnect,
159 .id_table = usb_dsbr100_device_table,
162 /* Low-level device interface begins here */
164 /* switch on radio */
165 static int dsbr100_start(struct dsbr100_device *radio)
167 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
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),
173 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
174 0x01, 0x00, radio->transfer_buffer, 8, 300)<0)
177 return (radio->transfer_buffer)[0];
181 /* switch off radio */
182 static int dsbr100_stop(struct dsbr100_device *radio)
184 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
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),
190 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
191 0x00, 0x00, radio->transfer_buffer, 8, 300)<0)
194 return (radio->transfer_buffer)[0];
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)
200 freq = (freq/16*80)/1000+856;
201 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
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),
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),
212 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
213 0x00, 0x24, radio->transfer_buffer, 8, 300)<0) {
217 radio->stereo = ! ((radio->transfer_buffer)[0]&0x01);
218 return (radio->transfer_buffer)[0];
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)
225 if (usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
227 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
228 0x00 , 0x24, radio->transfer_buffer, 8, 300)<0)
231 radio->stereo = ! (radio->transfer_buffer[0]&0x01);
235 /* USB subsystem interface begins here */
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)
246 struct dsbr100_device *radio = usb_get_intfdata(intf);
248 usb_set_intfdata (intf, NULL);
250 video_unregister_device(radio->videodev);
251 radio->videodev = NULL;
261 static int vidioc_querycap(struct file *file, void *priv,
262 struct v4l2_capability *v)
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;
272 static int vidioc_g_tuner(struct file *file, void *priv,
273 struct v4l2_tuner *v)
275 struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
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;
288 v->audmode = V4L2_TUNER_MODE_STEREO;
290 v->audmode = V4L2_TUNER_MODE_MONO;
291 v->signal = 0xffff; /* We can't get the signal strength */
295 static int vidioc_s_tuner(struct file *file, void *priv,
296 struct v4l2_tuner *v)
304 static int vidioc_s_frequency(struct file *file, void *priv,
305 struct v4l2_frequency *f)
307 struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
309 radio->curfreq = f->frequency;
310 if (dsbr100_setfreq(radio, radio->curfreq)==-1)
311 warn("Set frequency failed");
315 static int vidioc_g_frequency(struct file *file, void *priv,
316 struct v4l2_frequency *f)
318 struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
320 f->type = V4L2_TUNER_RADIO;
321 f->frequency = radio->curfreq;
325 static int vidioc_queryctrl(struct file *file, void *priv,
326 struct v4l2_queryctrl *qc)
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]),
340 static int vidioc_g_ctrl(struct file *file, void *priv,
341 struct v4l2_control *ctrl)
343 struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
346 case V4L2_CID_AUDIO_MUTE:
347 ctrl->value = radio->muted;
353 static int vidioc_s_ctrl(struct file *file, void *priv,
354 struct v4l2_control *ctrl)
356 struct dsbr100_device *radio = video_get_drvdata(video_devdata(file));
359 case V4L2_CID_AUDIO_MUTE:
361 if (dsbr100_stop(radio)==-1)
362 warn("Radio did not respond properly");
364 if (dsbr100_start(radio)==-1)
365 warn("Radio did not respond properly");
372 static int vidioc_g_audio(struct file *file, void *priv,
373 struct v4l2_audio *a)
378 strcpy(a->name, "Radio");
379 a->capability = V4L2_AUDCAP_STEREO;
383 static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
389 static int vidioc_s_input(struct file *filp, void *priv, unsigned int i)
396 static int vidioc_s_audio(struct file *file, void *priv,
397 struct v4l2_audio *a)
404 static int usb_dsbr100_open(struct inode *inode, struct file *file)
406 struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
411 if (dsbr100_start(radio)<0) {
412 warn("Radio did not start up properly");
416 dsbr100_setfreq(radio, radio->curfreq);
420 static int usb_dsbr100_close(struct inode *inode, struct file *file)
422 struct dsbr100_device *radio=video_get_drvdata(video_devdata(file));
427 if (radio->removed) {
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,
444 static struct video_device dsbr100_videodev_template =
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,
465 /* check if the device is present and register with v4l and
467 static int usb_dsbr100_probe(struct usb_interface *intf,
468 const struct usb_device_id *id)
470 struct dsbr100_device *radio;
472 if (!(radio = kmalloc(sizeof(struct dsbr100_device), GFP_KERNEL)))
474 if (!(radio->videodev = video_device_alloc())) {
478 memcpy(radio->videodev, &dsbr100_videodev_template,
479 sizeof(dsbr100_videodev_template));
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);
491 usb_set_intfdata(intf, radio);
495 static int __init dsbr100_init(void)
497 int retval = usb_register(&usb_dsbr100_driver);
498 info(DRIVER_VERSION ":" DRIVER_DESC);
502 static void __exit dsbr100_exit(void)
504 usb_deregister(&usb_dsbr100_driver);
507 module_init (dsbr100_init);
508 module_exit (dsbr100_exit);
510 MODULE_AUTHOR( DRIVER_AUTHOR );
511 MODULE_DESCRIPTION( DRIVER_DESC );
512 MODULE_LICENSE("GPL");