blob: 8fdbe9f515607c19cafdd4a755ecb7c0bcc10f37 [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 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, version 2.
9 *
10 */
11
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090012#include <linux/slab.h>
Markus Grabner1027f4762010-08-12 01:35:30 +020013#include <linux/wait.h>
14#include <sound/control.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090015
Markus Grabner705ecec2009-02-27 19:43:04 -080016#include "audio.h"
17#include "capture.h"
18#include "control.h"
Markus Grabner1027f4762010-08-12 01:35:30 +020019#include "driver.h"
Markus Grabner705ecec2009-02-27 19:43:04 -080020#include "playback.h"
21#include "pod.h"
22
Markus Grabner705ecec2009-02-27 19:43:04 -080023#define POD_SYSEX_CODE 3
Markus Grabnere1a164d2010-08-23 01:08:25 +020024#define POD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */
Markus Grabner705ecec2009-02-27 19:43:04 -080025
Markus Grabnere1a164d2010-08-23 01:08:25 +020026/* *INDENT-OFF* */
Markus Grabner705ecec2009-02-27 19:43:04 -080027
28enum {
Markus Grabner705ecec2009-02-27 19:43:04 -080029 POD_SYSEX_SAVE = 0x24,
30 POD_SYSEX_SYSTEM = 0x56,
31 POD_SYSEX_SYSTEMREQ = 0x57,
32 /* POD_SYSEX_UPDATE = 0x6c, */ /* software update! */
33 POD_SYSEX_STORE = 0x71,
34 POD_SYSEX_FINISH = 0x72,
35 POD_SYSEX_DUMPMEM = 0x73,
36 POD_SYSEX_DUMP = 0x74,
37 POD_SYSEX_DUMPREQ = 0x75
38 /* POD_SYSEX_DUMPMEM2 = 0x76 */ /* dumps entire internal memory of PODxt Pro */
39};
40
41enum {
42 POD_monitor_level = 0x04,
43 POD_routing = 0x05,
44 POD_tuner_mute = 0x13,
45 POD_tuner_freq = 0x15,
46 POD_tuner_note = 0x16,
47 POD_tuner_pitch = 0x17,
Markus Grabner1027f4762010-08-12 01:35:30 +020048 POD_system_invalid = 0x10000
Markus Grabner705ecec2009-02-27 19:43:04 -080049};
50
Markus Grabnere1a164d2010-08-23 01:08:25 +020051/* *INDENT-ON* */
52
Markus Grabner705ecec2009-02-27 19:43:04 -080053enum {
54 POD_DUMP_MEMORY = 2
55};
56
57enum {
58 POD_BUSY_READ,
59 POD_BUSY_WRITE,
60 POD_CHANNEL_DIRTY,
61 POD_SAVE_PRESSED,
62 POD_BUSY_MIDISEND
63};
64
Markus Grabner705ecec2009-02-27 19:43:04 -080065static struct snd_ratden pod_ratden = {
66 .num_min = 78125,
67 .num_max = 78125,
68 .num_step = 1,
69 .den = 2
70};
71
72static struct line6_pcm_properties pod_pcm_properties = {
Markus Grabner1027f4762010-08-12 01:35:30 +020073 .snd_line6_playback_hw = {
Markus Grabnere1a164d2010-08-23 01:08:25 +020074 .info = (SNDRV_PCM_INFO_MMAP |
75 SNDRV_PCM_INFO_INTERLEAVED |
76 SNDRV_PCM_INFO_BLOCK_TRANSFER |
77 SNDRV_PCM_INFO_MMAP_VALID |
78 SNDRV_PCM_INFO_PAUSE |
Markus Grabner1027f4762010-08-12 01:35:30 +020079#ifdef CONFIG_PM
Markus Grabnere1a164d2010-08-23 01:08:25 +020080 SNDRV_PCM_INFO_RESUME |
Markus Grabner1027f4762010-08-12 01:35:30 +020081#endif
Markus Grabnere1a164d2010-08-23 01:08:25 +020082 SNDRV_PCM_INFO_SYNC_START),
83 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
84 .rates = SNDRV_PCM_RATE_KNOT,
85 .rate_min = 39062,
86 .rate_max = 39063,
87 .channels_min = 2,
88 .channels_max = 2,
89 .buffer_bytes_max = 60000,
90 .period_bytes_min = 64,
91 .period_bytes_max = 8192,
92 .periods_min = 1,
93 .periods_max = 1024},
Markus Grabner1027f4762010-08-12 01:35:30 +020094 .snd_line6_capture_hw = {
Markus Grabnere1a164d2010-08-23 01:08:25 +020095 .info = (SNDRV_PCM_INFO_MMAP |
96 SNDRV_PCM_INFO_INTERLEAVED |
97 SNDRV_PCM_INFO_BLOCK_TRANSFER |
98 SNDRV_PCM_INFO_MMAP_VALID |
Markus Grabner1027f4762010-08-12 01:35:30 +020099#ifdef CONFIG_PM
Markus Grabnere1a164d2010-08-23 01:08:25 +0200100 SNDRV_PCM_INFO_RESUME |
Markus Grabner1027f4762010-08-12 01:35:30 +0200101#endif
Markus Grabnere1a164d2010-08-23 01:08:25 +0200102 SNDRV_PCM_INFO_SYNC_START),
103 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
104 .rates = SNDRV_PCM_RATE_KNOT,
105 .rate_min = 39062,
106 .rate_max = 39063,
107 .channels_min = 2,
108 .channels_max = 2,
109 .buffer_bytes_max = 60000,
110 .period_bytes_min = 64,
111 .period_bytes_max = 8192,
112 .periods_min = 1,
113 .periods_max = 1024},
Markus Grabner705ecec2009-02-27 19:43:04 -0800114 .snd_line6_rates = {
Markus Grabnere1a164d2010-08-23 01:08:25 +0200115 .nrats = 1,
116 .rats = &pod_ratden},
Markus Grabner705ecec2009-02-27 19:43:04 -0800117 .bytes_per_frame = POD_BYTES_PER_FRAME
118};
119
Markus Grabner1027f4762010-08-12 01:35:30 +0200120static const char pod_request_channel[] = {
121 0xf0, 0x00, 0x01, 0x0c, 0x03, 0x75, 0xf7
122};
123
Markus Grabnere1a164d2010-08-23 01:08:25 +0200124static const char pod_version_header[] = {
Markus Grabner1027f4762010-08-12 01:35:30 +0200125 0xf2, 0x7e, 0x7f, 0x06, 0x02
126};
127
Markus Grabner1027f4762010-08-12 01:35:30 +0200128/* forward declarations: */
129static void pod_startup2(unsigned long data);
130static void pod_startup3(struct usb_line6_pod *pod);
131static void pod_startup4(struct usb_line6_pod *pod);
Markus Grabner705ecec2009-02-27 19:43:04 -0800132
Markus Grabnere1a164d2010-08-23 01:08:25 +0200133static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code,
134 int size)
Markus Grabner705ecec2009-02-27 19:43:04 -0800135{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200136 return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code,
137 size);
Markus Grabner705ecec2009-02-27 19:43:04 -0800138}
139
140/*
141 Send channel dump data to the PODxt Pro.
142*/
143static void pod_dump(struct usb_line6_pod *pod, const unsigned char *data)
144{
145 int size = 1 + sizeof(pod->prog_data);
146 char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_DUMP, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800147 if (!sysex)
148 return;
149 /* Don't know what this is good for, but PODxt Pro transmits it, so we
150 * also do... */
151 sysex[SYSEX_DATA_OFS] = 5;
Markus Grabner705ecec2009-02-27 19:43:04 -0800152 memcpy(sysex + SYSEX_DATA_OFS + 1, data, sizeof(pod->prog_data));
153 line6_send_sysex_message(&pod->line6, sysex, size);
154 memcpy(&pod->prog_data, data, sizeof(pod->prog_data));
Markus Grabner705ecec2009-02-27 19:43:04 -0800155 kfree(sysex);
156}
157
158/*
159 Store parameter value in driver memory and mark it as dirty.
160*/
161static void pod_store_parameter(struct usb_line6_pod *pod, int param, int value)
162{
163 pod->prog_data.control[param] = value;
Markus Grabner705ecec2009-02-27 19:43:04 -0800164 pod->dirty = 1;
165}
166
167/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200168 Handle SAVE button.
Markus Grabner705ecec2009-02-27 19:43:04 -0800169*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200170static void pod_save_button_pressed(struct usb_line6_pod *pod, int type,
171 int index)
Markus Grabner705ecec2009-02-27 19:43:04 -0800172{
173 pod->dirty = 0;
174 set_bit(POD_SAVE_PRESSED, &pod->atomic_flags);
175}
176
177/*
178 Process a completely received message.
179*/
Markus Grabner1027f4762010-08-12 01:35:30 +0200180void line6_pod_process_message(struct usb_line6_pod *pod)
Markus Grabner705ecec2009-02-27 19:43:04 -0800181{
182 const unsigned char *buf = pod->line6.buffer_message;
183
184 /* filter messages by type */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800185 switch (buf[0] & 0xf0) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800186 case LINE6_PARAM_CHANGE:
187 case LINE6_PROGRAM_CHANGE:
188 case LINE6_SYSEX_BEGIN:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200189 break; /* handle these further down */
Markus Grabner705ecec2009-02-27 19:43:04 -0800190
191 default:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200192 return; /* ignore all others */
Markus Grabner705ecec2009-02-27 19:43:04 -0800193 }
194
195 /* process all remaining messages */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800196 switch (buf[0]) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800197 case LINE6_PARAM_CHANGE | LINE6_CHANNEL_DEVICE:
198 pod_store_parameter(pod, buf[1], buf[2]);
199 /* intentionally no break here! */
200
201 case LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST:
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800202 if ((buf[1] == POD_amp_model_setup) ||
203 (buf[1] == POD_effect_setup))
204 /* these also affect other settings */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200205 line6_dump_request_async(&pod->dumpreq, &pod->line6, 0,
206 LINE6_DUMP_CURRENT);
Markus Grabner705ecec2009-02-27 19:43:04 -0800207
208 break;
209
210 case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_DEVICE:
211 case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST:
Markus Grabner705ecec2009-02-27 19:43:04 -0800212 pod->dirty = 0;
213 set_bit(POD_CHANNEL_DIRTY, &pod->atomic_flags);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200214 line6_dump_request_async(&pod->dumpreq, &pod->line6, 0,
215 LINE6_DUMP_CURRENT);
Markus Grabner705ecec2009-02-27 19:43:04 -0800216 break;
217
218 case LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE:
219 case LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN:
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800220 if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) == 0) {
221 switch (buf[5]) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800222 case POD_SYSEX_DUMP:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200223 if (pod->line6.message_length ==
224 sizeof(pod->prog_data) + 7) {
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800225 switch (pod->dumpreq.in_progress) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800226 case LINE6_DUMP_CURRENT:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200227 memcpy(&pod->prog_data, buf + 7,
228 sizeof(pod->prog_data));
Markus Grabner705ecec2009-02-27 19:43:04 -0800229 break;
230
231 case POD_DUMP_MEMORY:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200232 memcpy(&pod->prog_data_buf,
233 buf + 7,
234 sizeof
235 (pod->prog_data_buf));
Markus Grabner705ecec2009-02-27 19:43:04 -0800236 break;
237
238 default:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100239 dev_dbg(pod->line6.ifcdev,
240 "unknown dump code %02X\n",
241 pod->dumpreq.in_progress);
Markus Grabner705ecec2009-02-27 19:43:04 -0800242 }
243
244 line6_dump_finished(&pod->dumpreq);
Markus Grabner1027f4762010-08-12 01:35:30 +0200245 pod_startup3(pod);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800246 } else
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100247 dev_dbg(pod->line6.ifcdev,
248 "wrong size of channel dump message (%d instead of %d)\n",
249 pod->line6.message_length,
250 (int)sizeof(pod->prog_data) +
251 7);
Markus Grabner705ecec2009-02-27 19:43:04 -0800252
253 break;
254
Markus Grabnere1a164d2010-08-23 01:08:25 +0200255 case POD_SYSEX_SYSTEM:{
256 short value =
257 ((int)buf[7] << 12) | ((int)buf[8]
258 << 8) |
259 ((int)buf[9] << 4) | (int)buf[10];
Markus Grabner705ecec2009-02-27 19:43:04 -0800260
261#define PROCESS_SYSTEM_PARAM(x) \
262 case POD_ ## x: \
263 pod->x.value = value; \
Markus Grabner1027f4762010-08-12 01:35:30 +0200264 wake_up(&pod->x.wait); \
Markus Grabner705ecec2009-02-27 19:43:04 -0800265 break;
266
Markus Grabnere1a164d2010-08-23 01:08:25 +0200267 switch (buf[6]) {
268 PROCESS_SYSTEM_PARAM
269 (monitor_level);
270 PROCESS_SYSTEM_PARAM(routing);
271 PROCESS_SYSTEM_PARAM
272 (tuner_mute);
273 PROCESS_SYSTEM_PARAM
274 (tuner_freq);
275 PROCESS_SYSTEM_PARAM
276 (tuner_note);
277 PROCESS_SYSTEM_PARAM
278 (tuner_pitch);
Markus Grabner705ecec2009-02-27 19:43:04 -0800279
280#undef PROCESS_SYSTEM_PARAM
281
Markus Grabnere1a164d2010-08-23 01:08:25 +0200282 default:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100283 dev_dbg(pod->line6.ifcdev,
284 "unknown tuner/system response %02X\n",
285 buf[6]);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200286 }
Markus Grabner705ecec2009-02-27 19:43:04 -0800287
Markus Grabnere1a164d2010-08-23 01:08:25 +0200288 break;
289 }
Markus Grabner705ecec2009-02-27 19:43:04 -0800290
291 case POD_SYSEX_FINISH:
292 /* do we need to respond to this? */
293 break;
294
295 case POD_SYSEX_SAVE:
296 pod_save_button_pressed(pod, buf[6], buf[7]);
297 break;
298
Markus Grabner705ecec2009-02-27 19:43:04 -0800299 case POD_SYSEX_STORE:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100300 dev_dbg(pod->line6.ifcdev,
301 "message %02X not yet implemented\n",
302 buf[5]);
Markus Grabner705ecec2009-02-27 19:43:04 -0800303 break;
304
305 default:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100306 dev_dbg(pod->line6.ifcdev,
307 "unknown sysex message %02X\n",
308 buf[5]);
Markus Grabner705ecec2009-02-27 19:43:04 -0800309 }
Markus Grabnere1a164d2010-08-23 01:08:25 +0200310 } else
311 if (memcmp
312 (buf, pod_version_header,
313 sizeof(pod_version_header)) == 0) {
314 pod->firmware_version =
315 buf[13] * 100 + buf[14] * 10 + buf[15];
316 pod->device_id =
317 ((int)buf[8] << 16) | ((int)buf[9] << 8) | (int)
318 buf[10];
Markus Grabner1027f4762010-08-12 01:35:30 +0200319 pod_startup4(pod);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800320 } else
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100321 dev_dbg(pod->line6.ifcdev, "unknown sysex header\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800322
323 break;
324
325 case LINE6_SYSEX_END:
326 break;
327
328 default:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100329 dev_dbg(pod->line6.ifcdev, "POD: unknown message %02X\n",
330 buf[0]);
Markus Grabner705ecec2009-02-27 19:43:04 -0800331 }
332}
333
334/*
335 Detect some cases that require a channel dump after sending a command to the
336 device. Important notes:
337 *) The actual dump request can not be sent here since we are not allowed to
338 wait for the completion of the first message in this context, and sending
339 the dump request before completion of the previous message leaves the POD
340 in an undefined state. The dump request will be sent when the echoed
341 commands are received.
342 *) This method fails if a param change message is "chopped" after the first
343 byte.
344*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200345void line6_pod_midi_postprocess(struct usb_line6_pod *pod, unsigned char *data,
346 int length)
Markus Grabner705ecec2009-02-27 19:43:04 -0800347{
348 int i;
349
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800350 if (!pod->midi_postprocess)
Markus Grabner705ecec2009-02-27 19:43:04 -0800351 return;
352
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800353 for (i = 0; i < length; ++i) {
354 if (data[i] == (LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800355 line6_invalidate_current(&pod->dumpreq);
356 break;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200357 } else
358 if ((data[i] == (LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST))
359 && (i < length - 1))
360 if ((data[i + 1] == POD_amp_model_setup)
361 || (data[i + 1] == POD_effect_setup)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800362 line6_invalidate_current(&pod->dumpreq);
363 break;
364 }
365 }
366}
367
368/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800369 Transmit PODxt Pro control parameter.
370*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200371void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param,
Johannes Thumshirn5b9bd2a2012-06-27 21:25:57 +0200372 u8 value)
Markus Grabner705ecec2009-02-27 19:43:04 -0800373{
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800374 if (line6_transmit_parameter(&pod->line6, param, value) == 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800375 pod_store_parameter(pod, param, value);
376
Markus Grabnere1a164d2010-08-23 01:08:25 +0200377 if ((param == POD_amp_model_setup) || (param == POD_effect_setup)) /* these also affect other settings */
Markus Grabner705ecec2009-02-27 19:43:04 -0800378 line6_invalidate_current(&pod->dumpreq);
379}
380
381/*
382 Resolve value to memory location.
383*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200384static int pod_resolve(const char *buf, short block0, short block1,
385 unsigned char *location)
Markus Grabner705ecec2009-02-27 19:43:04 -0800386{
Johannes Thumshirn1d0e8342012-06-27 21:26:01 +0200387 u8 value;
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600388 short block;
389 int ret;
390
Johannes Thumshirn1d0e8342012-06-27 21:26:01 +0200391 ret = kstrtou8(buf, 10, &value);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600392 if (ret)
393 return ret;
394
395 block = (value < 0x40) ? block0 : block1;
Markus Grabner705ecec2009-02-27 19:43:04 -0800396 value &= 0x3f;
397 location[0] = block >> 7;
398 location[1] = value | (block & 0x7f);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600399 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800400}
401
402/*
403 Send command to store channel/effects setup/amp setup to PODxt Pro.
404*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200405static ssize_t pod_send_store_command(struct device *dev, const char *buf,
406 size_t count, short block0, short block1)
Markus Grabner705ecec2009-02-27 19:43:04 -0800407{
408 struct usb_interface *interface = to_usb_interface(dev);
409 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600410 int ret;
Markus Grabner705ecec2009-02-27 19:43:04 -0800411 int size = 3 + sizeof(pod->prog_data_buf);
412 char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_STORE, size);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600413
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800414 if (!sysex)
415 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800416
Markus Grabnere1a164d2010-08-23 01:08:25 +0200417 sysex[SYSEX_DATA_OFS] = 5; /* see pod_dump() */
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600418 ret = pod_resolve(buf, block0, block1, sysex + SYSEX_DATA_OFS + 1);
419 if (ret) {
420 kfree(sysex);
421 return ret;
422 }
423
Markus Grabnere1a164d2010-08-23 01:08:25 +0200424 memcpy(sysex + SYSEX_DATA_OFS + 3, &pod->prog_data_buf,
425 sizeof(pod->prog_data_buf));
Markus Grabner705ecec2009-02-27 19:43:04 -0800426
427 line6_send_sysex_message(&pod->line6, sysex, size);
428 kfree(sysex);
429 /* needs some delay here on AMD64 platform */
430 return count;
431}
432
433/*
434 Send command to retrieve channel/effects setup/amp setup to PODxt Pro.
435*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200436static ssize_t pod_send_retrieve_command(struct device *dev, const char *buf,
437 size_t count, short block0,
438 short block1)
Markus Grabner705ecec2009-02-27 19:43:04 -0800439{
440 struct usb_interface *interface = to_usb_interface(dev);
441 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600442 int ret;
Markus Grabner705ecec2009-02-27 19:43:04 -0800443 int size = 4;
444 char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_DUMPMEM, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800445
446 if (!sysex)
447 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800448
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600449 ret = pod_resolve(buf, block0, block1, sysex + SYSEX_DATA_OFS);
450 if (ret) {
451 kfree(sysex);
452 return ret;
453 }
Markus Grabner705ecec2009-02-27 19:43:04 -0800454 sysex[SYSEX_DATA_OFS + 2] = 0;
455 sysex[SYSEX_DATA_OFS + 3] = 0;
456 line6_dump_started(&pod->dumpreq, POD_DUMP_MEMORY);
457
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800458 if (line6_send_sysex_message(&pod->line6, sysex, size) < size)
Markus Grabner705ecec2009-02-27 19:43:04 -0800459 line6_dump_finished(&pod->dumpreq);
460
461 kfree(sysex);
462 /* needs some delay here on AMD64 platform */
463 return count;
464}
465
466/*
467 Generic get name function.
468*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200469static ssize_t get_name_generic(struct usb_line6_pod *pod, const char *str,
470 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800471{
472 int length = 0;
473 const char *p1;
474 char *p2;
475 char *last_non_space = buf;
476
Markus Grabner1027f4762010-08-12 01:35:30 +0200477 int retval = line6_dump_wait_interruptible(&pod->dumpreq);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800478 if (retval < 0)
479 return retval;
Markus Grabner705ecec2009-02-27 19:43:04 -0800480
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800481 for (p1 = str, p2 = buf; *p1; ++p1, ++p2) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800482 *p2 = *p1;
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800483 if (*p2 != ' ')
484 last_non_space = p2;
485 if (++length == POD_NAME_LENGTH)
486 break;
Markus Grabner705ecec2009-02-27 19:43:04 -0800487 }
488
489 *(last_non_space + 1) = '\n';
490 return last_non_space - buf + 2;
491}
492
493/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800494 "read" request on "name" special file.
495*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800496static ssize_t pod_get_name(struct device *dev, struct device_attribute *attr,
497 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800498{
499 struct usb_interface *interface = to_usb_interface(dev);
500 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200501 return get_name_generic(pod, pod->prog_data.header + POD_NAME_OFFSET,
502 buf);
Markus Grabner705ecec2009-02-27 19:43:04 -0800503}
504
505/*
506 "read" request on "name" special file.
507*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800508static ssize_t pod_get_name_buf(struct device *dev,
509 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800510{
511 struct usb_interface *interface = to_usb_interface(dev);
512 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200513 return get_name_generic(pod,
514 pod->prog_data_buf.header + POD_NAME_OFFSET,
515 buf);
Markus Grabner705ecec2009-02-27 19:43:04 -0800516}
517
518/*
519 "read" request on "dump" special file.
520*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800521static ssize_t pod_get_dump(struct device *dev, struct device_attribute *attr,
522 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800523{
524 struct usb_interface *interface = to_usb_interface(dev);
525 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Markus Grabner1027f4762010-08-12 01:35:30 +0200526 int retval = line6_dump_wait_interruptible(&pod->dumpreq);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800527 if (retval < 0)
528 return retval;
Markus Grabner705ecec2009-02-27 19:43:04 -0800529 memcpy(buf, &pod->prog_data, sizeof(pod->prog_data));
530 return sizeof(pod->prog_data);
531}
532
533/*
534 "write" request on "dump" special file.
535*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800536static ssize_t pod_set_dump(struct device *dev, struct device_attribute *attr,
537 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800538{
539 struct usb_interface *interface = to_usb_interface(dev);
540 struct usb_line6_pod *pod = usb_get_intfdata(interface);
541
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800542 if (count != sizeof(pod->prog_data)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800543 dev_err(pod->line6.ifcdev,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200544 "data block must be exactly %d bytes\n",
545 (int)sizeof(pod->prog_data));
Markus Grabner705ecec2009-02-27 19:43:04 -0800546 return -EINVAL;
547 }
548
549 pod_dump(pod, buf);
550 return sizeof(pod->prog_data);
551}
552
553/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200554 Identify system parameters related to the tuner.
555*/
556static bool pod_is_tuner(int code)
557{
558 return
Markus Grabnere1a164d2010-08-23 01:08:25 +0200559 (code == POD_tuner_mute) ||
560 (code == POD_tuner_freq) ||
561 (code == POD_tuner_note) || (code == POD_tuner_pitch);
Markus Grabner1027f4762010-08-12 01:35:30 +0200562}
563
564/*
565 Get system parameter (as integer).
Markus Grabner705ecec2009-02-27 19:43:04 -0800566 @param tuner non-zero, if code refers to a tuner parameter
567*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200568static int pod_get_system_param_int(struct usb_line6_pod *pod, int *value,
569 int code, struct ValueWait *param, int sign)
Markus Grabner705ecec2009-02-27 19:43:04 -0800570{
571 char *sysex;
Markus Grabner705ecec2009-02-27 19:43:04 -0800572 static const int size = 1;
573 int retval = 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800574
Markus Grabnere1a164d2010-08-23 01:08:25 +0200575 if (((pod->prog_data.control[POD_tuner] & 0x40) == 0)
576 && pod_is_tuner(code))
Markus Grabner705ecec2009-02-27 19:43:04 -0800577 return -ENODEV;
578
Markus Grabner1027f4762010-08-12 01:35:30 +0200579 /* send value request to device: */
Markus Grabner705ecec2009-02-27 19:43:04 -0800580 param->value = POD_system_invalid;
581 sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEMREQ, size);
Markus Grabner1027f4762010-08-12 01:35:30 +0200582
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800583 if (!sysex)
Markus Grabner1027f4762010-08-12 01:35:30 +0200584 return -ENOMEM;
585
Markus Grabner705ecec2009-02-27 19:43:04 -0800586 sysex[SYSEX_DATA_OFS] = code;
587 line6_send_sysex_message(&pod->line6, sysex, size);
588 kfree(sysex);
589
Markus Grabner1027f4762010-08-12 01:35:30 +0200590 /* wait for device to respond: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200591 retval =
592 wait_event_interruptible(param->wait,
593 param->value != POD_system_invalid);
Markus Grabner705ecec2009-02-27 19:43:04 -0800594
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800595 if (retval < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800596 return retval;
597
Markus Grabnere1a164d2010-08-23 01:08:25 +0200598 *value = sign ? (int)(signed short)param->value : (int)(unsigned short)
599 param->value;
Markus Grabner1027f4762010-08-12 01:35:30 +0200600
Markus Grabnere1a164d2010-08-23 01:08:25 +0200601 if (*value == POD_system_invalid)
602 *value = 0; /* don't report uninitialized values */
Markus Grabner1027f4762010-08-12 01:35:30 +0200603
604 return 0;
605}
606
607/*
608 Get system parameter (as string).
609 @param tuner non-zero, if code refers to a tuner parameter
610*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200611static ssize_t pod_get_system_param_string(struct usb_line6_pod *pod, char *buf,
612 int code, struct ValueWait *param,
613 int sign)
Markus Grabner1027f4762010-08-12 01:35:30 +0200614{
615 int retval, value = 0;
616 retval = pod_get_system_param_int(pod, &value, code, param, sign);
617
Markus Grabnere1a164d2010-08-23 01:08:25 +0200618 if (retval < 0)
Markus Grabner1027f4762010-08-12 01:35:30 +0200619 return retval;
620
Markus Grabner705ecec2009-02-27 19:43:04 -0800621 return sprintf(buf, "%d\n", value);
622}
623
624/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200625 Send system parameter (from integer).
Markus Grabner705ecec2009-02-27 19:43:04 -0800626 @param tuner non-zero, if code refers to a tuner parameter
627*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200628static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
629 int code)
Markus Grabner705ecec2009-02-27 19:43:04 -0800630{
631 char *sysex;
632 static const int size = 5;
Markus Grabner705ecec2009-02-27 19:43:04 -0800633
Markus Grabnere1a164d2010-08-23 01:08:25 +0200634 if (((pod->prog_data.control[POD_tuner] & 0x40) == 0)
635 && pod_is_tuner(code))
Markus Grabner705ecec2009-02-27 19:43:04 -0800636 return -EINVAL;
637
638 /* send value to tuner: */
639 sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800640 if (!sysex)
Markus Grabner1027f4762010-08-12 01:35:30 +0200641 return -ENOMEM;
Markus Grabner705ecec2009-02-27 19:43:04 -0800642 sysex[SYSEX_DATA_OFS] = code;
643 sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200644 sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f;
645 sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f;
646 sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f;
Markus Grabner705ecec2009-02-27 19:43:04 -0800647 line6_send_sysex_message(&pod->line6, sysex, size);
648 kfree(sysex);
Markus Grabner1027f4762010-08-12 01:35:30 +0200649 return 0;
650}
651
652/*
653 Send system parameter (from string).
654 @param tuner non-zero, if code refers to a tuner parameter
655*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200656static ssize_t pod_set_system_param_string(struct usb_line6_pod *pod,
657 const char *buf, int count, int code,
658 unsigned short mask)
Markus Grabner1027f4762010-08-12 01:35:30 +0200659{
660 int retval;
661 unsigned short value = simple_strtoul(buf, NULL, 10) & mask;
662 retval = pod_set_system_param_int(pod, value, code);
663 return (retval < 0) ? retval : count;
Markus Grabner705ecec2009-02-27 19:43:04 -0800664}
665
666/*
667 "read" request on "dump_buf" special file.
668*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800669static ssize_t pod_get_dump_buf(struct device *dev,
670 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800671{
672 struct usb_interface *interface = to_usb_interface(dev);
673 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Markus Grabner1027f4762010-08-12 01:35:30 +0200674 int retval = line6_dump_wait_interruptible(&pod->dumpreq);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800675 if (retval < 0)
676 return retval;
Markus Grabner705ecec2009-02-27 19:43:04 -0800677 memcpy(buf, &pod->prog_data_buf, sizeof(pod->prog_data_buf));
678 return sizeof(pod->prog_data_buf);
679}
680
681/*
682 "write" request on "dump_buf" special file.
683*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800684static ssize_t pod_set_dump_buf(struct device *dev,
685 struct device_attribute *attr,
686 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800687{
688 struct usb_interface *interface = to_usb_interface(dev);
689 struct usb_line6_pod *pod = usb_get_intfdata(interface);
690
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800691 if (count != sizeof(pod->prog_data)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800692 dev_err(pod->line6.ifcdev,
Markus Grabner1027f4762010-08-12 01:35:30 +0200693 "data block must be exactly %d bytes\n",
694 (int)sizeof(pod->prog_data));
Markus Grabner705ecec2009-02-27 19:43:04 -0800695 return -EINVAL;
696 }
697
698 memcpy(&pod->prog_data_buf, buf, sizeof(pod->prog_data));
699 return sizeof(pod->prog_data);
700}
701
702/*
703 "write" request on "finish" special file.
704*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800705static ssize_t pod_set_finish(struct device *dev,
706 struct device_attribute *attr,
707 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800708{
709 struct usb_interface *interface = to_usb_interface(dev);
710 struct usb_line6_pod *pod = usb_get_intfdata(interface);
711 int size = 0;
712 char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_FINISH, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800713 if (!sysex)
714 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800715 line6_send_sysex_message(&pod->line6, sysex, size);
716 kfree(sysex);
717 return count;
718}
719
720/*
721 "write" request on "store_channel" special file.
722*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800723static ssize_t pod_set_store_channel(struct device *dev,
724 struct device_attribute *attr,
725 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800726{
727 return pod_send_store_command(dev, buf, count, 0x0000, 0x00c0);
728}
729
730/*
731 "write" request on "store_effects_setup" special file.
732*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800733static ssize_t pod_set_store_effects_setup(struct device *dev,
734 struct device_attribute *attr,
735 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800736{
737 return pod_send_store_command(dev, buf, count, 0x0080, 0x0080);
738}
739
740/*
741 "write" request on "store_amp_setup" special file.
742*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800743static ssize_t pod_set_store_amp_setup(struct device *dev,
744 struct device_attribute *attr,
745 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800746{
747 return pod_send_store_command(dev, buf, count, 0x0040, 0x0100);
748}
749
750/*
751 "write" request on "retrieve_channel" special file.
752*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800753static ssize_t pod_set_retrieve_channel(struct device *dev,
754 struct device_attribute *attr,
755 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800756{
757 return pod_send_retrieve_command(dev, buf, count, 0x0000, 0x00c0);
758}
759
760/*
761 "write" request on "retrieve_effects_setup" special file.
762*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800763static ssize_t pod_set_retrieve_effects_setup(struct device *dev,
764 struct device_attribute *attr,
765 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800766{
767 return pod_send_retrieve_command(dev, buf, count, 0x0080, 0x0080);
768}
769
770/*
771 "write" request on "retrieve_amp_setup" special file.
772*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800773static ssize_t pod_set_retrieve_amp_setup(struct device *dev,
774 struct device_attribute *attr,
775 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800776{
777 return pod_send_retrieve_command(dev, buf, count, 0x0040, 0x0100);
778}
779
780/*
781 "read" request on "dirty" special file.
782*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800783static ssize_t pod_get_dirty(struct device *dev, struct device_attribute *attr,
784 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800785{
786 struct usb_interface *interface = to_usb_interface(dev);
787 struct usb_line6_pod *pod = usb_get_intfdata(interface);
788 buf[0] = pod->dirty ? '1' : '0';
789 buf[1] = '\n';
790 return 2;
791}
792
793/*
794 "read" request on "midi_postprocess" special file.
795*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800796static ssize_t pod_get_midi_postprocess(struct device *dev,
797 struct device_attribute *attr,
798 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800799{
800 struct usb_interface *interface = to_usb_interface(dev);
801 struct usb_line6_pod *pod = usb_get_intfdata(interface);
802 return sprintf(buf, "%d\n", pod->midi_postprocess);
803}
804
805/*
806 "write" request on "midi_postprocess" special file.
807*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800808static ssize_t pod_set_midi_postprocess(struct device *dev,
809 struct device_attribute *attr,
810 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800811{
812 struct usb_interface *interface = to_usb_interface(dev);
813 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Johannes Thumshirn06501782012-06-27 21:26:03 +0200814 u8 value;
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600815 int ret;
816
Johannes Thumshirn06501782012-06-27 21:26:03 +0200817 ret = kstrtou8(buf, 10, &value);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600818 if (ret)
819 return ret;
820
Markus Grabner705ecec2009-02-27 19:43:04 -0800821 pod->midi_postprocess = value ? 1 : 0;
822 return count;
823}
824
825/*
826 "read" request on "serial_number" special file.
827*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800828static ssize_t pod_get_serial_number(struct device *dev,
829 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800830{
831 struct usb_interface *interface = to_usb_interface(dev);
832 struct usb_line6_pod *pod = usb_get_intfdata(interface);
833 return sprintf(buf, "%d\n", pod->serial_number);
834}
835
836/*
837 "read" request on "firmware_version" special file.
838*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800839static ssize_t pod_get_firmware_version(struct device *dev,
840 struct device_attribute *attr,
841 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800842{
843 struct usb_interface *interface = to_usb_interface(dev);
844 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800845 return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
846 pod->firmware_version % 100);
Markus Grabner705ecec2009-02-27 19:43:04 -0800847}
848
849/*
850 "read" request on "device_id" special file.
851*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800852static ssize_t pod_get_device_id(struct device *dev,
853 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800854{
855 struct usb_interface *interface = to_usb_interface(dev);
856 struct usb_line6_pod *pod = usb_get_intfdata(interface);
857 return sprintf(buf, "%d\n", pod->device_id);
858}
859
860/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200861 POD startup procedure.
862 This is a sequence of functions with special requirements (e.g., must
863 not run immediately after initialization, must not run in interrupt
864 context). After the last one has finished, the device is ready to use.
865*/
866
867static void pod_startup1(struct usb_line6_pod *pod)
868{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200869 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT);
Markus Grabner1027f4762010-08-12 01:35:30 +0200870
871 /* delay startup procedure: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200872 line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
873 (unsigned long)pod);
Markus Grabner1027f4762010-08-12 01:35:30 +0200874}
875
876static void pod_startup2(unsigned long data)
877{
878 struct usb_line6_pod *pod = (struct usb_line6_pod *)data;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200879
880 /* schedule another startup procedure until startup is complete: */
881 if (pod->startup_progress >= POD_STARTUP_LAST)
882 return;
883
884 pod->startup_progress = POD_STARTUP_DUMPREQ;
885 line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
886 (unsigned long)pod);
Markus Grabner1027f4762010-08-12 01:35:30 +0200887
888 /* current channel dump: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200889 line6_dump_request_async(&pod->dumpreq, &pod->line6, 0,
890 LINE6_DUMP_CURRENT);
Markus Grabner1027f4762010-08-12 01:35:30 +0200891}
892
893static void pod_startup3(struct usb_line6_pod *pod)
894{
895 struct usb_line6 *line6 = &pod->line6;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200896 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ);
Markus Grabner1027f4762010-08-12 01:35:30 +0200897
898 /* request firmware version: */
899 line6_version_request_async(line6);
900}
901
902static void pod_startup4(struct usb_line6_pod *pod)
903{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200904 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE);
Markus Grabner1027f4762010-08-12 01:35:30 +0200905
906 /* schedule work for global work queue: */
907 schedule_work(&pod->startup_work);
908}
909
910static void pod_startup5(struct work_struct *work)
911{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200912 struct usb_line6_pod *pod =
913 container_of(work, struct usb_line6_pod, startup_work);
Markus Grabner1027f4762010-08-12 01:35:30 +0200914 struct usb_line6 *line6 = &pod->line6;
915
Markus Grabnere1a164d2010-08-23 01:08:25 +0200916 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP);
Markus Grabner1027f4762010-08-12 01:35:30 +0200917
918 /* serial number: */
919 line6_read_serial_number(&pod->line6, &pod->serial_number);
920
921 /* ALSA audio interface: */
922 line6_register_audio(line6);
923
924 /* device files: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200925 line6_pod_create_files(pod->firmware_version,
926 line6->properties->device_bit, line6->ifcdev);
Markus Grabner1027f4762010-08-12 01:35:30 +0200927}
928
929#define POD_GET_SYSTEM_PARAM(code, sign) \
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800930static ssize_t pod_get_ ## code(struct device *dev, \
931 struct device_attribute *attr, char *buf) \
Markus Grabner705ecec2009-02-27 19:43:04 -0800932{ \
933 struct usb_interface *interface = to_usb_interface(dev); \
934 struct usb_line6_pod *pod = usb_get_intfdata(interface); \
Markus Grabner1027f4762010-08-12 01:35:30 +0200935 return pod_get_system_param_string(pod, buf, POD_ ## code, \
936 &pod->code, sign); \
Markus Grabner705ecec2009-02-27 19:43:04 -0800937}
938
Markus Grabner1027f4762010-08-12 01:35:30 +0200939#define POD_GET_SET_SYSTEM_PARAM(code, mask, sign) \
940POD_GET_SYSTEM_PARAM(code, sign) \
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800941static ssize_t pod_set_ ## code(struct device *dev, \
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800942 struct device_attribute *attr, \
943 const char *buf, size_t count) \
Markus Grabner705ecec2009-02-27 19:43:04 -0800944{ \
945 struct usb_interface *interface = to_usb_interface(dev); \
946 struct usb_line6_pod *pod = usb_get_intfdata(interface); \
Markus Grabner1027f4762010-08-12 01:35:30 +0200947 return pod_set_system_param_string(pod, buf, count, POD_ ## code, mask); \
Markus Grabner705ecec2009-02-27 19:43:04 -0800948}
949
Markus Grabner1027f4762010-08-12 01:35:30 +0200950POD_GET_SET_SYSTEM_PARAM(monitor_level, 0xffff, 0);
951POD_GET_SET_SYSTEM_PARAM(routing, 0x0003, 0);
952POD_GET_SET_SYSTEM_PARAM(tuner_mute, 0x0001, 0);
953POD_GET_SET_SYSTEM_PARAM(tuner_freq, 0xffff, 0);
954POD_GET_SYSTEM_PARAM(tuner_note, 1);
955POD_GET_SYSTEM_PARAM(tuner_pitch, 1);
Markus Grabner705ecec2009-02-27 19:43:04 -0800956
957#undef GET_SET_SYSTEM_PARAM
958#undef GET_SYSTEM_PARAM
959
960/* POD special files: */
Markus Grabner705ecec2009-02-27 19:43:04 -0800961static DEVICE_ATTR(device_id, S_IRUGO, pod_get_device_id, line6_nop_write);
962static DEVICE_ATTR(dirty, S_IRUGO, pod_get_dirty, line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800963static DEVICE_ATTR(dump, S_IWUSR | S_IRUGO, pod_get_dump, pod_set_dump);
964static DEVICE_ATTR(dump_buf, S_IWUSR | S_IRUGO, pod_get_dump_buf,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200965 pod_set_dump_buf);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800966static DEVICE_ATTR(finish, S_IWUSR, line6_nop_read, pod_set_finish);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200967static DEVICE_ATTR(firmware_version, S_IRUGO, pod_get_firmware_version,
968 line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800969static DEVICE_ATTR(midi_postprocess, S_IWUSR | S_IRUGO,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200970 pod_get_midi_postprocess, pod_set_midi_postprocess);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800971static DEVICE_ATTR(monitor_level, S_IWUSR | S_IRUGO, pod_get_monitor_level,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200972 pod_set_monitor_level);
Markus Grabner705ecec2009-02-27 19:43:04 -0800973static DEVICE_ATTR(name, S_IRUGO, pod_get_name, line6_nop_write);
974static DEVICE_ATTR(name_buf, S_IRUGO, pod_get_name_buf, line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800975static DEVICE_ATTR(retrieve_amp_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200976 pod_set_retrieve_amp_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800977static DEVICE_ATTR(retrieve_channel, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200978 pod_set_retrieve_channel);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800979static DEVICE_ATTR(retrieve_effects_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200980 pod_set_retrieve_effects_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800981static DEVICE_ATTR(routing, S_IWUSR | S_IRUGO, pod_get_routing,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200982 pod_set_routing);
983static DEVICE_ATTR(serial_number, S_IRUGO, pod_get_serial_number,
984 line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800985static DEVICE_ATTR(store_amp_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200986 pod_set_store_amp_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800987static DEVICE_ATTR(store_channel, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200988 pod_set_store_channel);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800989static DEVICE_ATTR(store_effects_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200990 pod_set_store_effects_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800991static DEVICE_ATTR(tuner_freq, S_IWUSR | S_IRUGO, pod_get_tuner_freq,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200992 pod_set_tuner_freq);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800993static DEVICE_ATTR(tuner_mute, S_IWUSR | S_IRUGO, pod_get_tuner_mute,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200994 pod_set_tuner_mute);
Markus Grabner705ecec2009-02-27 19:43:04 -0800995static DEVICE_ATTR(tuner_note, S_IRUGO, pod_get_tuner_note, line6_nop_write);
996static DEVICE_ATTR(tuner_pitch, S_IRUGO, pod_get_tuner_pitch, line6_nop_write);
997
Markus Grabner1027f4762010-08-12 01:35:30 +0200998#ifdef CONFIG_LINE6_USB_RAW
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800999static DEVICE_ATTR(raw, S_IWUSR, line6_nop_read, line6_set_raw);
Markus Grabner705ecec2009-02-27 19:43:04 -08001000#endif
1001
Markus Grabner1027f4762010-08-12 01:35:30 +02001002/* control info callback */
1003static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol,
1004 struct snd_ctl_elem_info *uinfo)
1005{
1006 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
1007 uinfo->count = 1;
1008 uinfo->value.integer.min = 0;
1009 uinfo->value.integer.max = 65535;
1010 return 0;
1011}
1012
1013/* control get callback */
1014static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol,
1015 struct snd_ctl_elem_value *ucontrol)
1016{
1017 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
1018 struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
1019 ucontrol->value.integer.value[0] = pod->monitor_level.value;
1020 return 0;
1021}
1022
1023/* control put callback */
1024static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol,
1025 struct snd_ctl_elem_value *ucontrol)
1026{
1027 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
1028 struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
1029
Markus Grabnere1a164d2010-08-23 01:08:25 +02001030 if (ucontrol->value.integer.value[0] == pod->monitor_level.value)
Markus Grabner1027f4762010-08-12 01:35:30 +02001031 return 0;
1032
1033 pod->monitor_level.value = ucontrol->value.integer.value[0];
Markus Grabnere1a164d2010-08-23 01:08:25 +02001034 pod_set_system_param_int(pod, ucontrol->value.integer.value[0],
1035 POD_monitor_level);
Markus Grabner1027f4762010-08-12 01:35:30 +02001036 return 1;
1037}
1038
1039/* control definition */
1040static struct snd_kcontrol_new pod_control_monitor = {
1041 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1042 .name = "Monitor Playback Volume",
1043 .index = 0,
1044 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1045 .info = snd_pod_control_monitor_info,
1046 .get = snd_pod_control_monitor_get,
1047 .put = snd_pod_control_monitor_put
1048};
1049
Markus Grabner705ecec2009-02-27 19:43:04 -08001050/*
1051 POD destructor.
1052*/
1053static void pod_destruct(struct usb_interface *interface)
1054{
1055 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Markus Grabner705ecec2009-02-27 19:43:04 -08001056
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001057 if (pod == NULL)
1058 return;
Stefan Hajnoczi188e6642011-12-10 02:12:30 +01001059 line6_cleanup_audio(&pod->line6);
Markus Grabner705ecec2009-02-27 19:43:04 -08001060
Markus Grabnere1a164d2010-08-23 01:08:25 +02001061 del_timer(&pod->startup_timer);
1062 cancel_work_sync(&pod->startup_work);
1063
Markus Grabner705ecec2009-02-27 19:43:04 -08001064 /* free dump request data: */
1065 line6_dumpreq_destruct(&pod->dumpreq);
Markus Grabner705ecec2009-02-27 19:43:04 -08001066}
1067
1068/*
1069 Create sysfs entries.
1070*/
Greg Kroah-Hartmanb702ed252009-02-27 20:45:03 -08001071static int pod_create_files2(struct device *dev)
Markus Grabner705ecec2009-02-27 19:43:04 -08001072{
1073 int err;
1074
Markus Grabner705ecec2009-02-27 19:43:04 -08001075 CHECK_RETURN(device_create_file(dev, &dev_attr_device_id));
1076 CHECK_RETURN(device_create_file(dev, &dev_attr_dirty));
1077 CHECK_RETURN(device_create_file(dev, &dev_attr_dump));
1078 CHECK_RETURN(device_create_file(dev, &dev_attr_dump_buf));
1079 CHECK_RETURN(device_create_file(dev, &dev_attr_finish));
1080 CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version));
1081 CHECK_RETURN(device_create_file(dev, &dev_attr_midi_postprocess));
1082 CHECK_RETURN(device_create_file(dev, &dev_attr_monitor_level));
1083 CHECK_RETURN(device_create_file(dev, &dev_attr_name));
1084 CHECK_RETURN(device_create_file(dev, &dev_attr_name_buf));
1085 CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_amp_setup));
1086 CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_channel));
1087 CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_effects_setup));
1088 CHECK_RETURN(device_create_file(dev, &dev_attr_routing));
1089 CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number));
1090 CHECK_RETURN(device_create_file(dev, &dev_attr_store_amp_setup));
1091 CHECK_RETURN(device_create_file(dev, &dev_attr_store_channel));
1092 CHECK_RETURN(device_create_file(dev, &dev_attr_store_effects_setup));
1093 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_freq));
1094 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_mute));
1095 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_note));
1096 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_pitch));
1097
Markus Grabner1027f4762010-08-12 01:35:30 +02001098#ifdef CONFIG_LINE6_USB_RAW
Markus Grabner705ecec2009-02-27 19:43:04 -08001099 CHECK_RETURN(device_create_file(dev, &dev_attr_raw));
1100#endif
1101
1102 return 0;
1103}
1104
1105/*
Markus Grabner1027f4762010-08-12 01:35:30 +02001106 Try to init POD device.
Markus Grabner705ecec2009-02-27 19:43:04 -08001107*/
Markus Grabnere1a164d2010-08-23 01:08:25 +02001108static int pod_try_init(struct usb_interface *interface,
1109 struct usb_line6_pod *pod)
Markus Grabner705ecec2009-02-27 19:43:04 -08001110{
1111 int err;
1112 struct usb_line6 *line6 = &pod->line6;
1113
Markus Grabnere1a164d2010-08-23 01:08:25 +02001114 init_timer(&pod->startup_timer);
1115 INIT_WORK(&pod->startup_work, pod_startup5);
1116
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001117 if ((interface == NULL) || (pod == NULL))
1118 return -ENODEV;
Markus Grabner705ecec2009-02-27 19:43:04 -08001119
Markus Grabner705ecec2009-02-27 19:43:04 -08001120 /* initialize wait queues: */
1121 init_waitqueue_head(&pod->monitor_level.wait);
1122 init_waitqueue_head(&pod->routing.wait);
1123 init_waitqueue_head(&pod->tuner_mute.wait);
1124 init_waitqueue_head(&pod->tuner_freq.wait);
1125 init_waitqueue_head(&pod->tuner_note.wait);
1126 init_waitqueue_head(&pod->tuner_pitch.wait);
Markus Grabner705ecec2009-02-27 19:43:04 -08001127
Markus Grabner705ecec2009-02-27 19:43:04 -08001128 /* initialize USB buffers: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001129 err = line6_dumpreq_init(&pod->dumpreq, pod_request_channel,
1130 sizeof(pod_request_channel));
1131 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001132 dev_err(&interface->dev, "Out of memory\n");
Markus Grabner705ecec2009-02-27 19:43:04 -08001133 return -ENOMEM;
1134 }
1135
Markus Grabner705ecec2009-02-27 19:43:04 -08001136 /* create sysfs entries: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001137 err = pod_create_files2(&interface->dev);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001138 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -08001139 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -08001140
1141 /* initialize audio system: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001142 err = line6_init_audio(line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001143 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -08001144 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -08001145
1146 /* initialize MIDI subsystem: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001147 err = line6_init_midi(line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001148 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -08001149 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -08001150
1151 /* initialize PCM subsystem: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001152 err = line6_init_pcm(line6, &pod_pcm_properties);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001153 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -08001154 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -08001155
Markus Grabner1027f4762010-08-12 01:35:30 +02001156 /* register monitor control: */
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001157 err = snd_ctl_add(line6->card,
1158 snd_ctl_new1(&pod_control_monitor, line6->line6pcm));
1159 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -08001160 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -08001161
Markus Grabner1027f4762010-08-12 01:35:30 +02001162 /*
Markus Grabnere1a164d2010-08-23 01:08:25 +02001163 When the sound card is registered at this point, the PODxt Live
1164 displays "Invalid Code Error 07", so we do it later in the event
1165 handler.
1166 */
Markus Grabner1027f4762010-08-12 01:35:30 +02001167
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001168 if (pod->line6.properties->capabilities & LINE6_BIT_CONTROL) {
Markus Grabner1027f4762010-08-12 01:35:30 +02001169 pod->monitor_level.value = POD_system_invalid;
1170
1171 /* initiate startup procedure: */
1172 pod_startup1(pod);
Markus Grabner705ecec2009-02-27 19:43:04 -08001173 }
1174
1175 return 0;
1176}
1177
1178/*
Markus Grabner1027f4762010-08-12 01:35:30 +02001179 Init POD device (and clean up in case of failure).
1180*/
1181int line6_pod_init(struct usb_interface *interface, struct usb_line6_pod *pod)
1182{
1183 int err = pod_try_init(interface, pod);
1184
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001185 if (err < 0)
Markus Grabner1027f4762010-08-12 01:35:30 +02001186 pod_destruct(interface);
Markus Grabner1027f4762010-08-12 01:35:30 +02001187
1188 return err;
1189}
1190
1191/*
Markus Grabner705ecec2009-02-27 19:43:04 -08001192 POD device disconnected.
1193*/
Markus Grabner1027f4762010-08-12 01:35:30 +02001194void line6_pod_disconnect(struct usb_interface *interface)
Markus Grabner705ecec2009-02-27 19:43:04 -08001195{
1196 struct usb_line6_pod *pod;
1197
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001198 if (interface == NULL)
1199 return;
Markus Grabner705ecec2009-02-27 19:43:04 -08001200 pod = usb_get_intfdata(interface);
1201
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001202 if (pod != NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001203 struct snd_line6_pcm *line6pcm = pod->line6.line6pcm;
1204 struct device *dev = &interface->dev;
1205
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001206 if (line6pcm != NULL)
Markus Grabner1027f4762010-08-12 01:35:30 +02001207 line6_pcm_disconnect(line6pcm);
Markus Grabner705ecec2009-02-27 19:43:04 -08001208
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001209 if (dev != NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001210 /* remove sysfs entries: */
Markus Grabnere1a164d2010-08-23 01:08:25 +02001211 line6_pod_remove_files(pod->firmware_version,
1212 pod->line6.
1213 properties->device_bit, dev);
Markus Grabner705ecec2009-02-27 19:43:04 -08001214
Markus Grabner705ecec2009-02-27 19:43:04 -08001215 device_remove_file(dev, &dev_attr_device_id);
1216 device_remove_file(dev, &dev_attr_dirty);
1217 device_remove_file(dev, &dev_attr_dump);
1218 device_remove_file(dev, &dev_attr_dump_buf);
1219 device_remove_file(dev, &dev_attr_finish);
1220 device_remove_file(dev, &dev_attr_firmware_version);
1221 device_remove_file(dev, &dev_attr_midi_postprocess);
1222 device_remove_file(dev, &dev_attr_monitor_level);
1223 device_remove_file(dev, &dev_attr_name);
1224 device_remove_file(dev, &dev_attr_name_buf);
1225 device_remove_file(dev, &dev_attr_retrieve_amp_setup);
1226 device_remove_file(dev, &dev_attr_retrieve_channel);
Markus Grabnere1a164d2010-08-23 01:08:25 +02001227 device_remove_file(dev,
1228 &dev_attr_retrieve_effects_setup);
Markus Grabner705ecec2009-02-27 19:43:04 -08001229 device_remove_file(dev, &dev_attr_routing);
1230 device_remove_file(dev, &dev_attr_serial_number);
1231 device_remove_file(dev, &dev_attr_store_amp_setup);
1232 device_remove_file(dev, &dev_attr_store_channel);
1233 device_remove_file(dev, &dev_attr_store_effects_setup);
1234 device_remove_file(dev, &dev_attr_tuner_freq);
1235 device_remove_file(dev, &dev_attr_tuner_mute);
1236 device_remove_file(dev, &dev_attr_tuner_note);
1237 device_remove_file(dev, &dev_attr_tuner_pitch);
1238
Markus Grabner1027f4762010-08-12 01:35:30 +02001239#ifdef CONFIG_LINE6_USB_RAW
Markus Grabner705ecec2009-02-27 19:43:04 -08001240 device_remove_file(dev, &dev_attr_raw);
1241#endif
1242 }
1243 }
1244
1245 pod_destruct(interface);
1246}