blob: 5c462b72a850ccd9ff180ef448f76630762e70fd [file] [log] [blame]
Markus Grabner705ecec2009-02-27 19:43:04 -08001/*
Markus Grabnere1a164d2010-08-23 01:08:25 +02002 * Line6 Linux USB driver - 0.9.1beta
Markus Grabner705ecec2009-02-27 19:43:04 -08003 *
Markus Grabner1027f4762010-08-12 01:35:30 +02004 * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
Markus Grabner705ecec2009-02-27 19:43:04 -08005 * 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
Markus Grabner1027f4762010-08-12 01:35:30 +020013#include <linux/wait.h>
14#include <sound/control.h>
Markus Grabner705ecec2009-02-27 19:43:04 -080015
16#include "audio.h"
17#include "capture.h"
Markus Grabner1027f4762010-08-12 01:35:30 +020018#include "driver.h"
Markus Grabner705ecec2009-02-27 19:43:04 -080019#include "playback.h"
20#include "toneport.h"
21
Markus Grabner705ecec2009-02-27 19:43:04 -080022static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2);
23
Markus Grabner1027f4762010-08-12 01:35:30 +020024#define TONEPORT_PCM_DELAY 1
25
Markus Grabner705ecec2009-02-27 19:43:04 -080026static 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 = {
Shawn Bohrer63a4a8b2009-11-15 22:17:58 -060034 .snd_line6_playback_hw = {
Markus Grabnere1a164d2010-08-23 01:08:25 +020035 .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 |
Markus Grabner1027f4762010-08-12 01:35:30 +020040#ifdef CONFIG_PM
Markus Grabnere1a164d2010-08-23 01:08:25 +020041 SNDRV_PCM_INFO_RESUME |
Markus Grabner1027f4762010-08-12 01:35:30 +020042#endif
Markus Grabnere1a164d2010-08-23 01:08:25 +020043 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},
Shawn Bohrer63a4a8b2009-11-15 22:17:58 -060055 .snd_line6_capture_hw = {
Markus Grabnere1a164d2010-08-23 01:08:25 +020056 .info = (SNDRV_PCM_INFO_MMAP |
57 SNDRV_PCM_INFO_INTERLEAVED |
58 SNDRV_PCM_INFO_BLOCK_TRANSFER |
59 SNDRV_PCM_INFO_MMAP_VALID |
Markus Grabner1027f4762010-08-12 01:35:30 +020060#ifdef CONFIG_PM
Markus Grabnere1a164d2010-08-23 01:08:25 +020061 SNDRV_PCM_INFO_RESUME |
Markus Grabner1027f4762010-08-12 01:35:30 +020062#endif
Markus Grabnere1a164d2010-08-23 01:08:25 +020063 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},
Markus Grabner705ecec2009-02-27 19:43:04 -080075 .snd_line6_rates = {
Markus Grabnere1a164d2010-08-23 01:08:25 +020076 .nrats = 1,
77 .rats = &toneport_ratden},
Markus Grabner705ecec2009-02-27 19:43:04 -080078 .bytes_per_frame = 4
79};
80
81/*
82 For the led on Guitarport.
Greg Kroah-Hartman63537732009-02-27 22:43:45 -080083 Brightness goes from 0x00 to 0x26. Set a value above this to have led
84 blink.
Markus Grabner705ecec2009-02-27 19:43:04 -080085 (void cmd_0x02(byte red, byte green)
86*/
87static int led_red = 0x00;
88static int led_green = 0x26;
89
Stefan Hajnoczi709b2fa2013-01-11 23:08:13 +010090static const struct {
Markus Grabner1027f4762010-08-12 01:35:30 +020091 const char *name;
92 int code;
Stefan Hajnoczi709b2fa2013-01-11 23:08:13 +010093} toneport_source_info[] = {
Markus Grabnere1a164d2010-08-23 01:08:25 +020094 {"Microphone", 0x0a01},
95 {"Line", 0x0801},
96 {"Instrument", 0x0b01},
97 {"Inst & Mic", 0x0901}
Markus Grabner1027f4762010-08-12 01:35:30 +020098};
99
Chris Rorvicka23a8bf2015-01-12 12:42:42 -0800100static bool toneport_has_led(enum line6_device_type type)
Markus Grabner1027f4762010-08-12 01:35:30 +0200101{
102 return
Chris Rorvicka23a8bf2015-01-12 12:42:42 -0800103 (type == LINE6_GUITARPORT) ||
104 (type == LINE6_TONEPORT_GX);
Markus Grabner1027f4762010-08-12 01:35:30 +0200105 /* add your device here if you are missing support for the LEDs */
106}
107
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800108static void toneport_update_led(struct device *dev)
109{
110 struct usb_interface *interface = to_usb_interface(dev);
111 struct usb_line6_toneport *tp = usb_get_intfdata(interface);
112 struct usb_line6 *line6;
Markus Grabner705ecec2009-02-27 19:43:04 -0800113
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800114 if (!tp)
115 return;
116
117 line6 = &tp->line6;
118 if (line6)
119 toneport_send_cmd(line6->usbdev, (led_red << 8) | 0x0002,
120 led_green);
Markus Grabner705ecec2009-02-27 19:43:04 -0800121}
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800122
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800123static ssize_t toneport_set_led_red(struct device *dev,
124 struct device_attribute *attr,
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800125 const char *buf, size_t count)
126{
Shawn Bohrerbb950a12009-11-15 22:17:59 -0600127 int retval;
Shawn Bohrerbb950a12009-11-15 22:17:59 -0600128
Stefan Hajnoczib07d9452012-11-11 13:24:44 +0100129 retval = kstrtoint(buf, 10, &led_red);
Shawn Bohrerbb950a12009-11-15 22:17:59 -0600130 if (retval)
131 return retval;
132
Markus Grabner705ecec2009-02-27 19:43:04 -0800133 toneport_update_led(dev);
134 return count;
135}
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800136
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800137static ssize_t toneport_set_led_green(struct device *dev,
138 struct device_attribute *attr,
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800139 const char *buf, size_t count)
140{
Shawn Bohrerbb950a12009-11-15 22:17:59 -0600141 int retval;
Shawn Bohrerbb950a12009-11-15 22:17:59 -0600142
Stefan Hajnoczib07d9452012-11-11 13:24:44 +0100143 retval = kstrtoint(buf, 10, &led_green);
Shawn Bohrerbb950a12009-11-15 22:17:59 -0600144 if (retval)
145 return retval;
146
Markus Grabner705ecec2009-02-27 19:43:04 -0800147 toneport_update_led(dev);
148 return count;
149}
150
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800151static DEVICE_ATTR(led_red, S_IWUSR | S_IRUGO, line6_nop_read,
Shawn Bohrer63a4a8b2009-11-15 22:17:58 -0600152 toneport_set_led_red);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800153static DEVICE_ATTR(led_green, S_IWUSR | S_IRUGO, line6_nop_read,
Shawn Bohrer63a4a8b2009-11-15 22:17:58 -0600154 toneport_set_led_green);
Markus Grabner705ecec2009-02-27 19:43:04 -0800155
156static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)
157{
158 int ret;
Markus Grabner705ecec2009-02-27 19:43:04 -0800159
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800160 ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
161 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
162 cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ);
163
164 if (ret < 0) {
Greg Kroah-Hartmand86938f2012-04-20 16:53:32 -0700165 dev_err(&usbdev->dev, "send failed (error %d)\n", ret);
Markus Grabner705ecec2009-02-27 19:43:04 -0800166 return ret;
167 }
168
169 return 0;
170}
171
Markus Grabner1027f4762010-08-12 01:35:30 +0200172/* monitor info callback */
173static int snd_toneport_monitor_info(struct snd_kcontrol *kcontrol,
174 struct snd_ctl_elem_info *uinfo)
175{
176 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
177 uinfo->count = 1;
178 uinfo->value.integer.min = 0;
179 uinfo->value.integer.max = 256;
180 return 0;
181}
182
183/* monitor get callback */
184static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol,
185 struct snd_ctl_elem_value *ucontrol)
186{
187 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
Jerry Snitselaarf3c52612014-04-24 00:31:48 -0700188
Markus Grabner1027f4762010-08-12 01:35:30 +0200189 ucontrol->value.integer.value[0] = line6pcm->volume_monitor;
190 return 0;
191}
192
193/* monitor put callback */
194static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol,
195 struct snd_ctl_elem_value *ucontrol)
196{
197 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
198
Markus Grabnere1a164d2010-08-23 01:08:25 +0200199 if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor)
Markus Grabner1027f4762010-08-12 01:35:30 +0200200 return 0;
201
202 line6pcm->volume_monitor = ucontrol->value.integer.value[0];
Markus Grabnere1a164d2010-08-23 01:08:25 +0200203
204 if (line6pcm->volume_monitor > 0)
Markus Grabner0ca54882012-01-20 00:09:09 +0100205 line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_MONITOR);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200206 else
Markus Grabner0ca54882012-01-20 00:09:09 +0100207 line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200208
Markus Grabner1027f4762010-08-12 01:35:30 +0200209 return 1;
210}
211
212/* source info callback */
213static int snd_toneport_source_info(struct snd_kcontrol *kcontrol,
214 struct snd_ctl_elem_info *uinfo)
215{
216 const int size = ARRAY_SIZE(toneport_source_info);
Fabian Mewesa6b46992014-03-24 23:46:31 +0100217
Markus Grabner1027f4762010-08-12 01:35:30 +0200218 uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
219 uinfo->count = 1;
220 uinfo->value.enumerated.items = size;
221
Markus Grabnere1a164d2010-08-23 01:08:25 +0200222 if (uinfo->value.enumerated.item >= size)
Markus Grabner1027f4762010-08-12 01:35:30 +0200223 uinfo->value.enumerated.item = size - 1;
224
225 strcpy(uinfo->value.enumerated.name,
226 toneport_source_info[uinfo->value.enumerated.item].name);
227
228 return 0;
229}
230
231/* source get callback */
232static int snd_toneport_source_get(struct snd_kcontrol *kcontrol,
233 struct snd_ctl_elem_value *ucontrol)
234{
235 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200236 struct usb_line6_toneport *toneport =
237 (struct usb_line6_toneport *)line6pcm->line6;
Markus Grabner1027f4762010-08-12 01:35:30 +0200238 ucontrol->value.enumerated.item[0] = toneport->source;
239 return 0;
240}
241
242/* source put callback */
243static int snd_toneport_source_put(struct snd_kcontrol *kcontrol,
244 struct snd_ctl_elem_value *ucontrol)
245{
246 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200247 struct usb_line6_toneport *toneport =
248 (struct usb_line6_toneport *)line6pcm->line6;
Dan Carpenterc3cb7182013-09-13 11:07:13 +0300249 unsigned int source;
Markus Grabner1027f4762010-08-12 01:35:30 +0200250
Dan Carpenterc3cb7182013-09-13 11:07:13 +0300251 source = ucontrol->value.enumerated.item[0];
252 if (source >= ARRAY_SIZE(toneport_source_info))
253 return -EINVAL;
254 if (source == toneport->source)
Markus Grabner1027f4762010-08-12 01:35:30 +0200255 return 0;
256
Dan Carpenterc3cb7182013-09-13 11:07:13 +0300257 toneport->source = source;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200258 toneport_send_cmd(toneport->line6.usbdev,
Dan Carpenterc3cb7182013-09-13 11:07:13 +0300259 toneport_source_info[source].code, 0x0000);
Markus Grabner1027f4762010-08-12 01:35:30 +0200260 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;
Jerry Snitselaarf3c52612014-04-24 00:31:48 -0700267
Markus Grabner0ca54882012-01-20 00:09:09 +0100268 line6_pcm_acquire(line6->line6pcm, LINE6_BITS_PCM_MONITOR);
Markus Grabner1027f4762010-08-12 01:35:30 +0200269}
270
271/* control definition */
272static struct snd_kcontrol_new toneport_control_monitor = {
273 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
274 .name = "Monitor Playback Volume",
275 .index = 0,
276 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
277 .info = snd_toneport_monitor_info,
278 .get = snd_toneport_monitor_get,
279 .put = snd_toneport_monitor_put
280};
281
282/* source selector definition */
283static struct snd_kcontrol_new toneport_control_source = {
284 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
285 .name = "PCM Capture Source",
286 .index = 0,
287 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
288 .info = snd_toneport_source_info,
289 .get = snd_toneport_source_get,
290 .put = snd_toneport_source_put
291};
292
Markus Grabner705ecec2009-02-27 19:43:04 -0800293/*
294 Toneport destructor.
295*/
296static void toneport_destruct(struct usb_interface *interface)
297{
298 struct usb_line6_toneport *toneport = usb_get_intfdata(interface);
Markus Grabner705ecec2009-02-27 19:43:04 -0800299
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800300 if (toneport == NULL)
301 return;
Stefan Hajnoczi188e6642011-12-10 02:12:30 +0100302 line6_cleanup_audio(&toneport->line6);
Markus Grabner705ecec2009-02-27 19:43:04 -0800303}
304
305/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200306 Setup Toneport device.
Markus Grabner705ecec2009-02-27 19:43:04 -0800307*/
Markus Grabner1027f4762010-08-12 01:35:30 +0200308static void toneport_setup(struct usb_line6_toneport *toneport)
Markus Grabner705ecec2009-02-27 19:43:04 -0800309{
Markus Grabner1027f4762010-08-12 01:35:30 +0200310 int ticks;
Markus Grabner705ecec2009-02-27 19:43:04 -0800311 struct usb_line6 *line6 = &toneport->line6;
Markus Grabner1027f4762010-08-12 01:35:30 +0200312 struct usb_device *usbdev = line6->usbdev;
313
314 /* sync time on device with host: */
315 ticks = (int)get_seconds();
316 line6_write_data(line6, 0x80c6, &ticks, 4);
317
318 /* enable device: */
319 toneport_send_cmd(usbdev, 0x0301, 0x0000);
320
321 /* initialize source select: */
Chris Rorvicka23a8bf2015-01-12 12:42:42 -0800322 switch (line6->type) {
323 case LINE6_TONEPORT_UX1:
324 case LINE6_TONEPORT_UX2:
325 case LINE6_PODSTUDIO_UX1:
326 case LINE6_PODSTUDIO_UX2:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200327 toneport_send_cmd(usbdev,
328 toneport_source_info[toneport->source].code,
329 0x0000);
Chris Rorvicka23a8bf2015-01-12 12:42:42 -0800330 default:
331 break;
Markus Grabner1027f4762010-08-12 01:35:30 +0200332 }
333
Chris Rorvicka23a8bf2015-01-12 12:42:42 -0800334 if (toneport_has_led(line6->type))
Markus Grabner1027f4762010-08-12 01:35:30 +0200335 toneport_update_led(&usbdev->dev);
336}
337
338/*
339 Try to init Toneport device.
340*/
341static int toneport_try_init(struct usb_interface *interface,
Chris Rorvicka221dd42015-01-12 12:42:56 -0800342 struct usb_line6 *line6)
Markus Grabner1027f4762010-08-12 01:35:30 +0200343{
344 int err;
Chris Rorvicka221dd42015-01-12 12:42:56 -0800345 struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6;
Markus Grabner705ecec2009-02-27 19:43:04 -0800346
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800347 if ((interface == NULL) || (toneport == NULL))
Markus Grabner705ecec2009-02-27 19:43:04 -0800348 return -ENODEV;
349
Chris Rorvicka46c4672015-01-12 12:42:59 -0800350 line6->disconnect = line6_toneport_disconnect;
351
Markus Grabner705ecec2009-02-27 19:43:04 -0800352 /* initialize audio system: */
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800353 err = line6_init_audio(line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700354 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800355 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800356
357 /* initialize PCM subsystem: */
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800358 err = line6_init_pcm(line6, &toneport_pcm_properties);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700359 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800360 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800361
Markus Grabner1027f4762010-08-12 01:35:30 +0200362 /* register monitor control: */
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700363 err = snd_ctl_add(line6->card,
364 snd_ctl_new1(&toneport_control_monitor,
365 line6->line6pcm));
366 if (err < 0)
Markus Grabner1027f4762010-08-12 01:35:30 +0200367 return err;
Markus Grabner1027f4762010-08-12 01:35:30 +0200368
369 /* register source select control: */
Chris Rorvicka23a8bf2015-01-12 12:42:42 -0800370 switch (line6->type) {
371 case LINE6_TONEPORT_UX1:
372 case LINE6_TONEPORT_UX2:
373 case LINE6_PODSTUDIO_UX1:
374 case LINE6_PODSTUDIO_UX2:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200375 err =
376 snd_ctl_add(line6->card,
377 snd_ctl_new1(&toneport_control_source,
378 line6->line6pcm));
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700379 if (err < 0)
Markus Grabner1027f4762010-08-12 01:35:30 +0200380 return err;
Chris Rorvicka23a8bf2015-01-12 12:42:42 -0800381
382 default:
383 break;
Markus Grabner1027f4762010-08-12 01:35:30 +0200384 }
385
Markus Grabner705ecec2009-02-27 19:43:04 -0800386 /* register audio system: */
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800387 err = line6_register_audio(line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700388 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800389 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800390
Markus Grabner705ecec2009-02-27 19:43:04 -0800391 line6_read_serial_number(line6, &toneport->serial_number);
392 line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1);
393
Chris Rorvicka23a8bf2015-01-12 12:42:42 -0800394 if (toneport_has_led(line6->type)) {
Markus Grabnere1a164d2010-08-23 01:08:25 +0200395 CHECK_RETURN(device_create_file
396 (&interface->dev, &dev_attr_led_red));
397 CHECK_RETURN(device_create_file
398 (&interface->dev, &dev_attr_led_green));
Markus Grabner705ecec2009-02-27 19:43:04 -0800399 }
400
Markus Grabner1027f4762010-08-12 01:35:30 +0200401 toneport_setup(toneport);
402
403 init_timer(&toneport->timer);
404 toneport->timer.expires = jiffies + TONEPORT_PCM_DELAY * HZ;
405 toneport->timer.function = toneport_start_pcm;
406 toneport->timer.data = (unsigned long)toneport;
407 add_timer(&toneport->timer);
408
Markus Grabner705ecec2009-02-27 19:43:04 -0800409 return 0;
410}
411
412/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200413 Init Toneport device (and clean up in case of failure).
414*/
415int line6_toneport_init(struct usb_interface *interface,
Chris Rorvicka221dd42015-01-12 12:42:56 -0800416 struct usb_line6 *line6)
Markus Grabner1027f4762010-08-12 01:35:30 +0200417{
Chris Rorvicka221dd42015-01-12 12:42:56 -0800418 int err = toneport_try_init(interface, line6);
Markus Grabner1027f4762010-08-12 01:35:30 +0200419
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700420 if (err < 0)
Markus Grabner1027f4762010-08-12 01:35:30 +0200421 toneport_destruct(interface);
Markus Grabner1027f4762010-08-12 01:35:30 +0200422
423 return err;
424}
425
426/*
427 Resume Toneport device after reset.
428*/
429void line6_toneport_reset_resume(struct usb_line6_toneport *toneport)
430{
431 toneport_setup(toneport);
432}
433
434/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800435 Toneport device disconnected.
436*/
Markus Grabner1027f4762010-08-12 01:35:30 +0200437void line6_toneport_disconnect(struct usb_interface *interface)
Markus Grabner705ecec2009-02-27 19:43:04 -0800438{
439 struct usb_line6_toneport *toneport;
Rickard Strandqvista248ce02015-01-12 12:42:34 -0800440 struct snd_line6_pcm *line6pcm;
Markus Grabner705ecec2009-02-27 19:43:04 -0800441
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800442 if (interface == NULL)
443 return;
Markus Grabner705ecec2009-02-27 19:43:04 -0800444
Markus Grabner1027f4762010-08-12 01:35:30 +0200445 toneport = usb_get_intfdata(interface);
Rickard Strandqvista248ce02015-01-12 12:42:34 -0800446 if (NULL == toneport)
447 return;
448
Markus Grabner1027f4762010-08-12 01:35:30 +0200449 del_timer_sync(&toneport->timer);
450
Chris Rorvicka23a8bf2015-01-12 12:42:42 -0800451 if (toneport_has_led(toneport->line6.type)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800452 device_remove_file(&interface->dev, &dev_attr_led_red);
453 device_remove_file(&interface->dev, &dev_attr_led_green);
454 }
455
Rickard Strandqvista248ce02015-01-12 12:42:34 -0800456 line6pcm = toneport->line6.line6pcm;
457 if (line6pcm != NULL) {
458 line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
459 line6_pcm_disconnect(line6pcm);
Markus Grabner705ecec2009-02-27 19:43:04 -0800460 }
461
462 toneport_destruct(interface);
463}