blob: a529dd3d604e7b69a9254fb395dfb8f46c4654dd [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
Markus Grabnere1a164d2010-08-23 01:08:25 +020090struct ToneportSourceInfo {
Markus Grabner1027f4762010-08-12 01:35:30 +020091 const char *name;
92 int code;
93};
94
95static const struct ToneportSourceInfo toneport_source_info[] = {
Markus Grabnere1a164d2010-08-23 01:08:25 +020096 {"Microphone", 0x0a01},
97 {"Line", 0x0801},
98 {"Instrument", 0x0b01},
99 {"Inst & Mic", 0x0901}
Markus Grabner1027f4762010-08-12 01:35:30 +0200100};
101
102static bool toneport_has_led(short product)
103{
104 return
Markus Grabnere1a164d2010-08-23 01:08:25 +0200105 (product == LINE6_DEVID_GUITARPORT) ||
106 (product == LINE6_DEVID_TONEPORT_GX);
Markus Grabner1027f4762010-08-12 01:35:30 +0200107 /* add your device here if you are missing support for the LEDs */
108}
109
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800110static 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;
Markus Grabner705ecec2009-02-27 19:43:04 -0800115
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800116 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);
Markus Grabner705ecec2009-02-27 19:43:04 -0800123}
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800124
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800125static ssize_t toneport_set_led_red(struct device *dev,
126 struct device_attribute *attr,
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800127 const char *buf, size_t count)
128{
Shawn Bohrerbb950a12009-11-15 22:17:59 -0600129 int retval;
Shawn Bohrerbb950a12009-11-15 22:17:59 -0600130
Stefan Hajnoczib07d9452012-11-11 13:24:44 +0100131 retval = kstrtoint(buf, 10, &led_red);
Shawn Bohrerbb950a12009-11-15 22:17:59 -0600132 if (retval)
133 return retval;
134
Markus Grabner705ecec2009-02-27 19:43:04 -0800135 toneport_update_led(dev);
136 return count;
137}
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800138
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800139static ssize_t toneport_set_led_green(struct device *dev,
140 struct device_attribute *attr,
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800141 const char *buf, size_t count)
142{
Shawn Bohrerbb950a12009-11-15 22:17:59 -0600143 int retval;
Shawn Bohrerbb950a12009-11-15 22:17:59 -0600144
Stefan Hajnoczib07d9452012-11-11 13:24:44 +0100145 retval = kstrtoint(buf, 10, &led_green);
Shawn Bohrerbb950a12009-11-15 22:17:59 -0600146 if (retval)
147 return retval;
148
Markus Grabner705ecec2009-02-27 19:43:04 -0800149 toneport_update_led(dev);
150 return count;
151}
152
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800153static DEVICE_ATTR(led_red, S_IWUSR | S_IRUGO, line6_nop_read,
Shawn Bohrer63a4a8b2009-11-15 22:17:58 -0600154 toneport_set_led_red);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800155static DEVICE_ATTR(led_green, S_IWUSR | S_IRUGO, line6_nop_read,
Shawn Bohrer63a4a8b2009-11-15 22:17:58 -0600156 toneport_set_led_green);
Markus Grabner705ecec2009-02-27 19:43:04 -0800157
158static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)
159{
160 int ret;
Markus Grabner705ecec2009-02-27 19:43:04 -0800161
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800162 ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
163 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
164 cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ);
165
166 if (ret < 0) {
Greg Kroah-Hartmand86938f2012-04-20 16:53:32 -0700167 dev_err(&usbdev->dev, "send failed (error %d)\n", ret);
Markus Grabner705ecec2009-02-27 19:43:04 -0800168 return ret;
169 }
170
171 return 0;
172}
173
Markus Grabner1027f4762010-08-12 01:35:30 +0200174/* monitor info callback */
175static int snd_toneport_monitor_info(struct snd_kcontrol *kcontrol,
176 struct snd_ctl_elem_info *uinfo)
177{
178 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
179 uinfo->count = 1;
180 uinfo->value.integer.min = 0;
181 uinfo->value.integer.max = 256;
182 return 0;
183}
184
185/* monitor get callback */
186static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol,
187 struct snd_ctl_elem_value *ucontrol)
188{
189 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
190 ucontrol->value.integer.value[0] = line6pcm->volume_monitor;
191 return 0;
192}
193
194/* monitor put callback */
195static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol,
196 struct snd_ctl_elem_value *ucontrol)
197{
198 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
199
Markus Grabnere1a164d2010-08-23 01:08:25 +0200200 if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor)
Markus Grabner1027f4762010-08-12 01:35:30 +0200201 return 0;
202
203 line6pcm->volume_monitor = ucontrol->value.integer.value[0];
Markus Grabnere1a164d2010-08-23 01:08:25 +0200204
205 if (line6pcm->volume_monitor > 0)
Markus Grabner0ca54882012-01-20 00:09:09 +0100206 line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_MONITOR);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200207 else
Markus Grabner0ca54882012-01-20 00:09:09 +0100208 line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200209
Markus Grabner1027f4762010-08-12 01:35:30 +0200210 return 1;
211}
212
213/* source info callback */
214static int snd_toneport_source_info(struct snd_kcontrol *kcontrol,
215 struct snd_ctl_elem_info *uinfo)
216{
217 const int size = ARRAY_SIZE(toneport_source_info);
218 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;
Markus Grabner1027f4762010-08-12 01:35:30 +0200249
Markus Grabnere1a164d2010-08-23 01:08:25 +0200250 if (ucontrol->value.enumerated.item[0] == toneport->source)
Markus Grabner1027f4762010-08-12 01:35:30 +0200251 return 0;
252
253 toneport->source = ucontrol->value.enumerated.item[0];
Markus Grabnere1a164d2010-08-23 01:08:25 +0200254 toneport_send_cmd(toneport->line6.usbdev,
255 toneport_source_info[toneport->source].code, 0x0000);
Markus Grabner1027f4762010-08-12 01:35:30 +0200256 return 1;
257}
258
259static void toneport_start_pcm(unsigned long arg)
260{
261 struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg;
262 struct usb_line6 *line6 = &toneport->line6;
Markus Grabner0ca54882012-01-20 00:09:09 +0100263 line6_pcm_acquire(line6->line6pcm, LINE6_BITS_PCM_MONITOR);
Markus Grabner1027f4762010-08-12 01:35:30 +0200264}
265
266/* control definition */
267static struct snd_kcontrol_new toneport_control_monitor = {
268 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
269 .name = "Monitor Playback Volume",
270 .index = 0,
271 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
272 .info = snd_toneport_monitor_info,
273 .get = snd_toneport_monitor_get,
274 .put = snd_toneport_monitor_put
275};
276
277/* source selector definition */
278static struct snd_kcontrol_new toneport_control_source = {
279 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
280 .name = "PCM Capture Source",
281 .index = 0,
282 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
283 .info = snd_toneport_source_info,
284 .get = snd_toneport_source_get,
285 .put = snd_toneport_source_put
286};
287
Markus Grabner705ecec2009-02-27 19:43:04 -0800288/*
289 Toneport destructor.
290*/
291static void toneport_destruct(struct usb_interface *interface)
292{
293 struct usb_line6_toneport *toneport = usb_get_intfdata(interface);
Markus Grabner705ecec2009-02-27 19:43:04 -0800294
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800295 if (toneport == NULL)
296 return;
Stefan Hajnoczi188e6642011-12-10 02:12:30 +0100297 line6_cleanup_audio(&toneport->line6);
Markus Grabner705ecec2009-02-27 19:43:04 -0800298}
299
300/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200301 Setup Toneport device.
Markus Grabner705ecec2009-02-27 19:43:04 -0800302*/
Markus Grabner1027f4762010-08-12 01:35:30 +0200303static void toneport_setup(struct usb_line6_toneport *toneport)
Markus Grabner705ecec2009-02-27 19:43:04 -0800304{
Markus Grabner1027f4762010-08-12 01:35:30 +0200305 int ticks;
Markus Grabner705ecec2009-02-27 19:43:04 -0800306 struct usb_line6 *line6 = &toneport->line6;
Markus Grabner1027f4762010-08-12 01:35:30 +0200307 struct usb_device *usbdev = line6->usbdev;
308
309 /* sync time on device with host: */
310 ticks = (int)get_seconds();
311 line6_write_data(line6, 0x80c6, &ticks, 4);
312
313 /* enable device: */
314 toneport_send_cmd(usbdev, 0x0301, 0x0000);
315
316 /* initialize source select: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200317 switch (usbdev->descriptor.idProduct) {
Markus Grabner1027f4762010-08-12 01:35:30 +0200318 case LINE6_DEVID_TONEPORT_UX1:
Markus Grabner12177ac2012-01-20 00:09:08 +0100319 case LINE6_DEVID_TONEPORT_UX2:
Markus Grabner1027f4762010-08-12 01:35:30 +0200320 case LINE6_DEVID_PODSTUDIO_UX1:
Markus Grabner12177ac2012-01-20 00:09:08 +0100321 case LINE6_DEVID_PODSTUDIO_UX2:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200322 toneport_send_cmd(usbdev,
323 toneport_source_info[toneport->source].code,
324 0x0000);
Markus Grabner1027f4762010-08-12 01:35:30 +0200325 }
326
327 if (toneport_has_led(usbdev->descriptor.idProduct))
328 toneport_update_led(&usbdev->dev);
329}
330
331/*
332 Try to init Toneport device.
333*/
334static int toneport_try_init(struct usb_interface *interface,
335 struct usb_line6_toneport *toneport)
336{
337 int err;
338 struct usb_line6 *line6 = &toneport->line6;
339 struct usb_device *usbdev = line6->usbdev;
Markus Grabner705ecec2009-02-27 19:43:04 -0800340
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800341 if ((interface == NULL) || (toneport == NULL))
Markus Grabner705ecec2009-02-27 19:43:04 -0800342 return -ENODEV;
343
344 /* initialize audio system: */
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800345 err = line6_init_audio(line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700346 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800347 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800348
349 /* initialize PCM subsystem: */
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800350 err = line6_init_pcm(line6, &toneport_pcm_properties);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700351 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800352 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800353
Markus Grabner1027f4762010-08-12 01:35:30 +0200354 /* register monitor control: */
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700355 err = snd_ctl_add(line6->card,
356 snd_ctl_new1(&toneport_control_monitor,
357 line6->line6pcm));
358 if (err < 0)
Markus Grabner1027f4762010-08-12 01:35:30 +0200359 return err;
Markus Grabner1027f4762010-08-12 01:35:30 +0200360
361 /* register source select control: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200362 switch (usbdev->descriptor.idProduct) {
Markus Grabner1027f4762010-08-12 01:35:30 +0200363 case LINE6_DEVID_TONEPORT_UX1:
Markus Grabner12177ac2012-01-20 00:09:08 +0100364 case LINE6_DEVID_TONEPORT_UX2:
Markus Grabner1027f4762010-08-12 01:35:30 +0200365 case LINE6_DEVID_PODSTUDIO_UX1:
Markus Grabner12177ac2012-01-20 00:09:08 +0100366 case LINE6_DEVID_PODSTUDIO_UX2:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200367 err =
368 snd_ctl_add(line6->card,
369 snd_ctl_new1(&toneport_control_source,
370 line6->line6pcm));
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700371 if (err < 0)
Markus Grabner1027f4762010-08-12 01:35:30 +0200372 return err;
Markus Grabner1027f4762010-08-12 01:35:30 +0200373 }
374
Markus Grabner705ecec2009-02-27 19:43:04 -0800375 /* register audio system: */
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800376 err = line6_register_audio(line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700377 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800378 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800379
Markus Grabner705ecec2009-02-27 19:43:04 -0800380 line6_read_serial_number(line6, &toneport->serial_number);
381 line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1);
382
Markus Grabner1027f4762010-08-12 01:35:30 +0200383 if (toneport_has_led(usbdev->descriptor.idProduct)) {
Markus Grabnere1a164d2010-08-23 01:08:25 +0200384 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));
Markus Grabner705ecec2009-02-27 19:43:04 -0800388 }
389
Markus Grabner1027f4762010-08-12 01:35:30 +0200390 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
Markus Grabner705ecec2009-02-27 19:43:04 -0800398 return 0;
399}
400
401/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200402 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
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700409 if (err < 0)
Markus Grabner1027f4762010-08-12 01:35:30 +0200410 toneport_destruct(interface);
Markus Grabner1027f4762010-08-12 01:35:30 +0200411
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/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800424 Toneport device disconnected.
425*/
Markus Grabner1027f4762010-08-12 01:35:30 +0200426void line6_toneport_disconnect(struct usb_interface *interface)
Markus Grabner705ecec2009-02-27 19:43:04 -0800427{
428 struct usb_line6_toneport *toneport;
429
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800430 if (interface == NULL)
431 return;
Markus Grabner705ecec2009-02-27 19:43:04 -0800432
Markus Grabner1027f4762010-08-12 01:35:30 +0200433 toneport = usb_get_intfdata(interface);
434 del_timer_sync(&toneport->timer);
435
436 if (toneport_has_led(toneport->line6.usbdev->descriptor.idProduct)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800437 device_remove_file(&interface->dev, &dev_attr_led_red);
438 device_remove_file(&interface->dev, &dev_attr_led_green);
439 }
440
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800441 if (toneport != NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800442 struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm;
443
Greg Kroah-Hartman63537732009-02-27 22:43:45 -0800444 if (line6pcm != NULL) {
Markus Grabner0ca54882012-01-20 00:09:09 +0100445 line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
Markus Grabner1027f4762010-08-12 01:35:30 +0200446 line6_pcm_disconnect(line6pcm);
Markus Grabner705ecec2009-02-27 19:43:04 -0800447 }
448 }
449
450 toneport_destruct(interface);
451}