blob: 56eab0a76578ff265e6cf6678a3751edc665291a [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/*
Stefan Hajnoczib772fe92012-11-22 20:48:43 +0100141 Store parameter value in driver memory.
Markus Grabner705ecec2009-02-27 19:43:04 -0800142*/
143static void pod_store_parameter(struct usb_line6_pod *pod, int param, int value)
144{
145 pod->prog_data.control[param] = value;
Markus Grabner705ecec2009-02-27 19:43:04 -0800146}
147
148/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200149 Handle SAVE button.
Markus Grabner705ecec2009-02-27 19:43:04 -0800150*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200151static void pod_save_button_pressed(struct usb_line6_pod *pod, int type,
152 int index)
Markus Grabner705ecec2009-02-27 19:43:04 -0800153{
Markus Grabner705ecec2009-02-27 19:43:04 -0800154 set_bit(POD_SAVE_PRESSED, &pod->atomic_flags);
155}
156
157/*
158 Process a completely received message.
159*/
Markus Grabner1027f4762010-08-12 01:35:30 +0200160void line6_pod_process_message(struct usb_line6_pod *pod)
Markus Grabner705ecec2009-02-27 19:43:04 -0800161{
162 const unsigned char *buf = pod->line6.buffer_message;
163
164 /* filter messages by type */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800165 switch (buf[0] & 0xf0) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800166 case LINE6_PARAM_CHANGE:
167 case LINE6_PROGRAM_CHANGE:
168 case LINE6_SYSEX_BEGIN:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200169 break; /* handle these further down */
Markus Grabner705ecec2009-02-27 19:43:04 -0800170
171 default:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200172 return; /* ignore all others */
Markus Grabner705ecec2009-02-27 19:43:04 -0800173 }
174
175 /* process all remaining messages */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800176 switch (buf[0]) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800177 case LINE6_PARAM_CHANGE | LINE6_CHANNEL_DEVICE:
178 pod_store_parameter(pod, buf[1], buf[2]);
179 /* intentionally no break here! */
180
181 case LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST:
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800182 if ((buf[1] == POD_amp_model_setup) ||
183 (buf[1] == POD_effect_setup))
184 /* these also affect other settings */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200185 line6_dump_request_async(&pod->dumpreq, &pod->line6, 0,
186 LINE6_DUMP_CURRENT);
Markus Grabner705ecec2009-02-27 19:43:04 -0800187
188 break;
189
190 case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_DEVICE:
191 case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST:
Markus Grabner705ecec2009-02-27 19:43:04 -0800192 set_bit(POD_CHANNEL_DIRTY, &pod->atomic_flags);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200193 line6_dump_request_async(&pod->dumpreq, &pod->line6, 0,
194 LINE6_DUMP_CURRENT);
Markus Grabner705ecec2009-02-27 19:43:04 -0800195 break;
196
197 case LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE:
198 case LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN:
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800199 if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) == 0) {
200 switch (buf[5]) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800201 case POD_SYSEX_DUMP:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200202 if (pod->line6.message_length ==
203 sizeof(pod->prog_data) + 7) {
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800204 switch (pod->dumpreq.in_progress) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800205 case LINE6_DUMP_CURRENT:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200206 memcpy(&pod->prog_data, buf + 7,
207 sizeof(pod->prog_data));
Markus Grabner705ecec2009-02-27 19:43:04 -0800208 break;
209
210 case POD_DUMP_MEMORY:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200211 memcpy(&pod->prog_data_buf,
212 buf + 7,
213 sizeof
214 (pod->prog_data_buf));
Markus Grabner705ecec2009-02-27 19:43:04 -0800215 break;
216
217 default:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100218 dev_dbg(pod->line6.ifcdev,
219 "unknown dump code %02X\n",
220 pod->dumpreq.in_progress);
Markus Grabner705ecec2009-02-27 19:43:04 -0800221 }
222
223 line6_dump_finished(&pod->dumpreq);
Markus Grabner1027f4762010-08-12 01:35:30 +0200224 pod_startup3(pod);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800225 } else
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100226 dev_dbg(pod->line6.ifcdev,
227 "wrong size of channel dump message (%d instead of %d)\n",
228 pod->line6.message_length,
229 (int)sizeof(pod->prog_data) +
230 7);
Markus Grabner705ecec2009-02-27 19:43:04 -0800231
232 break;
233
Markus Grabnere1a164d2010-08-23 01:08:25 +0200234 case POD_SYSEX_SYSTEM:{
235 short value =
236 ((int)buf[7] << 12) | ((int)buf[8]
237 << 8) |
238 ((int)buf[9] << 4) | (int)buf[10];
Markus Grabner705ecec2009-02-27 19:43:04 -0800239
240#define PROCESS_SYSTEM_PARAM(x) \
241 case POD_ ## x: \
242 pod->x.value = value; \
Markus Grabner1027f4762010-08-12 01:35:30 +0200243 wake_up(&pod->x.wait); \
Markus Grabner705ecec2009-02-27 19:43:04 -0800244 break;
245
Markus Grabnere1a164d2010-08-23 01:08:25 +0200246 switch (buf[6]) {
247 PROCESS_SYSTEM_PARAM
248 (monitor_level);
249 PROCESS_SYSTEM_PARAM(routing);
250 PROCESS_SYSTEM_PARAM
251 (tuner_mute);
252 PROCESS_SYSTEM_PARAM
253 (tuner_freq);
254 PROCESS_SYSTEM_PARAM
255 (tuner_note);
256 PROCESS_SYSTEM_PARAM
257 (tuner_pitch);
Markus Grabner705ecec2009-02-27 19:43:04 -0800258
259#undef PROCESS_SYSTEM_PARAM
260
Markus Grabnere1a164d2010-08-23 01:08:25 +0200261 default:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100262 dev_dbg(pod->line6.ifcdev,
263 "unknown tuner/system response %02X\n",
264 buf[6]);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200265 }
Markus Grabner705ecec2009-02-27 19:43:04 -0800266
Markus Grabnere1a164d2010-08-23 01:08:25 +0200267 break;
268 }
Markus Grabner705ecec2009-02-27 19:43:04 -0800269
270 case POD_SYSEX_FINISH:
271 /* do we need to respond to this? */
272 break;
273
274 case POD_SYSEX_SAVE:
275 pod_save_button_pressed(pod, buf[6], buf[7]);
276 break;
277
Markus Grabner705ecec2009-02-27 19:43:04 -0800278 case POD_SYSEX_STORE:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100279 dev_dbg(pod->line6.ifcdev,
280 "message %02X not yet implemented\n",
281 buf[5]);
Markus Grabner705ecec2009-02-27 19:43:04 -0800282 break;
283
284 default:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100285 dev_dbg(pod->line6.ifcdev,
286 "unknown sysex message %02X\n",
287 buf[5]);
Markus Grabner705ecec2009-02-27 19:43:04 -0800288 }
Markus Grabnere1a164d2010-08-23 01:08:25 +0200289 } else
290 if (memcmp
291 (buf, pod_version_header,
292 sizeof(pod_version_header)) == 0) {
293 pod->firmware_version =
294 buf[13] * 100 + buf[14] * 10 + buf[15];
295 pod->device_id =
296 ((int)buf[8] << 16) | ((int)buf[9] << 8) | (int)
297 buf[10];
Markus Grabner1027f4762010-08-12 01:35:30 +0200298 pod_startup4(pod);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800299 } else
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100300 dev_dbg(pod->line6.ifcdev, "unknown sysex header\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800301
302 break;
303
304 case LINE6_SYSEX_END:
305 break;
306
307 default:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100308 dev_dbg(pod->line6.ifcdev, "POD: unknown message %02X\n",
309 buf[0]);
Markus Grabner705ecec2009-02-27 19:43:04 -0800310 }
311}
312
313/*
314 Detect some cases that require a channel dump after sending a command to the
315 device. Important notes:
316 *) The actual dump request can not be sent here since we are not allowed to
317 wait for the completion of the first message in this context, and sending
318 the dump request before completion of the previous message leaves the POD
319 in an undefined state. The dump request will be sent when the echoed
320 commands are received.
321 *) This method fails if a param change message is "chopped" after the first
322 byte.
323*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200324void line6_pod_midi_postprocess(struct usb_line6_pod *pod, unsigned char *data,
325 int length)
Markus Grabner705ecec2009-02-27 19:43:04 -0800326{
327 int i;
328
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800329 if (!pod->midi_postprocess)
Markus Grabner705ecec2009-02-27 19:43:04 -0800330 return;
331
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800332 for (i = 0; i < length; ++i) {
333 if (data[i] == (LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800334 line6_invalidate_current(&pod->dumpreq);
335 break;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200336 } else
337 if ((data[i] == (LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST))
338 && (i < length - 1))
339 if ((data[i + 1] == POD_amp_model_setup)
340 || (data[i + 1] == POD_effect_setup)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800341 line6_invalidate_current(&pod->dumpreq);
342 break;
343 }
344 }
345}
346
347/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800348 Transmit PODxt Pro control parameter.
349*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200350void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param,
Johannes Thumshirn5b9bd2a2012-06-27 21:25:57 +0200351 u8 value)
Markus Grabner705ecec2009-02-27 19:43:04 -0800352{
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800353 if (line6_transmit_parameter(&pod->line6, param, value) == 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800354 pod_store_parameter(pod, param, value);
355
Markus Grabnere1a164d2010-08-23 01:08:25 +0200356 if ((param == POD_amp_model_setup) || (param == POD_effect_setup)) /* these also affect other settings */
Markus Grabner705ecec2009-02-27 19:43:04 -0800357 line6_invalidate_current(&pod->dumpreq);
358}
359
360/*
361 Resolve value to memory location.
362*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200363static int pod_resolve(const char *buf, short block0, short block1,
364 unsigned char *location)
Markus Grabner705ecec2009-02-27 19:43:04 -0800365{
Johannes Thumshirn1d0e8342012-06-27 21:26:01 +0200366 u8 value;
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600367 short block;
368 int ret;
369
Johannes Thumshirn1d0e8342012-06-27 21:26:01 +0200370 ret = kstrtou8(buf, 10, &value);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600371 if (ret)
372 return ret;
373
374 block = (value < 0x40) ? block0 : block1;
Markus Grabner705ecec2009-02-27 19:43:04 -0800375 value &= 0x3f;
376 location[0] = block >> 7;
377 location[1] = value | (block & 0x7f);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600378 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800379}
380
381/*
382 Send command to store channel/effects setup/amp setup to PODxt Pro.
383*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200384static ssize_t pod_send_store_command(struct device *dev, const char *buf,
385 size_t count, short block0, short block1)
Markus Grabner705ecec2009-02-27 19:43:04 -0800386{
387 struct usb_interface *interface = to_usb_interface(dev);
388 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600389 int ret;
Markus Grabner705ecec2009-02-27 19:43:04 -0800390 int size = 3 + sizeof(pod->prog_data_buf);
391 char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_STORE, size);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600392
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800393 if (!sysex)
394 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800395
Stefan Hajnoczi980688f2012-11-22 20:48:44 +0100396 /* Don't know what this is good for, but PODxt Pro transmits it, so we
397 * also do... */
398 sysex[SYSEX_DATA_OFS] = 5;
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600399 ret = pod_resolve(buf, block0, block1, sysex + SYSEX_DATA_OFS + 1);
400 if (ret) {
401 kfree(sysex);
402 return ret;
403 }
404
Markus Grabnere1a164d2010-08-23 01:08:25 +0200405 memcpy(sysex + SYSEX_DATA_OFS + 3, &pod->prog_data_buf,
406 sizeof(pod->prog_data_buf));
Markus Grabner705ecec2009-02-27 19:43:04 -0800407
408 line6_send_sysex_message(&pod->line6, sysex, size);
409 kfree(sysex);
410 /* needs some delay here on AMD64 platform */
411 return count;
412}
413
414/*
415 Send command to retrieve channel/effects setup/amp setup to PODxt Pro.
416*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200417static ssize_t pod_send_retrieve_command(struct device *dev, const char *buf,
418 size_t count, short block0,
419 short block1)
Markus Grabner705ecec2009-02-27 19:43:04 -0800420{
421 struct usb_interface *interface = to_usb_interface(dev);
422 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600423 int ret;
Markus Grabner705ecec2009-02-27 19:43:04 -0800424 int size = 4;
425 char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_DUMPMEM, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800426
427 if (!sysex)
428 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800429
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600430 ret = pod_resolve(buf, block0, block1, sysex + SYSEX_DATA_OFS);
431 if (ret) {
432 kfree(sysex);
433 return ret;
434 }
Markus Grabner705ecec2009-02-27 19:43:04 -0800435 sysex[SYSEX_DATA_OFS + 2] = 0;
436 sysex[SYSEX_DATA_OFS + 3] = 0;
437 line6_dump_started(&pod->dumpreq, POD_DUMP_MEMORY);
438
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800439 if (line6_send_sysex_message(&pod->line6, sysex, size) < size)
Markus Grabner705ecec2009-02-27 19:43:04 -0800440 line6_dump_finished(&pod->dumpreq);
441
442 kfree(sysex);
443 /* needs some delay here on AMD64 platform */
444 return count;
445}
446
447/*
448 Generic get name function.
449*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200450static ssize_t get_name_generic(struct usb_line6_pod *pod, const char *str,
451 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800452{
453 int length = 0;
454 const char *p1;
455 char *p2;
456 char *last_non_space = buf;
457
Markus Grabner1027f4762010-08-12 01:35:30 +0200458 int retval = line6_dump_wait_interruptible(&pod->dumpreq);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800459 if (retval < 0)
460 return retval;
Markus Grabner705ecec2009-02-27 19:43:04 -0800461
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800462 for (p1 = str, p2 = buf; *p1; ++p1, ++p2) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800463 *p2 = *p1;
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800464 if (*p2 != ' ')
465 last_non_space = p2;
466 if (++length == POD_NAME_LENGTH)
467 break;
Markus Grabner705ecec2009-02-27 19:43:04 -0800468 }
469
470 *(last_non_space + 1) = '\n';
471 return last_non_space - buf + 2;
472}
473
474/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800475 "read" request on "name" special file.
476*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800477static ssize_t pod_get_name(struct device *dev, struct device_attribute *attr,
478 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800479{
480 struct usb_interface *interface = to_usb_interface(dev);
481 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200482 return get_name_generic(pod, pod->prog_data.header + POD_NAME_OFFSET,
483 buf);
Markus Grabner705ecec2009-02-27 19:43:04 -0800484}
485
486/*
487 "read" request on "name" special file.
488*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800489static ssize_t pod_get_name_buf(struct device *dev,
490 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800491{
492 struct usb_interface *interface = to_usb_interface(dev);
493 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200494 return get_name_generic(pod,
495 pod->prog_data_buf.header + POD_NAME_OFFSET,
496 buf);
Markus Grabner705ecec2009-02-27 19:43:04 -0800497}
498
499/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200500 Identify system parameters related to the tuner.
501*/
502static bool pod_is_tuner(int code)
503{
504 return
Markus Grabnere1a164d2010-08-23 01:08:25 +0200505 (code == POD_tuner_mute) ||
506 (code == POD_tuner_freq) ||
507 (code == POD_tuner_note) || (code == POD_tuner_pitch);
Markus Grabner1027f4762010-08-12 01:35:30 +0200508}
509
510/*
511 Get system parameter (as integer).
Markus Grabner705ecec2009-02-27 19:43:04 -0800512 @param tuner non-zero, if code refers to a tuner parameter
513*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200514static int pod_get_system_param_int(struct usb_line6_pod *pod, int *value,
515 int code, struct ValueWait *param, int sign)
Markus Grabner705ecec2009-02-27 19:43:04 -0800516{
517 char *sysex;
Markus Grabner705ecec2009-02-27 19:43:04 -0800518 static const int size = 1;
519 int retval = 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800520
Markus Grabnere1a164d2010-08-23 01:08:25 +0200521 if (((pod->prog_data.control[POD_tuner] & 0x40) == 0)
522 && pod_is_tuner(code))
Markus Grabner705ecec2009-02-27 19:43:04 -0800523 return -ENODEV;
524
Markus Grabner1027f4762010-08-12 01:35:30 +0200525 /* send value request to device: */
Markus Grabner705ecec2009-02-27 19:43:04 -0800526 param->value = POD_system_invalid;
527 sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEMREQ, size);
Markus Grabner1027f4762010-08-12 01:35:30 +0200528
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800529 if (!sysex)
Markus Grabner1027f4762010-08-12 01:35:30 +0200530 return -ENOMEM;
531
Markus Grabner705ecec2009-02-27 19:43:04 -0800532 sysex[SYSEX_DATA_OFS] = code;
533 line6_send_sysex_message(&pod->line6, sysex, size);
534 kfree(sysex);
535
Markus Grabner1027f4762010-08-12 01:35:30 +0200536 /* wait for device to respond: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200537 retval =
538 wait_event_interruptible(param->wait,
539 param->value != POD_system_invalid);
Markus Grabner705ecec2009-02-27 19:43:04 -0800540
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800541 if (retval < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800542 return retval;
543
Markus Grabnere1a164d2010-08-23 01:08:25 +0200544 *value = sign ? (int)(signed short)param->value : (int)(unsigned short)
545 param->value;
Markus Grabner1027f4762010-08-12 01:35:30 +0200546
Markus Grabnere1a164d2010-08-23 01:08:25 +0200547 if (*value == POD_system_invalid)
548 *value = 0; /* don't report uninitialized values */
Markus Grabner1027f4762010-08-12 01:35:30 +0200549
550 return 0;
551}
552
553/*
554 Get system parameter (as string).
555 @param tuner non-zero, if code refers to a tuner parameter
556*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200557static ssize_t pod_get_system_param_string(struct usb_line6_pod *pod, char *buf,
558 int code, struct ValueWait *param,
559 int sign)
Markus Grabner1027f4762010-08-12 01:35:30 +0200560{
561 int retval, value = 0;
562 retval = pod_get_system_param_int(pod, &value, code, param, sign);
563
Markus Grabnere1a164d2010-08-23 01:08:25 +0200564 if (retval < 0)
Markus Grabner1027f4762010-08-12 01:35:30 +0200565 return retval;
566
Markus Grabner705ecec2009-02-27 19:43:04 -0800567 return sprintf(buf, "%d\n", value);
568}
569
570/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200571 Send system parameter (from integer).
Markus Grabner705ecec2009-02-27 19:43:04 -0800572 @param tuner non-zero, if code refers to a tuner parameter
573*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200574static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
575 int code)
Markus Grabner705ecec2009-02-27 19:43:04 -0800576{
577 char *sysex;
578 static const int size = 5;
Markus Grabner705ecec2009-02-27 19:43:04 -0800579
Markus Grabnere1a164d2010-08-23 01:08:25 +0200580 if (((pod->prog_data.control[POD_tuner] & 0x40) == 0)
581 && pod_is_tuner(code))
Markus Grabner705ecec2009-02-27 19:43:04 -0800582 return -EINVAL;
583
584 /* send value to tuner: */
585 sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800586 if (!sysex)
Markus Grabner1027f4762010-08-12 01:35:30 +0200587 return -ENOMEM;
Markus Grabner705ecec2009-02-27 19:43:04 -0800588 sysex[SYSEX_DATA_OFS] = code;
589 sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200590 sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f;
591 sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f;
592 sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f;
Markus Grabner705ecec2009-02-27 19:43:04 -0800593 line6_send_sysex_message(&pod->line6, sysex, size);
594 kfree(sysex);
Markus Grabner1027f4762010-08-12 01:35:30 +0200595 return 0;
596}
597
598/*
599 Send system parameter (from string).
600 @param tuner non-zero, if code refers to a tuner parameter
601*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200602static ssize_t pod_set_system_param_string(struct usb_line6_pod *pod,
603 const char *buf, int count, int code,
604 unsigned short mask)
Markus Grabner1027f4762010-08-12 01:35:30 +0200605{
606 int retval;
607 unsigned short value = simple_strtoul(buf, NULL, 10) & mask;
608 retval = pod_set_system_param_int(pod, value, code);
609 return (retval < 0) ? retval : count;
Markus Grabner705ecec2009-02-27 19:43:04 -0800610}
611
612/*
613 "read" request on "dump_buf" special file.
614*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800615static ssize_t pod_get_dump_buf(struct device *dev,
616 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800617{
618 struct usb_interface *interface = to_usb_interface(dev);
619 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Markus Grabner1027f4762010-08-12 01:35:30 +0200620 int retval = line6_dump_wait_interruptible(&pod->dumpreq);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800621 if (retval < 0)
622 return retval;
Markus Grabner705ecec2009-02-27 19:43:04 -0800623 memcpy(buf, &pod->prog_data_buf, sizeof(pod->prog_data_buf));
624 return sizeof(pod->prog_data_buf);
625}
626
627/*
628 "write" request on "dump_buf" special file.
629*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800630static ssize_t pod_set_dump_buf(struct device *dev,
631 struct device_attribute *attr,
632 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800633{
634 struct usb_interface *interface = to_usb_interface(dev);
635 struct usb_line6_pod *pod = usb_get_intfdata(interface);
636
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800637 if (count != sizeof(pod->prog_data)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800638 dev_err(pod->line6.ifcdev,
Markus Grabner1027f4762010-08-12 01:35:30 +0200639 "data block must be exactly %d bytes\n",
640 (int)sizeof(pod->prog_data));
Markus Grabner705ecec2009-02-27 19:43:04 -0800641 return -EINVAL;
642 }
643
644 memcpy(&pod->prog_data_buf, buf, sizeof(pod->prog_data));
645 return sizeof(pod->prog_data);
646}
647
648/*
649 "write" request on "finish" special file.
650*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800651static ssize_t pod_set_finish(struct device *dev,
652 struct device_attribute *attr,
653 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800654{
655 struct usb_interface *interface = to_usb_interface(dev);
656 struct usb_line6_pod *pod = usb_get_intfdata(interface);
657 int size = 0;
658 char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_FINISH, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800659 if (!sysex)
660 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800661 line6_send_sysex_message(&pod->line6, sysex, size);
662 kfree(sysex);
663 return count;
664}
665
666/*
667 "write" request on "store_channel" special file.
668*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800669static ssize_t pod_set_store_channel(struct device *dev,
670 struct device_attribute *attr,
671 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800672{
673 return pod_send_store_command(dev, buf, count, 0x0000, 0x00c0);
674}
675
676/*
677 "write" request on "store_effects_setup" special file.
678*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800679static ssize_t pod_set_store_effects_setup(struct device *dev,
680 struct device_attribute *attr,
681 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800682{
683 return pod_send_store_command(dev, buf, count, 0x0080, 0x0080);
684}
685
686/*
687 "write" request on "store_amp_setup" special file.
688*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800689static ssize_t pod_set_store_amp_setup(struct device *dev,
690 struct device_attribute *attr,
691 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800692{
693 return pod_send_store_command(dev, buf, count, 0x0040, 0x0100);
694}
695
696/*
697 "write" request on "retrieve_channel" special file.
698*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800699static ssize_t pod_set_retrieve_channel(struct device *dev,
700 struct device_attribute *attr,
701 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800702{
703 return pod_send_retrieve_command(dev, buf, count, 0x0000, 0x00c0);
704}
705
706/*
707 "write" request on "retrieve_effects_setup" special file.
708*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800709static ssize_t pod_set_retrieve_effects_setup(struct device *dev,
710 struct device_attribute *attr,
711 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800712{
713 return pod_send_retrieve_command(dev, buf, count, 0x0080, 0x0080);
714}
715
716/*
717 "write" request on "retrieve_amp_setup" special file.
718*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800719static ssize_t pod_set_retrieve_amp_setup(struct device *dev,
720 struct device_attribute *attr,
721 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800722{
723 return pod_send_retrieve_command(dev, buf, count, 0x0040, 0x0100);
724}
725
726/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800727 "read" request on "midi_postprocess" special file.
728*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800729static ssize_t pod_get_midi_postprocess(struct device *dev,
730 struct device_attribute *attr,
731 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800732{
733 struct usb_interface *interface = to_usb_interface(dev);
734 struct usb_line6_pod *pod = usb_get_intfdata(interface);
735 return sprintf(buf, "%d\n", pod->midi_postprocess);
736}
737
738/*
739 "write" request on "midi_postprocess" special file.
740*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800741static ssize_t pod_set_midi_postprocess(struct device *dev,
742 struct device_attribute *attr,
743 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800744{
745 struct usb_interface *interface = to_usb_interface(dev);
746 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Johannes Thumshirn06501782012-06-27 21:26:03 +0200747 u8 value;
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600748 int ret;
749
Johannes Thumshirn06501782012-06-27 21:26:03 +0200750 ret = kstrtou8(buf, 10, &value);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600751 if (ret)
752 return ret;
753
Markus Grabner705ecec2009-02-27 19:43:04 -0800754 pod->midi_postprocess = value ? 1 : 0;
755 return count;
756}
757
758/*
759 "read" request on "serial_number" special file.
760*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800761static ssize_t pod_get_serial_number(struct device *dev,
762 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800763{
764 struct usb_interface *interface = to_usb_interface(dev);
765 struct usb_line6_pod *pod = usb_get_intfdata(interface);
766 return sprintf(buf, "%d\n", pod->serial_number);
767}
768
769/*
770 "read" request on "firmware_version" special file.
771*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800772static ssize_t pod_get_firmware_version(struct device *dev,
773 struct device_attribute *attr,
774 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800775{
776 struct usb_interface *interface = to_usb_interface(dev);
777 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800778 return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
779 pod->firmware_version % 100);
Markus Grabner705ecec2009-02-27 19:43:04 -0800780}
781
782/*
783 "read" request on "device_id" special file.
784*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800785static ssize_t pod_get_device_id(struct device *dev,
786 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800787{
788 struct usb_interface *interface = to_usb_interface(dev);
789 struct usb_line6_pod *pod = usb_get_intfdata(interface);
790 return sprintf(buf, "%d\n", pod->device_id);
791}
792
793/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200794 POD startup procedure.
795 This is a sequence of functions with special requirements (e.g., must
796 not run immediately after initialization, must not run in interrupt
797 context). After the last one has finished, the device is ready to use.
798*/
799
800static void pod_startup1(struct usb_line6_pod *pod)
801{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200802 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT);
Markus Grabner1027f4762010-08-12 01:35:30 +0200803
804 /* delay startup procedure: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200805 line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
806 (unsigned long)pod);
Markus Grabner1027f4762010-08-12 01:35:30 +0200807}
808
809static void pod_startup2(unsigned long data)
810{
811 struct usb_line6_pod *pod = (struct usb_line6_pod *)data;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200812
813 /* schedule another startup procedure until startup is complete: */
814 if (pod->startup_progress >= POD_STARTUP_LAST)
815 return;
816
817 pod->startup_progress = POD_STARTUP_DUMPREQ;
818 line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
819 (unsigned long)pod);
Markus Grabner1027f4762010-08-12 01:35:30 +0200820
821 /* current channel dump: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200822 line6_dump_request_async(&pod->dumpreq, &pod->line6, 0,
823 LINE6_DUMP_CURRENT);
Markus Grabner1027f4762010-08-12 01:35:30 +0200824}
825
826static void pod_startup3(struct usb_line6_pod *pod)
827{
828 struct usb_line6 *line6 = &pod->line6;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200829 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ);
Markus Grabner1027f4762010-08-12 01:35:30 +0200830
831 /* request firmware version: */
832 line6_version_request_async(line6);
833}
834
835static void pod_startup4(struct usb_line6_pod *pod)
836{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200837 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE);
Markus Grabner1027f4762010-08-12 01:35:30 +0200838
839 /* schedule work for global work queue: */
840 schedule_work(&pod->startup_work);
841}
842
843static void pod_startup5(struct work_struct *work)
844{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200845 struct usb_line6_pod *pod =
846 container_of(work, struct usb_line6_pod, startup_work);
Markus Grabner1027f4762010-08-12 01:35:30 +0200847 struct usb_line6 *line6 = &pod->line6;
848
Markus Grabnere1a164d2010-08-23 01:08:25 +0200849 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP);
Markus Grabner1027f4762010-08-12 01:35:30 +0200850
851 /* serial number: */
852 line6_read_serial_number(&pod->line6, &pod->serial_number);
853
854 /* ALSA audio interface: */
855 line6_register_audio(line6);
856
857 /* device files: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200858 line6_pod_create_files(pod->firmware_version,
859 line6->properties->device_bit, line6->ifcdev);
Markus Grabner1027f4762010-08-12 01:35:30 +0200860}
861
862#define POD_GET_SYSTEM_PARAM(code, sign) \
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800863static ssize_t pod_get_ ## code(struct device *dev, \
864 struct device_attribute *attr, char *buf) \
Markus Grabner705ecec2009-02-27 19:43:04 -0800865{ \
866 struct usb_interface *interface = to_usb_interface(dev); \
867 struct usb_line6_pod *pod = usb_get_intfdata(interface); \
Markus Grabner1027f4762010-08-12 01:35:30 +0200868 return pod_get_system_param_string(pod, buf, POD_ ## code, \
869 &pod->code, sign); \
Markus Grabner705ecec2009-02-27 19:43:04 -0800870}
871
Markus Grabner1027f4762010-08-12 01:35:30 +0200872#define POD_GET_SET_SYSTEM_PARAM(code, mask, sign) \
873POD_GET_SYSTEM_PARAM(code, sign) \
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800874static ssize_t pod_set_ ## code(struct device *dev, \
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800875 struct device_attribute *attr, \
876 const char *buf, size_t count) \
Markus Grabner705ecec2009-02-27 19:43:04 -0800877{ \
878 struct usb_interface *interface = to_usb_interface(dev); \
879 struct usb_line6_pod *pod = usb_get_intfdata(interface); \
Markus Grabner1027f4762010-08-12 01:35:30 +0200880 return pod_set_system_param_string(pod, buf, count, POD_ ## code, mask); \
Markus Grabner705ecec2009-02-27 19:43:04 -0800881}
882
Markus Grabner1027f4762010-08-12 01:35:30 +0200883POD_GET_SET_SYSTEM_PARAM(monitor_level, 0xffff, 0);
884POD_GET_SET_SYSTEM_PARAM(routing, 0x0003, 0);
885POD_GET_SET_SYSTEM_PARAM(tuner_mute, 0x0001, 0);
886POD_GET_SET_SYSTEM_PARAM(tuner_freq, 0xffff, 0);
887POD_GET_SYSTEM_PARAM(tuner_note, 1);
888POD_GET_SYSTEM_PARAM(tuner_pitch, 1);
Markus Grabner705ecec2009-02-27 19:43:04 -0800889
890#undef GET_SET_SYSTEM_PARAM
891#undef GET_SYSTEM_PARAM
892
893/* POD special files: */
Markus Grabner705ecec2009-02-27 19:43:04 -0800894static DEVICE_ATTR(device_id, S_IRUGO, pod_get_device_id, line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800895static DEVICE_ATTR(dump_buf, S_IWUSR | S_IRUGO, pod_get_dump_buf,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200896 pod_set_dump_buf);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800897static DEVICE_ATTR(finish, S_IWUSR, line6_nop_read, pod_set_finish);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200898static DEVICE_ATTR(firmware_version, S_IRUGO, pod_get_firmware_version,
899 line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800900static DEVICE_ATTR(midi_postprocess, S_IWUSR | S_IRUGO,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200901 pod_get_midi_postprocess, pod_set_midi_postprocess);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800902static DEVICE_ATTR(monitor_level, S_IWUSR | S_IRUGO, pod_get_monitor_level,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200903 pod_set_monitor_level);
Markus Grabner705ecec2009-02-27 19:43:04 -0800904static DEVICE_ATTR(name, S_IRUGO, pod_get_name, line6_nop_write);
905static DEVICE_ATTR(name_buf, S_IRUGO, pod_get_name_buf, line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800906static DEVICE_ATTR(retrieve_amp_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200907 pod_set_retrieve_amp_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800908static DEVICE_ATTR(retrieve_channel, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200909 pod_set_retrieve_channel);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800910static DEVICE_ATTR(retrieve_effects_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200911 pod_set_retrieve_effects_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800912static DEVICE_ATTR(routing, S_IWUSR | S_IRUGO, pod_get_routing,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200913 pod_set_routing);
914static DEVICE_ATTR(serial_number, S_IRUGO, pod_get_serial_number,
915 line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800916static DEVICE_ATTR(store_amp_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200917 pod_set_store_amp_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800918static DEVICE_ATTR(store_channel, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200919 pod_set_store_channel);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800920static DEVICE_ATTR(store_effects_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200921 pod_set_store_effects_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800922static DEVICE_ATTR(tuner_freq, S_IWUSR | S_IRUGO, pod_get_tuner_freq,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200923 pod_set_tuner_freq);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800924static DEVICE_ATTR(tuner_mute, S_IWUSR | S_IRUGO, pod_get_tuner_mute,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200925 pod_set_tuner_mute);
Markus Grabner705ecec2009-02-27 19:43:04 -0800926static DEVICE_ATTR(tuner_note, S_IRUGO, pod_get_tuner_note, line6_nop_write);
927static DEVICE_ATTR(tuner_pitch, S_IRUGO, pod_get_tuner_pitch, line6_nop_write);
928
Markus Grabner1027f4762010-08-12 01:35:30 +0200929#ifdef CONFIG_LINE6_USB_RAW
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800930static DEVICE_ATTR(raw, S_IWUSR, line6_nop_read, line6_set_raw);
Markus Grabner705ecec2009-02-27 19:43:04 -0800931#endif
932
Markus Grabner1027f4762010-08-12 01:35:30 +0200933/* control info callback */
934static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol,
935 struct snd_ctl_elem_info *uinfo)
936{
937 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
938 uinfo->count = 1;
939 uinfo->value.integer.min = 0;
940 uinfo->value.integer.max = 65535;
941 return 0;
942}
943
944/* control get callback */
945static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol,
946 struct snd_ctl_elem_value *ucontrol)
947{
948 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
949 struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
950 ucontrol->value.integer.value[0] = pod->monitor_level.value;
951 return 0;
952}
953
954/* control put callback */
955static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol,
956 struct snd_ctl_elem_value *ucontrol)
957{
958 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
959 struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
960
Markus Grabnere1a164d2010-08-23 01:08:25 +0200961 if (ucontrol->value.integer.value[0] == pod->monitor_level.value)
Markus Grabner1027f4762010-08-12 01:35:30 +0200962 return 0;
963
964 pod->monitor_level.value = ucontrol->value.integer.value[0];
Markus Grabnere1a164d2010-08-23 01:08:25 +0200965 pod_set_system_param_int(pod, ucontrol->value.integer.value[0],
966 POD_monitor_level);
Markus Grabner1027f4762010-08-12 01:35:30 +0200967 return 1;
968}
969
970/* control definition */
971static struct snd_kcontrol_new pod_control_monitor = {
972 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
973 .name = "Monitor Playback Volume",
974 .index = 0,
975 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
976 .info = snd_pod_control_monitor_info,
977 .get = snd_pod_control_monitor_get,
978 .put = snd_pod_control_monitor_put
979};
980
Markus Grabner705ecec2009-02-27 19:43:04 -0800981/*
982 POD destructor.
983*/
984static void pod_destruct(struct usb_interface *interface)
985{
986 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Markus Grabner705ecec2009-02-27 19:43:04 -0800987
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800988 if (pod == NULL)
989 return;
Stefan Hajnoczi188e6642011-12-10 02:12:30 +0100990 line6_cleanup_audio(&pod->line6);
Markus Grabner705ecec2009-02-27 19:43:04 -0800991
Markus Grabnere1a164d2010-08-23 01:08:25 +0200992 del_timer(&pod->startup_timer);
993 cancel_work_sync(&pod->startup_work);
994
Markus Grabner705ecec2009-02-27 19:43:04 -0800995 /* free dump request data: */
996 line6_dumpreq_destruct(&pod->dumpreq);
Markus Grabner705ecec2009-02-27 19:43:04 -0800997}
998
999/*
1000 Create sysfs entries.
1001*/
Greg Kroah-Hartmanb702ed252009-02-27 20:45:03 -08001002static int pod_create_files2(struct device *dev)
Markus Grabner705ecec2009-02-27 19:43:04 -08001003{
1004 int err;
1005
Markus Grabner705ecec2009-02-27 19:43:04 -08001006 CHECK_RETURN(device_create_file(dev, &dev_attr_device_id));
Markus Grabner705ecec2009-02-27 19:43:04 -08001007 CHECK_RETURN(device_create_file(dev, &dev_attr_dump_buf));
1008 CHECK_RETURN(device_create_file(dev, &dev_attr_finish));
1009 CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version));
1010 CHECK_RETURN(device_create_file(dev, &dev_attr_midi_postprocess));
1011 CHECK_RETURN(device_create_file(dev, &dev_attr_monitor_level));
1012 CHECK_RETURN(device_create_file(dev, &dev_attr_name));
1013 CHECK_RETURN(device_create_file(dev, &dev_attr_name_buf));
1014 CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_amp_setup));
1015 CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_channel));
1016 CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_effects_setup));
1017 CHECK_RETURN(device_create_file(dev, &dev_attr_routing));
1018 CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number));
1019 CHECK_RETURN(device_create_file(dev, &dev_attr_store_amp_setup));
1020 CHECK_RETURN(device_create_file(dev, &dev_attr_store_channel));
1021 CHECK_RETURN(device_create_file(dev, &dev_attr_store_effects_setup));
1022 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_freq));
1023 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_mute));
1024 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_note));
1025 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_pitch));
1026
Markus Grabner1027f4762010-08-12 01:35:30 +02001027#ifdef CONFIG_LINE6_USB_RAW
Markus Grabner705ecec2009-02-27 19:43:04 -08001028 CHECK_RETURN(device_create_file(dev, &dev_attr_raw));
1029#endif
1030
1031 return 0;
1032}
1033
1034/*
Markus Grabner1027f4762010-08-12 01:35:30 +02001035 Try to init POD device.
Markus Grabner705ecec2009-02-27 19:43:04 -08001036*/
Markus Grabnere1a164d2010-08-23 01:08:25 +02001037static int pod_try_init(struct usb_interface *interface,
1038 struct usb_line6_pod *pod)
Markus Grabner705ecec2009-02-27 19:43:04 -08001039{
1040 int err;
1041 struct usb_line6 *line6 = &pod->line6;
1042
Markus Grabnere1a164d2010-08-23 01:08:25 +02001043 init_timer(&pod->startup_timer);
1044 INIT_WORK(&pod->startup_work, pod_startup5);
1045
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001046 if ((interface == NULL) || (pod == NULL))
1047 return -ENODEV;
Markus Grabner705ecec2009-02-27 19:43:04 -08001048
Markus Grabner705ecec2009-02-27 19:43:04 -08001049 /* initialize wait queues: */
1050 init_waitqueue_head(&pod->monitor_level.wait);
1051 init_waitqueue_head(&pod->routing.wait);
1052 init_waitqueue_head(&pod->tuner_mute.wait);
1053 init_waitqueue_head(&pod->tuner_freq.wait);
1054 init_waitqueue_head(&pod->tuner_note.wait);
1055 init_waitqueue_head(&pod->tuner_pitch.wait);
Markus Grabner705ecec2009-02-27 19:43:04 -08001056
Markus Grabner705ecec2009-02-27 19:43:04 -08001057 /* initialize USB buffers: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001058 err = line6_dumpreq_init(&pod->dumpreq, pod_request_channel,
1059 sizeof(pod_request_channel));
1060 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001061 dev_err(&interface->dev, "Out of memory\n");
Markus Grabner705ecec2009-02-27 19:43:04 -08001062 return -ENOMEM;
1063 }
1064
Markus Grabner705ecec2009-02-27 19:43:04 -08001065 /* create sysfs entries: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001066 err = pod_create_files2(&interface->dev);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001067 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -08001068 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -08001069
1070 /* initialize audio system: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001071 err = line6_init_audio(line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001072 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -08001073 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -08001074
1075 /* initialize MIDI subsystem: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001076 err = line6_init_midi(line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001077 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -08001078 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -08001079
1080 /* initialize PCM subsystem: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001081 err = line6_init_pcm(line6, &pod_pcm_properties);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001082 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -08001083 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -08001084
Markus Grabner1027f4762010-08-12 01:35:30 +02001085 /* register monitor control: */
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001086 err = snd_ctl_add(line6->card,
1087 snd_ctl_new1(&pod_control_monitor, line6->line6pcm));
1088 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -08001089 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -08001090
Markus Grabner1027f4762010-08-12 01:35:30 +02001091 /*
Markus Grabnere1a164d2010-08-23 01:08:25 +02001092 When the sound card is registered at this point, the PODxt Live
1093 displays "Invalid Code Error 07", so we do it later in the event
1094 handler.
1095 */
Markus Grabner1027f4762010-08-12 01:35:30 +02001096
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001097 if (pod->line6.properties->capabilities & LINE6_BIT_CONTROL) {
Markus Grabner1027f4762010-08-12 01:35:30 +02001098 pod->monitor_level.value = POD_system_invalid;
1099
1100 /* initiate startup procedure: */
1101 pod_startup1(pod);
Markus Grabner705ecec2009-02-27 19:43:04 -08001102 }
1103
1104 return 0;
1105}
1106
1107/*
Markus Grabner1027f4762010-08-12 01:35:30 +02001108 Init POD device (and clean up in case of failure).
1109*/
1110int line6_pod_init(struct usb_interface *interface, struct usb_line6_pod *pod)
1111{
1112 int err = pod_try_init(interface, pod);
1113
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001114 if (err < 0)
Markus Grabner1027f4762010-08-12 01:35:30 +02001115 pod_destruct(interface);
Markus Grabner1027f4762010-08-12 01:35:30 +02001116
1117 return err;
1118}
1119
1120/*
Markus Grabner705ecec2009-02-27 19:43:04 -08001121 POD device disconnected.
1122*/
Markus Grabner1027f4762010-08-12 01:35:30 +02001123void line6_pod_disconnect(struct usb_interface *interface)
Markus Grabner705ecec2009-02-27 19:43:04 -08001124{
1125 struct usb_line6_pod *pod;
1126
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001127 if (interface == NULL)
1128 return;
Markus Grabner705ecec2009-02-27 19:43:04 -08001129 pod = usb_get_intfdata(interface);
1130
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001131 if (pod != NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001132 struct snd_line6_pcm *line6pcm = pod->line6.line6pcm;
1133 struct device *dev = &interface->dev;
1134
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001135 if (line6pcm != NULL)
Markus Grabner1027f4762010-08-12 01:35:30 +02001136 line6_pcm_disconnect(line6pcm);
Markus Grabner705ecec2009-02-27 19:43:04 -08001137
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001138 if (dev != NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001139 /* remove sysfs entries: */
Markus Grabnere1a164d2010-08-23 01:08:25 +02001140 line6_pod_remove_files(pod->firmware_version,
1141 pod->line6.
1142 properties->device_bit, dev);
Markus Grabner705ecec2009-02-27 19:43:04 -08001143
Markus Grabner705ecec2009-02-27 19:43:04 -08001144 device_remove_file(dev, &dev_attr_device_id);
Markus Grabner705ecec2009-02-27 19:43:04 -08001145 device_remove_file(dev, &dev_attr_dump_buf);
1146 device_remove_file(dev, &dev_attr_finish);
1147 device_remove_file(dev, &dev_attr_firmware_version);
1148 device_remove_file(dev, &dev_attr_midi_postprocess);
1149 device_remove_file(dev, &dev_attr_monitor_level);
1150 device_remove_file(dev, &dev_attr_name);
1151 device_remove_file(dev, &dev_attr_name_buf);
1152 device_remove_file(dev, &dev_attr_retrieve_amp_setup);
1153 device_remove_file(dev, &dev_attr_retrieve_channel);
Markus Grabnere1a164d2010-08-23 01:08:25 +02001154 device_remove_file(dev,
1155 &dev_attr_retrieve_effects_setup);
Markus Grabner705ecec2009-02-27 19:43:04 -08001156 device_remove_file(dev, &dev_attr_routing);
1157 device_remove_file(dev, &dev_attr_serial_number);
1158 device_remove_file(dev, &dev_attr_store_amp_setup);
1159 device_remove_file(dev, &dev_attr_store_channel);
1160 device_remove_file(dev, &dev_attr_store_effects_setup);
1161 device_remove_file(dev, &dev_attr_tuner_freq);
1162 device_remove_file(dev, &dev_attr_tuner_mute);
1163 device_remove_file(dev, &dev_attr_tuner_note);
1164 device_remove_file(dev, &dev_attr_tuner_pitch);
1165
Markus Grabner1027f4762010-08-12 01:35:30 +02001166#ifdef CONFIG_LINE6_USB_RAW
Markus Grabner705ecec2009-02-27 19:43:04 -08001167 device_remove_file(dev, &dev_attr_raw);
1168#endif
1169 }
1170 }
1171
1172 pod_destruct(interface);
1173}