1/*
2 * Copyright 2013 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
3 *
4 * This program is free software; you may redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; version 2 of the License.
7 *
8 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
9 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
10 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
11 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
12 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
13 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
14 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
15 * SOFTWARE.
16 */
17
18#include <linux/kernel.h>
19#include <linux/module.h>
20#include <linux/init.h>
21#include <linux/slab.h>
22#include <linux/input.h>
23#include <linux/usb.h>
24#include <linux/hid.h>
25#include <linux/mutex.h>
26#include <linux/videodev2.h>
27#include <asm/unaligned.h>
28#include <media/v4l2-device.h>
29#include <media/v4l2-ioctl.h>
30#include <media/v4l2-ctrls.h>
31#include <media/v4l2-event.h>
32
33/*
34 * 'Thanko's Raremono' is a Japanese si4734-based AM/FM/SW USB receiver:
35 *
36 * http://www.raremono.jp/product/484.html/
37 *
38 * The USB protocol has been reversed engineered using wireshark, initially
39 * by Dinesh Ram <dinesh.ram@cern.ch> and finished by Hans Verkuil
40 * <hverkuil@xs4all.nl>.
41 *
42 * Sadly the firmware used in this product hides lots of goodies since the
43 * si4734 has more features than are supported by the firmware. Oh well...
44 */
45
46/* driver and module definitions */
47MODULE_AUTHOR("Hans Verkuil <hverkuil@xs4all.nl>");
48MODULE_DESCRIPTION("Thanko's Raremono AM/FM/SW Receiver USB driver");
49MODULE_LICENSE("GPL v2");
50
51/*
52 * The Device announces itself as Cygnal Integrated Products, Inc.
53 *
54 * The vendor and product IDs (and in fact all other lsusb information as
55 * well) are identical to the si470x Silicon Labs USB FM Radio Reference
56 * Design board, even though this card has a si4734 device. Clearly the
57 * designer of this product never bothered to change the USB IDs.
58 */
59
60/* USB Device ID List */
61static struct usb_device_id usb_raremono_device_table[] = {
62	{USB_DEVICE_AND_INTERFACE_INFO(0x10c4, 0x818a, USB_CLASS_HID, 0, 0) },
63	{ }						/* Terminating entry */
64};
65
66MODULE_DEVICE_TABLE(usb, usb_raremono_device_table);
67
68#define BUFFER_LENGTH 64
69
70/* Timeout is set to a high value, could probably be reduced. Need more tests */
71#define USB_TIMEOUT 10000
72
73/* Frequency limits in KHz */
74#define FM_FREQ_RANGE_LOW	64000
75#define FM_FREQ_RANGE_HIGH	108000
76
77#define AM_FREQ_RANGE_LOW	520
78#define AM_FREQ_RANGE_HIGH	1710
79
80#define SW_FREQ_RANGE_LOW	2300
81#define SW_FREQ_RANGE_HIGH	26100
82
83enum { BAND_FM, BAND_AM, BAND_SW };
84
85static const struct v4l2_frequency_band bands[] = {
86	/* Band FM */
87	{
88		.type = V4L2_TUNER_RADIO,
89		.index = 0,
90		.capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
91			      V4L2_TUNER_CAP_FREQ_BANDS,
92		.rangelow   = FM_FREQ_RANGE_LOW * 16,
93		.rangehigh  = FM_FREQ_RANGE_HIGH * 16,
94		.modulation = V4L2_BAND_MODULATION_FM,
95	},
96	/* Band AM */
97	{
98		.type = V4L2_TUNER_RADIO,
99		.index = 1,
100		.capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
101		.rangelow   = AM_FREQ_RANGE_LOW * 16,
102		.rangehigh  = AM_FREQ_RANGE_HIGH * 16,
103		.modulation = V4L2_BAND_MODULATION_AM,
104	},
105	/* Band SW */
106	{
107		.type = V4L2_TUNER_RADIO,
108		.index = 2,
109		.capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_FREQ_BANDS,
110		.rangelow   = SW_FREQ_RANGE_LOW * 16,
111		.rangehigh  = SW_FREQ_RANGE_HIGH * 16,
112		.modulation = V4L2_BAND_MODULATION_AM,
113	},
114};
115
116struct raremono_device {
117	struct usb_device *usbdev;
118	struct usb_interface *intf;
119	struct video_device vdev;
120	struct v4l2_device v4l2_dev;
121	struct mutex lock;
122
123	u8 *buffer;
124	u32 band;
125	unsigned curfreq;
126};
127
128static inline struct raremono_device *to_raremono_dev(struct v4l2_device *v4l2_dev)
129{
130	return container_of(v4l2_dev, struct raremono_device, v4l2_dev);
131}
132
133/* Set frequency. */
134static int raremono_cmd_main(struct raremono_device *radio, unsigned band, unsigned freq)
135{
136	unsigned band_offset;
137	int ret;
138
139	switch (band) {
140	case BAND_FM:
141		band_offset = 1;
142		freq /= 10;
143		break;
144	case BAND_AM:
145		band_offset = 0;
146		break;
147	default:
148		band_offset = 2;
149		break;
150	}
151	radio->buffer[0] = 0x04 + band_offset;
152	radio->buffer[1] = freq >> 8;
153	radio->buffer[2] = freq & 0xff;
154
155	ret = usb_control_msg(radio->usbdev, usb_sndctrlpipe(radio->usbdev, 0),
156			HID_REQ_SET_REPORT,
157			USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
158			0x0300 + radio->buffer[0], 2,
159			radio->buffer, 3, USB_TIMEOUT);
160
161	if (ret < 0) {
162		dev_warn(radio->v4l2_dev.dev, "%s failed (%d)\n", __func__, ret);
163		return ret;
164	}
165	radio->curfreq = (band == BAND_FM) ? freq * 10 : freq;
166	return 0;
167}
168
169/* Handle unplugging the device.
170 * We call video_unregister_device in any case.
171 * The last function called in this procedure is
172 * usb_raremono_device_release.
173 */
174static void usb_raremono_disconnect(struct usb_interface *intf)
175{
176	struct raremono_device *radio = to_raremono_dev(usb_get_intfdata(intf));
177
178	dev_info(&intf->dev, "Thanko's Raremono disconnected\n");
179
180	mutex_lock(&radio->lock);
181	usb_set_intfdata(intf, NULL);
182	video_unregister_device(&radio->vdev);
183	v4l2_device_disconnect(&radio->v4l2_dev);
184	mutex_unlock(&radio->lock);
185	v4l2_device_put(&radio->v4l2_dev);
186}
187
188/*
189 * Linux Video interface
190 */
191static int vidioc_querycap(struct file *file, void *priv,
192					struct v4l2_capability *v)
193{
194	struct raremono_device *radio = video_drvdata(file);
195
196	strlcpy(v->driver, "radio-raremono", sizeof(v->driver));
197	strlcpy(v->card, "Thanko's Raremono", sizeof(v->card));
198	usb_make_path(radio->usbdev, v->bus_info, sizeof(v->bus_info));
199	v->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO;
200	v->capabilities = v->device_caps | V4L2_CAP_DEVICE_CAPS;
201	return 0;
202}
203
204static int vidioc_enum_freq_bands(struct file *file, void *priv,
205		struct v4l2_frequency_band *band)
206{
207	if (band->tuner != 0)
208		return -EINVAL;
209
210	if (band->index >= ARRAY_SIZE(bands))
211		return -EINVAL;
212
213	*band = bands[band->index];
214
215	return 0;
216}
217
218static int vidioc_g_tuner(struct file *file, void *priv,
219		struct v4l2_tuner *v)
220{
221	struct raremono_device *radio = video_drvdata(file);
222	int ret;
223
224	if (v->index > 0)
225		return -EINVAL;
226
227	strlcpy(v->name, "AM/FM/SW", sizeof(v->name));
228	v->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
229		V4L2_TUNER_CAP_FREQ_BANDS;
230	v->rangelow = AM_FREQ_RANGE_LOW * 16;
231	v->rangehigh = FM_FREQ_RANGE_HIGH * 16;
232	v->rxsubchans = V4L2_TUNER_SUB_STEREO | V4L2_TUNER_SUB_MONO;
233	v->audmode = (radio->curfreq < FM_FREQ_RANGE_LOW) ?
234		V4L2_TUNER_MODE_MONO : V4L2_TUNER_MODE_STEREO;
235	memset(radio->buffer, 1, BUFFER_LENGTH);
236	ret = usb_control_msg(radio->usbdev, usb_rcvctrlpipe(radio->usbdev, 0),
237			1, 0xa1, 0x030d, 2, radio->buffer, BUFFER_LENGTH, USB_TIMEOUT);
238
239	if (ret < 0) {
240		dev_warn(radio->v4l2_dev.dev, "%s failed (%d)\n", __func__, ret);
241		return ret;
242	}
243	v->signal = ((radio->buffer[1] & 0xf) << 8 | radio->buffer[2]) << 4;
244	return 0;
245}
246
247static int vidioc_s_tuner(struct file *file, void *priv,
248					const struct v4l2_tuner *v)
249{
250	return v->index ? -EINVAL : 0;
251}
252
253static int vidioc_s_frequency(struct file *file, void *priv,
254				const struct v4l2_frequency *f)
255{
256	struct raremono_device *radio = video_drvdata(file);
257	u32 freq = f->frequency;
258	unsigned band;
259
260	if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
261		return -EINVAL;
262
263	if (f->frequency >= (FM_FREQ_RANGE_LOW + SW_FREQ_RANGE_HIGH) * 8)
264		band = BAND_FM;
265	else if (f->frequency <= (AM_FREQ_RANGE_HIGH + SW_FREQ_RANGE_LOW) * 8)
266		band = BAND_AM;
267	else
268		band = BAND_SW;
269
270	freq = clamp_t(u32, f->frequency, bands[band].rangelow, bands[band].rangehigh);
271	return raremono_cmd_main(radio, band, freq / 16);
272}
273
274static int vidioc_g_frequency(struct file *file, void *priv,
275				struct v4l2_frequency *f)
276{
277	struct raremono_device *radio = video_drvdata(file);
278
279	if (f->tuner != 0)
280		return -EINVAL;
281	f->type = V4L2_TUNER_RADIO;
282	f->frequency = radio->curfreq * 16;
283	return 0;
284}
285
286/* File system interface */
287static const struct v4l2_file_operations usb_raremono_fops = {
288	.owner		= THIS_MODULE,
289	.open           = v4l2_fh_open,
290	.release        = v4l2_fh_release,
291	.unlocked_ioctl	= video_ioctl2,
292};
293
294static const struct v4l2_ioctl_ops usb_raremono_ioctl_ops = {
295	.vidioc_querycap = vidioc_querycap,
296	.vidioc_g_tuner = vidioc_g_tuner,
297	.vidioc_s_tuner = vidioc_s_tuner,
298	.vidioc_g_frequency = vidioc_g_frequency,
299	.vidioc_s_frequency = vidioc_s_frequency,
300	.vidioc_enum_freq_bands = vidioc_enum_freq_bands,
301};
302
303/* check if the device is present and register with v4l and usb if it is */
304static int usb_raremono_probe(struct usb_interface *intf,
305				const struct usb_device_id *id)
306{
307	struct raremono_device *radio;
308	int retval = 0;
309
310	radio = devm_kzalloc(&intf->dev, sizeof(struct raremono_device), GFP_KERNEL);
311	if (radio)
312		radio->buffer = devm_kmalloc(&intf->dev, BUFFER_LENGTH, GFP_KERNEL);
313
314	if (!radio || !radio->buffer)
315		return -ENOMEM;
316
317	radio->usbdev = interface_to_usbdev(intf);
318	radio->intf = intf;
319
320	/*
321	 * This device uses the same USB IDs as the si470x SiLabs reference
322	 * design. So do an additional check: attempt to read the device ID
323	 * from the si470x: the lower 12 bits are 0x0242 for the si470x. The
324	 * Raremono always returns 0x0800 (the meaning of that is unknown, but
325	 * at least it works).
326	 *
327	 * We use this check to determine which device we are dealing with.
328	 */
329	msleep(20);
330	retval = usb_control_msg(radio->usbdev,
331		usb_rcvctrlpipe(radio->usbdev, 0),
332		HID_REQ_GET_REPORT,
333		USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
334		1, 2,
335		radio->buffer, 3, 500);
336	if (retval != 3 ||
337	    (get_unaligned_be16(&radio->buffer[1]) & 0xfff) == 0x0242) {
338		dev_info(&intf->dev, "this is not Thanko's Raremono.\n");
339		return -ENODEV;
340	}
341
342	dev_info(&intf->dev, "Thanko's Raremono connected: (%04X:%04X)\n",
343			id->idVendor, id->idProduct);
344
345	retval = v4l2_device_register(&intf->dev, &radio->v4l2_dev);
346	if (retval < 0) {
347		dev_err(&intf->dev, "couldn't register v4l2_device\n");
348		return retval;
349	}
350
351	mutex_init(&radio->lock);
352
353	strlcpy(radio->vdev.name, radio->v4l2_dev.name,
354		sizeof(radio->vdev.name));
355	radio->vdev.v4l2_dev = &radio->v4l2_dev;
356	radio->vdev.fops = &usb_raremono_fops;
357	radio->vdev.ioctl_ops = &usb_raremono_ioctl_ops;
358	radio->vdev.lock = &radio->lock;
359	radio->vdev.release = video_device_release_empty;
360
361	usb_set_intfdata(intf, &radio->v4l2_dev);
362
363	video_set_drvdata(&radio->vdev, radio);
364
365	raremono_cmd_main(radio, BAND_FM, 95160);
366
367	retval = video_register_device(&radio->vdev, VFL_TYPE_RADIO, -1);
368	if (retval == 0) {
369		dev_info(&intf->dev, "V4L2 device registered as %s\n",
370				video_device_node_name(&radio->vdev));
371		return 0;
372	}
373	dev_err(&intf->dev, "could not register video device\n");
374	v4l2_device_unregister(&radio->v4l2_dev);
375	return retval;
376}
377
378/* USB subsystem interface */
379static struct usb_driver usb_raremono_driver = {
380	.name			= "radio-raremono",
381	.probe			= usb_raremono_probe,
382	.disconnect		= usb_raremono_disconnect,
383	.id_table		= usb_raremono_device_table,
384};
385
386module_usb_driver(usb_raremono_driver);
387