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
95static 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
119devices, 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
125static int usb_dsbr100_probe(struct usb_interface *intf,
126			     const struct usb_device_id *id);
127static void usb_dsbr100_disconnect(struct usb_interface *intf);
128static int usb_dsbr100_open(struct inode *inode, struct file *file);
129static int usb_dsbr100_close(struct inode *inode, struct file *file);
130
131static int radio_nr = -1;
132module_param(radio_nr, int, 0);
133
134/* Data for one (physical) device */
135struct 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
147static struct usb_device_id usb_dsbr100_device_table [] = {
148	{ USB_DEVICE(DSB100_VENDOR, DSB100_PRODUCT) },
149	{ }						/* Terminating entry */
150};
151
152MODULE_DEVICE_TABLE (usb, usb_dsbr100_device_table);
153
154/* USB subsystem interface */
155static 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 */
165static 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 */
182static 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 */
198static 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
222sees a stereo signal or not.  Pity. */
223static 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
238if nothing keeps us from doing it.  If something is still
239keeping us busy, the release callback of v4l will take care
240of releasing it.  stv680.c does not relase its private
241data, so I don't do this here either.  Checking out the
242code I'd expect I better did that, but if there's a memory
243leak here it's tiny (~50 bytes per disconnect) */
244static 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
261static 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
272static 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
295static 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
304static 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
315static 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
325static 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
340static 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
353static 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
372static 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
383static int vidioc_g_input(struct file *filp, void *priv, unsigned int *i)
384{
385	*i = 0;
386	return 0;
387}
388
389static 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
396static 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
404static 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
420static 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 */
434static 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 */
444static 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
466usb if it is */
467static 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
495static 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
502static void __exit dsbr100_exit(void)
503{
504	usb_deregister(&usb_dsbr100_driver);
505}
506
507module_init (dsbr100_init);
508module_exit (dsbr100_exit);
509
510MODULE_AUTHOR( DRIVER_AUTHOR );
511MODULE_DESCRIPTION( DRIVER_DESC );
512MODULE_LICENSE("GPL");
513