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