blob: 7c76b65d4ab66e29cd447a0a67aa1f617204de98 [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/*
Stefan Hajnoczib772fe92012-11-22 20:48:43 +0100159 Store parameter value in driver memory.
Markus Grabner705ecec2009-02-27 19:43:04 -0800160*/
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}
165
166/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200167 Handle SAVE button.
Markus Grabner705ecec2009-02-27 19:43:04 -0800168*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200169static void pod_save_button_pressed(struct usb_line6_pod *pod, int type,
170 int index)
Markus Grabner705ecec2009-02-27 19:43:04 -0800171{
Markus Grabner705ecec2009-02-27 19:43:04 -0800172 set_bit(POD_SAVE_PRESSED, &pod->atomic_flags);
173}
174
175/*
176 Process a completely received message.
177*/
Markus Grabner1027f4762010-08-12 01:35:30 +0200178void line6_pod_process_message(struct usb_line6_pod *pod)
Markus Grabner705ecec2009-02-27 19:43:04 -0800179{
180 const unsigned char *buf = pod->line6.buffer_message;
181
182 /* filter messages by type */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800183 switch (buf[0] & 0xf0) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800184 case LINE6_PARAM_CHANGE:
185 case LINE6_PROGRAM_CHANGE:
186 case LINE6_SYSEX_BEGIN:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200187 break; /* handle these further down */
Markus Grabner705ecec2009-02-27 19:43:04 -0800188
189 default:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200190 return; /* ignore all others */
Markus Grabner705ecec2009-02-27 19:43:04 -0800191 }
192
193 /* process all remaining messages */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800194 switch (buf[0]) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800195 case LINE6_PARAM_CHANGE | LINE6_CHANNEL_DEVICE:
196 pod_store_parameter(pod, buf[1], buf[2]);
197 /* intentionally no break here! */
198
199 case LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST:
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800200 if ((buf[1] == POD_amp_model_setup) ||
201 (buf[1] == POD_effect_setup))
202 /* these also affect other settings */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200203 line6_dump_request_async(&pod->dumpreq, &pod->line6, 0,
204 LINE6_DUMP_CURRENT);
Markus Grabner705ecec2009-02-27 19:43:04 -0800205
206 break;
207
208 case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_DEVICE:
209 case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST:
Markus Grabner705ecec2009-02-27 19:43:04 -0800210 set_bit(POD_CHANNEL_DIRTY, &pod->atomic_flags);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200211 line6_dump_request_async(&pod->dumpreq, &pod->line6, 0,
212 LINE6_DUMP_CURRENT);
Markus Grabner705ecec2009-02-27 19:43:04 -0800213 break;
214
215 case LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE:
216 case LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN:
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800217 if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) == 0) {
218 switch (buf[5]) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800219 case POD_SYSEX_DUMP:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200220 if (pod->line6.message_length ==
221 sizeof(pod->prog_data) + 7) {
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800222 switch (pod->dumpreq.in_progress) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800223 case LINE6_DUMP_CURRENT:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200224 memcpy(&pod->prog_data, buf + 7,
225 sizeof(pod->prog_data));
Markus Grabner705ecec2009-02-27 19:43:04 -0800226 break;
227
228 case POD_DUMP_MEMORY:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200229 memcpy(&pod->prog_data_buf,
230 buf + 7,
231 sizeof
232 (pod->prog_data_buf));
Markus Grabner705ecec2009-02-27 19:43:04 -0800233 break;
234
235 default:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100236 dev_dbg(pod->line6.ifcdev,
237 "unknown dump code %02X\n",
238 pod->dumpreq.in_progress);
Markus Grabner705ecec2009-02-27 19:43:04 -0800239 }
240
241 line6_dump_finished(&pod->dumpreq);
Markus Grabner1027f4762010-08-12 01:35:30 +0200242 pod_startup3(pod);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800243 } else
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100244 dev_dbg(pod->line6.ifcdev,
245 "wrong size of channel dump message (%d instead of %d)\n",
246 pod->line6.message_length,
247 (int)sizeof(pod->prog_data) +
248 7);
Markus Grabner705ecec2009-02-27 19:43:04 -0800249
250 break;
251
Markus Grabnere1a164d2010-08-23 01:08:25 +0200252 case POD_SYSEX_SYSTEM:{
253 short value =
254 ((int)buf[7] << 12) | ((int)buf[8]
255 << 8) |
256 ((int)buf[9] << 4) | (int)buf[10];
Markus Grabner705ecec2009-02-27 19:43:04 -0800257
258#define PROCESS_SYSTEM_PARAM(x) \
259 case POD_ ## x: \
260 pod->x.value = value; \
Markus Grabner1027f4762010-08-12 01:35:30 +0200261 wake_up(&pod->x.wait); \
Markus Grabner705ecec2009-02-27 19:43:04 -0800262 break;
263
Markus Grabnere1a164d2010-08-23 01:08:25 +0200264 switch (buf[6]) {
265 PROCESS_SYSTEM_PARAM
266 (monitor_level);
267 PROCESS_SYSTEM_PARAM(routing);
268 PROCESS_SYSTEM_PARAM
269 (tuner_mute);
270 PROCESS_SYSTEM_PARAM
271 (tuner_freq);
272 PROCESS_SYSTEM_PARAM
273 (tuner_note);
274 PROCESS_SYSTEM_PARAM
275 (tuner_pitch);
Markus Grabner705ecec2009-02-27 19:43:04 -0800276
277#undef PROCESS_SYSTEM_PARAM
278
Markus Grabnere1a164d2010-08-23 01:08:25 +0200279 default:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100280 dev_dbg(pod->line6.ifcdev,
281 "unknown tuner/system response %02X\n",
282 buf[6]);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200283 }
Markus Grabner705ecec2009-02-27 19:43:04 -0800284
Markus Grabnere1a164d2010-08-23 01:08:25 +0200285 break;
286 }
Markus Grabner705ecec2009-02-27 19:43:04 -0800287
288 case POD_SYSEX_FINISH:
289 /* do we need to respond to this? */
290 break;
291
292 case POD_SYSEX_SAVE:
293 pod_save_button_pressed(pod, buf[6], buf[7]);
294 break;
295
Markus Grabner705ecec2009-02-27 19:43:04 -0800296 case POD_SYSEX_STORE:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100297 dev_dbg(pod->line6.ifcdev,
298 "message %02X not yet implemented\n",
299 buf[5]);
Markus Grabner705ecec2009-02-27 19:43:04 -0800300 break;
301
302 default:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100303 dev_dbg(pod->line6.ifcdev,
304 "unknown sysex message %02X\n",
305 buf[5]);
Markus Grabner705ecec2009-02-27 19:43:04 -0800306 }
Markus Grabnere1a164d2010-08-23 01:08:25 +0200307 } else
308 if (memcmp
309 (buf, pod_version_header,
310 sizeof(pod_version_header)) == 0) {
311 pod->firmware_version =
312 buf[13] * 100 + buf[14] * 10 + buf[15];
313 pod->device_id =
314 ((int)buf[8] << 16) | ((int)buf[9] << 8) | (int)
315 buf[10];
Markus Grabner1027f4762010-08-12 01:35:30 +0200316 pod_startup4(pod);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800317 } else
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100318 dev_dbg(pod->line6.ifcdev, "unknown sysex header\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800319
320 break;
321
322 case LINE6_SYSEX_END:
323 break;
324
325 default:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100326 dev_dbg(pod->line6.ifcdev, "POD: unknown message %02X\n",
327 buf[0]);
Markus Grabner705ecec2009-02-27 19:43:04 -0800328 }
329}
330
331/*
332 Detect some cases that require a channel dump after sending a command to the
333 device. Important notes:
334 *) The actual dump request can not be sent here since we are not allowed to
335 wait for the completion of the first message in this context, and sending
336 the dump request before completion of the previous message leaves the POD
337 in an undefined state. The dump request will be sent when the echoed
338 commands are received.
339 *) This method fails if a param change message is "chopped" after the first
340 byte.
341*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200342void line6_pod_midi_postprocess(struct usb_line6_pod *pod, unsigned char *data,
343 int length)
Markus Grabner705ecec2009-02-27 19:43:04 -0800344{
345 int i;
346
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800347 if (!pod->midi_postprocess)
Markus Grabner705ecec2009-02-27 19:43:04 -0800348 return;
349
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800350 for (i = 0; i < length; ++i) {
351 if (data[i] == (LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800352 line6_invalidate_current(&pod->dumpreq);
353 break;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200354 } else
355 if ((data[i] == (LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST))
356 && (i < length - 1))
357 if ((data[i + 1] == POD_amp_model_setup)
358 || (data[i + 1] == POD_effect_setup)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800359 line6_invalidate_current(&pod->dumpreq);
360 break;
361 }
362 }
363}
364
365/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800366 Transmit PODxt Pro control parameter.
367*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200368void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param,
Johannes Thumshirn5b9bd2a2012-06-27 21:25:57 +0200369 u8 value)
Markus Grabner705ecec2009-02-27 19:43:04 -0800370{
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800371 if (line6_transmit_parameter(&pod->line6, param, value) == 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800372 pod_store_parameter(pod, param, value);
373
Markus Grabnere1a164d2010-08-23 01:08:25 +0200374 if ((param == POD_amp_model_setup) || (param == POD_effect_setup)) /* these also affect other settings */
Markus Grabner705ecec2009-02-27 19:43:04 -0800375 line6_invalidate_current(&pod->dumpreq);
376}
377
378/*
379 Resolve value to memory location.
380*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200381static int pod_resolve(const char *buf, short block0, short block1,
382 unsigned char *location)
Markus Grabner705ecec2009-02-27 19:43:04 -0800383{
Johannes Thumshirn1d0e8342012-06-27 21:26:01 +0200384 u8 value;
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600385 short block;
386 int ret;
387
Johannes Thumshirn1d0e8342012-06-27 21:26:01 +0200388 ret = kstrtou8(buf, 10, &value);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600389 if (ret)
390 return ret;
391
392 block = (value < 0x40) ? block0 : block1;
Markus Grabner705ecec2009-02-27 19:43:04 -0800393 value &= 0x3f;
394 location[0] = block >> 7;
395 location[1] = value | (block & 0x7f);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600396 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800397}
398
399/*
400 Send command to store channel/effects setup/amp setup to PODxt Pro.
401*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200402static ssize_t pod_send_store_command(struct device *dev, const char *buf,
403 size_t count, short block0, short block1)
Markus Grabner705ecec2009-02-27 19:43:04 -0800404{
405 struct usb_interface *interface = to_usb_interface(dev);
406 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600407 int ret;
Markus Grabner705ecec2009-02-27 19:43:04 -0800408 int size = 3 + sizeof(pod->prog_data_buf);
409 char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_STORE, size);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600410
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800411 if (!sysex)
412 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800413
Markus Grabnere1a164d2010-08-23 01:08:25 +0200414 sysex[SYSEX_DATA_OFS] = 5; /* see pod_dump() */
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600415 ret = pod_resolve(buf, block0, block1, sysex + SYSEX_DATA_OFS + 1);
416 if (ret) {
417 kfree(sysex);
418 return ret;
419 }
420
Markus Grabnere1a164d2010-08-23 01:08:25 +0200421 memcpy(sysex + SYSEX_DATA_OFS + 3, &pod->prog_data_buf,
422 sizeof(pod->prog_data_buf));
Markus Grabner705ecec2009-02-27 19:43:04 -0800423
424 line6_send_sysex_message(&pod->line6, sysex, size);
425 kfree(sysex);
426 /* needs some delay here on AMD64 platform */
427 return count;
428}
429
430/*
431 Send command to retrieve channel/effects setup/amp setup to PODxt Pro.
432*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200433static ssize_t pod_send_retrieve_command(struct device *dev, const char *buf,
434 size_t count, short block0,
435 short block1)
Markus Grabner705ecec2009-02-27 19:43:04 -0800436{
437 struct usb_interface *interface = to_usb_interface(dev);
438 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600439 int ret;
Markus Grabner705ecec2009-02-27 19:43:04 -0800440 int size = 4;
441 char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_DUMPMEM, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800442
443 if (!sysex)
444 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800445
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600446 ret = pod_resolve(buf, block0, block1, sysex + SYSEX_DATA_OFS);
447 if (ret) {
448 kfree(sysex);
449 return ret;
450 }
Markus Grabner705ecec2009-02-27 19:43:04 -0800451 sysex[SYSEX_DATA_OFS + 2] = 0;
452 sysex[SYSEX_DATA_OFS + 3] = 0;
453 line6_dump_started(&pod->dumpreq, POD_DUMP_MEMORY);
454
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800455 if (line6_send_sysex_message(&pod->line6, sysex, size) < size)
Markus Grabner705ecec2009-02-27 19:43:04 -0800456 line6_dump_finished(&pod->dumpreq);
457
458 kfree(sysex);
459 /* needs some delay here on AMD64 platform */
460 return count;
461}
462
463/*
464 Generic get name function.
465*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200466static ssize_t get_name_generic(struct usb_line6_pod *pod, const char *str,
467 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800468{
469 int length = 0;
470 const char *p1;
471 char *p2;
472 char *last_non_space = buf;
473
Markus Grabner1027f4762010-08-12 01:35:30 +0200474 int retval = line6_dump_wait_interruptible(&pod->dumpreq);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800475 if (retval < 0)
476 return retval;
Markus Grabner705ecec2009-02-27 19:43:04 -0800477
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800478 for (p1 = str, p2 = buf; *p1; ++p1, ++p2) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800479 *p2 = *p1;
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800480 if (*p2 != ' ')
481 last_non_space = p2;
482 if (++length == POD_NAME_LENGTH)
483 break;
Markus Grabner705ecec2009-02-27 19:43:04 -0800484 }
485
486 *(last_non_space + 1) = '\n';
487 return last_non_space - buf + 2;
488}
489
490/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800491 "read" request on "name" special file.
492*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800493static ssize_t pod_get_name(struct device *dev, struct device_attribute *attr,
494 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800495{
496 struct usb_interface *interface = to_usb_interface(dev);
497 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200498 return get_name_generic(pod, pod->prog_data.header + POD_NAME_OFFSET,
499 buf);
Markus Grabner705ecec2009-02-27 19:43:04 -0800500}
501
502/*
503 "read" request on "name" special file.
504*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800505static ssize_t pod_get_name_buf(struct device *dev,
506 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800507{
508 struct usb_interface *interface = to_usb_interface(dev);
509 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200510 return get_name_generic(pod,
511 pod->prog_data_buf.header + POD_NAME_OFFSET,
512 buf);
Markus Grabner705ecec2009-02-27 19:43:04 -0800513}
514
515/*
516 "read" request on "dump" special file.
517*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800518static ssize_t pod_get_dump(struct device *dev, struct device_attribute *attr,
519 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800520{
521 struct usb_interface *interface = to_usb_interface(dev);
522 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Markus Grabner1027f4762010-08-12 01:35:30 +0200523 int retval = line6_dump_wait_interruptible(&pod->dumpreq);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800524 if (retval < 0)
525 return retval;
Markus Grabner705ecec2009-02-27 19:43:04 -0800526 memcpy(buf, &pod->prog_data, sizeof(pod->prog_data));
527 return sizeof(pod->prog_data);
528}
529
530/*
531 "write" request on "dump" special file.
532*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800533static ssize_t pod_set_dump(struct device *dev, struct device_attribute *attr,
534 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800535{
536 struct usb_interface *interface = to_usb_interface(dev);
537 struct usb_line6_pod *pod = usb_get_intfdata(interface);
538
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800539 if (count != sizeof(pod->prog_data)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800540 dev_err(pod->line6.ifcdev,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200541 "data block must be exactly %d bytes\n",
542 (int)sizeof(pod->prog_data));
Markus Grabner705ecec2009-02-27 19:43:04 -0800543 return -EINVAL;
544 }
545
546 pod_dump(pod, buf);
547 return sizeof(pod->prog_data);
548}
549
550/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200551 Identify system parameters related to the tuner.
552*/
553static bool pod_is_tuner(int code)
554{
555 return
Markus Grabnere1a164d2010-08-23 01:08:25 +0200556 (code == POD_tuner_mute) ||
557 (code == POD_tuner_freq) ||
558 (code == POD_tuner_note) || (code == POD_tuner_pitch);
Markus Grabner1027f4762010-08-12 01:35:30 +0200559}
560
561/*
562 Get system parameter (as integer).
Markus Grabner705ecec2009-02-27 19:43:04 -0800563 @param tuner non-zero, if code refers to a tuner parameter
564*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200565static int pod_get_system_param_int(struct usb_line6_pod *pod, int *value,
566 int code, struct ValueWait *param, int sign)
Markus Grabner705ecec2009-02-27 19:43:04 -0800567{
568 char *sysex;
Markus Grabner705ecec2009-02-27 19:43:04 -0800569 static const int size = 1;
570 int retval = 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800571
Markus Grabnere1a164d2010-08-23 01:08:25 +0200572 if (((pod->prog_data.control[POD_tuner] & 0x40) == 0)
573 && pod_is_tuner(code))
Markus Grabner705ecec2009-02-27 19:43:04 -0800574 return -ENODEV;
575
Markus Grabner1027f4762010-08-12 01:35:30 +0200576 /* send value request to device: */
Markus Grabner705ecec2009-02-27 19:43:04 -0800577 param->value = POD_system_invalid;
578 sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEMREQ, size);
Markus Grabner1027f4762010-08-12 01:35:30 +0200579
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800580 if (!sysex)
Markus Grabner1027f4762010-08-12 01:35:30 +0200581 return -ENOMEM;
582
Markus Grabner705ecec2009-02-27 19:43:04 -0800583 sysex[SYSEX_DATA_OFS] = code;
584 line6_send_sysex_message(&pod->line6, sysex, size);
585 kfree(sysex);
586
Markus Grabner1027f4762010-08-12 01:35:30 +0200587 /* wait for device to respond: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200588 retval =
589 wait_event_interruptible(param->wait,
590 param->value != POD_system_invalid);
Markus Grabner705ecec2009-02-27 19:43:04 -0800591
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800592 if (retval < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800593 return retval;
594
Markus Grabnere1a164d2010-08-23 01:08:25 +0200595 *value = sign ? (int)(signed short)param->value : (int)(unsigned short)
596 param->value;
Markus Grabner1027f4762010-08-12 01:35:30 +0200597
Markus Grabnere1a164d2010-08-23 01:08:25 +0200598 if (*value == POD_system_invalid)
599 *value = 0; /* don't report uninitialized values */
Markus Grabner1027f4762010-08-12 01:35:30 +0200600
601 return 0;
602}
603
604/*
605 Get system parameter (as string).
606 @param tuner non-zero, if code refers to a tuner parameter
607*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200608static ssize_t pod_get_system_param_string(struct usb_line6_pod *pod, char *buf,
609 int code, struct ValueWait *param,
610 int sign)
Markus Grabner1027f4762010-08-12 01:35:30 +0200611{
612 int retval, value = 0;
613 retval = pod_get_system_param_int(pod, &value, code, param, sign);
614
Markus Grabnere1a164d2010-08-23 01:08:25 +0200615 if (retval < 0)
Markus Grabner1027f4762010-08-12 01:35:30 +0200616 return retval;
617
Markus Grabner705ecec2009-02-27 19:43:04 -0800618 return sprintf(buf, "%d\n", value);
619}
620
621/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200622 Send system parameter (from integer).
Markus Grabner705ecec2009-02-27 19:43:04 -0800623 @param tuner non-zero, if code refers to a tuner parameter
624*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200625static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
626 int code)
Markus Grabner705ecec2009-02-27 19:43:04 -0800627{
628 char *sysex;
629 static const int size = 5;
Markus Grabner705ecec2009-02-27 19:43:04 -0800630
Markus Grabnere1a164d2010-08-23 01:08:25 +0200631 if (((pod->prog_data.control[POD_tuner] & 0x40) == 0)
632 && pod_is_tuner(code))
Markus Grabner705ecec2009-02-27 19:43:04 -0800633 return -EINVAL;
634
635 /* send value to tuner: */
636 sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800637 if (!sysex)
Markus Grabner1027f4762010-08-12 01:35:30 +0200638 return -ENOMEM;
Markus Grabner705ecec2009-02-27 19:43:04 -0800639 sysex[SYSEX_DATA_OFS] = code;
640 sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200641 sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f;
642 sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f;
643 sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f;
Markus Grabner705ecec2009-02-27 19:43:04 -0800644 line6_send_sysex_message(&pod->line6, sysex, size);
645 kfree(sysex);
Markus Grabner1027f4762010-08-12 01:35:30 +0200646 return 0;
647}
648
649/*
650 Send system parameter (from string).
651 @param tuner non-zero, if code refers to a tuner parameter
652*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200653static ssize_t pod_set_system_param_string(struct usb_line6_pod *pod,
654 const char *buf, int count, int code,
655 unsigned short mask)
Markus Grabner1027f4762010-08-12 01:35:30 +0200656{
657 int retval;
658 unsigned short value = simple_strtoul(buf, NULL, 10) & mask;
659 retval = pod_set_system_param_int(pod, value, code);
660 return (retval < 0) ? retval : count;
Markus Grabner705ecec2009-02-27 19:43:04 -0800661}
662
663/*
664 "read" request on "dump_buf" special file.
665*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800666static ssize_t pod_get_dump_buf(struct device *dev,
667 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800668{
669 struct usb_interface *interface = to_usb_interface(dev);
670 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Markus Grabner1027f4762010-08-12 01:35:30 +0200671 int retval = line6_dump_wait_interruptible(&pod->dumpreq);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800672 if (retval < 0)
673 return retval;
Markus Grabner705ecec2009-02-27 19:43:04 -0800674 memcpy(buf, &pod->prog_data_buf, sizeof(pod->prog_data_buf));
675 return sizeof(pod->prog_data_buf);
676}
677
678/*
679 "write" request on "dump_buf" special file.
680*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800681static ssize_t pod_set_dump_buf(struct device *dev,
682 struct device_attribute *attr,
683 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800684{
685 struct usb_interface *interface = to_usb_interface(dev);
686 struct usb_line6_pod *pod = usb_get_intfdata(interface);
687
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800688 if (count != sizeof(pod->prog_data)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800689 dev_err(pod->line6.ifcdev,
Markus Grabner1027f4762010-08-12 01:35:30 +0200690 "data block must be exactly %d bytes\n",
691 (int)sizeof(pod->prog_data));
Markus Grabner705ecec2009-02-27 19:43:04 -0800692 return -EINVAL;
693 }
694
695 memcpy(&pod->prog_data_buf, buf, sizeof(pod->prog_data));
696 return sizeof(pod->prog_data);
697}
698
699/*
700 "write" request on "finish" special file.
701*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800702static ssize_t pod_set_finish(struct device *dev,
703 struct device_attribute *attr,
704 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800705{
706 struct usb_interface *interface = to_usb_interface(dev);
707 struct usb_line6_pod *pod = usb_get_intfdata(interface);
708 int size = 0;
709 char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_FINISH, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800710 if (!sysex)
711 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800712 line6_send_sysex_message(&pod->line6, sysex, size);
713 kfree(sysex);
714 return count;
715}
716
717/*
718 "write" request on "store_channel" special file.
719*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800720static ssize_t pod_set_store_channel(struct device *dev,
721 struct device_attribute *attr,
722 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800723{
724 return pod_send_store_command(dev, buf, count, 0x0000, 0x00c0);
725}
726
727/*
728 "write" request on "store_effects_setup" special file.
729*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800730static ssize_t pod_set_store_effects_setup(struct device *dev,
731 struct device_attribute *attr,
732 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800733{
734 return pod_send_store_command(dev, buf, count, 0x0080, 0x0080);
735}
736
737/*
738 "write" request on "store_amp_setup" special file.
739*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800740static ssize_t pod_set_store_amp_setup(struct device *dev,
741 struct device_attribute *attr,
742 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800743{
744 return pod_send_store_command(dev, buf, count, 0x0040, 0x0100);
745}
746
747/*
748 "write" request on "retrieve_channel" special file.
749*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800750static ssize_t pod_set_retrieve_channel(struct device *dev,
751 struct device_attribute *attr,
752 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800753{
754 return pod_send_retrieve_command(dev, buf, count, 0x0000, 0x00c0);
755}
756
757/*
758 "write" request on "retrieve_effects_setup" special file.
759*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800760static ssize_t pod_set_retrieve_effects_setup(struct device *dev,
761 struct device_attribute *attr,
762 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800763{
764 return pod_send_retrieve_command(dev, buf, count, 0x0080, 0x0080);
765}
766
767/*
768 "write" request on "retrieve_amp_setup" special file.
769*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800770static ssize_t pod_set_retrieve_amp_setup(struct device *dev,
771 struct device_attribute *attr,
772 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800773{
774 return pod_send_retrieve_command(dev, buf, count, 0x0040, 0x0100);
775}
776
777/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800778 "read" request on "midi_postprocess" special file.
779*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800780static ssize_t pod_get_midi_postprocess(struct device *dev,
781 struct device_attribute *attr,
782 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800783{
784 struct usb_interface *interface = to_usb_interface(dev);
785 struct usb_line6_pod *pod = usb_get_intfdata(interface);
786 return sprintf(buf, "%d\n", pod->midi_postprocess);
787}
788
789/*
790 "write" request on "midi_postprocess" special file.
791*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800792static ssize_t pod_set_midi_postprocess(struct device *dev,
793 struct device_attribute *attr,
794 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800795{
796 struct usb_interface *interface = to_usb_interface(dev);
797 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Johannes Thumshirn06501782012-06-27 21:26:03 +0200798 u8 value;
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600799 int ret;
800
Johannes Thumshirn06501782012-06-27 21:26:03 +0200801 ret = kstrtou8(buf, 10, &value);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600802 if (ret)
803 return ret;
804
Markus Grabner705ecec2009-02-27 19:43:04 -0800805 pod->midi_postprocess = value ? 1 : 0;
806 return count;
807}
808
809/*
810 "read" request on "serial_number" special file.
811*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800812static ssize_t pod_get_serial_number(struct device *dev,
813 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800814{
815 struct usb_interface *interface = to_usb_interface(dev);
816 struct usb_line6_pod *pod = usb_get_intfdata(interface);
817 return sprintf(buf, "%d\n", pod->serial_number);
818}
819
820/*
821 "read" request on "firmware_version" special file.
822*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800823static ssize_t pod_get_firmware_version(struct device *dev,
824 struct device_attribute *attr,
825 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800826{
827 struct usb_interface *interface = to_usb_interface(dev);
828 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800829 return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
830 pod->firmware_version % 100);
Markus Grabner705ecec2009-02-27 19:43:04 -0800831}
832
833/*
834 "read" request on "device_id" special file.
835*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800836static ssize_t pod_get_device_id(struct device *dev,
837 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800838{
839 struct usb_interface *interface = to_usb_interface(dev);
840 struct usb_line6_pod *pod = usb_get_intfdata(interface);
841 return sprintf(buf, "%d\n", pod->device_id);
842}
843
844/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200845 POD startup procedure.
846 This is a sequence of functions with special requirements (e.g., must
847 not run immediately after initialization, must not run in interrupt
848 context). After the last one has finished, the device is ready to use.
849*/
850
851static void pod_startup1(struct usb_line6_pod *pod)
852{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200853 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT);
Markus Grabner1027f4762010-08-12 01:35:30 +0200854
855 /* delay startup procedure: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200856 line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
857 (unsigned long)pod);
Markus Grabner1027f4762010-08-12 01:35:30 +0200858}
859
860static void pod_startup2(unsigned long data)
861{
862 struct usb_line6_pod *pod = (struct usb_line6_pod *)data;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200863
864 /* schedule another startup procedure until startup is complete: */
865 if (pod->startup_progress >= POD_STARTUP_LAST)
866 return;
867
868 pod->startup_progress = POD_STARTUP_DUMPREQ;
869 line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
870 (unsigned long)pod);
Markus Grabner1027f4762010-08-12 01:35:30 +0200871
872 /* current channel dump: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200873 line6_dump_request_async(&pod->dumpreq, &pod->line6, 0,
874 LINE6_DUMP_CURRENT);
Markus Grabner1027f4762010-08-12 01:35:30 +0200875}
876
877static void pod_startup3(struct usb_line6_pod *pod)
878{
879 struct usb_line6 *line6 = &pod->line6;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200880 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ);
Markus Grabner1027f4762010-08-12 01:35:30 +0200881
882 /* request firmware version: */
883 line6_version_request_async(line6);
884}
885
886static void pod_startup4(struct usb_line6_pod *pod)
887{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200888 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE);
Markus Grabner1027f4762010-08-12 01:35:30 +0200889
890 /* schedule work for global work queue: */
891 schedule_work(&pod->startup_work);
892}
893
894static void pod_startup5(struct work_struct *work)
895{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200896 struct usb_line6_pod *pod =
897 container_of(work, struct usb_line6_pod, startup_work);
Markus Grabner1027f4762010-08-12 01:35:30 +0200898 struct usb_line6 *line6 = &pod->line6;
899
Markus Grabnere1a164d2010-08-23 01:08:25 +0200900 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP);
Markus Grabner1027f4762010-08-12 01:35:30 +0200901
902 /* serial number: */
903 line6_read_serial_number(&pod->line6, &pod->serial_number);
904
905 /* ALSA audio interface: */
906 line6_register_audio(line6);
907
908 /* device files: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200909 line6_pod_create_files(pod->firmware_version,
910 line6->properties->device_bit, line6->ifcdev);
Markus Grabner1027f4762010-08-12 01:35:30 +0200911}
912
913#define POD_GET_SYSTEM_PARAM(code, sign) \
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800914static ssize_t pod_get_ ## code(struct device *dev, \
915 struct device_attribute *attr, char *buf) \
Markus Grabner705ecec2009-02-27 19:43:04 -0800916{ \
917 struct usb_interface *interface = to_usb_interface(dev); \
918 struct usb_line6_pod *pod = usb_get_intfdata(interface); \
Markus Grabner1027f4762010-08-12 01:35:30 +0200919 return pod_get_system_param_string(pod, buf, POD_ ## code, \
920 &pod->code, sign); \
Markus Grabner705ecec2009-02-27 19:43:04 -0800921}
922
Markus Grabner1027f4762010-08-12 01:35:30 +0200923#define POD_GET_SET_SYSTEM_PARAM(code, mask, sign) \
924POD_GET_SYSTEM_PARAM(code, sign) \
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800925static ssize_t pod_set_ ## code(struct device *dev, \
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800926 struct device_attribute *attr, \
927 const char *buf, size_t count) \
Markus Grabner705ecec2009-02-27 19:43:04 -0800928{ \
929 struct usb_interface *interface = to_usb_interface(dev); \
930 struct usb_line6_pod *pod = usb_get_intfdata(interface); \
Markus Grabner1027f4762010-08-12 01:35:30 +0200931 return pod_set_system_param_string(pod, buf, count, POD_ ## code, mask); \
Markus Grabner705ecec2009-02-27 19:43:04 -0800932}
933
Markus Grabner1027f4762010-08-12 01:35:30 +0200934POD_GET_SET_SYSTEM_PARAM(monitor_level, 0xffff, 0);
935POD_GET_SET_SYSTEM_PARAM(routing, 0x0003, 0);
936POD_GET_SET_SYSTEM_PARAM(tuner_mute, 0x0001, 0);
937POD_GET_SET_SYSTEM_PARAM(tuner_freq, 0xffff, 0);
938POD_GET_SYSTEM_PARAM(tuner_note, 1);
939POD_GET_SYSTEM_PARAM(tuner_pitch, 1);
Markus Grabner705ecec2009-02-27 19:43:04 -0800940
941#undef GET_SET_SYSTEM_PARAM
942#undef GET_SYSTEM_PARAM
943
944/* POD special files: */
Markus Grabner705ecec2009-02-27 19:43:04 -0800945static DEVICE_ATTR(device_id, S_IRUGO, pod_get_device_id, line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800946static DEVICE_ATTR(dump, S_IWUSR | S_IRUGO, pod_get_dump, pod_set_dump);
947static DEVICE_ATTR(dump_buf, S_IWUSR | S_IRUGO, pod_get_dump_buf,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200948 pod_set_dump_buf);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800949static DEVICE_ATTR(finish, S_IWUSR, line6_nop_read, pod_set_finish);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200950static DEVICE_ATTR(firmware_version, S_IRUGO, pod_get_firmware_version,
951 line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800952static DEVICE_ATTR(midi_postprocess, S_IWUSR | S_IRUGO,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200953 pod_get_midi_postprocess, pod_set_midi_postprocess);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800954static DEVICE_ATTR(monitor_level, S_IWUSR | S_IRUGO, pod_get_monitor_level,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200955 pod_set_monitor_level);
Markus Grabner705ecec2009-02-27 19:43:04 -0800956static DEVICE_ATTR(name, S_IRUGO, pod_get_name, line6_nop_write);
957static DEVICE_ATTR(name_buf, S_IRUGO, pod_get_name_buf, line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800958static DEVICE_ATTR(retrieve_amp_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200959 pod_set_retrieve_amp_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800960static DEVICE_ATTR(retrieve_channel, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200961 pod_set_retrieve_channel);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800962static DEVICE_ATTR(retrieve_effects_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200963 pod_set_retrieve_effects_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800964static DEVICE_ATTR(routing, S_IWUSR | S_IRUGO, pod_get_routing,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200965 pod_set_routing);
966static DEVICE_ATTR(serial_number, S_IRUGO, pod_get_serial_number,
967 line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800968static DEVICE_ATTR(store_amp_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200969 pod_set_store_amp_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800970static DEVICE_ATTR(store_channel, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200971 pod_set_store_channel);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800972static DEVICE_ATTR(store_effects_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200973 pod_set_store_effects_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800974static DEVICE_ATTR(tuner_freq, S_IWUSR | S_IRUGO, pod_get_tuner_freq,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200975 pod_set_tuner_freq);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800976static DEVICE_ATTR(tuner_mute, S_IWUSR | S_IRUGO, pod_get_tuner_mute,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200977 pod_set_tuner_mute);
Markus Grabner705ecec2009-02-27 19:43:04 -0800978static DEVICE_ATTR(tuner_note, S_IRUGO, pod_get_tuner_note, line6_nop_write);
979static DEVICE_ATTR(tuner_pitch, S_IRUGO, pod_get_tuner_pitch, line6_nop_write);
980
Markus Grabner1027f4762010-08-12 01:35:30 +0200981#ifdef CONFIG_LINE6_USB_RAW
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800982static DEVICE_ATTR(raw, S_IWUSR, line6_nop_read, line6_set_raw);
Markus Grabner705ecec2009-02-27 19:43:04 -0800983#endif
984
Markus Grabner1027f4762010-08-12 01:35:30 +0200985/* control info callback */
986static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol,
987 struct snd_ctl_elem_info *uinfo)
988{
989 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
990 uinfo->count = 1;
991 uinfo->value.integer.min = 0;
992 uinfo->value.integer.max = 65535;
993 return 0;
994}
995
996/* control get callback */
997static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol,
998 struct snd_ctl_elem_value *ucontrol)
999{
1000 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
1001 struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
1002 ucontrol->value.integer.value[0] = pod->monitor_level.value;
1003 return 0;
1004}
1005
1006/* control put callback */
1007static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol,
1008 struct snd_ctl_elem_value *ucontrol)
1009{
1010 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
1011 struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
1012
Markus Grabnere1a164d2010-08-23 01:08:25 +02001013 if (ucontrol->value.integer.value[0] == pod->monitor_level.value)
Markus Grabner1027f4762010-08-12 01:35:30 +02001014 return 0;
1015
1016 pod->monitor_level.value = ucontrol->value.integer.value[0];
Markus Grabnere1a164d2010-08-23 01:08:25 +02001017 pod_set_system_param_int(pod, ucontrol->value.integer.value[0],
1018 POD_monitor_level);
Markus Grabner1027f4762010-08-12 01:35:30 +02001019 return 1;
1020}
1021
1022/* control definition */
1023static struct snd_kcontrol_new pod_control_monitor = {
1024 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
1025 .name = "Monitor Playback Volume",
1026 .index = 0,
1027 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
1028 .info = snd_pod_control_monitor_info,
1029 .get = snd_pod_control_monitor_get,
1030 .put = snd_pod_control_monitor_put
1031};
1032
Markus Grabner705ecec2009-02-27 19:43:04 -08001033/*
1034 POD destructor.
1035*/
1036static void pod_destruct(struct usb_interface *interface)
1037{
1038 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Markus Grabner705ecec2009-02-27 19:43:04 -08001039
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001040 if (pod == NULL)
1041 return;
Stefan Hajnoczi188e6642011-12-10 02:12:30 +01001042 line6_cleanup_audio(&pod->line6);
Markus Grabner705ecec2009-02-27 19:43:04 -08001043
Markus Grabnere1a164d2010-08-23 01:08:25 +02001044 del_timer(&pod->startup_timer);
1045 cancel_work_sync(&pod->startup_work);
1046
Markus Grabner705ecec2009-02-27 19:43:04 -08001047 /* free dump request data: */
1048 line6_dumpreq_destruct(&pod->dumpreq);
Markus Grabner705ecec2009-02-27 19:43:04 -08001049}
1050
1051/*
1052 Create sysfs entries.
1053*/
Greg Kroah-Hartmanb702ed252009-02-27 20:45:03 -08001054static int pod_create_files2(struct device *dev)
Markus Grabner705ecec2009-02-27 19:43:04 -08001055{
1056 int err;
1057
Markus Grabner705ecec2009-02-27 19:43:04 -08001058 CHECK_RETURN(device_create_file(dev, &dev_attr_device_id));
Markus Grabner705ecec2009-02-27 19:43:04 -08001059 CHECK_RETURN(device_create_file(dev, &dev_attr_dump));
1060 CHECK_RETURN(device_create_file(dev, &dev_attr_dump_buf));
1061 CHECK_RETURN(device_create_file(dev, &dev_attr_finish));
1062 CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version));
1063 CHECK_RETURN(device_create_file(dev, &dev_attr_midi_postprocess));
1064 CHECK_RETURN(device_create_file(dev, &dev_attr_monitor_level));
1065 CHECK_RETURN(device_create_file(dev, &dev_attr_name));
1066 CHECK_RETURN(device_create_file(dev, &dev_attr_name_buf));
1067 CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_amp_setup));
1068 CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_channel));
1069 CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_effects_setup));
1070 CHECK_RETURN(device_create_file(dev, &dev_attr_routing));
1071 CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number));
1072 CHECK_RETURN(device_create_file(dev, &dev_attr_store_amp_setup));
1073 CHECK_RETURN(device_create_file(dev, &dev_attr_store_channel));
1074 CHECK_RETURN(device_create_file(dev, &dev_attr_store_effects_setup));
1075 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_freq));
1076 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_mute));
1077 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_note));
1078 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_pitch));
1079
Markus Grabner1027f4762010-08-12 01:35:30 +02001080#ifdef CONFIG_LINE6_USB_RAW
Markus Grabner705ecec2009-02-27 19:43:04 -08001081 CHECK_RETURN(device_create_file(dev, &dev_attr_raw));
1082#endif
1083
1084 return 0;
1085}
1086
1087/*
Markus Grabner1027f4762010-08-12 01:35:30 +02001088 Try to init POD device.
Markus Grabner705ecec2009-02-27 19:43:04 -08001089*/
Markus Grabnere1a164d2010-08-23 01:08:25 +02001090static int pod_try_init(struct usb_interface *interface,
1091 struct usb_line6_pod *pod)
Markus Grabner705ecec2009-02-27 19:43:04 -08001092{
1093 int err;
1094 struct usb_line6 *line6 = &pod->line6;
1095
Markus Grabnere1a164d2010-08-23 01:08:25 +02001096 init_timer(&pod->startup_timer);
1097 INIT_WORK(&pod->startup_work, pod_startup5);
1098
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001099 if ((interface == NULL) || (pod == NULL))
1100 return -ENODEV;
Markus Grabner705ecec2009-02-27 19:43:04 -08001101
Markus Grabner705ecec2009-02-27 19:43:04 -08001102 /* initialize wait queues: */
1103 init_waitqueue_head(&pod->monitor_level.wait);
1104 init_waitqueue_head(&pod->routing.wait);
1105 init_waitqueue_head(&pod->tuner_mute.wait);
1106 init_waitqueue_head(&pod->tuner_freq.wait);
1107 init_waitqueue_head(&pod->tuner_note.wait);
1108 init_waitqueue_head(&pod->tuner_pitch.wait);
Markus Grabner705ecec2009-02-27 19:43:04 -08001109
Markus Grabner705ecec2009-02-27 19:43:04 -08001110 /* initialize USB buffers: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001111 err = line6_dumpreq_init(&pod->dumpreq, pod_request_channel,
1112 sizeof(pod_request_channel));
1113 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001114 dev_err(&interface->dev, "Out of memory\n");
Markus Grabner705ecec2009-02-27 19:43:04 -08001115 return -ENOMEM;
1116 }
1117
Markus Grabner705ecec2009-02-27 19:43:04 -08001118 /* create sysfs entries: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001119 err = pod_create_files2(&interface->dev);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001120 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -08001121 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -08001122
1123 /* initialize audio system: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001124 err = line6_init_audio(line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001125 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -08001126 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -08001127
1128 /* initialize MIDI subsystem: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001129 err = line6_init_midi(line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001130 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -08001131 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -08001132
1133 /* initialize PCM subsystem: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001134 err = line6_init_pcm(line6, &pod_pcm_properties);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001135 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -08001136 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -08001137
Markus Grabner1027f4762010-08-12 01:35:30 +02001138 /* register monitor control: */
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001139 err = snd_ctl_add(line6->card,
1140 snd_ctl_new1(&pod_control_monitor, line6->line6pcm));
1141 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -08001142 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -08001143
Markus Grabner1027f4762010-08-12 01:35:30 +02001144 /*
Markus Grabnere1a164d2010-08-23 01:08:25 +02001145 When the sound card is registered at this point, the PODxt Live
1146 displays "Invalid Code Error 07", so we do it later in the event
1147 handler.
1148 */
Markus Grabner1027f4762010-08-12 01:35:30 +02001149
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001150 if (pod->line6.properties->capabilities & LINE6_BIT_CONTROL) {
Markus Grabner1027f4762010-08-12 01:35:30 +02001151 pod->monitor_level.value = POD_system_invalid;
1152
1153 /* initiate startup procedure: */
1154 pod_startup1(pod);
Markus Grabner705ecec2009-02-27 19:43:04 -08001155 }
1156
1157 return 0;
1158}
1159
1160/*
Markus Grabner1027f4762010-08-12 01:35:30 +02001161 Init POD device (and clean up in case of failure).
1162*/
1163int line6_pod_init(struct usb_interface *interface, struct usb_line6_pod *pod)
1164{
1165 int err = pod_try_init(interface, pod);
1166
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001167 if (err < 0)
Markus Grabner1027f4762010-08-12 01:35:30 +02001168 pod_destruct(interface);
Markus Grabner1027f4762010-08-12 01:35:30 +02001169
1170 return err;
1171}
1172
1173/*
Markus Grabner705ecec2009-02-27 19:43:04 -08001174 POD device disconnected.
1175*/
Markus Grabner1027f4762010-08-12 01:35:30 +02001176void line6_pod_disconnect(struct usb_interface *interface)
Markus Grabner705ecec2009-02-27 19:43:04 -08001177{
1178 struct usb_line6_pod *pod;
1179
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001180 if (interface == NULL)
1181 return;
Markus Grabner705ecec2009-02-27 19:43:04 -08001182 pod = usb_get_intfdata(interface);
1183
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001184 if (pod != NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001185 struct snd_line6_pcm *line6pcm = pod->line6.line6pcm;
1186 struct device *dev = &interface->dev;
1187
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001188 if (line6pcm != NULL)
Markus Grabner1027f4762010-08-12 01:35:30 +02001189 line6_pcm_disconnect(line6pcm);
Markus Grabner705ecec2009-02-27 19:43:04 -08001190
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001191 if (dev != NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001192 /* remove sysfs entries: */
Markus Grabnere1a164d2010-08-23 01:08:25 +02001193 line6_pod_remove_files(pod->firmware_version,
1194 pod->line6.
1195 properties->device_bit, dev);
Markus Grabner705ecec2009-02-27 19:43:04 -08001196
Markus Grabner705ecec2009-02-27 19:43:04 -08001197 device_remove_file(dev, &dev_attr_device_id);
Markus Grabner705ecec2009-02-27 19:43:04 -08001198 device_remove_file(dev, &dev_attr_dump);
1199 device_remove_file(dev, &dev_attr_dump_buf);
1200 device_remove_file(dev, &dev_attr_finish);
1201 device_remove_file(dev, &dev_attr_firmware_version);
1202 device_remove_file(dev, &dev_attr_midi_postprocess);
1203 device_remove_file(dev, &dev_attr_monitor_level);
1204 device_remove_file(dev, &dev_attr_name);
1205 device_remove_file(dev, &dev_attr_name_buf);
1206 device_remove_file(dev, &dev_attr_retrieve_amp_setup);
1207 device_remove_file(dev, &dev_attr_retrieve_channel);
Markus Grabnere1a164d2010-08-23 01:08:25 +02001208 device_remove_file(dev,
1209 &dev_attr_retrieve_effects_setup);
Markus Grabner705ecec2009-02-27 19:43:04 -08001210 device_remove_file(dev, &dev_attr_routing);
1211 device_remove_file(dev, &dev_attr_serial_number);
1212 device_remove_file(dev, &dev_attr_store_amp_setup);
1213 device_remove_file(dev, &dev_attr_store_channel);
1214 device_remove_file(dev, &dev_attr_store_effects_setup);
1215 device_remove_file(dev, &dev_attr_tuner_freq);
1216 device_remove_file(dev, &dev_attr_tuner_mute);
1217 device_remove_file(dev, &dev_attr_tuner_note);
1218 device_remove_file(dev, &dev_attr_tuner_pitch);
1219
Markus Grabner1027f4762010-08-12 01:35:30 +02001220#ifdef CONFIG_LINE6_USB_RAW
Markus Grabner705ecec2009-02-27 19:43:04 -08001221 device_remove_file(dev, &dev_attr_raw);
1222#endif
1223 }
1224 }
1225
1226 pod_destruct(interface);
1227}