blob: 165c7ad6bcce4ec8949c9e81e0db7bf205267a73 [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]) {
Stefan Hajnoczi410cefa2012-11-22 20:48:46 +0100247 case POD_monitor_level:
Stefan Hajnoczi2c35dc22012-11-22 20:48:47 +0100248 pod->monitor_level = value;
Stefan Hajnoczi410cefa2012-11-22 20:48:46 +0100249 break;
250
Markus Grabnere1a164d2010-08-23 01:08:25 +0200251 PROCESS_SYSTEM_PARAM(routing);
252 PROCESS_SYSTEM_PARAM
253 (tuner_mute);
254 PROCESS_SYSTEM_PARAM
255 (tuner_freq);
256 PROCESS_SYSTEM_PARAM
257 (tuner_note);
258 PROCESS_SYSTEM_PARAM
259 (tuner_pitch);
Markus Grabner705ecec2009-02-27 19:43:04 -0800260
261#undef PROCESS_SYSTEM_PARAM
262
Markus Grabnere1a164d2010-08-23 01:08:25 +0200263 default:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100264 dev_dbg(pod->line6.ifcdev,
265 "unknown tuner/system response %02X\n",
266 buf[6]);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200267 }
Markus Grabner705ecec2009-02-27 19:43:04 -0800268
Markus Grabnere1a164d2010-08-23 01:08:25 +0200269 break;
270 }
Markus Grabner705ecec2009-02-27 19:43:04 -0800271
272 case POD_SYSEX_FINISH:
273 /* do we need to respond to this? */
274 break;
275
276 case POD_SYSEX_SAVE:
277 pod_save_button_pressed(pod, buf[6], buf[7]);
278 break;
279
Markus Grabner705ecec2009-02-27 19:43:04 -0800280 case POD_SYSEX_STORE:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100281 dev_dbg(pod->line6.ifcdev,
282 "message %02X not yet implemented\n",
283 buf[5]);
Markus Grabner705ecec2009-02-27 19:43:04 -0800284 break;
285
286 default:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100287 dev_dbg(pod->line6.ifcdev,
288 "unknown sysex message %02X\n",
289 buf[5]);
Markus Grabner705ecec2009-02-27 19:43:04 -0800290 }
Markus Grabnere1a164d2010-08-23 01:08:25 +0200291 } else
292 if (memcmp
293 (buf, pod_version_header,
294 sizeof(pod_version_header)) == 0) {
295 pod->firmware_version =
296 buf[13] * 100 + buf[14] * 10 + buf[15];
297 pod->device_id =
298 ((int)buf[8] << 16) | ((int)buf[9] << 8) | (int)
299 buf[10];
Markus Grabner1027f4762010-08-12 01:35:30 +0200300 pod_startup4(pod);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800301 } else
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100302 dev_dbg(pod->line6.ifcdev, "unknown sysex header\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800303
304 break;
305
306 case LINE6_SYSEX_END:
307 break;
308
309 default:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100310 dev_dbg(pod->line6.ifcdev, "POD: unknown message %02X\n",
311 buf[0]);
Markus Grabner705ecec2009-02-27 19:43:04 -0800312 }
313}
314
315/*
316 Detect some cases that require a channel dump after sending a command to the
317 device. Important notes:
318 *) The actual dump request can not be sent here since we are not allowed to
319 wait for the completion of the first message in this context, and sending
320 the dump request before completion of the previous message leaves the POD
321 in an undefined state. The dump request will be sent when the echoed
322 commands are received.
323 *) This method fails if a param change message is "chopped" after the first
324 byte.
325*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200326void line6_pod_midi_postprocess(struct usb_line6_pod *pod, unsigned char *data,
327 int length)
Markus Grabner705ecec2009-02-27 19:43:04 -0800328{
329 int i;
330
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800331 if (!pod->midi_postprocess)
Markus Grabner705ecec2009-02-27 19:43:04 -0800332 return;
333
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800334 for (i = 0; i < length; ++i) {
335 if (data[i] == (LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800336 line6_invalidate_current(&pod->dumpreq);
337 break;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200338 } else
339 if ((data[i] == (LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST))
340 && (i < length - 1))
341 if ((data[i + 1] == POD_amp_model_setup)
342 || (data[i + 1] == POD_effect_setup)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800343 line6_invalidate_current(&pod->dumpreq);
344 break;
345 }
346 }
347}
348
349/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800350 Transmit PODxt Pro control parameter.
351*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200352void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param,
Johannes Thumshirn5b9bd2a2012-06-27 21:25:57 +0200353 u8 value)
Markus Grabner705ecec2009-02-27 19:43:04 -0800354{
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800355 if (line6_transmit_parameter(&pod->line6, param, value) == 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800356 pod_store_parameter(pod, param, value);
357
Markus Grabnere1a164d2010-08-23 01:08:25 +0200358 if ((param == POD_amp_model_setup) || (param == POD_effect_setup)) /* these also affect other settings */
Markus Grabner705ecec2009-02-27 19:43:04 -0800359 line6_invalidate_current(&pod->dumpreq);
360}
361
362/*
363 Resolve value to memory location.
364*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200365static int pod_resolve(const char *buf, short block0, short block1,
366 unsigned char *location)
Markus Grabner705ecec2009-02-27 19:43:04 -0800367{
Johannes Thumshirn1d0e8342012-06-27 21:26:01 +0200368 u8 value;
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600369 short block;
370 int ret;
371
Johannes Thumshirn1d0e8342012-06-27 21:26:01 +0200372 ret = kstrtou8(buf, 10, &value);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600373 if (ret)
374 return ret;
375
376 block = (value < 0x40) ? block0 : block1;
Markus Grabner705ecec2009-02-27 19:43:04 -0800377 value &= 0x3f;
378 location[0] = block >> 7;
379 location[1] = value | (block & 0x7f);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600380 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800381}
382
383/*
384 Send command to store channel/effects setup/amp setup to PODxt Pro.
385*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200386static ssize_t pod_send_store_command(struct device *dev, const char *buf,
387 size_t count, short block0, short block1)
Markus Grabner705ecec2009-02-27 19:43:04 -0800388{
389 struct usb_interface *interface = to_usb_interface(dev);
390 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600391 int ret;
Markus Grabner705ecec2009-02-27 19:43:04 -0800392 int size = 3 + sizeof(pod->prog_data_buf);
393 char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_STORE, size);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600394
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800395 if (!sysex)
396 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800397
Stefan Hajnoczi980688f2012-11-22 20:48:44 +0100398 /* Don't know what this is good for, but PODxt Pro transmits it, so we
399 * also do... */
400 sysex[SYSEX_DATA_OFS] = 5;
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600401 ret = pod_resolve(buf, block0, block1, sysex + SYSEX_DATA_OFS + 1);
402 if (ret) {
403 kfree(sysex);
404 return ret;
405 }
406
Markus Grabnere1a164d2010-08-23 01:08:25 +0200407 memcpy(sysex + SYSEX_DATA_OFS + 3, &pod->prog_data_buf,
408 sizeof(pod->prog_data_buf));
Markus Grabner705ecec2009-02-27 19:43:04 -0800409
410 line6_send_sysex_message(&pod->line6, sysex, size);
411 kfree(sysex);
412 /* needs some delay here on AMD64 platform */
413 return count;
414}
415
416/*
417 Send command to retrieve channel/effects setup/amp setup to PODxt Pro.
418*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200419static ssize_t pod_send_retrieve_command(struct device *dev, const char *buf,
420 size_t count, short block0,
421 short block1)
Markus Grabner705ecec2009-02-27 19:43:04 -0800422{
423 struct usb_interface *interface = to_usb_interface(dev);
424 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600425 int ret;
Markus Grabner705ecec2009-02-27 19:43:04 -0800426 int size = 4;
427 char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_DUMPMEM, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800428
429 if (!sysex)
430 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800431
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600432 ret = pod_resolve(buf, block0, block1, sysex + SYSEX_DATA_OFS);
433 if (ret) {
434 kfree(sysex);
435 return ret;
436 }
Markus Grabner705ecec2009-02-27 19:43:04 -0800437 sysex[SYSEX_DATA_OFS + 2] = 0;
438 sysex[SYSEX_DATA_OFS + 3] = 0;
439 line6_dump_started(&pod->dumpreq, POD_DUMP_MEMORY);
440
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800441 if (line6_send_sysex_message(&pod->line6, sysex, size) < size)
Markus Grabner705ecec2009-02-27 19:43:04 -0800442 line6_dump_finished(&pod->dumpreq);
443
444 kfree(sysex);
445 /* needs some delay here on AMD64 platform */
446 return count;
447}
448
449/*
450 Generic get name function.
451*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200452static ssize_t get_name_generic(struct usb_line6_pod *pod, const char *str,
453 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800454{
455 int length = 0;
456 const char *p1;
457 char *p2;
458 char *last_non_space = buf;
459
Markus Grabner1027f4762010-08-12 01:35:30 +0200460 int retval = line6_dump_wait_interruptible(&pod->dumpreq);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800461 if (retval < 0)
462 return retval;
Markus Grabner705ecec2009-02-27 19:43:04 -0800463
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800464 for (p1 = str, p2 = buf; *p1; ++p1, ++p2) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800465 *p2 = *p1;
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800466 if (*p2 != ' ')
467 last_non_space = p2;
468 if (++length == POD_NAME_LENGTH)
469 break;
Markus Grabner705ecec2009-02-27 19:43:04 -0800470 }
471
472 *(last_non_space + 1) = '\n';
473 return last_non_space - buf + 2;
474}
475
476/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800477 "read" request on "name" special file.
478*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800479static ssize_t pod_get_name(struct device *dev, struct device_attribute *attr,
480 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800481{
482 struct usb_interface *interface = to_usb_interface(dev);
483 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200484 return get_name_generic(pod, pod->prog_data.header + POD_NAME_OFFSET,
485 buf);
Markus Grabner705ecec2009-02-27 19:43:04 -0800486}
487
488/*
489 "read" request on "name" special file.
490*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800491static ssize_t pod_get_name_buf(struct device *dev,
492 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800493{
494 struct usb_interface *interface = to_usb_interface(dev);
495 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200496 return get_name_generic(pod,
497 pod->prog_data_buf.header + POD_NAME_OFFSET,
498 buf);
Markus Grabner705ecec2009-02-27 19:43:04 -0800499}
500
501/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200502 Identify system parameters related to the tuner.
503*/
504static bool pod_is_tuner(int code)
505{
506 return
Markus Grabnere1a164d2010-08-23 01:08:25 +0200507 (code == POD_tuner_mute) ||
508 (code == POD_tuner_freq) ||
509 (code == POD_tuner_note) || (code == POD_tuner_pitch);
Markus Grabner1027f4762010-08-12 01:35:30 +0200510}
511
512/*
513 Get system parameter (as integer).
Markus Grabner705ecec2009-02-27 19:43:04 -0800514 @param tuner non-zero, if code refers to a tuner parameter
515*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200516static int pod_get_system_param_int(struct usb_line6_pod *pod, int *value,
517 int code, struct ValueWait *param, int sign)
Markus Grabner705ecec2009-02-27 19:43:04 -0800518{
519 char *sysex;
Markus Grabner705ecec2009-02-27 19:43:04 -0800520 static const int size = 1;
521 int retval = 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800522
Markus Grabnere1a164d2010-08-23 01:08:25 +0200523 if (((pod->prog_data.control[POD_tuner] & 0x40) == 0)
524 && pod_is_tuner(code))
Markus Grabner705ecec2009-02-27 19:43:04 -0800525 return -ENODEV;
526
Markus Grabner1027f4762010-08-12 01:35:30 +0200527 /* send value request to device: */
Markus Grabner705ecec2009-02-27 19:43:04 -0800528 param->value = POD_system_invalid;
529 sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEMREQ, size);
Markus Grabner1027f4762010-08-12 01:35:30 +0200530
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800531 if (!sysex)
Markus Grabner1027f4762010-08-12 01:35:30 +0200532 return -ENOMEM;
533
Markus Grabner705ecec2009-02-27 19:43:04 -0800534 sysex[SYSEX_DATA_OFS] = code;
535 line6_send_sysex_message(&pod->line6, sysex, size);
536 kfree(sysex);
537
Markus Grabner1027f4762010-08-12 01:35:30 +0200538 /* wait for device to respond: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200539 retval =
540 wait_event_interruptible(param->wait,
541 param->value != POD_system_invalid);
Markus Grabner705ecec2009-02-27 19:43:04 -0800542
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800543 if (retval < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800544 return retval;
545
Markus Grabnere1a164d2010-08-23 01:08:25 +0200546 *value = sign ? (int)(signed short)param->value : (int)(unsigned short)
547 param->value;
Markus Grabner1027f4762010-08-12 01:35:30 +0200548
Markus Grabnere1a164d2010-08-23 01:08:25 +0200549 if (*value == POD_system_invalid)
550 *value = 0; /* don't report uninitialized values */
Markus Grabner1027f4762010-08-12 01:35:30 +0200551
552 return 0;
553}
554
555/*
556 Get system parameter (as string).
557 @param tuner non-zero, if code refers to a tuner parameter
558*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200559static ssize_t pod_get_system_param_string(struct usb_line6_pod *pod, char *buf,
560 int code, struct ValueWait *param,
561 int sign)
Markus Grabner1027f4762010-08-12 01:35:30 +0200562{
563 int retval, value = 0;
564 retval = pod_get_system_param_int(pod, &value, code, param, sign);
565
Markus Grabnere1a164d2010-08-23 01:08:25 +0200566 if (retval < 0)
Markus Grabner1027f4762010-08-12 01:35:30 +0200567 return retval;
568
Markus Grabner705ecec2009-02-27 19:43:04 -0800569 return sprintf(buf, "%d\n", value);
570}
571
572/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200573 Send system parameter (from integer).
Markus Grabner705ecec2009-02-27 19:43:04 -0800574 @param tuner non-zero, if code refers to a tuner parameter
575*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200576static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
577 int code)
Markus Grabner705ecec2009-02-27 19:43:04 -0800578{
579 char *sysex;
580 static const int size = 5;
Markus Grabner705ecec2009-02-27 19:43:04 -0800581
Markus Grabnere1a164d2010-08-23 01:08:25 +0200582 if (((pod->prog_data.control[POD_tuner] & 0x40) == 0)
583 && pod_is_tuner(code))
Markus Grabner705ecec2009-02-27 19:43:04 -0800584 return -EINVAL;
585
586 /* send value to tuner: */
587 sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800588 if (!sysex)
Markus Grabner1027f4762010-08-12 01:35:30 +0200589 return -ENOMEM;
Markus Grabner705ecec2009-02-27 19:43:04 -0800590 sysex[SYSEX_DATA_OFS] = code;
591 sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200592 sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f;
593 sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f;
594 sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f;
Markus Grabner705ecec2009-02-27 19:43:04 -0800595 line6_send_sysex_message(&pod->line6, sysex, size);
596 kfree(sysex);
Markus Grabner1027f4762010-08-12 01:35:30 +0200597 return 0;
598}
599
600/*
601 Send system parameter (from string).
602 @param tuner non-zero, if code refers to a tuner parameter
603*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200604static ssize_t pod_set_system_param_string(struct usb_line6_pod *pod,
605 const char *buf, int count, int code,
606 unsigned short mask)
Markus Grabner1027f4762010-08-12 01:35:30 +0200607{
608 int retval;
609 unsigned short value = simple_strtoul(buf, NULL, 10) & mask;
610 retval = pod_set_system_param_int(pod, value, code);
611 return (retval < 0) ? retval : count;
Markus Grabner705ecec2009-02-27 19:43:04 -0800612}
613
614/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800615 "write" request on "finish" special file.
616*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800617static ssize_t pod_set_finish(struct device *dev,
618 struct device_attribute *attr,
619 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800620{
621 struct usb_interface *interface = to_usb_interface(dev);
622 struct usb_line6_pod *pod = usb_get_intfdata(interface);
623 int size = 0;
624 char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_FINISH, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800625 if (!sysex)
626 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800627 line6_send_sysex_message(&pod->line6, sysex, size);
628 kfree(sysex);
629 return count;
630}
631
632/*
633 "write" request on "store_channel" special file.
634*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800635static ssize_t pod_set_store_channel(struct device *dev,
636 struct device_attribute *attr,
637 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800638{
639 return pod_send_store_command(dev, buf, count, 0x0000, 0x00c0);
640}
641
642/*
643 "write" request on "store_effects_setup" special file.
644*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800645static ssize_t pod_set_store_effects_setup(struct device *dev,
646 struct device_attribute *attr,
647 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800648{
649 return pod_send_store_command(dev, buf, count, 0x0080, 0x0080);
650}
651
652/*
653 "write" request on "store_amp_setup" special file.
654*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800655static ssize_t pod_set_store_amp_setup(struct device *dev,
656 struct device_attribute *attr,
657 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800658{
659 return pod_send_store_command(dev, buf, count, 0x0040, 0x0100);
660}
661
662/*
663 "write" request on "retrieve_channel" special file.
664*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800665static ssize_t pod_set_retrieve_channel(struct device *dev,
666 struct device_attribute *attr,
667 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800668{
669 return pod_send_retrieve_command(dev, buf, count, 0x0000, 0x00c0);
670}
671
672/*
673 "write" request on "retrieve_effects_setup" special file.
674*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800675static ssize_t pod_set_retrieve_effects_setup(struct device *dev,
676 struct device_attribute *attr,
677 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800678{
679 return pod_send_retrieve_command(dev, buf, count, 0x0080, 0x0080);
680}
681
682/*
683 "write" request on "retrieve_amp_setup" special file.
684*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800685static ssize_t pod_set_retrieve_amp_setup(struct device *dev,
686 struct device_attribute *attr,
687 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800688{
689 return pod_send_retrieve_command(dev, buf, count, 0x0040, 0x0100);
690}
691
692/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800693 "read" request on "midi_postprocess" special file.
694*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800695static ssize_t pod_get_midi_postprocess(struct device *dev,
696 struct device_attribute *attr,
697 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800698{
699 struct usb_interface *interface = to_usb_interface(dev);
700 struct usb_line6_pod *pod = usb_get_intfdata(interface);
701 return sprintf(buf, "%d\n", pod->midi_postprocess);
702}
703
704/*
705 "write" request on "midi_postprocess" special file.
706*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800707static ssize_t pod_set_midi_postprocess(struct device *dev,
708 struct device_attribute *attr,
709 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800710{
711 struct usb_interface *interface = to_usb_interface(dev);
712 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Johannes Thumshirn06501782012-06-27 21:26:03 +0200713 u8 value;
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600714 int ret;
715
Johannes Thumshirn06501782012-06-27 21:26:03 +0200716 ret = kstrtou8(buf, 10, &value);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600717 if (ret)
718 return ret;
719
Markus Grabner705ecec2009-02-27 19:43:04 -0800720 pod->midi_postprocess = value ? 1 : 0;
721 return count;
722}
723
724/*
725 "read" request on "serial_number" special file.
726*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800727static ssize_t pod_get_serial_number(struct device *dev,
728 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800729{
730 struct usb_interface *interface = to_usb_interface(dev);
731 struct usb_line6_pod *pod = usb_get_intfdata(interface);
732 return sprintf(buf, "%d\n", pod->serial_number);
733}
734
735/*
736 "read" request on "firmware_version" special file.
737*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800738static ssize_t pod_get_firmware_version(struct device *dev,
739 struct device_attribute *attr,
740 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800741{
742 struct usb_interface *interface = to_usb_interface(dev);
743 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800744 return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
745 pod->firmware_version % 100);
Markus Grabner705ecec2009-02-27 19:43:04 -0800746}
747
748/*
749 "read" request on "device_id" special file.
750*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800751static ssize_t pod_get_device_id(struct device *dev,
752 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800753{
754 struct usb_interface *interface = to_usb_interface(dev);
755 struct usb_line6_pod *pod = usb_get_intfdata(interface);
756 return sprintf(buf, "%d\n", pod->device_id);
757}
758
759/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200760 POD startup procedure.
761 This is a sequence of functions with special requirements (e.g., must
762 not run immediately after initialization, must not run in interrupt
763 context). After the last one has finished, the device is ready to use.
764*/
765
766static void pod_startup1(struct usb_line6_pod *pod)
767{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200768 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT);
Markus Grabner1027f4762010-08-12 01:35:30 +0200769
770 /* delay startup procedure: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200771 line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
772 (unsigned long)pod);
Markus Grabner1027f4762010-08-12 01:35:30 +0200773}
774
775static void pod_startup2(unsigned long data)
776{
777 struct usb_line6_pod *pod = (struct usb_line6_pod *)data;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200778
779 /* schedule another startup procedure until startup is complete: */
780 if (pod->startup_progress >= POD_STARTUP_LAST)
781 return;
782
783 pod->startup_progress = POD_STARTUP_DUMPREQ;
784 line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
785 (unsigned long)pod);
Markus Grabner1027f4762010-08-12 01:35:30 +0200786
787 /* current channel dump: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200788 line6_dump_request_async(&pod->dumpreq, &pod->line6, 0,
789 LINE6_DUMP_CURRENT);
Markus Grabner1027f4762010-08-12 01:35:30 +0200790}
791
792static void pod_startup3(struct usb_line6_pod *pod)
793{
794 struct usb_line6 *line6 = &pod->line6;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200795 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ);
Markus Grabner1027f4762010-08-12 01:35:30 +0200796
797 /* request firmware version: */
798 line6_version_request_async(line6);
799}
800
801static void pod_startup4(struct usb_line6_pod *pod)
802{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200803 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE);
Markus Grabner1027f4762010-08-12 01:35:30 +0200804
805 /* schedule work for global work queue: */
806 schedule_work(&pod->startup_work);
807}
808
809static void pod_startup5(struct work_struct *work)
810{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200811 struct usb_line6_pod *pod =
812 container_of(work, struct usb_line6_pod, startup_work);
Markus Grabner1027f4762010-08-12 01:35:30 +0200813 struct usb_line6 *line6 = &pod->line6;
814
Markus Grabnere1a164d2010-08-23 01:08:25 +0200815 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP);
Markus Grabner1027f4762010-08-12 01:35:30 +0200816
817 /* serial number: */
818 line6_read_serial_number(&pod->line6, &pod->serial_number);
819
820 /* ALSA audio interface: */
821 line6_register_audio(line6);
822
823 /* device files: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200824 line6_pod_create_files(pod->firmware_version,
825 line6->properties->device_bit, line6->ifcdev);
Markus Grabner1027f4762010-08-12 01:35:30 +0200826}
827
828#define POD_GET_SYSTEM_PARAM(code, sign) \
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800829static ssize_t pod_get_ ## code(struct device *dev, \
830 struct device_attribute *attr, char *buf) \
Markus Grabner705ecec2009-02-27 19:43:04 -0800831{ \
832 struct usb_interface *interface = to_usb_interface(dev); \
833 struct usb_line6_pod *pod = usb_get_intfdata(interface); \
Markus Grabner1027f4762010-08-12 01:35:30 +0200834 return pod_get_system_param_string(pod, buf, POD_ ## code, \
835 &pod->code, sign); \
Markus Grabner705ecec2009-02-27 19:43:04 -0800836}
837
Markus Grabner1027f4762010-08-12 01:35:30 +0200838#define POD_GET_SET_SYSTEM_PARAM(code, mask, sign) \
839POD_GET_SYSTEM_PARAM(code, sign) \
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800840static ssize_t pod_set_ ## code(struct device *dev, \
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800841 struct device_attribute *attr, \
842 const char *buf, size_t count) \
Markus Grabner705ecec2009-02-27 19:43:04 -0800843{ \
844 struct usb_interface *interface = to_usb_interface(dev); \
845 struct usb_line6_pod *pod = usb_get_intfdata(interface); \
Markus Grabner1027f4762010-08-12 01:35:30 +0200846 return pod_set_system_param_string(pod, buf, count, POD_ ## code, mask); \
Markus Grabner705ecec2009-02-27 19:43:04 -0800847}
848
Markus Grabner1027f4762010-08-12 01:35:30 +0200849POD_GET_SET_SYSTEM_PARAM(routing, 0x0003, 0);
850POD_GET_SET_SYSTEM_PARAM(tuner_mute, 0x0001, 0);
851POD_GET_SET_SYSTEM_PARAM(tuner_freq, 0xffff, 0);
852POD_GET_SYSTEM_PARAM(tuner_note, 1);
853POD_GET_SYSTEM_PARAM(tuner_pitch, 1);
Markus Grabner705ecec2009-02-27 19:43:04 -0800854
855#undef GET_SET_SYSTEM_PARAM
856#undef GET_SYSTEM_PARAM
857
858/* POD special files: */
Markus Grabner705ecec2009-02-27 19:43:04 -0800859static DEVICE_ATTR(device_id, S_IRUGO, pod_get_device_id, line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800860static DEVICE_ATTR(finish, S_IWUSR, line6_nop_read, pod_set_finish);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200861static DEVICE_ATTR(firmware_version, S_IRUGO, pod_get_firmware_version,
862 line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800863static DEVICE_ATTR(midi_postprocess, S_IWUSR | S_IRUGO,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200864 pod_get_midi_postprocess, pod_set_midi_postprocess);
Markus Grabner705ecec2009-02-27 19:43:04 -0800865static DEVICE_ATTR(name, S_IRUGO, pod_get_name, line6_nop_write);
866static DEVICE_ATTR(name_buf, S_IRUGO, pod_get_name_buf, line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800867static DEVICE_ATTR(retrieve_amp_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200868 pod_set_retrieve_amp_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800869static DEVICE_ATTR(retrieve_channel, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200870 pod_set_retrieve_channel);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800871static DEVICE_ATTR(retrieve_effects_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200872 pod_set_retrieve_effects_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800873static DEVICE_ATTR(routing, S_IWUSR | S_IRUGO, pod_get_routing,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200874 pod_set_routing);
875static DEVICE_ATTR(serial_number, S_IRUGO, pod_get_serial_number,
876 line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800877static DEVICE_ATTR(store_amp_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200878 pod_set_store_amp_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800879static DEVICE_ATTR(store_channel, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200880 pod_set_store_channel);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800881static DEVICE_ATTR(store_effects_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200882 pod_set_store_effects_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800883static DEVICE_ATTR(tuner_freq, S_IWUSR | S_IRUGO, pod_get_tuner_freq,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200884 pod_set_tuner_freq);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800885static DEVICE_ATTR(tuner_mute, S_IWUSR | S_IRUGO, pod_get_tuner_mute,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200886 pod_set_tuner_mute);
Markus Grabner705ecec2009-02-27 19:43:04 -0800887static DEVICE_ATTR(tuner_note, S_IRUGO, pod_get_tuner_note, line6_nop_write);
888static DEVICE_ATTR(tuner_pitch, S_IRUGO, pod_get_tuner_pitch, line6_nop_write);
889
Markus Grabner1027f4762010-08-12 01:35:30 +0200890#ifdef CONFIG_LINE6_USB_RAW
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800891static DEVICE_ATTR(raw, S_IWUSR, line6_nop_read, line6_set_raw);
Markus Grabner705ecec2009-02-27 19:43:04 -0800892#endif
893
Markus Grabner1027f4762010-08-12 01:35:30 +0200894/* control info callback */
895static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol,
896 struct snd_ctl_elem_info *uinfo)
897{
898 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
899 uinfo->count = 1;
900 uinfo->value.integer.min = 0;
901 uinfo->value.integer.max = 65535;
902 return 0;
903}
904
905/* control get callback */
906static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol,
907 struct snd_ctl_elem_value *ucontrol)
908{
909 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
910 struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
Stefan Hajnoczi2c35dc22012-11-22 20:48:47 +0100911 ucontrol->value.integer.value[0] = pod->monitor_level;
Markus Grabner1027f4762010-08-12 01:35:30 +0200912 return 0;
913}
914
915/* control put callback */
916static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol,
917 struct snd_ctl_elem_value *ucontrol)
918{
919 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
920 struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
921
Stefan Hajnoczi2c35dc22012-11-22 20:48:47 +0100922 if (ucontrol->value.integer.value[0] == pod->monitor_level)
Markus Grabner1027f4762010-08-12 01:35:30 +0200923 return 0;
924
Stefan Hajnoczi2c35dc22012-11-22 20:48:47 +0100925 pod->monitor_level = ucontrol->value.integer.value[0];
Markus Grabnere1a164d2010-08-23 01:08:25 +0200926 pod_set_system_param_int(pod, ucontrol->value.integer.value[0],
927 POD_monitor_level);
Markus Grabner1027f4762010-08-12 01:35:30 +0200928 return 1;
929}
930
931/* control definition */
932static struct snd_kcontrol_new pod_control_monitor = {
933 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
934 .name = "Monitor Playback Volume",
935 .index = 0,
936 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
937 .info = snd_pod_control_monitor_info,
938 .get = snd_pod_control_monitor_get,
939 .put = snd_pod_control_monitor_put
940};
941
Markus Grabner705ecec2009-02-27 19:43:04 -0800942/*
943 POD destructor.
944*/
945static void pod_destruct(struct usb_interface *interface)
946{
947 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Markus Grabner705ecec2009-02-27 19:43:04 -0800948
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800949 if (pod == NULL)
950 return;
Stefan Hajnoczi188e6642011-12-10 02:12:30 +0100951 line6_cleanup_audio(&pod->line6);
Markus Grabner705ecec2009-02-27 19:43:04 -0800952
Markus Grabnere1a164d2010-08-23 01:08:25 +0200953 del_timer(&pod->startup_timer);
954 cancel_work_sync(&pod->startup_work);
955
Markus Grabner705ecec2009-02-27 19:43:04 -0800956 /* free dump request data: */
957 line6_dumpreq_destruct(&pod->dumpreq);
Markus Grabner705ecec2009-02-27 19:43:04 -0800958}
959
960/*
961 Create sysfs entries.
962*/
Greg Kroah-Hartmanb702ed252009-02-27 20:45:03 -0800963static int pod_create_files2(struct device *dev)
Markus Grabner705ecec2009-02-27 19:43:04 -0800964{
965 int err;
966
Markus Grabner705ecec2009-02-27 19:43:04 -0800967 CHECK_RETURN(device_create_file(dev, &dev_attr_device_id));
Markus Grabner705ecec2009-02-27 19:43:04 -0800968 CHECK_RETURN(device_create_file(dev, &dev_attr_finish));
969 CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version));
970 CHECK_RETURN(device_create_file(dev, &dev_attr_midi_postprocess));
Markus Grabner705ecec2009-02-27 19:43:04 -0800971 CHECK_RETURN(device_create_file(dev, &dev_attr_name));
972 CHECK_RETURN(device_create_file(dev, &dev_attr_name_buf));
973 CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_amp_setup));
974 CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_channel));
975 CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_effects_setup));
976 CHECK_RETURN(device_create_file(dev, &dev_attr_routing));
977 CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number));
978 CHECK_RETURN(device_create_file(dev, &dev_attr_store_amp_setup));
979 CHECK_RETURN(device_create_file(dev, &dev_attr_store_channel));
980 CHECK_RETURN(device_create_file(dev, &dev_attr_store_effects_setup));
981 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_freq));
982 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_mute));
983 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_note));
984 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_pitch));
985
Markus Grabner1027f4762010-08-12 01:35:30 +0200986#ifdef CONFIG_LINE6_USB_RAW
Markus Grabner705ecec2009-02-27 19:43:04 -0800987 CHECK_RETURN(device_create_file(dev, &dev_attr_raw));
988#endif
989
990 return 0;
991}
992
993/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200994 Try to init POD device.
Markus Grabner705ecec2009-02-27 19:43:04 -0800995*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200996static int pod_try_init(struct usb_interface *interface,
997 struct usb_line6_pod *pod)
Markus Grabner705ecec2009-02-27 19:43:04 -0800998{
999 int err;
1000 struct usb_line6 *line6 = &pod->line6;
1001
Markus Grabnere1a164d2010-08-23 01:08:25 +02001002 init_timer(&pod->startup_timer);
1003 INIT_WORK(&pod->startup_work, pod_startup5);
1004
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001005 if ((interface == NULL) || (pod == NULL))
1006 return -ENODEV;
Markus Grabner705ecec2009-02-27 19:43:04 -08001007
Markus Grabner705ecec2009-02-27 19:43:04 -08001008 /* initialize wait queues: */
Markus Grabner705ecec2009-02-27 19:43:04 -08001009 init_waitqueue_head(&pod->routing.wait);
1010 init_waitqueue_head(&pod->tuner_mute.wait);
1011 init_waitqueue_head(&pod->tuner_freq.wait);
1012 init_waitqueue_head(&pod->tuner_note.wait);
1013 init_waitqueue_head(&pod->tuner_pitch.wait);
Markus Grabner705ecec2009-02-27 19:43:04 -08001014
Markus Grabner705ecec2009-02-27 19:43:04 -08001015 /* initialize USB buffers: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001016 err = line6_dumpreq_init(&pod->dumpreq, pod_request_channel,
1017 sizeof(pod_request_channel));
1018 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001019 dev_err(&interface->dev, "Out of memory\n");
Markus Grabner705ecec2009-02-27 19:43:04 -08001020 return -ENOMEM;
1021 }
1022
Markus Grabner705ecec2009-02-27 19:43:04 -08001023 /* create sysfs entries: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001024 err = pod_create_files2(&interface->dev);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001025 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -08001026 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -08001027
1028 /* initialize audio system: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001029 err = line6_init_audio(line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001030 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -08001031 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -08001032
1033 /* initialize MIDI subsystem: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001034 err = line6_init_midi(line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001035 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -08001036 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -08001037
1038 /* initialize PCM subsystem: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001039 err = line6_init_pcm(line6, &pod_pcm_properties);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001040 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -08001041 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -08001042
Markus Grabner1027f4762010-08-12 01:35:30 +02001043 /* register monitor control: */
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001044 err = snd_ctl_add(line6->card,
1045 snd_ctl_new1(&pod_control_monitor, line6->line6pcm));
1046 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -08001047 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -08001048
Markus Grabner1027f4762010-08-12 01:35:30 +02001049 /*
Markus Grabnere1a164d2010-08-23 01:08:25 +02001050 When the sound card is registered at this point, the PODxt Live
1051 displays "Invalid Code Error 07", so we do it later in the event
1052 handler.
1053 */
Markus Grabner1027f4762010-08-12 01:35:30 +02001054
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001055 if (pod->line6.properties->capabilities & LINE6_BIT_CONTROL) {
Stefan Hajnoczi2c35dc22012-11-22 20:48:47 +01001056 pod->monitor_level = POD_system_invalid;
Markus Grabner1027f4762010-08-12 01:35:30 +02001057
1058 /* initiate startup procedure: */
1059 pod_startup1(pod);
Markus Grabner705ecec2009-02-27 19:43:04 -08001060 }
1061
1062 return 0;
1063}
1064
1065/*
Markus Grabner1027f4762010-08-12 01:35:30 +02001066 Init POD device (and clean up in case of failure).
1067*/
1068int line6_pod_init(struct usb_interface *interface, struct usb_line6_pod *pod)
1069{
1070 int err = pod_try_init(interface, pod);
1071
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001072 if (err < 0)
Markus Grabner1027f4762010-08-12 01:35:30 +02001073 pod_destruct(interface);
Markus Grabner1027f4762010-08-12 01:35:30 +02001074
1075 return err;
1076}
1077
1078/*
Markus Grabner705ecec2009-02-27 19:43:04 -08001079 POD device disconnected.
1080*/
Markus Grabner1027f4762010-08-12 01:35:30 +02001081void line6_pod_disconnect(struct usb_interface *interface)
Markus Grabner705ecec2009-02-27 19:43:04 -08001082{
1083 struct usb_line6_pod *pod;
1084
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001085 if (interface == NULL)
1086 return;
Markus Grabner705ecec2009-02-27 19:43:04 -08001087 pod = usb_get_intfdata(interface);
1088
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001089 if (pod != NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001090 struct snd_line6_pcm *line6pcm = pod->line6.line6pcm;
1091 struct device *dev = &interface->dev;
1092
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001093 if (line6pcm != NULL)
Markus Grabner1027f4762010-08-12 01:35:30 +02001094 line6_pcm_disconnect(line6pcm);
Markus Grabner705ecec2009-02-27 19:43:04 -08001095
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001096 if (dev != NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001097 /* remove sysfs entries: */
Markus Grabnere1a164d2010-08-23 01:08:25 +02001098 line6_pod_remove_files(pod->firmware_version,
1099 pod->line6.
1100 properties->device_bit, dev);
Markus Grabner705ecec2009-02-27 19:43:04 -08001101
Markus Grabner705ecec2009-02-27 19:43:04 -08001102 device_remove_file(dev, &dev_attr_device_id);
Markus Grabner705ecec2009-02-27 19:43:04 -08001103 device_remove_file(dev, &dev_attr_finish);
1104 device_remove_file(dev, &dev_attr_firmware_version);
1105 device_remove_file(dev, &dev_attr_midi_postprocess);
Markus Grabner705ecec2009-02-27 19:43:04 -08001106 device_remove_file(dev, &dev_attr_name);
1107 device_remove_file(dev, &dev_attr_name_buf);
1108 device_remove_file(dev, &dev_attr_retrieve_amp_setup);
1109 device_remove_file(dev, &dev_attr_retrieve_channel);
Markus Grabnere1a164d2010-08-23 01:08:25 +02001110 device_remove_file(dev,
1111 &dev_attr_retrieve_effects_setup);
Markus Grabner705ecec2009-02-27 19:43:04 -08001112 device_remove_file(dev, &dev_attr_routing);
1113 device_remove_file(dev, &dev_attr_serial_number);
1114 device_remove_file(dev, &dev_attr_store_amp_setup);
1115 device_remove_file(dev, &dev_attr_store_channel);
1116 device_remove_file(dev, &dev_attr_store_effects_setup);
1117 device_remove_file(dev, &dev_attr_tuner_freq);
1118 device_remove_file(dev, &dev_attr_tuner_mute);
1119 device_remove_file(dev, &dev_attr_tuner_note);
1120 device_remove_file(dev, &dev_attr_tuner_pitch);
1121
Markus Grabner1027f4762010-08-12 01:35:30 +02001122#ifdef CONFIG_LINE6_USB_RAW
Markus Grabner705ecec2009-02-27 19:43:04 -08001123 device_remove_file(dev, &dev_attr_raw);
1124#endif
1125 }
1126 }
1127
1128 pod_destruct(interface);
1129}