blob: 6d6cd5ada6d4670c04d02bba29dee9f8cd6f6f3d [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 Grabner1027f472010-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 Grabner1027f472010-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 Grabner1027f472010-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 Grabner1027f472010-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 Grabner1027f472010-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 Grabner1027f472010-08-12 01:35:30 +020079#ifdef CONFIG_PM
Markus Grabnere1a164d2010-08-23 01:08:25 +020080 SNDRV_PCM_INFO_RESUME |
Markus Grabner1027f472010-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 Grabner1027f472010-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 Grabner1027f472010-08-12 01:35:30 +020099#ifdef CONFIG_PM
Markus Grabnere1a164d2010-08-23 01:08:25 +0200100 SNDRV_PCM_INFO_RESUME |
Markus Grabner1027f472010-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 Grabner1027f472010-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 Grabner1027f472010-08-12 01:35:30 +0200125 0xf2, 0x7e, 0x7f, 0x06, 0x02
126};
127
Markus Grabner1027f472010-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 Grabner1027f472010-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 Grabner1027f472010-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 Grabner1027f472010-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 Grabner1027f472010-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 Grabner1027f472010-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/*
Markus Grabner1027f472010-08-12 01:35:30 +0200450 Identify system parameters related to the tuner.
451*/
452static bool pod_is_tuner(int code)
453{
454 return
Markus Grabnere1a164d2010-08-23 01:08:25 +0200455 (code == POD_tuner_mute) ||
456 (code == POD_tuner_freq) ||
457 (code == POD_tuner_note) || (code == POD_tuner_pitch);
Markus Grabner1027f472010-08-12 01:35:30 +0200458}
459
460/*
461 Get system parameter (as integer).
Markus Grabner705ecec2009-02-27 19:43:04 -0800462 @param tuner non-zero, if code refers to a tuner parameter
463*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200464static int pod_get_system_param_int(struct usb_line6_pod *pod, int *value,
465 int code, struct ValueWait *param, int sign)
Markus Grabner705ecec2009-02-27 19:43:04 -0800466{
467 char *sysex;
Markus Grabner705ecec2009-02-27 19:43:04 -0800468 static const int size = 1;
469 int retval = 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800470
Markus Grabnere1a164d2010-08-23 01:08:25 +0200471 if (((pod->prog_data.control[POD_tuner] & 0x40) == 0)
472 && pod_is_tuner(code))
Markus Grabner705ecec2009-02-27 19:43:04 -0800473 return -ENODEV;
474
Markus Grabner1027f472010-08-12 01:35:30 +0200475 /* send value request to device: */
Markus Grabner705ecec2009-02-27 19:43:04 -0800476 param->value = POD_system_invalid;
477 sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEMREQ, size);
Markus Grabner1027f472010-08-12 01:35:30 +0200478
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800479 if (!sysex)
Markus Grabner1027f472010-08-12 01:35:30 +0200480 return -ENOMEM;
481
Markus Grabner705ecec2009-02-27 19:43:04 -0800482 sysex[SYSEX_DATA_OFS] = code;
483 line6_send_sysex_message(&pod->line6, sysex, size);
484 kfree(sysex);
485
Markus Grabner1027f472010-08-12 01:35:30 +0200486 /* wait for device to respond: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200487 retval =
488 wait_event_interruptible(param->wait,
489 param->value != POD_system_invalid);
Markus Grabner705ecec2009-02-27 19:43:04 -0800490
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800491 if (retval < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800492 return retval;
493
Markus Grabnere1a164d2010-08-23 01:08:25 +0200494 *value = sign ? (int)(signed short)param->value : (int)(unsigned short)
495 param->value;
Markus Grabner1027f472010-08-12 01:35:30 +0200496
Markus Grabnere1a164d2010-08-23 01:08:25 +0200497 if (*value == POD_system_invalid)
498 *value = 0; /* don't report uninitialized values */
Markus Grabner1027f472010-08-12 01:35:30 +0200499
500 return 0;
501}
502
503/*
504 Get system parameter (as string).
505 @param tuner non-zero, if code refers to a tuner parameter
506*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200507static ssize_t pod_get_system_param_string(struct usb_line6_pod *pod, char *buf,
508 int code, struct ValueWait *param,
509 int sign)
Markus Grabner1027f472010-08-12 01:35:30 +0200510{
511 int retval, value = 0;
512 retval = pod_get_system_param_int(pod, &value, code, param, sign);
513
Markus Grabnere1a164d2010-08-23 01:08:25 +0200514 if (retval < 0)
Markus Grabner1027f472010-08-12 01:35:30 +0200515 return retval;
516
Markus Grabner705ecec2009-02-27 19:43:04 -0800517 return sprintf(buf, "%d\n", value);
518}
519
520/*
Markus Grabner1027f472010-08-12 01:35:30 +0200521 Send system parameter (from integer).
Markus Grabner705ecec2009-02-27 19:43:04 -0800522 @param tuner non-zero, if code refers to a tuner parameter
523*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200524static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
525 int code)
Markus Grabner705ecec2009-02-27 19:43:04 -0800526{
527 char *sysex;
528 static const int size = 5;
Markus Grabner705ecec2009-02-27 19:43:04 -0800529
Markus Grabnere1a164d2010-08-23 01:08:25 +0200530 if (((pod->prog_data.control[POD_tuner] & 0x40) == 0)
531 && pod_is_tuner(code))
Markus Grabner705ecec2009-02-27 19:43:04 -0800532 return -EINVAL;
533
534 /* send value to tuner: */
535 sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800536 if (!sysex)
Markus Grabner1027f472010-08-12 01:35:30 +0200537 return -ENOMEM;
Markus Grabner705ecec2009-02-27 19:43:04 -0800538 sysex[SYSEX_DATA_OFS] = code;
539 sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200540 sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f;
541 sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f;
542 sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f;
Markus Grabner705ecec2009-02-27 19:43:04 -0800543 line6_send_sysex_message(&pod->line6, sysex, size);
544 kfree(sysex);
Markus Grabner1027f472010-08-12 01:35:30 +0200545 return 0;
546}
547
548/*
549 Send system parameter (from string).
550 @param tuner non-zero, if code refers to a tuner parameter
551*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200552static ssize_t pod_set_system_param_string(struct usb_line6_pod *pod,
553 const char *buf, int count, int code,
554 unsigned short mask)
Markus Grabner1027f472010-08-12 01:35:30 +0200555{
556 int retval;
557 unsigned short value = simple_strtoul(buf, NULL, 10) & mask;
558 retval = pod_set_system_param_int(pod, value, code);
559 return (retval < 0) ? retval : count;
Markus Grabner705ecec2009-02-27 19:43:04 -0800560}
561
562/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800563 "write" request on "finish" special file.
564*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800565static ssize_t pod_set_finish(struct device *dev,
566 struct device_attribute *attr,
567 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800568{
569 struct usb_interface *interface = to_usb_interface(dev);
570 struct usb_line6_pod *pod = usb_get_intfdata(interface);
571 int size = 0;
572 char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_FINISH, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800573 if (!sysex)
574 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800575 line6_send_sysex_message(&pod->line6, sysex, size);
576 kfree(sysex);
577 return count;
578}
579
580/*
581 "write" request on "store_channel" special file.
582*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800583static ssize_t pod_set_store_channel(struct device *dev,
584 struct device_attribute *attr,
585 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800586{
587 return pod_send_store_command(dev, buf, count, 0x0000, 0x00c0);
588}
589
590/*
591 "write" request on "store_effects_setup" special file.
592*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800593static ssize_t pod_set_store_effects_setup(struct device *dev,
594 struct device_attribute *attr,
595 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800596{
597 return pod_send_store_command(dev, buf, count, 0x0080, 0x0080);
598}
599
600/*
601 "write" request on "store_amp_setup" special file.
602*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800603static ssize_t pod_set_store_amp_setup(struct device *dev,
604 struct device_attribute *attr,
605 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800606{
607 return pod_send_store_command(dev, buf, count, 0x0040, 0x0100);
608}
609
610/*
611 "write" request on "retrieve_channel" special file.
612*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800613static ssize_t pod_set_retrieve_channel(struct device *dev,
614 struct device_attribute *attr,
615 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800616{
617 return pod_send_retrieve_command(dev, buf, count, 0x0000, 0x00c0);
618}
619
620/*
621 "write" request on "retrieve_effects_setup" special file.
622*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800623static ssize_t pod_set_retrieve_effects_setup(struct device *dev,
624 struct device_attribute *attr,
625 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800626{
627 return pod_send_retrieve_command(dev, buf, count, 0x0080, 0x0080);
628}
629
630/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800631 "read" request on "midi_postprocess" special file.
632*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800633static ssize_t pod_get_midi_postprocess(struct device *dev,
634 struct device_attribute *attr,
635 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800636{
637 struct usb_interface *interface = to_usb_interface(dev);
638 struct usb_line6_pod *pod = usb_get_intfdata(interface);
639 return sprintf(buf, "%d\n", pod->midi_postprocess);
640}
641
642/*
643 "write" request on "midi_postprocess" special file.
644*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800645static ssize_t pod_set_midi_postprocess(struct device *dev,
646 struct device_attribute *attr,
647 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800648{
649 struct usb_interface *interface = to_usb_interface(dev);
650 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Johannes Thumshirn06501782012-06-27 21:26:03 +0200651 u8 value;
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600652 int ret;
653
Johannes Thumshirn06501782012-06-27 21:26:03 +0200654 ret = kstrtou8(buf, 10, &value);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600655 if (ret)
656 return ret;
657
Markus Grabner705ecec2009-02-27 19:43:04 -0800658 pod->midi_postprocess = value ? 1 : 0;
659 return count;
660}
661
662/*
663 "read" request on "serial_number" special file.
664*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800665static ssize_t pod_get_serial_number(struct device *dev,
666 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800667{
668 struct usb_interface *interface = to_usb_interface(dev);
669 struct usb_line6_pod *pod = usb_get_intfdata(interface);
670 return sprintf(buf, "%d\n", pod->serial_number);
671}
672
673/*
674 "read" request on "firmware_version" special file.
675*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800676static ssize_t pod_get_firmware_version(struct device *dev,
677 struct device_attribute *attr,
678 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800679{
680 struct usb_interface *interface = to_usb_interface(dev);
681 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800682 return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
683 pod->firmware_version % 100);
Markus Grabner705ecec2009-02-27 19:43:04 -0800684}
685
686/*
687 "read" request on "device_id" special file.
688*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800689static ssize_t pod_get_device_id(struct device *dev,
690 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800691{
692 struct usb_interface *interface = to_usb_interface(dev);
693 struct usb_line6_pod *pod = usb_get_intfdata(interface);
694 return sprintf(buf, "%d\n", pod->device_id);
695}
696
697/*
Markus Grabner1027f472010-08-12 01:35:30 +0200698 POD startup procedure.
699 This is a sequence of functions with special requirements (e.g., must
700 not run immediately after initialization, must not run in interrupt
701 context). After the last one has finished, the device is ready to use.
702*/
703
704static void pod_startup1(struct usb_line6_pod *pod)
705{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200706 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT);
Markus Grabner1027f472010-08-12 01:35:30 +0200707
708 /* delay startup procedure: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200709 line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
710 (unsigned long)pod);
Markus Grabner1027f472010-08-12 01:35:30 +0200711}
712
713static void pod_startup2(unsigned long data)
714{
715 struct usb_line6_pod *pod = (struct usb_line6_pod *)data;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200716
717 /* schedule another startup procedure until startup is complete: */
718 if (pod->startup_progress >= POD_STARTUP_LAST)
719 return;
720
721 pod->startup_progress = POD_STARTUP_DUMPREQ;
722 line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
723 (unsigned long)pod);
Markus Grabner1027f472010-08-12 01:35:30 +0200724
725 /* current channel dump: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200726 line6_dump_request_async(&pod->dumpreq, &pod->line6, 0,
727 LINE6_DUMP_CURRENT);
Markus Grabner1027f472010-08-12 01:35:30 +0200728}
729
730static void pod_startup3(struct usb_line6_pod *pod)
731{
732 struct usb_line6 *line6 = &pod->line6;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200733 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ);
Markus Grabner1027f472010-08-12 01:35:30 +0200734
735 /* request firmware version: */
736 line6_version_request_async(line6);
737}
738
739static void pod_startup4(struct usb_line6_pod *pod)
740{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200741 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE);
Markus Grabner1027f472010-08-12 01:35:30 +0200742
743 /* schedule work for global work queue: */
744 schedule_work(&pod->startup_work);
745}
746
747static void pod_startup5(struct work_struct *work)
748{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200749 struct usb_line6_pod *pod =
750 container_of(work, struct usb_line6_pod, startup_work);
Markus Grabner1027f472010-08-12 01:35:30 +0200751 struct usb_line6 *line6 = &pod->line6;
752
Markus Grabnere1a164d2010-08-23 01:08:25 +0200753 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP);
Markus Grabner1027f472010-08-12 01:35:30 +0200754
755 /* serial number: */
756 line6_read_serial_number(&pod->line6, &pod->serial_number);
757
758 /* ALSA audio interface: */
759 line6_register_audio(line6);
760
761 /* device files: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200762 line6_pod_create_files(pod->firmware_version,
763 line6->properties->device_bit, line6->ifcdev);
Markus Grabner1027f472010-08-12 01:35:30 +0200764}
765
766#define POD_GET_SYSTEM_PARAM(code, sign) \
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800767static ssize_t pod_get_ ## code(struct device *dev, \
768 struct device_attribute *attr, char *buf) \
Markus Grabner705ecec2009-02-27 19:43:04 -0800769{ \
770 struct usb_interface *interface = to_usb_interface(dev); \
771 struct usb_line6_pod *pod = usb_get_intfdata(interface); \
Markus Grabner1027f472010-08-12 01:35:30 +0200772 return pod_get_system_param_string(pod, buf, POD_ ## code, \
773 &pod->code, sign); \
Markus Grabner705ecec2009-02-27 19:43:04 -0800774}
775
Markus Grabner1027f472010-08-12 01:35:30 +0200776#define POD_GET_SET_SYSTEM_PARAM(code, mask, sign) \
777POD_GET_SYSTEM_PARAM(code, sign) \
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800778static ssize_t pod_set_ ## code(struct device *dev, \
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800779 struct device_attribute *attr, \
780 const char *buf, size_t count) \
Markus Grabner705ecec2009-02-27 19:43:04 -0800781{ \
782 struct usb_interface *interface = to_usb_interface(dev); \
783 struct usb_line6_pod *pod = usb_get_intfdata(interface); \
Markus Grabner1027f472010-08-12 01:35:30 +0200784 return pod_set_system_param_string(pod, buf, count, POD_ ## code, mask); \
Markus Grabner705ecec2009-02-27 19:43:04 -0800785}
786
Markus Grabner1027f472010-08-12 01:35:30 +0200787POD_GET_SET_SYSTEM_PARAM(routing, 0x0003, 0);
788POD_GET_SET_SYSTEM_PARAM(tuner_mute, 0x0001, 0);
789POD_GET_SET_SYSTEM_PARAM(tuner_freq, 0xffff, 0);
790POD_GET_SYSTEM_PARAM(tuner_note, 1);
791POD_GET_SYSTEM_PARAM(tuner_pitch, 1);
Markus Grabner705ecec2009-02-27 19:43:04 -0800792
793#undef GET_SET_SYSTEM_PARAM
794#undef GET_SYSTEM_PARAM
795
796/* POD special files: */
Markus Grabner705ecec2009-02-27 19:43:04 -0800797static DEVICE_ATTR(device_id, S_IRUGO, pod_get_device_id, line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800798static DEVICE_ATTR(finish, S_IWUSR, line6_nop_read, pod_set_finish);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200799static DEVICE_ATTR(firmware_version, S_IRUGO, pod_get_firmware_version,
800 line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800801static DEVICE_ATTR(midi_postprocess, S_IWUSR | S_IRUGO,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200802 pod_get_midi_postprocess, pod_set_midi_postprocess);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800803static DEVICE_ATTR(retrieve_channel, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200804 pod_set_retrieve_channel);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800805static DEVICE_ATTR(retrieve_effects_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200806 pod_set_retrieve_effects_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800807static DEVICE_ATTR(routing, S_IWUSR | S_IRUGO, pod_get_routing,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200808 pod_set_routing);
809static DEVICE_ATTR(serial_number, S_IRUGO, pod_get_serial_number,
810 line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800811static DEVICE_ATTR(store_amp_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200812 pod_set_store_amp_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800813static DEVICE_ATTR(store_channel, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200814 pod_set_store_channel);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800815static DEVICE_ATTR(store_effects_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200816 pod_set_store_effects_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800817static DEVICE_ATTR(tuner_freq, S_IWUSR | S_IRUGO, pod_get_tuner_freq,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200818 pod_set_tuner_freq);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800819static DEVICE_ATTR(tuner_mute, S_IWUSR | S_IRUGO, pod_get_tuner_mute,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200820 pod_set_tuner_mute);
Markus Grabner705ecec2009-02-27 19:43:04 -0800821static DEVICE_ATTR(tuner_note, S_IRUGO, pod_get_tuner_note, line6_nop_write);
822static DEVICE_ATTR(tuner_pitch, S_IRUGO, pod_get_tuner_pitch, line6_nop_write);
823
Markus Grabner1027f472010-08-12 01:35:30 +0200824#ifdef CONFIG_LINE6_USB_RAW
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800825static DEVICE_ATTR(raw, S_IWUSR, line6_nop_read, line6_set_raw);
Markus Grabner705ecec2009-02-27 19:43:04 -0800826#endif
827
Markus Grabner1027f472010-08-12 01:35:30 +0200828/* control info callback */
829static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol,
830 struct snd_ctl_elem_info *uinfo)
831{
832 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
833 uinfo->count = 1;
834 uinfo->value.integer.min = 0;
835 uinfo->value.integer.max = 65535;
836 return 0;
837}
838
839/* control get callback */
840static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol,
841 struct snd_ctl_elem_value *ucontrol)
842{
843 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
844 struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
Stefan Hajnoczi2c35dc22012-11-22 20:48:47 +0100845 ucontrol->value.integer.value[0] = pod->monitor_level;
Markus Grabner1027f472010-08-12 01:35:30 +0200846 return 0;
847}
848
849/* control put callback */
850static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol,
851 struct snd_ctl_elem_value *ucontrol)
852{
853 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
854 struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
855
Stefan Hajnoczi2c35dc22012-11-22 20:48:47 +0100856 if (ucontrol->value.integer.value[0] == pod->monitor_level)
Markus Grabner1027f472010-08-12 01:35:30 +0200857 return 0;
858
Stefan Hajnoczi2c35dc22012-11-22 20:48:47 +0100859 pod->monitor_level = ucontrol->value.integer.value[0];
Markus Grabnere1a164d2010-08-23 01:08:25 +0200860 pod_set_system_param_int(pod, ucontrol->value.integer.value[0],
861 POD_monitor_level);
Markus Grabner1027f472010-08-12 01:35:30 +0200862 return 1;
863}
864
865/* control definition */
866static struct snd_kcontrol_new pod_control_monitor = {
867 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
868 .name = "Monitor Playback Volume",
869 .index = 0,
870 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
871 .info = snd_pod_control_monitor_info,
872 .get = snd_pod_control_monitor_get,
873 .put = snd_pod_control_monitor_put
874};
875
Markus Grabner705ecec2009-02-27 19:43:04 -0800876/*
877 POD destructor.
878*/
879static void pod_destruct(struct usb_interface *interface)
880{
881 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Markus Grabner705ecec2009-02-27 19:43:04 -0800882
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800883 if (pod == NULL)
884 return;
Stefan Hajnoczi188e6642011-12-10 02:12:30 +0100885 line6_cleanup_audio(&pod->line6);
Markus Grabner705ecec2009-02-27 19:43:04 -0800886
Markus Grabnere1a164d2010-08-23 01:08:25 +0200887 del_timer(&pod->startup_timer);
888 cancel_work_sync(&pod->startup_work);
889
Markus Grabner705ecec2009-02-27 19:43:04 -0800890 /* free dump request data: */
891 line6_dumpreq_destruct(&pod->dumpreq);
Markus Grabner705ecec2009-02-27 19:43:04 -0800892}
893
894/*
895 Create sysfs entries.
896*/
Greg Kroah-Hartmanb702ed252009-02-27 20:45:03 -0800897static int pod_create_files2(struct device *dev)
Markus Grabner705ecec2009-02-27 19:43:04 -0800898{
899 int err;
900
Markus Grabner705ecec2009-02-27 19:43:04 -0800901 CHECK_RETURN(device_create_file(dev, &dev_attr_device_id));
Markus Grabner705ecec2009-02-27 19:43:04 -0800902 CHECK_RETURN(device_create_file(dev, &dev_attr_finish));
903 CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version));
904 CHECK_RETURN(device_create_file(dev, &dev_attr_midi_postprocess));
Markus Grabner705ecec2009-02-27 19:43:04 -0800905 CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_channel));
906 CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_effects_setup));
907 CHECK_RETURN(device_create_file(dev, &dev_attr_routing));
908 CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number));
909 CHECK_RETURN(device_create_file(dev, &dev_attr_store_amp_setup));
910 CHECK_RETURN(device_create_file(dev, &dev_attr_store_channel));
911 CHECK_RETURN(device_create_file(dev, &dev_attr_store_effects_setup));
912 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_freq));
913 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_mute));
914 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_note));
915 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_pitch));
916
Markus Grabner1027f472010-08-12 01:35:30 +0200917#ifdef CONFIG_LINE6_USB_RAW
Markus Grabner705ecec2009-02-27 19:43:04 -0800918 CHECK_RETURN(device_create_file(dev, &dev_attr_raw));
919#endif
920
921 return 0;
922}
923
924/*
Markus Grabner1027f472010-08-12 01:35:30 +0200925 Try to init POD device.
Markus Grabner705ecec2009-02-27 19:43:04 -0800926*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200927static int pod_try_init(struct usb_interface *interface,
928 struct usb_line6_pod *pod)
Markus Grabner705ecec2009-02-27 19:43:04 -0800929{
930 int err;
931 struct usb_line6 *line6 = &pod->line6;
932
Markus Grabnere1a164d2010-08-23 01:08:25 +0200933 init_timer(&pod->startup_timer);
934 INIT_WORK(&pod->startup_work, pod_startup5);
935
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800936 if ((interface == NULL) || (pod == NULL))
937 return -ENODEV;
Markus Grabner705ecec2009-02-27 19:43:04 -0800938
Markus Grabner705ecec2009-02-27 19:43:04 -0800939 /* initialize wait queues: */
Markus Grabner705ecec2009-02-27 19:43:04 -0800940 init_waitqueue_head(&pod->routing.wait);
941 init_waitqueue_head(&pod->tuner_mute.wait);
942 init_waitqueue_head(&pod->tuner_freq.wait);
943 init_waitqueue_head(&pod->tuner_note.wait);
944 init_waitqueue_head(&pod->tuner_pitch.wait);
Markus Grabner705ecec2009-02-27 19:43:04 -0800945
Markus Grabner705ecec2009-02-27 19:43:04 -0800946 /* initialize USB buffers: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800947 err = line6_dumpreq_init(&pod->dumpreq, pod_request_channel,
948 sizeof(pod_request_channel));
949 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800950 dev_err(&interface->dev, "Out of memory\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800951 return -ENOMEM;
952 }
953
Markus Grabner705ecec2009-02-27 19:43:04 -0800954 /* create sysfs entries: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800955 err = pod_create_files2(&interface->dev);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700956 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800957 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800958
959 /* initialize audio system: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800960 err = line6_init_audio(line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700961 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800962 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800963
964 /* initialize MIDI subsystem: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800965 err = line6_init_midi(line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700966 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800967 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800968
969 /* initialize PCM subsystem: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800970 err = line6_init_pcm(line6, &pod_pcm_properties);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700971 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800972 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800973
Markus Grabner1027f472010-08-12 01:35:30 +0200974 /* register monitor control: */
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700975 err = snd_ctl_add(line6->card,
976 snd_ctl_new1(&pod_control_monitor, line6->line6pcm));
977 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800978 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800979
Markus Grabner1027f472010-08-12 01:35:30 +0200980 /*
Markus Grabnere1a164d2010-08-23 01:08:25 +0200981 When the sound card is registered at this point, the PODxt Live
982 displays "Invalid Code Error 07", so we do it later in the event
983 handler.
984 */
Markus Grabner1027f472010-08-12 01:35:30 +0200985
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800986 if (pod->line6.properties->capabilities & LINE6_BIT_CONTROL) {
Stefan Hajnoczi2c35dc22012-11-22 20:48:47 +0100987 pod->monitor_level = POD_system_invalid;
Markus Grabner1027f472010-08-12 01:35:30 +0200988
989 /* initiate startup procedure: */
990 pod_startup1(pod);
Markus Grabner705ecec2009-02-27 19:43:04 -0800991 }
992
993 return 0;
994}
995
996/*
Markus Grabner1027f472010-08-12 01:35:30 +0200997 Init POD device (and clean up in case of failure).
998*/
999int line6_pod_init(struct usb_interface *interface, struct usb_line6_pod *pod)
1000{
1001 int err = pod_try_init(interface, pod);
1002
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001003 if (err < 0)
Markus Grabner1027f472010-08-12 01:35:30 +02001004 pod_destruct(interface);
Markus Grabner1027f472010-08-12 01:35:30 +02001005
1006 return err;
1007}
1008
1009/*
Markus Grabner705ecec2009-02-27 19:43:04 -08001010 POD device disconnected.
1011*/
Markus Grabner1027f472010-08-12 01:35:30 +02001012void line6_pod_disconnect(struct usb_interface *interface)
Markus Grabner705ecec2009-02-27 19:43:04 -08001013{
1014 struct usb_line6_pod *pod;
1015
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001016 if (interface == NULL)
1017 return;
Markus Grabner705ecec2009-02-27 19:43:04 -08001018 pod = usb_get_intfdata(interface);
1019
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001020 if (pod != NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001021 struct snd_line6_pcm *line6pcm = pod->line6.line6pcm;
1022 struct device *dev = &interface->dev;
1023
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001024 if (line6pcm != NULL)
Markus Grabner1027f472010-08-12 01:35:30 +02001025 line6_pcm_disconnect(line6pcm);
Markus Grabner705ecec2009-02-27 19:43:04 -08001026
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001027 if (dev != NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001028 /* remove sysfs entries: */
Markus Grabnere1a164d2010-08-23 01:08:25 +02001029 line6_pod_remove_files(pod->firmware_version,
1030 pod->line6.
1031 properties->device_bit, dev);
Markus Grabner705ecec2009-02-27 19:43:04 -08001032
Markus Grabner705ecec2009-02-27 19:43:04 -08001033 device_remove_file(dev, &dev_attr_device_id);
Markus Grabner705ecec2009-02-27 19:43:04 -08001034 device_remove_file(dev, &dev_attr_finish);
1035 device_remove_file(dev, &dev_attr_firmware_version);
1036 device_remove_file(dev, &dev_attr_midi_postprocess);
Markus Grabner705ecec2009-02-27 19:43:04 -08001037 device_remove_file(dev, &dev_attr_retrieve_channel);
Markus Grabnere1a164d2010-08-23 01:08:25 +02001038 device_remove_file(dev,
1039 &dev_attr_retrieve_effects_setup);
Markus Grabner705ecec2009-02-27 19:43:04 -08001040 device_remove_file(dev, &dev_attr_routing);
1041 device_remove_file(dev, &dev_attr_serial_number);
1042 device_remove_file(dev, &dev_attr_store_amp_setup);
1043 device_remove_file(dev, &dev_attr_store_channel);
1044 device_remove_file(dev, &dev_attr_store_effects_setup);
1045 device_remove_file(dev, &dev_attr_tuner_freq);
1046 device_remove_file(dev, &dev_attr_tuner_mute);
1047 device_remove_file(dev, &dev_attr_tuner_note);
1048 device_remove_file(dev, &dev_attr_tuner_pitch);
1049
Markus Grabner1027f472010-08-12 01:35:30 +02001050#ifdef CONFIG_LINE6_USB_RAW
Markus Grabner705ecec2009-02-27 19:43:04 -08001051 device_remove_file(dev, &dev_attr_raw);
1052#endif
1053 }
1054 }
1055
1056 pod_destruct(interface);
1057}