toneport.c revision 188e664502dc47f83775a556e6db52cd8cc0b5fc
1/*
2 * Line6 Linux USB driver - 0.9.1beta
3 *
4 * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
5 *                         Emil Myhrman (emil.myhrman@gmail.com)
6 *
7 *	This program is free software; you can redistribute it and/or
8 *	modify it under the terms of the GNU General Public License as
9 *	published by the Free Software Foundation, version 2.
10 *
11 */
12
13#include <linux/wait.h>
14#include <sound/control.h>
15
16#include "audio.h"
17#include "capture.h"
18#include "driver.h"
19#include "playback.h"
20#include "toneport.h"
21
22static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2);
23
24#define TONEPORT_PCM_DELAY 1
25
26static struct snd_ratden toneport_ratden = {
27	.num_min = 44100,
28	.num_max = 44100,
29	.num_step = 1,
30	.den = 1
31};
32
33static struct line6_pcm_properties toneport_pcm_properties = {
34	.snd_line6_playback_hw = {
35				  .info = (SNDRV_PCM_INFO_MMAP |
36					   SNDRV_PCM_INFO_INTERLEAVED |
37					   SNDRV_PCM_INFO_BLOCK_TRANSFER |
38					   SNDRV_PCM_INFO_MMAP_VALID |
39					   SNDRV_PCM_INFO_PAUSE |
40#ifdef CONFIG_PM
41					   SNDRV_PCM_INFO_RESUME |
42#endif
43					   SNDRV_PCM_INFO_SYNC_START),
44				  .formats = SNDRV_PCM_FMTBIT_S16_LE,
45				  .rates = SNDRV_PCM_RATE_KNOT,
46				  .rate_min = 44100,
47				  .rate_max = 44100,
48				  .channels_min = 2,
49				  .channels_max = 2,
50				  .buffer_bytes_max = 60000,
51				  .period_bytes_min = 64,
52				  .period_bytes_max = 8192,
53				  .periods_min = 1,
54				  .periods_max = 1024},
55	.snd_line6_capture_hw = {
56				 .info = (SNDRV_PCM_INFO_MMAP |
57					  SNDRV_PCM_INFO_INTERLEAVED |
58					  SNDRV_PCM_INFO_BLOCK_TRANSFER |
59					  SNDRV_PCM_INFO_MMAP_VALID |
60#ifdef CONFIG_PM
61					  SNDRV_PCM_INFO_RESUME |
62#endif
63					  SNDRV_PCM_INFO_SYNC_START),
64				 .formats = SNDRV_PCM_FMTBIT_S16_LE,
65				 .rates = SNDRV_PCM_RATE_KNOT,
66				 .rate_min = 44100,
67				 .rate_max = 44100,
68				 .channels_min = 2,
69				 .channels_max = 2,
70				 .buffer_bytes_max = 60000,
71				 .period_bytes_min = 64,
72				 .period_bytes_max = 8192,
73				 .periods_min = 1,
74				 .periods_max = 1024},
75	.snd_line6_rates = {
76			    .nrats = 1,
77			    .rats = &toneport_ratden},
78	.bytes_per_frame = 4
79};
80
81/*
82	For the led on Guitarport.
83	Brightness goes from 0x00 to 0x26. Set a value above this to have led
84	blink.
85	(void cmd_0x02(byte red, byte green)
86*/
87static int led_red = 0x00;
88static int led_green = 0x26;
89
90struct ToneportSourceInfo {
91	const char *name;
92	int code;
93};
94
95static const struct ToneportSourceInfo toneport_source_info[] = {
96	{"Microphone", 0x0a01},
97	{"Line", 0x0801},
98	{"Instrument", 0x0b01},
99	{"Inst & Mic", 0x0901}
100};
101
102static bool toneport_has_led(short product)
103{
104	return
105	    (product == LINE6_DEVID_GUITARPORT) ||
106	    (product == LINE6_DEVID_TONEPORT_GX);
107	/* add your device here if you are missing support for the LEDs */
108}
109
110static void toneport_update_led(struct device *dev)
111{
112	struct usb_interface *interface = to_usb_interface(dev);
113	struct usb_line6_toneport *tp = usb_get_intfdata(interface);
114	struct usb_line6 *line6;
115
116	if (!tp)
117		return;
118
119	line6 = &tp->line6;
120	if (line6)
121		toneport_send_cmd(line6->usbdev, (led_red << 8) | 0x0002,
122				  led_green);
123}
124
125static ssize_t toneport_set_led_red(struct device *dev,
126				    struct device_attribute *attr,
127				    const char *buf, size_t count)
128{
129	int retval;
130	long value;
131
132	retval = strict_strtol(buf, 10, &value);
133	if (retval)
134		return retval;
135
136	led_red = value;
137	toneport_update_led(dev);
138	return count;
139}
140
141static ssize_t toneport_set_led_green(struct device *dev,
142				      struct device_attribute *attr,
143				      const char *buf, size_t count)
144{
145	int retval;
146	long value;
147
148	retval = strict_strtol(buf, 10, &value);
149	if (retval)
150		return retval;
151
152	led_green = value;
153	toneport_update_led(dev);
154	return count;
155}
156
157static DEVICE_ATTR(led_red, S_IWUSR | S_IRUGO, line6_nop_read,
158		   toneport_set_led_red);
159static DEVICE_ATTR(led_green, S_IWUSR | S_IRUGO, line6_nop_read,
160		   toneport_set_led_green);
161
162static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)
163{
164	int ret;
165
166	ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
167			      USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
168			      cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ);
169
170	if (ret < 0) {
171		err("send failed (error %d)\n", ret);
172		return ret;
173	}
174
175	return 0;
176}
177
178/* monitor info callback */
179static int snd_toneport_monitor_info(struct snd_kcontrol *kcontrol,
180				     struct snd_ctl_elem_info *uinfo)
181{
182	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
183	uinfo->count = 1;
184	uinfo->value.integer.min = 0;
185	uinfo->value.integer.max = 256;
186	return 0;
187}
188
189/* monitor get callback */
190static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol,
191				    struct snd_ctl_elem_value *ucontrol)
192{
193	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
194	ucontrol->value.integer.value[0] = line6pcm->volume_monitor;
195	return 0;
196}
197
198/* monitor put callback */
199static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol,
200				    struct snd_ctl_elem_value *ucontrol)
201{
202	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
203
204	if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor)
205		return 0;
206
207	line6pcm->volume_monitor = ucontrol->value.integer.value[0];
208
209	if (line6pcm->volume_monitor > 0)
210		line6_pcm_start(line6pcm, MASK_PCM_MONITOR);
211	else
212		line6_pcm_stop(line6pcm, MASK_PCM_MONITOR);
213
214	return 1;
215}
216
217/* source info callback */
218static int snd_toneport_source_info(struct snd_kcontrol *kcontrol,
219				    struct snd_ctl_elem_info *uinfo)
220{
221	const int size = ARRAY_SIZE(toneport_source_info);
222	uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
223	uinfo->count = 1;
224	uinfo->value.enumerated.items = size;
225
226	if (uinfo->value.enumerated.item >= size)
227		uinfo->value.enumerated.item = size - 1;
228
229	strcpy(uinfo->value.enumerated.name,
230	       toneport_source_info[uinfo->value.enumerated.item].name);
231
232	return 0;
233}
234
235/* source get callback */
236static int snd_toneport_source_get(struct snd_kcontrol *kcontrol,
237				   struct snd_ctl_elem_value *ucontrol)
238{
239	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
240	struct usb_line6_toneport *toneport =
241	    (struct usb_line6_toneport *)line6pcm->line6;
242	ucontrol->value.enumerated.item[0] = toneport->source;
243	return 0;
244}
245
246/* source put callback */
247static int snd_toneport_source_put(struct snd_kcontrol *kcontrol,
248				   struct snd_ctl_elem_value *ucontrol)
249{
250	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
251	struct usb_line6_toneport *toneport =
252	    (struct usb_line6_toneport *)line6pcm->line6;
253
254	if (ucontrol->value.enumerated.item[0] == toneport->source)
255		return 0;
256
257	toneport->source = ucontrol->value.enumerated.item[0];
258	toneport_send_cmd(toneport->line6.usbdev,
259			  toneport_source_info[toneport->source].code, 0x0000);
260	return 1;
261}
262
263static void toneport_start_pcm(unsigned long arg)
264{
265	struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg;
266	struct usb_line6 *line6 = &toneport->line6;
267	line6_pcm_start(line6->line6pcm, MASK_PCM_MONITOR);
268}
269
270/* control definition */
271static struct snd_kcontrol_new toneport_control_monitor = {
272	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
273	.name = "Monitor Playback Volume",
274	.index = 0,
275	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
276	.info = snd_toneport_monitor_info,
277	.get = snd_toneport_monitor_get,
278	.put = snd_toneport_monitor_put
279};
280
281/* source selector definition */
282static struct snd_kcontrol_new toneport_control_source = {
283	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
284	.name = "PCM Capture Source",
285	.index = 0,
286	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
287	.info = snd_toneport_source_info,
288	.get = snd_toneport_source_get,
289	.put = snd_toneport_source_put
290};
291
292/*
293	Toneport destructor.
294*/
295static void toneport_destruct(struct usb_interface *interface)
296{
297	struct usb_line6_toneport *toneport = usb_get_intfdata(interface);
298
299	if (toneport == NULL)
300		return;
301	line6_cleanup_audio(&toneport->line6);
302}
303
304/*
305	Setup Toneport device.
306*/
307static void toneport_setup(struct usb_line6_toneport *toneport)
308{
309	int ticks;
310	struct usb_line6 *line6 = &toneport->line6;
311	struct usb_device *usbdev = line6->usbdev;
312
313	/* sync time on device with host: */
314	ticks = (int)get_seconds();
315	line6_write_data(line6, 0x80c6, &ticks, 4);
316
317	/* enable device: */
318	toneport_send_cmd(usbdev, 0x0301, 0x0000);
319
320	/* initialize source select: */
321	switch (usbdev->descriptor.idProduct) {
322	case LINE6_DEVID_TONEPORT_UX1:
323	case LINE6_DEVID_PODSTUDIO_UX1:
324		toneport_send_cmd(usbdev,
325				  toneport_source_info[toneport->source].code,
326				  0x0000);
327	}
328
329	if (toneport_has_led(usbdev->descriptor.idProduct))
330		toneport_update_led(&usbdev->dev);
331}
332
333/*
334	 Try to init Toneport device.
335*/
336static int toneport_try_init(struct usb_interface *interface,
337			     struct usb_line6_toneport *toneport)
338{
339	int err;
340	struct usb_line6 *line6 = &toneport->line6;
341	struct usb_device *usbdev = line6->usbdev;
342
343	if ((interface == NULL) || (toneport == NULL))
344		return -ENODEV;
345
346	/* initialize audio system: */
347	err = line6_init_audio(line6);
348	if (err < 0)
349		return err;
350
351	/* initialize PCM subsystem: */
352	err = line6_init_pcm(line6, &toneport_pcm_properties);
353	if (err < 0)
354		return err;
355
356	/* register monitor control: */
357	err = snd_ctl_add(line6->card,
358			  snd_ctl_new1(&toneport_control_monitor,
359				       line6->line6pcm));
360	if (err < 0)
361		return err;
362
363	/* register source select control: */
364	switch (usbdev->descriptor.idProduct) {
365	case LINE6_DEVID_TONEPORT_UX1:
366	case LINE6_DEVID_PODSTUDIO_UX1:
367		err =
368		    snd_ctl_add(line6->card,
369				snd_ctl_new1(&toneport_control_source,
370					     line6->line6pcm));
371		if (err < 0)
372			return err;
373	}
374
375	/* register audio system: */
376	err = line6_register_audio(line6);
377	if (err < 0)
378		return err;
379
380	line6_read_serial_number(line6, &toneport->serial_number);
381	line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1);
382
383	if (toneport_has_led(usbdev->descriptor.idProduct)) {
384		CHECK_RETURN(device_create_file
385			     (&interface->dev, &dev_attr_led_red));
386		CHECK_RETURN(device_create_file
387			     (&interface->dev, &dev_attr_led_green));
388	}
389
390	toneport_setup(toneport);
391
392	init_timer(&toneport->timer);
393	toneport->timer.expires = jiffies + TONEPORT_PCM_DELAY * HZ;
394	toneport->timer.function = toneport_start_pcm;
395	toneport->timer.data = (unsigned long)toneport;
396	add_timer(&toneport->timer);
397
398	return 0;
399}
400
401/*
402	 Init Toneport device (and clean up in case of failure).
403*/
404int line6_toneport_init(struct usb_interface *interface,
405			struct usb_line6_toneport *toneport)
406{
407	int err = toneport_try_init(interface, toneport);
408
409	if (err < 0)
410		toneport_destruct(interface);
411
412	return err;
413}
414
415/*
416	Resume Toneport device after reset.
417*/
418void line6_toneport_reset_resume(struct usb_line6_toneport *toneport)
419{
420	toneport_setup(toneport);
421}
422
423/*
424	Toneport device disconnected.
425*/
426void line6_toneport_disconnect(struct usb_interface *interface)
427{
428	struct usb_line6_toneport *toneport;
429
430	if (interface == NULL)
431		return;
432
433	toneport = usb_get_intfdata(interface);
434	del_timer_sync(&toneport->timer);
435
436	if (toneport_has_led(toneport->line6.usbdev->descriptor.idProduct)) {
437		device_remove_file(&interface->dev, &dev_attr_led_red);
438		device_remove_file(&interface->dev, &dev_attr_led_green);
439	}
440
441	if (toneport != NULL) {
442		struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm;
443
444		if (line6pcm != NULL) {
445			line6_pcm_stop(line6pcm, MASK_PCM_MONITOR);
446			line6_pcm_disconnect(line6pcm);
447		}
448	}
449
450	toneport_destruct(interface);
451}
452