xref: /openbmc/linux/drivers/media/radio/dsbr100.c (revision 96de0e252cedffad61b3cb5e05662c591898e69a)
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.
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");
513