blob: dbf821ebb5861eb7a7091906b4a47b6a0680016d [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/*
Markus Grabner1027f4762010-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 Grabner1027f4762010-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 Grabner1027f4762010-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 Grabner1027f4762010-08-12 01:35:30 +0200478
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800479 if (!sysex)
Markus Grabner1027f4762010-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 Grabner1027f4762010-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 Grabner1027f4762010-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 Grabner1027f4762010-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 Grabner1027f4762010-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 Grabner1027f4762010-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 Grabner1027f4762010-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 Grabner1027f4762010-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 Grabner1027f4762010-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 Grabner1027f4762010-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/*
631 "write" request on "retrieve_amp_setup" special file.
632*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800633static ssize_t pod_set_retrieve_amp_setup(struct device *dev,
634 struct device_attribute *attr,
635 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800636{
637 return pod_send_retrieve_command(dev, buf, count, 0x0040, 0x0100);
638}
639
640/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800641 "read" request on "midi_postprocess" special file.
642*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800643static ssize_t pod_get_midi_postprocess(struct device *dev,
644 struct device_attribute *attr,
645 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800646{
647 struct usb_interface *interface = to_usb_interface(dev);
648 struct usb_line6_pod *pod = usb_get_intfdata(interface);
649 return sprintf(buf, "%d\n", pod->midi_postprocess);
650}
651
652/*
653 "write" request on "midi_postprocess" special file.
654*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800655static ssize_t pod_set_midi_postprocess(struct device *dev,
656 struct device_attribute *attr,
657 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800658{
659 struct usb_interface *interface = to_usb_interface(dev);
660 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Johannes Thumshirn06501782012-06-27 21:26:03 +0200661 u8 value;
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600662 int ret;
663
Johannes Thumshirn06501782012-06-27 21:26:03 +0200664 ret = kstrtou8(buf, 10, &value);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600665 if (ret)
666 return ret;
667
Markus Grabner705ecec2009-02-27 19:43:04 -0800668 pod->midi_postprocess = value ? 1 : 0;
669 return count;
670}
671
672/*
673 "read" request on "serial_number" special file.
674*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800675static ssize_t pod_get_serial_number(struct device *dev,
676 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800677{
678 struct usb_interface *interface = to_usb_interface(dev);
679 struct usb_line6_pod *pod = usb_get_intfdata(interface);
680 return sprintf(buf, "%d\n", pod->serial_number);
681}
682
683/*
684 "read" request on "firmware_version" special file.
685*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800686static ssize_t pod_get_firmware_version(struct device *dev,
687 struct device_attribute *attr,
688 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800689{
690 struct usb_interface *interface = to_usb_interface(dev);
691 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800692 return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
693 pod->firmware_version % 100);
Markus Grabner705ecec2009-02-27 19:43:04 -0800694}
695
696/*
697 "read" request on "device_id" special file.
698*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800699static ssize_t pod_get_device_id(struct device *dev,
700 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800701{
702 struct usb_interface *interface = to_usb_interface(dev);
703 struct usb_line6_pod *pod = usb_get_intfdata(interface);
704 return sprintf(buf, "%d\n", pod->device_id);
705}
706
707/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200708 POD startup procedure.
709 This is a sequence of functions with special requirements (e.g., must
710 not run immediately after initialization, must not run in interrupt
711 context). After the last one has finished, the device is ready to use.
712*/
713
714static void pod_startup1(struct usb_line6_pod *pod)
715{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200716 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT);
Markus Grabner1027f4762010-08-12 01:35:30 +0200717
718 /* delay startup procedure: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200719 line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
720 (unsigned long)pod);
Markus Grabner1027f4762010-08-12 01:35:30 +0200721}
722
723static void pod_startup2(unsigned long data)
724{
725 struct usb_line6_pod *pod = (struct usb_line6_pod *)data;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200726
727 /* schedule another startup procedure until startup is complete: */
728 if (pod->startup_progress >= POD_STARTUP_LAST)
729 return;
730
731 pod->startup_progress = POD_STARTUP_DUMPREQ;
732 line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
733 (unsigned long)pod);
Markus Grabner1027f4762010-08-12 01:35:30 +0200734
735 /* current channel dump: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200736 line6_dump_request_async(&pod->dumpreq, &pod->line6, 0,
737 LINE6_DUMP_CURRENT);
Markus Grabner1027f4762010-08-12 01:35:30 +0200738}
739
740static void pod_startup3(struct usb_line6_pod *pod)
741{
742 struct usb_line6 *line6 = &pod->line6;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200743 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ);
Markus Grabner1027f4762010-08-12 01:35:30 +0200744
745 /* request firmware version: */
746 line6_version_request_async(line6);
747}
748
749static void pod_startup4(struct usb_line6_pod *pod)
750{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200751 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE);
Markus Grabner1027f4762010-08-12 01:35:30 +0200752
753 /* schedule work for global work queue: */
754 schedule_work(&pod->startup_work);
755}
756
757static void pod_startup5(struct work_struct *work)
758{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200759 struct usb_line6_pod *pod =
760 container_of(work, struct usb_line6_pod, startup_work);
Markus Grabner1027f4762010-08-12 01:35:30 +0200761 struct usb_line6 *line6 = &pod->line6;
762
Markus Grabnere1a164d2010-08-23 01:08:25 +0200763 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP);
Markus Grabner1027f4762010-08-12 01:35:30 +0200764
765 /* serial number: */
766 line6_read_serial_number(&pod->line6, &pod->serial_number);
767
768 /* ALSA audio interface: */
769 line6_register_audio(line6);
770
771 /* device files: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200772 line6_pod_create_files(pod->firmware_version,
773 line6->properties->device_bit, line6->ifcdev);
Markus Grabner1027f4762010-08-12 01:35:30 +0200774}
775
776#define POD_GET_SYSTEM_PARAM(code, sign) \
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800777static ssize_t pod_get_ ## code(struct device *dev, \
778 struct device_attribute *attr, char *buf) \
Markus Grabner705ecec2009-02-27 19:43:04 -0800779{ \
780 struct usb_interface *interface = to_usb_interface(dev); \
781 struct usb_line6_pod *pod = usb_get_intfdata(interface); \
Markus Grabner1027f4762010-08-12 01:35:30 +0200782 return pod_get_system_param_string(pod, buf, POD_ ## code, \
783 &pod->code, sign); \
Markus Grabner705ecec2009-02-27 19:43:04 -0800784}
785
Markus Grabner1027f4762010-08-12 01:35:30 +0200786#define POD_GET_SET_SYSTEM_PARAM(code, mask, sign) \
787POD_GET_SYSTEM_PARAM(code, sign) \
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800788static ssize_t pod_set_ ## code(struct device *dev, \
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800789 struct device_attribute *attr, \
790 const char *buf, size_t count) \
Markus Grabner705ecec2009-02-27 19:43:04 -0800791{ \
792 struct usb_interface *interface = to_usb_interface(dev); \
793 struct usb_line6_pod *pod = usb_get_intfdata(interface); \
Markus Grabner1027f4762010-08-12 01:35:30 +0200794 return pod_set_system_param_string(pod, buf, count, POD_ ## code, mask); \
Markus Grabner705ecec2009-02-27 19:43:04 -0800795}
796
Markus Grabner1027f4762010-08-12 01:35:30 +0200797POD_GET_SET_SYSTEM_PARAM(routing, 0x0003, 0);
798POD_GET_SET_SYSTEM_PARAM(tuner_mute, 0x0001, 0);
799POD_GET_SET_SYSTEM_PARAM(tuner_freq, 0xffff, 0);
800POD_GET_SYSTEM_PARAM(tuner_note, 1);
801POD_GET_SYSTEM_PARAM(tuner_pitch, 1);
Markus Grabner705ecec2009-02-27 19:43:04 -0800802
803#undef GET_SET_SYSTEM_PARAM
804#undef GET_SYSTEM_PARAM
805
806/* POD special files: */
Markus Grabner705ecec2009-02-27 19:43:04 -0800807static DEVICE_ATTR(device_id, S_IRUGO, pod_get_device_id, line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800808static DEVICE_ATTR(finish, S_IWUSR, line6_nop_read, pod_set_finish);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200809static DEVICE_ATTR(firmware_version, S_IRUGO, pod_get_firmware_version,
810 line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800811static DEVICE_ATTR(midi_postprocess, S_IWUSR | S_IRUGO,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200812 pod_get_midi_postprocess, pod_set_midi_postprocess);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800813static DEVICE_ATTR(retrieve_amp_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200814 pod_set_retrieve_amp_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800815static DEVICE_ATTR(retrieve_channel, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200816 pod_set_retrieve_channel);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800817static DEVICE_ATTR(retrieve_effects_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200818 pod_set_retrieve_effects_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800819static DEVICE_ATTR(routing, S_IWUSR | S_IRUGO, pod_get_routing,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200820 pod_set_routing);
821static DEVICE_ATTR(serial_number, S_IRUGO, pod_get_serial_number,
822 line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800823static DEVICE_ATTR(store_amp_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200824 pod_set_store_amp_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800825static DEVICE_ATTR(store_channel, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200826 pod_set_store_channel);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800827static DEVICE_ATTR(store_effects_setup, S_IWUSR, line6_nop_read,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200828 pod_set_store_effects_setup);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800829static DEVICE_ATTR(tuner_freq, S_IWUSR | S_IRUGO, pod_get_tuner_freq,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200830 pod_set_tuner_freq);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800831static DEVICE_ATTR(tuner_mute, S_IWUSR | S_IRUGO, pod_get_tuner_mute,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200832 pod_set_tuner_mute);
Markus Grabner705ecec2009-02-27 19:43:04 -0800833static DEVICE_ATTR(tuner_note, S_IRUGO, pod_get_tuner_note, line6_nop_write);
834static DEVICE_ATTR(tuner_pitch, S_IRUGO, pod_get_tuner_pitch, line6_nop_write);
835
Markus Grabner1027f4762010-08-12 01:35:30 +0200836#ifdef CONFIG_LINE6_USB_RAW
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800837static DEVICE_ATTR(raw, S_IWUSR, line6_nop_read, line6_set_raw);
Markus Grabner705ecec2009-02-27 19:43:04 -0800838#endif
839
Markus Grabner1027f4762010-08-12 01:35:30 +0200840/* control info callback */
841static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol,
842 struct snd_ctl_elem_info *uinfo)
843{
844 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
845 uinfo->count = 1;
846 uinfo->value.integer.min = 0;
847 uinfo->value.integer.max = 65535;
848 return 0;
849}
850
851/* control get callback */
852static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol,
853 struct snd_ctl_elem_value *ucontrol)
854{
855 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
856 struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
Stefan Hajnoczi2c35dc22012-11-22 20:48:47 +0100857 ucontrol->value.integer.value[0] = pod->monitor_level;
Markus Grabner1027f4762010-08-12 01:35:30 +0200858 return 0;
859}
860
861/* control put callback */
862static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol,
863 struct snd_ctl_elem_value *ucontrol)
864{
865 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
866 struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
867
Stefan Hajnoczi2c35dc22012-11-22 20:48:47 +0100868 if (ucontrol->value.integer.value[0] == pod->monitor_level)
Markus Grabner1027f4762010-08-12 01:35:30 +0200869 return 0;
870
Stefan Hajnoczi2c35dc22012-11-22 20:48:47 +0100871 pod->monitor_level = ucontrol->value.integer.value[0];
Markus Grabnere1a164d2010-08-23 01:08:25 +0200872 pod_set_system_param_int(pod, ucontrol->value.integer.value[0],
873 POD_monitor_level);
Markus Grabner1027f4762010-08-12 01:35:30 +0200874 return 1;
875}
876
877/* control definition */
878static struct snd_kcontrol_new pod_control_monitor = {
879 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
880 .name = "Monitor Playback Volume",
881 .index = 0,
882 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
883 .info = snd_pod_control_monitor_info,
884 .get = snd_pod_control_monitor_get,
885 .put = snd_pod_control_monitor_put
886};
887
Markus Grabner705ecec2009-02-27 19:43:04 -0800888/*
889 POD destructor.
890*/
891static void pod_destruct(struct usb_interface *interface)
892{
893 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Markus Grabner705ecec2009-02-27 19:43:04 -0800894
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800895 if (pod == NULL)
896 return;
Stefan Hajnoczi188e6642011-12-10 02:12:30 +0100897 line6_cleanup_audio(&pod->line6);
Markus Grabner705ecec2009-02-27 19:43:04 -0800898
Markus Grabnere1a164d2010-08-23 01:08:25 +0200899 del_timer(&pod->startup_timer);
900 cancel_work_sync(&pod->startup_work);
901
Markus Grabner705ecec2009-02-27 19:43:04 -0800902 /* free dump request data: */
903 line6_dumpreq_destruct(&pod->dumpreq);
Markus Grabner705ecec2009-02-27 19:43:04 -0800904}
905
906/*
907 Create sysfs entries.
908*/
Greg Kroah-Hartmanb702ed252009-02-27 20:45:03 -0800909static int pod_create_files2(struct device *dev)
Markus Grabner705ecec2009-02-27 19:43:04 -0800910{
911 int err;
912
Markus Grabner705ecec2009-02-27 19:43:04 -0800913 CHECK_RETURN(device_create_file(dev, &dev_attr_device_id));
Markus Grabner705ecec2009-02-27 19:43:04 -0800914 CHECK_RETURN(device_create_file(dev, &dev_attr_finish));
915 CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version));
916 CHECK_RETURN(device_create_file(dev, &dev_attr_midi_postprocess));
Markus Grabner705ecec2009-02-27 19:43:04 -0800917 CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_amp_setup));
918 CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_channel));
919 CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_effects_setup));
920 CHECK_RETURN(device_create_file(dev, &dev_attr_routing));
921 CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number));
922 CHECK_RETURN(device_create_file(dev, &dev_attr_store_amp_setup));
923 CHECK_RETURN(device_create_file(dev, &dev_attr_store_channel));
924 CHECK_RETURN(device_create_file(dev, &dev_attr_store_effects_setup));
925 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_freq));
926 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_mute));
927 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_note));
928 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_pitch));
929
Markus Grabner1027f4762010-08-12 01:35:30 +0200930#ifdef CONFIG_LINE6_USB_RAW
Markus Grabner705ecec2009-02-27 19:43:04 -0800931 CHECK_RETURN(device_create_file(dev, &dev_attr_raw));
932#endif
933
934 return 0;
935}
936
937/*
Markus Grabner1027f4762010-08-12 01:35:30 +0200938 Try to init POD device.
Markus Grabner705ecec2009-02-27 19:43:04 -0800939*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200940static int pod_try_init(struct usb_interface *interface,
941 struct usb_line6_pod *pod)
Markus Grabner705ecec2009-02-27 19:43:04 -0800942{
943 int err;
944 struct usb_line6 *line6 = &pod->line6;
945
Markus Grabnere1a164d2010-08-23 01:08:25 +0200946 init_timer(&pod->startup_timer);
947 INIT_WORK(&pod->startup_work, pod_startup5);
948
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800949 if ((interface == NULL) || (pod == NULL))
950 return -ENODEV;
Markus Grabner705ecec2009-02-27 19:43:04 -0800951
Markus Grabner705ecec2009-02-27 19:43:04 -0800952 /* initialize wait queues: */
Markus Grabner705ecec2009-02-27 19:43:04 -0800953 init_waitqueue_head(&pod->routing.wait);
954 init_waitqueue_head(&pod->tuner_mute.wait);
955 init_waitqueue_head(&pod->tuner_freq.wait);
956 init_waitqueue_head(&pod->tuner_note.wait);
957 init_waitqueue_head(&pod->tuner_pitch.wait);
Markus Grabner705ecec2009-02-27 19:43:04 -0800958
Markus Grabner705ecec2009-02-27 19:43:04 -0800959 /* initialize USB buffers: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800960 err = line6_dumpreq_init(&pod->dumpreq, pod_request_channel,
961 sizeof(pod_request_channel));
962 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800963 dev_err(&interface->dev, "Out of memory\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800964 return -ENOMEM;
965 }
966
Markus Grabner705ecec2009-02-27 19:43:04 -0800967 /* create sysfs entries: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800968 err = pod_create_files2(&interface->dev);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700969 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800970 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800971
972 /* initialize audio system: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800973 err = line6_init_audio(line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700974 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800975 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800976
977 /* initialize MIDI subsystem: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800978 err = line6_init_midi(line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700979 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800980 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800981
982 /* initialize PCM subsystem: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800983 err = line6_init_pcm(line6, &pod_pcm_properties);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700984 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800985 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800986
Markus Grabner1027f4762010-08-12 01:35:30 +0200987 /* register monitor control: */
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700988 err = snd_ctl_add(line6->card,
989 snd_ctl_new1(&pod_control_monitor, line6->line6pcm));
990 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800991 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800992
Markus Grabner1027f4762010-08-12 01:35:30 +0200993 /*
Markus Grabnere1a164d2010-08-23 01:08:25 +0200994 When the sound card is registered at this point, the PODxt Live
995 displays "Invalid Code Error 07", so we do it later in the event
996 handler.
997 */
Markus Grabner1027f4762010-08-12 01:35:30 +0200998
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800999 if (pod->line6.properties->capabilities & LINE6_BIT_CONTROL) {
Stefan Hajnoczi2c35dc22012-11-22 20:48:47 +01001000 pod->monitor_level = POD_system_invalid;
Markus Grabner1027f4762010-08-12 01:35:30 +02001001
1002 /* initiate startup procedure: */
1003 pod_startup1(pod);
Markus Grabner705ecec2009-02-27 19:43:04 -08001004 }
1005
1006 return 0;
1007}
1008
1009/*
Markus Grabner1027f4762010-08-12 01:35:30 +02001010 Init POD device (and clean up in case of failure).
1011*/
1012int line6_pod_init(struct usb_interface *interface, struct usb_line6_pod *pod)
1013{
1014 int err = pod_try_init(interface, pod);
1015
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001016 if (err < 0)
Markus Grabner1027f4762010-08-12 01:35:30 +02001017 pod_destruct(interface);
Markus Grabner1027f4762010-08-12 01:35:30 +02001018
1019 return err;
1020}
1021
1022/*
Markus Grabner705ecec2009-02-27 19:43:04 -08001023 POD device disconnected.
1024*/
Markus Grabner1027f4762010-08-12 01:35:30 +02001025void line6_pod_disconnect(struct usb_interface *interface)
Markus Grabner705ecec2009-02-27 19:43:04 -08001026{
1027 struct usb_line6_pod *pod;
1028
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001029 if (interface == NULL)
1030 return;
Markus Grabner705ecec2009-02-27 19:43:04 -08001031 pod = usb_get_intfdata(interface);
1032
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001033 if (pod != NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001034 struct snd_line6_pcm *line6pcm = pod->line6.line6pcm;
1035 struct device *dev = &interface->dev;
1036
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -07001037 if (line6pcm != NULL)
Markus Grabner1027f4762010-08-12 01:35:30 +02001038 line6_pcm_disconnect(line6pcm);
Markus Grabner705ecec2009-02-27 19:43:04 -08001039
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001040 if (dev != NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001041 /* remove sysfs entries: */
Markus Grabnere1a164d2010-08-23 01:08:25 +02001042 line6_pod_remove_files(pod->firmware_version,
1043 pod->line6.
1044 properties->device_bit, dev);
Markus Grabner705ecec2009-02-27 19:43:04 -08001045
Markus Grabner705ecec2009-02-27 19:43:04 -08001046 device_remove_file(dev, &dev_attr_device_id);
Markus Grabner705ecec2009-02-27 19:43:04 -08001047 device_remove_file(dev, &dev_attr_finish);
1048 device_remove_file(dev, &dev_attr_firmware_version);
1049 device_remove_file(dev, &dev_attr_midi_postprocess);
Markus Grabner705ecec2009-02-27 19:43:04 -08001050 device_remove_file(dev, &dev_attr_retrieve_amp_setup);
1051 device_remove_file(dev, &dev_attr_retrieve_channel);
Markus Grabnere1a164d2010-08-23 01:08:25 +02001052 device_remove_file(dev,
1053 &dev_attr_retrieve_effects_setup);
Markus Grabner705ecec2009-02-27 19:43:04 -08001054 device_remove_file(dev, &dev_attr_routing);
1055 device_remove_file(dev, &dev_attr_serial_number);
1056 device_remove_file(dev, &dev_attr_store_amp_setup);
1057 device_remove_file(dev, &dev_attr_store_channel);
1058 device_remove_file(dev, &dev_attr_store_effects_setup);
1059 device_remove_file(dev, &dev_attr_tuner_freq);
1060 device_remove_file(dev, &dev_attr_tuner_mute);
1061 device_remove_file(dev, &dev_attr_tuner_note);
1062 device_remove_file(dev, &dev_attr_tuner_pitch);
1063
Markus Grabner1027f4762010-08-12 01:35:30 +02001064#ifdef CONFIG_LINE6_USB_RAW
Markus Grabner705ecec2009-02-27 19:43:04 -08001065 device_remove_file(dev, &dev_attr_raw);
1066#endif
1067 }
1068 }
1069
1070 pod_destruct(interface);
1071}