1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Line 6 Linux USB driver
4*4882a593Smuzhiyun *
5*4882a593Smuzhiyun * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
6*4882a593Smuzhiyun * Emil Myhrman (emil.myhrman@gmail.com)
7*4882a593Smuzhiyun */
8*4882a593Smuzhiyun
9*4882a593Smuzhiyun #include <linux/wait.h>
10*4882a593Smuzhiyun #include <linux/usb.h>
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <linux/leds.h>
14*4882a593Smuzhiyun #include <sound/core.h>
15*4882a593Smuzhiyun #include <sound/control.h>
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun #include "capture.h"
18*4882a593Smuzhiyun #include "driver.h"
19*4882a593Smuzhiyun #include "playback.h"
20*4882a593Smuzhiyun
21*4882a593Smuzhiyun enum line6_device_type {
22*4882a593Smuzhiyun LINE6_GUITARPORT,
23*4882a593Smuzhiyun LINE6_PODSTUDIO_GX,
24*4882a593Smuzhiyun LINE6_PODSTUDIO_UX1,
25*4882a593Smuzhiyun LINE6_PODSTUDIO_UX2,
26*4882a593Smuzhiyun LINE6_TONEPORT_GX,
27*4882a593Smuzhiyun LINE6_TONEPORT_UX1,
28*4882a593Smuzhiyun LINE6_TONEPORT_UX2,
29*4882a593Smuzhiyun };
30*4882a593Smuzhiyun
31*4882a593Smuzhiyun struct usb_line6_toneport;
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun struct toneport_led {
34*4882a593Smuzhiyun struct led_classdev dev;
35*4882a593Smuzhiyun char name[64];
36*4882a593Smuzhiyun struct usb_line6_toneport *toneport;
37*4882a593Smuzhiyun bool registered;
38*4882a593Smuzhiyun };
39*4882a593Smuzhiyun
40*4882a593Smuzhiyun struct usb_line6_toneport {
41*4882a593Smuzhiyun /* Generic Line 6 USB data */
42*4882a593Smuzhiyun struct usb_line6 line6;
43*4882a593Smuzhiyun
44*4882a593Smuzhiyun /* Source selector */
45*4882a593Smuzhiyun int source;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun /* Serial number of device */
48*4882a593Smuzhiyun u32 serial_number;
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun /* Firmware version (x 100) */
51*4882a593Smuzhiyun u8 firmware_version;
52*4882a593Smuzhiyun
53*4882a593Smuzhiyun /* Device type */
54*4882a593Smuzhiyun enum line6_device_type type;
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun /* LED instances */
57*4882a593Smuzhiyun struct toneport_led leds[2];
58*4882a593Smuzhiyun };
59*4882a593Smuzhiyun
60*4882a593Smuzhiyun #define line6_to_toneport(x) container_of(x, struct usb_line6_toneport, line6)
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2);
63*4882a593Smuzhiyun
64*4882a593Smuzhiyun #define TONEPORT_PCM_DELAY 1
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun static const struct snd_ratden toneport_ratden = {
67*4882a593Smuzhiyun .num_min = 44100,
68*4882a593Smuzhiyun .num_max = 44100,
69*4882a593Smuzhiyun .num_step = 1,
70*4882a593Smuzhiyun .den = 1
71*4882a593Smuzhiyun };
72*4882a593Smuzhiyun
73*4882a593Smuzhiyun static struct line6_pcm_properties toneport_pcm_properties = {
74*4882a593Smuzhiyun .playback_hw = {
75*4882a593Smuzhiyun .info = (SNDRV_PCM_INFO_MMAP |
76*4882a593Smuzhiyun SNDRV_PCM_INFO_INTERLEAVED |
77*4882a593Smuzhiyun SNDRV_PCM_INFO_BLOCK_TRANSFER |
78*4882a593Smuzhiyun SNDRV_PCM_INFO_MMAP_VALID |
79*4882a593Smuzhiyun SNDRV_PCM_INFO_PAUSE |
80*4882a593Smuzhiyun SNDRV_PCM_INFO_SYNC_START),
81*4882a593Smuzhiyun .formats = SNDRV_PCM_FMTBIT_S16_LE,
82*4882a593Smuzhiyun .rates = SNDRV_PCM_RATE_KNOT,
83*4882a593Smuzhiyun .rate_min = 44100,
84*4882a593Smuzhiyun .rate_max = 44100,
85*4882a593Smuzhiyun .channels_min = 2,
86*4882a593Smuzhiyun .channels_max = 2,
87*4882a593Smuzhiyun .buffer_bytes_max = 60000,
88*4882a593Smuzhiyun .period_bytes_min = 64,
89*4882a593Smuzhiyun .period_bytes_max = 8192,
90*4882a593Smuzhiyun .periods_min = 1,
91*4882a593Smuzhiyun .periods_max = 1024},
92*4882a593Smuzhiyun .capture_hw = {
93*4882a593Smuzhiyun .info = (SNDRV_PCM_INFO_MMAP |
94*4882a593Smuzhiyun SNDRV_PCM_INFO_INTERLEAVED |
95*4882a593Smuzhiyun SNDRV_PCM_INFO_BLOCK_TRANSFER |
96*4882a593Smuzhiyun SNDRV_PCM_INFO_MMAP_VALID |
97*4882a593Smuzhiyun SNDRV_PCM_INFO_SYNC_START),
98*4882a593Smuzhiyun .formats = SNDRV_PCM_FMTBIT_S16_LE,
99*4882a593Smuzhiyun .rates = SNDRV_PCM_RATE_KNOT,
100*4882a593Smuzhiyun .rate_min = 44100,
101*4882a593Smuzhiyun .rate_max = 44100,
102*4882a593Smuzhiyun .channels_min = 2,
103*4882a593Smuzhiyun .channels_max = 2,
104*4882a593Smuzhiyun .buffer_bytes_max = 60000,
105*4882a593Smuzhiyun .period_bytes_min = 64,
106*4882a593Smuzhiyun .period_bytes_max = 8192,
107*4882a593Smuzhiyun .periods_min = 1,
108*4882a593Smuzhiyun .periods_max = 1024},
109*4882a593Smuzhiyun .rates = {
110*4882a593Smuzhiyun .nrats = 1,
111*4882a593Smuzhiyun .rats = &toneport_ratden},
112*4882a593Smuzhiyun .bytes_per_channel = 2
113*4882a593Smuzhiyun };
114*4882a593Smuzhiyun
115*4882a593Smuzhiyun static const struct {
116*4882a593Smuzhiyun const char *name;
117*4882a593Smuzhiyun int code;
118*4882a593Smuzhiyun } toneport_source_info[] = {
119*4882a593Smuzhiyun {"Microphone", 0x0a01},
120*4882a593Smuzhiyun {"Line", 0x0801},
121*4882a593Smuzhiyun {"Instrument", 0x0b01},
122*4882a593Smuzhiyun {"Inst & Mic", 0x0901}
123*4882a593Smuzhiyun };
124*4882a593Smuzhiyun
toneport_send_cmd(struct usb_device * usbdev,int cmd1,int cmd2)125*4882a593Smuzhiyun static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun int ret;
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun ret = usb_control_msg_send(usbdev, 0, 0x67,
130*4882a593Smuzhiyun USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
131*4882a593Smuzhiyun cmd1, cmd2, NULL, 0, LINE6_TIMEOUT,
132*4882a593Smuzhiyun GFP_KERNEL);
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun if (ret) {
135*4882a593Smuzhiyun dev_err(&usbdev->dev, "send failed (error %d)\n", ret);
136*4882a593Smuzhiyun return ret;
137*4882a593Smuzhiyun }
138*4882a593Smuzhiyun
139*4882a593Smuzhiyun return 0;
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun
142*4882a593Smuzhiyun /* monitor info callback */
snd_toneport_monitor_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)143*4882a593Smuzhiyun static int snd_toneport_monitor_info(struct snd_kcontrol *kcontrol,
144*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
147*4882a593Smuzhiyun uinfo->count = 1;
148*4882a593Smuzhiyun uinfo->value.integer.min = 0;
149*4882a593Smuzhiyun uinfo->value.integer.max = 256;
150*4882a593Smuzhiyun return 0;
151*4882a593Smuzhiyun }
152*4882a593Smuzhiyun
153*4882a593Smuzhiyun /* monitor get callback */
snd_toneport_monitor_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)154*4882a593Smuzhiyun static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol,
155*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
156*4882a593Smuzhiyun {
157*4882a593Smuzhiyun struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
158*4882a593Smuzhiyun
159*4882a593Smuzhiyun ucontrol->value.integer.value[0] = line6pcm->volume_monitor;
160*4882a593Smuzhiyun return 0;
161*4882a593Smuzhiyun }
162*4882a593Smuzhiyun
163*4882a593Smuzhiyun /* monitor put callback */
snd_toneport_monitor_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)164*4882a593Smuzhiyun static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol,
165*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
166*4882a593Smuzhiyun {
167*4882a593Smuzhiyun struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
168*4882a593Smuzhiyun int err;
169*4882a593Smuzhiyun
170*4882a593Smuzhiyun if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor)
171*4882a593Smuzhiyun return 0;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun line6pcm->volume_monitor = ucontrol->value.integer.value[0];
174*4882a593Smuzhiyun
175*4882a593Smuzhiyun if (line6pcm->volume_monitor > 0) {
176*4882a593Smuzhiyun err = line6_pcm_acquire(line6pcm, LINE6_STREAM_MONITOR, true);
177*4882a593Smuzhiyun if (err < 0) {
178*4882a593Smuzhiyun line6pcm->volume_monitor = 0;
179*4882a593Smuzhiyun line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR);
180*4882a593Smuzhiyun return err;
181*4882a593Smuzhiyun }
182*4882a593Smuzhiyun } else {
183*4882a593Smuzhiyun line6_pcm_release(line6pcm, LINE6_STREAM_MONITOR);
184*4882a593Smuzhiyun }
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun return 1;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun
189*4882a593Smuzhiyun /* source info callback */
snd_toneport_source_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)190*4882a593Smuzhiyun static int snd_toneport_source_info(struct snd_kcontrol *kcontrol,
191*4882a593Smuzhiyun struct snd_ctl_elem_info *uinfo)
192*4882a593Smuzhiyun {
193*4882a593Smuzhiyun const int size = ARRAY_SIZE(toneport_source_info);
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
196*4882a593Smuzhiyun uinfo->count = 1;
197*4882a593Smuzhiyun uinfo->value.enumerated.items = size;
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun if (uinfo->value.enumerated.item >= size)
200*4882a593Smuzhiyun uinfo->value.enumerated.item = size - 1;
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun strcpy(uinfo->value.enumerated.name,
203*4882a593Smuzhiyun toneport_source_info[uinfo->value.enumerated.item].name);
204*4882a593Smuzhiyun
205*4882a593Smuzhiyun return 0;
206*4882a593Smuzhiyun }
207*4882a593Smuzhiyun
208*4882a593Smuzhiyun /* source get callback */
snd_toneport_source_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)209*4882a593Smuzhiyun static int snd_toneport_source_get(struct snd_kcontrol *kcontrol,
210*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
211*4882a593Smuzhiyun {
212*4882a593Smuzhiyun struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
213*4882a593Smuzhiyun struct usb_line6_toneport *toneport = line6_to_toneport(line6pcm->line6);
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun ucontrol->value.enumerated.item[0] = toneport->source;
216*4882a593Smuzhiyun return 0;
217*4882a593Smuzhiyun }
218*4882a593Smuzhiyun
219*4882a593Smuzhiyun /* source put callback */
snd_toneport_source_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)220*4882a593Smuzhiyun static int snd_toneport_source_put(struct snd_kcontrol *kcontrol,
221*4882a593Smuzhiyun struct snd_ctl_elem_value *ucontrol)
222*4882a593Smuzhiyun {
223*4882a593Smuzhiyun struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
224*4882a593Smuzhiyun struct usb_line6_toneport *toneport = line6_to_toneport(line6pcm->line6);
225*4882a593Smuzhiyun unsigned int source;
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun source = ucontrol->value.enumerated.item[0];
228*4882a593Smuzhiyun if (source >= ARRAY_SIZE(toneport_source_info))
229*4882a593Smuzhiyun return -EINVAL;
230*4882a593Smuzhiyun if (source == toneport->source)
231*4882a593Smuzhiyun return 0;
232*4882a593Smuzhiyun
233*4882a593Smuzhiyun toneport->source = source;
234*4882a593Smuzhiyun toneport_send_cmd(toneport->line6.usbdev,
235*4882a593Smuzhiyun toneport_source_info[source].code, 0x0000);
236*4882a593Smuzhiyun return 1;
237*4882a593Smuzhiyun }
238*4882a593Smuzhiyun
toneport_startup(struct usb_line6 * line6)239*4882a593Smuzhiyun static void toneport_startup(struct usb_line6 *line6)
240*4882a593Smuzhiyun {
241*4882a593Smuzhiyun line6_pcm_acquire(line6->line6pcm, LINE6_STREAM_MONITOR, true);
242*4882a593Smuzhiyun }
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun /* control definition */
245*4882a593Smuzhiyun static const struct snd_kcontrol_new toneport_control_monitor = {
246*4882a593Smuzhiyun .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
247*4882a593Smuzhiyun .name = "Monitor Playback Volume",
248*4882a593Smuzhiyun .index = 0,
249*4882a593Smuzhiyun .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
250*4882a593Smuzhiyun .info = snd_toneport_monitor_info,
251*4882a593Smuzhiyun .get = snd_toneport_monitor_get,
252*4882a593Smuzhiyun .put = snd_toneport_monitor_put
253*4882a593Smuzhiyun };
254*4882a593Smuzhiyun
255*4882a593Smuzhiyun /* source selector definition */
256*4882a593Smuzhiyun static const struct snd_kcontrol_new toneport_control_source = {
257*4882a593Smuzhiyun .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
258*4882a593Smuzhiyun .name = "PCM Capture Source",
259*4882a593Smuzhiyun .index = 0,
260*4882a593Smuzhiyun .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
261*4882a593Smuzhiyun .info = snd_toneport_source_info,
262*4882a593Smuzhiyun .get = snd_toneport_source_get,
263*4882a593Smuzhiyun .put = snd_toneport_source_put
264*4882a593Smuzhiyun };
265*4882a593Smuzhiyun
266*4882a593Smuzhiyun /*
267*4882a593Smuzhiyun For the led on Guitarport.
268*4882a593Smuzhiyun Brightness goes from 0x00 to 0x26. Set a value above this to have led
269*4882a593Smuzhiyun blink.
270*4882a593Smuzhiyun (void cmd_0x02(byte red, byte green)
271*4882a593Smuzhiyun */
272*4882a593Smuzhiyun
toneport_has_led(struct usb_line6_toneport * toneport)273*4882a593Smuzhiyun static bool toneport_has_led(struct usb_line6_toneport *toneport)
274*4882a593Smuzhiyun {
275*4882a593Smuzhiyun switch (toneport->type) {
276*4882a593Smuzhiyun case LINE6_GUITARPORT:
277*4882a593Smuzhiyun case LINE6_TONEPORT_GX:
278*4882a593Smuzhiyun /* add your device here if you are missing support for the LEDs */
279*4882a593Smuzhiyun return true;
280*4882a593Smuzhiyun
281*4882a593Smuzhiyun default:
282*4882a593Smuzhiyun return false;
283*4882a593Smuzhiyun }
284*4882a593Smuzhiyun }
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun static const char * const toneport_led_colors[2] = { "red", "green" };
287*4882a593Smuzhiyun static const int toneport_led_init_vals[2] = { 0x00, 0x26 };
288*4882a593Smuzhiyun
toneport_update_led(struct usb_line6_toneport * toneport)289*4882a593Smuzhiyun static void toneport_update_led(struct usb_line6_toneport *toneport)
290*4882a593Smuzhiyun {
291*4882a593Smuzhiyun toneport_send_cmd(toneport->line6.usbdev,
292*4882a593Smuzhiyun (toneport->leds[0].dev.brightness << 8) | 0x0002,
293*4882a593Smuzhiyun toneport->leds[1].dev.brightness);
294*4882a593Smuzhiyun }
295*4882a593Smuzhiyun
toneport_led_brightness_set(struct led_classdev * led_cdev,enum led_brightness brightness)296*4882a593Smuzhiyun static void toneport_led_brightness_set(struct led_classdev *led_cdev,
297*4882a593Smuzhiyun enum led_brightness brightness)
298*4882a593Smuzhiyun {
299*4882a593Smuzhiyun struct toneport_led *leds =
300*4882a593Smuzhiyun container_of(led_cdev, struct toneport_led, dev);
301*4882a593Smuzhiyun toneport_update_led(leds->toneport);
302*4882a593Smuzhiyun }
303*4882a593Smuzhiyun
toneport_init_leds(struct usb_line6_toneport * toneport)304*4882a593Smuzhiyun static int toneport_init_leds(struct usb_line6_toneport *toneport)
305*4882a593Smuzhiyun {
306*4882a593Smuzhiyun struct device *dev = &toneport->line6.usbdev->dev;
307*4882a593Smuzhiyun int i, err;
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun for (i = 0; i < 2; i++) {
310*4882a593Smuzhiyun struct toneport_led *led = &toneport->leds[i];
311*4882a593Smuzhiyun struct led_classdev *leddev = &led->dev;
312*4882a593Smuzhiyun
313*4882a593Smuzhiyun led->toneport = toneport;
314*4882a593Smuzhiyun snprintf(led->name, sizeof(led->name), "%s::%s",
315*4882a593Smuzhiyun dev_name(dev), toneport_led_colors[i]);
316*4882a593Smuzhiyun leddev->name = led->name;
317*4882a593Smuzhiyun leddev->brightness = toneport_led_init_vals[i];
318*4882a593Smuzhiyun leddev->max_brightness = 0x26;
319*4882a593Smuzhiyun leddev->brightness_set = toneport_led_brightness_set;
320*4882a593Smuzhiyun err = led_classdev_register(dev, leddev);
321*4882a593Smuzhiyun if (err)
322*4882a593Smuzhiyun return err;
323*4882a593Smuzhiyun led->registered = true;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun
326*4882a593Smuzhiyun return 0;
327*4882a593Smuzhiyun }
328*4882a593Smuzhiyun
toneport_remove_leds(struct usb_line6_toneport * toneport)329*4882a593Smuzhiyun static void toneport_remove_leds(struct usb_line6_toneport *toneport)
330*4882a593Smuzhiyun {
331*4882a593Smuzhiyun struct toneport_led *led;
332*4882a593Smuzhiyun int i;
333*4882a593Smuzhiyun
334*4882a593Smuzhiyun for (i = 0; i < 2; i++) {
335*4882a593Smuzhiyun led = &toneport->leds[i];
336*4882a593Smuzhiyun if (!led->registered)
337*4882a593Smuzhiyun break;
338*4882a593Smuzhiyun led_classdev_unregister(&led->dev);
339*4882a593Smuzhiyun led->registered = false;
340*4882a593Smuzhiyun }
341*4882a593Smuzhiyun }
342*4882a593Smuzhiyun
toneport_has_source_select(struct usb_line6_toneport * toneport)343*4882a593Smuzhiyun static bool toneport_has_source_select(struct usb_line6_toneport *toneport)
344*4882a593Smuzhiyun {
345*4882a593Smuzhiyun switch (toneport->type) {
346*4882a593Smuzhiyun case LINE6_TONEPORT_UX1:
347*4882a593Smuzhiyun case LINE6_TONEPORT_UX2:
348*4882a593Smuzhiyun case LINE6_PODSTUDIO_UX1:
349*4882a593Smuzhiyun case LINE6_PODSTUDIO_UX2:
350*4882a593Smuzhiyun return true;
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun default:
353*4882a593Smuzhiyun return false;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun }
356*4882a593Smuzhiyun
357*4882a593Smuzhiyun /*
358*4882a593Smuzhiyun Setup Toneport device.
359*4882a593Smuzhiyun */
toneport_setup(struct usb_line6_toneport * toneport)360*4882a593Smuzhiyun static int toneport_setup(struct usb_line6_toneport *toneport)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun u32 *ticks;
363*4882a593Smuzhiyun struct usb_line6 *line6 = &toneport->line6;
364*4882a593Smuzhiyun struct usb_device *usbdev = line6->usbdev;
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun ticks = kmalloc(sizeof(*ticks), GFP_KERNEL);
367*4882a593Smuzhiyun if (!ticks)
368*4882a593Smuzhiyun return -ENOMEM;
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun /* sync time on device with host: */
371*4882a593Smuzhiyun /* note: 32-bit timestamps overflow in year 2106 */
372*4882a593Smuzhiyun *ticks = (u32)ktime_get_real_seconds();
373*4882a593Smuzhiyun line6_write_data(line6, 0x80c6, ticks, 4);
374*4882a593Smuzhiyun kfree(ticks);
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun /* enable device: */
377*4882a593Smuzhiyun toneport_send_cmd(usbdev, 0x0301, 0x0000);
378*4882a593Smuzhiyun
379*4882a593Smuzhiyun /* initialize source select: */
380*4882a593Smuzhiyun if (toneport_has_source_select(toneport))
381*4882a593Smuzhiyun toneport_send_cmd(usbdev,
382*4882a593Smuzhiyun toneport_source_info[toneport->source].code,
383*4882a593Smuzhiyun 0x0000);
384*4882a593Smuzhiyun
385*4882a593Smuzhiyun if (toneport_has_led(toneport))
386*4882a593Smuzhiyun toneport_update_led(toneport);
387*4882a593Smuzhiyun
388*4882a593Smuzhiyun schedule_delayed_work(&toneport->line6.startup_work,
389*4882a593Smuzhiyun msecs_to_jiffies(TONEPORT_PCM_DELAY * 1000));
390*4882a593Smuzhiyun return 0;
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun
393*4882a593Smuzhiyun /*
394*4882a593Smuzhiyun Toneport device disconnected.
395*4882a593Smuzhiyun */
line6_toneport_disconnect(struct usb_line6 * line6)396*4882a593Smuzhiyun static void line6_toneport_disconnect(struct usb_line6 *line6)
397*4882a593Smuzhiyun {
398*4882a593Smuzhiyun struct usb_line6_toneport *toneport = line6_to_toneport(line6);
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun if (toneport_has_led(toneport))
401*4882a593Smuzhiyun toneport_remove_leds(toneport);
402*4882a593Smuzhiyun }
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun /*
406*4882a593Smuzhiyun Try to init Toneport device.
407*4882a593Smuzhiyun */
toneport_init(struct usb_line6 * line6,const struct usb_device_id * id)408*4882a593Smuzhiyun static int toneport_init(struct usb_line6 *line6,
409*4882a593Smuzhiyun const struct usb_device_id *id)
410*4882a593Smuzhiyun {
411*4882a593Smuzhiyun int err;
412*4882a593Smuzhiyun struct usb_line6_toneport *toneport = line6_to_toneport(line6);
413*4882a593Smuzhiyun
414*4882a593Smuzhiyun toneport->type = id->driver_info;
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun line6->disconnect = line6_toneport_disconnect;
417*4882a593Smuzhiyun line6->startup = toneport_startup;
418*4882a593Smuzhiyun
419*4882a593Smuzhiyun /* initialize PCM subsystem: */
420*4882a593Smuzhiyun err = line6_init_pcm(line6, &toneport_pcm_properties);
421*4882a593Smuzhiyun if (err < 0)
422*4882a593Smuzhiyun return err;
423*4882a593Smuzhiyun
424*4882a593Smuzhiyun /* register monitor control: */
425*4882a593Smuzhiyun err = snd_ctl_add(line6->card,
426*4882a593Smuzhiyun snd_ctl_new1(&toneport_control_monitor,
427*4882a593Smuzhiyun line6->line6pcm));
428*4882a593Smuzhiyun if (err < 0)
429*4882a593Smuzhiyun return err;
430*4882a593Smuzhiyun
431*4882a593Smuzhiyun /* register source select control: */
432*4882a593Smuzhiyun if (toneport_has_source_select(toneport)) {
433*4882a593Smuzhiyun err =
434*4882a593Smuzhiyun snd_ctl_add(line6->card,
435*4882a593Smuzhiyun snd_ctl_new1(&toneport_control_source,
436*4882a593Smuzhiyun line6->line6pcm));
437*4882a593Smuzhiyun if (err < 0)
438*4882a593Smuzhiyun return err;
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun
441*4882a593Smuzhiyun line6_read_serial_number(line6, &toneport->serial_number);
442*4882a593Smuzhiyun line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1);
443*4882a593Smuzhiyun
444*4882a593Smuzhiyun if (toneport_has_led(toneport)) {
445*4882a593Smuzhiyun err = toneport_init_leds(toneport);
446*4882a593Smuzhiyun if (err < 0)
447*4882a593Smuzhiyun return err;
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun
450*4882a593Smuzhiyun err = toneport_setup(toneport);
451*4882a593Smuzhiyun if (err)
452*4882a593Smuzhiyun return err;
453*4882a593Smuzhiyun
454*4882a593Smuzhiyun /* register audio system: */
455*4882a593Smuzhiyun return snd_card_register(line6->card);
456*4882a593Smuzhiyun }
457*4882a593Smuzhiyun
458*4882a593Smuzhiyun #ifdef CONFIG_PM
459*4882a593Smuzhiyun /*
460*4882a593Smuzhiyun Resume Toneport device after reset.
461*4882a593Smuzhiyun */
toneport_reset_resume(struct usb_interface * interface)462*4882a593Smuzhiyun static int toneport_reset_resume(struct usb_interface *interface)
463*4882a593Smuzhiyun {
464*4882a593Smuzhiyun int err;
465*4882a593Smuzhiyun
466*4882a593Smuzhiyun err = toneport_setup(usb_get_intfdata(interface));
467*4882a593Smuzhiyun if (err)
468*4882a593Smuzhiyun return err;
469*4882a593Smuzhiyun return line6_resume(interface);
470*4882a593Smuzhiyun }
471*4882a593Smuzhiyun #endif
472*4882a593Smuzhiyun
473*4882a593Smuzhiyun #define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
474*4882a593Smuzhiyun #define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
475*4882a593Smuzhiyun
476*4882a593Smuzhiyun /* table of devices that work with this driver */
477*4882a593Smuzhiyun static const struct usb_device_id toneport_id_table[] = {
478*4882a593Smuzhiyun { LINE6_DEVICE(0x4750), .driver_info = LINE6_GUITARPORT },
479*4882a593Smuzhiyun { LINE6_DEVICE(0x4153), .driver_info = LINE6_PODSTUDIO_GX },
480*4882a593Smuzhiyun { LINE6_DEVICE(0x4150), .driver_info = LINE6_PODSTUDIO_UX1 },
481*4882a593Smuzhiyun { LINE6_IF_NUM(0x4151, 0), .driver_info = LINE6_PODSTUDIO_UX2 },
482*4882a593Smuzhiyun { LINE6_DEVICE(0x4147), .driver_info = LINE6_TONEPORT_GX },
483*4882a593Smuzhiyun { LINE6_DEVICE(0x4141), .driver_info = LINE6_TONEPORT_UX1 },
484*4882a593Smuzhiyun { LINE6_IF_NUM(0x4142, 0), .driver_info = LINE6_TONEPORT_UX2 },
485*4882a593Smuzhiyun {}
486*4882a593Smuzhiyun };
487*4882a593Smuzhiyun
488*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, toneport_id_table);
489*4882a593Smuzhiyun
490*4882a593Smuzhiyun static const struct line6_properties toneport_properties_table[] = {
491*4882a593Smuzhiyun [LINE6_GUITARPORT] = {
492*4882a593Smuzhiyun .id = "GuitarPort",
493*4882a593Smuzhiyun .name = "GuitarPort",
494*4882a593Smuzhiyun .capabilities = LINE6_CAP_PCM,
495*4882a593Smuzhiyun .altsetting = 2, /* 1..4 seem to be ok */
496*4882a593Smuzhiyun /* no control channel */
497*4882a593Smuzhiyun .ep_audio_r = 0x82,
498*4882a593Smuzhiyun .ep_audio_w = 0x01,
499*4882a593Smuzhiyun },
500*4882a593Smuzhiyun [LINE6_PODSTUDIO_GX] = {
501*4882a593Smuzhiyun .id = "PODStudioGX",
502*4882a593Smuzhiyun .name = "POD Studio GX",
503*4882a593Smuzhiyun .capabilities = LINE6_CAP_PCM,
504*4882a593Smuzhiyun .altsetting = 2, /* 1..4 seem to be ok */
505*4882a593Smuzhiyun /* no control channel */
506*4882a593Smuzhiyun .ep_audio_r = 0x82,
507*4882a593Smuzhiyun .ep_audio_w = 0x01,
508*4882a593Smuzhiyun },
509*4882a593Smuzhiyun [LINE6_PODSTUDIO_UX1] = {
510*4882a593Smuzhiyun .id = "PODStudioUX1",
511*4882a593Smuzhiyun .name = "POD Studio UX1",
512*4882a593Smuzhiyun .capabilities = LINE6_CAP_PCM,
513*4882a593Smuzhiyun .altsetting = 2, /* 1..4 seem to be ok */
514*4882a593Smuzhiyun /* no control channel */
515*4882a593Smuzhiyun .ep_audio_r = 0x82,
516*4882a593Smuzhiyun .ep_audio_w = 0x01,
517*4882a593Smuzhiyun },
518*4882a593Smuzhiyun [LINE6_PODSTUDIO_UX2] = {
519*4882a593Smuzhiyun .id = "PODStudioUX2",
520*4882a593Smuzhiyun .name = "POD Studio UX2",
521*4882a593Smuzhiyun .capabilities = LINE6_CAP_PCM,
522*4882a593Smuzhiyun .altsetting = 2, /* defaults to 44.1kHz, 16-bit */
523*4882a593Smuzhiyun /* no control channel */
524*4882a593Smuzhiyun .ep_audio_r = 0x82,
525*4882a593Smuzhiyun .ep_audio_w = 0x01,
526*4882a593Smuzhiyun },
527*4882a593Smuzhiyun [LINE6_TONEPORT_GX] = {
528*4882a593Smuzhiyun .id = "TonePortGX",
529*4882a593Smuzhiyun .name = "TonePort GX",
530*4882a593Smuzhiyun .capabilities = LINE6_CAP_PCM,
531*4882a593Smuzhiyun .altsetting = 2, /* 1..4 seem to be ok */
532*4882a593Smuzhiyun /* no control channel */
533*4882a593Smuzhiyun .ep_audio_r = 0x82,
534*4882a593Smuzhiyun .ep_audio_w = 0x01,
535*4882a593Smuzhiyun },
536*4882a593Smuzhiyun [LINE6_TONEPORT_UX1] = {
537*4882a593Smuzhiyun .id = "TonePortUX1",
538*4882a593Smuzhiyun .name = "TonePort UX1",
539*4882a593Smuzhiyun .capabilities = LINE6_CAP_PCM,
540*4882a593Smuzhiyun .altsetting = 2, /* 1..4 seem to be ok */
541*4882a593Smuzhiyun /* no control channel */
542*4882a593Smuzhiyun .ep_audio_r = 0x82,
543*4882a593Smuzhiyun .ep_audio_w = 0x01,
544*4882a593Smuzhiyun },
545*4882a593Smuzhiyun [LINE6_TONEPORT_UX2] = {
546*4882a593Smuzhiyun .id = "TonePortUX2",
547*4882a593Smuzhiyun .name = "TonePort UX2",
548*4882a593Smuzhiyun .capabilities = LINE6_CAP_PCM,
549*4882a593Smuzhiyun .altsetting = 2, /* defaults to 44.1kHz, 16-bit */
550*4882a593Smuzhiyun /* no control channel */
551*4882a593Smuzhiyun .ep_audio_r = 0x82,
552*4882a593Smuzhiyun .ep_audio_w = 0x01,
553*4882a593Smuzhiyun },
554*4882a593Smuzhiyun };
555*4882a593Smuzhiyun
556*4882a593Smuzhiyun /*
557*4882a593Smuzhiyun Probe USB device.
558*4882a593Smuzhiyun */
toneport_probe(struct usb_interface * interface,const struct usb_device_id * id)559*4882a593Smuzhiyun static int toneport_probe(struct usb_interface *interface,
560*4882a593Smuzhiyun const struct usb_device_id *id)
561*4882a593Smuzhiyun {
562*4882a593Smuzhiyun return line6_probe(interface, id, "Line6-TonePort",
563*4882a593Smuzhiyun &toneport_properties_table[id->driver_info],
564*4882a593Smuzhiyun toneport_init, sizeof(struct usb_line6_toneport));
565*4882a593Smuzhiyun }
566*4882a593Smuzhiyun
567*4882a593Smuzhiyun static struct usb_driver toneport_driver = {
568*4882a593Smuzhiyun .name = KBUILD_MODNAME,
569*4882a593Smuzhiyun .probe = toneport_probe,
570*4882a593Smuzhiyun .disconnect = line6_disconnect,
571*4882a593Smuzhiyun #ifdef CONFIG_PM
572*4882a593Smuzhiyun .suspend = line6_suspend,
573*4882a593Smuzhiyun .resume = line6_resume,
574*4882a593Smuzhiyun .reset_resume = toneport_reset_resume,
575*4882a593Smuzhiyun #endif
576*4882a593Smuzhiyun .id_table = toneport_id_table,
577*4882a593Smuzhiyun };
578*4882a593Smuzhiyun
579*4882a593Smuzhiyun module_usb_driver(toneport_driver);
580*4882a593Smuzhiyun
581*4882a593Smuzhiyun MODULE_DESCRIPTION("TonePort USB driver");
582*4882a593Smuzhiyun MODULE_LICENSE("GPL");
583