blob: 57fbe2715eef2c8b9778b5fe8cb6bb1c490ee0dc [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,
Markus Grabner705ecec2009-02-27 19:43:04 -080043 POD_tuner_mute = 0x13,
44 POD_tuner_freq = 0x15,
45 POD_tuner_note = 0x16,
46 POD_tuner_pitch = 0x17,
Markus Grabner1027f472010-08-12 01:35:30 +020047 POD_system_invalid = 0x10000
Markus Grabner705ecec2009-02-27 19:43:04 -080048};
49
Markus Grabnere1a164d2010-08-23 01:08:25 +020050/* *INDENT-ON* */
51
Markus Grabner705ecec2009-02-27 19:43:04 -080052enum {
53 POD_DUMP_MEMORY = 2
54};
55
56enum {
57 POD_BUSY_READ,
58 POD_BUSY_WRITE,
59 POD_CHANNEL_DIRTY,
60 POD_SAVE_PRESSED,
61 POD_BUSY_MIDISEND
62};
63
Markus Grabner705ecec2009-02-27 19:43:04 -080064static struct snd_ratden pod_ratden = {
65 .num_min = 78125,
66 .num_max = 78125,
67 .num_step = 1,
68 .den = 2
69};
70
71static struct line6_pcm_properties pod_pcm_properties = {
Markus Grabner1027f472010-08-12 01:35:30 +020072 .snd_line6_playback_hw = {
Markus Grabnere1a164d2010-08-23 01:08:25 +020073 .info = (SNDRV_PCM_INFO_MMAP |
74 SNDRV_PCM_INFO_INTERLEAVED |
75 SNDRV_PCM_INFO_BLOCK_TRANSFER |
76 SNDRV_PCM_INFO_MMAP_VALID |
77 SNDRV_PCM_INFO_PAUSE |
Markus Grabner1027f472010-08-12 01:35:30 +020078#ifdef CONFIG_PM
Markus Grabnere1a164d2010-08-23 01:08:25 +020079 SNDRV_PCM_INFO_RESUME |
Markus Grabner1027f472010-08-12 01:35:30 +020080#endif
Markus Grabnere1a164d2010-08-23 01:08:25 +020081 SNDRV_PCM_INFO_SYNC_START),
82 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
83 .rates = SNDRV_PCM_RATE_KNOT,
84 .rate_min = 39062,
85 .rate_max = 39063,
86 .channels_min = 2,
87 .channels_max = 2,
88 .buffer_bytes_max = 60000,
89 .period_bytes_min = 64,
90 .period_bytes_max = 8192,
91 .periods_min = 1,
92 .periods_max = 1024},
Markus Grabner1027f472010-08-12 01:35:30 +020093 .snd_line6_capture_hw = {
Markus Grabnere1a164d2010-08-23 01:08:25 +020094 .info = (SNDRV_PCM_INFO_MMAP |
95 SNDRV_PCM_INFO_INTERLEAVED |
96 SNDRV_PCM_INFO_BLOCK_TRANSFER |
97 SNDRV_PCM_INFO_MMAP_VALID |
Markus Grabner1027f472010-08-12 01:35:30 +020098#ifdef CONFIG_PM
Markus Grabnere1a164d2010-08-23 01:08:25 +020099 SNDRV_PCM_INFO_RESUME |
Markus Grabner1027f472010-08-12 01:35:30 +0200100#endif
Markus Grabnere1a164d2010-08-23 01:08:25 +0200101 SNDRV_PCM_INFO_SYNC_START),
102 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
103 .rates = SNDRV_PCM_RATE_KNOT,
104 .rate_min = 39062,
105 .rate_max = 39063,
106 .channels_min = 2,
107 .channels_max = 2,
108 .buffer_bytes_max = 60000,
109 .period_bytes_min = 64,
110 .period_bytes_max = 8192,
111 .periods_min = 1,
112 .periods_max = 1024},
Markus Grabner705ecec2009-02-27 19:43:04 -0800113 .snd_line6_rates = {
Markus Grabnere1a164d2010-08-23 01:08:25 +0200114 .nrats = 1,
115 .rats = &pod_ratden},
Markus Grabner705ecec2009-02-27 19:43:04 -0800116 .bytes_per_frame = POD_BYTES_PER_FRAME
117};
118
Markus Grabner1027f472010-08-12 01:35:30 +0200119static const char pod_request_channel[] = {
120 0xf0, 0x00, 0x01, 0x0c, 0x03, 0x75, 0xf7
121};
122
Markus Grabnere1a164d2010-08-23 01:08:25 +0200123static const char pod_version_header[] = {
Markus Grabner1027f472010-08-12 01:35:30 +0200124 0xf2, 0x7e, 0x7f, 0x06, 0x02
125};
126
Markus Grabner1027f472010-08-12 01:35:30 +0200127/* forward declarations: */
128static void pod_startup2(unsigned long data);
129static void pod_startup3(struct usb_line6_pod *pod);
130static void pod_startup4(struct usb_line6_pod *pod);
Markus Grabner705ecec2009-02-27 19:43:04 -0800131
Markus Grabnere1a164d2010-08-23 01:08:25 +0200132static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code,
133 int size)
Markus Grabner705ecec2009-02-27 19:43:04 -0800134{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200135 return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code,
136 size);
Markus Grabner705ecec2009-02-27 19:43:04 -0800137}
138
139/*
Stefan Hajnoczib772fe92012-11-22 20:48:43 +0100140 Store parameter value in driver memory.
Markus Grabner705ecec2009-02-27 19:43:04 -0800141*/
142static void pod_store_parameter(struct usb_line6_pod *pod, int param, int value)
143{
144 pod->prog_data.control[param] = value;
Markus Grabner705ecec2009-02-27 19:43:04 -0800145}
146
147/*
Markus Grabner1027f472010-08-12 01:35:30 +0200148 Handle SAVE button.
Markus Grabner705ecec2009-02-27 19:43:04 -0800149*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200150static void pod_save_button_pressed(struct usb_line6_pod *pod, int type,
151 int index)
Markus Grabner705ecec2009-02-27 19:43:04 -0800152{
Markus Grabner705ecec2009-02-27 19:43:04 -0800153 set_bit(POD_SAVE_PRESSED, &pod->atomic_flags);
154}
155
156/*
157 Process a completely received message.
158*/
Markus Grabner1027f472010-08-12 01:35:30 +0200159void line6_pod_process_message(struct usb_line6_pod *pod)
Markus Grabner705ecec2009-02-27 19:43:04 -0800160{
161 const unsigned char *buf = pod->line6.buffer_message;
162
163 /* filter messages by type */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800164 switch (buf[0] & 0xf0) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800165 case LINE6_PARAM_CHANGE:
166 case LINE6_PROGRAM_CHANGE:
167 case LINE6_SYSEX_BEGIN:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200168 break; /* handle these further down */
Markus Grabner705ecec2009-02-27 19:43:04 -0800169
170 default:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200171 return; /* ignore all others */
Markus Grabner705ecec2009-02-27 19:43:04 -0800172 }
173
174 /* process all remaining messages */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800175 switch (buf[0]) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800176 case LINE6_PARAM_CHANGE | LINE6_CHANNEL_DEVICE:
177 pod_store_parameter(pod, buf[1], buf[2]);
178 /* intentionally no break here! */
179
180 case LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST:
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800181 if ((buf[1] == POD_amp_model_setup) ||
182 (buf[1] == POD_effect_setup))
183 /* these also affect other settings */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200184 line6_dump_request_async(&pod->dumpreq, &pod->line6, 0,
185 LINE6_DUMP_CURRENT);
Markus Grabner705ecec2009-02-27 19:43:04 -0800186
187 break;
188
189 case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_DEVICE:
190 case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST:
Markus Grabner705ecec2009-02-27 19:43:04 -0800191 set_bit(POD_CHANNEL_DIRTY, &pod->atomic_flags);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200192 line6_dump_request_async(&pod->dumpreq, &pod->line6, 0,
193 LINE6_DUMP_CURRENT);
Markus Grabner705ecec2009-02-27 19:43:04 -0800194 break;
195
196 case LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE:
197 case LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN:
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800198 if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) == 0) {
199 switch (buf[5]) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800200 case POD_SYSEX_DUMP:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200201 if (pod->line6.message_length ==
202 sizeof(pod->prog_data) + 7) {
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800203 switch (pod->dumpreq.in_progress) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800204 case LINE6_DUMP_CURRENT:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200205 memcpy(&pod->prog_data, buf + 7,
206 sizeof(pod->prog_data));
Markus Grabner705ecec2009-02-27 19:43:04 -0800207 break;
208
209 case POD_DUMP_MEMORY:
Markus Grabnere1a164d2010-08-23 01:08:25 +0200210 memcpy(&pod->prog_data_buf,
211 buf + 7,
212 sizeof
213 (pod->prog_data_buf));
Markus Grabner705ecec2009-02-27 19:43:04 -0800214 break;
215
216 default:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100217 dev_dbg(pod->line6.ifcdev,
218 "unknown dump code %02X\n",
219 pod->dumpreq.in_progress);
Markus Grabner705ecec2009-02-27 19:43:04 -0800220 }
221
222 line6_dump_finished(&pod->dumpreq);
Markus Grabner1027f472010-08-12 01:35:30 +0200223 pod_startup3(pod);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800224 } else
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100225 dev_dbg(pod->line6.ifcdev,
226 "wrong size of channel dump message (%d instead of %d)\n",
227 pod->line6.message_length,
228 (int)sizeof(pod->prog_data) +
229 7);
Markus Grabner705ecec2009-02-27 19:43:04 -0800230
231 break;
232
Markus Grabnere1a164d2010-08-23 01:08:25 +0200233 case POD_SYSEX_SYSTEM:{
234 short value =
235 ((int)buf[7] << 12) | ((int)buf[8]
236 << 8) |
237 ((int)buf[9] << 4) | (int)buf[10];
Markus Grabner705ecec2009-02-27 19:43:04 -0800238
239#define PROCESS_SYSTEM_PARAM(x) \
240 case POD_ ## x: \
241 pod->x.value = value; \
Markus Grabner1027f472010-08-12 01:35:30 +0200242 wake_up(&pod->x.wait); \
Markus Grabner705ecec2009-02-27 19:43:04 -0800243 break;
244
Markus Grabnere1a164d2010-08-23 01:08:25 +0200245 switch (buf[6]) {
Stefan Hajnoczi410cefa2012-11-22 20:48:46 +0100246 case POD_monitor_level:
Stefan Hajnoczi2c35dc22012-11-22 20:48:47 +0100247 pod->monitor_level = value;
Stefan Hajnoczi410cefa2012-11-22 20:48:46 +0100248 break;
249
Markus Grabnere1a164d2010-08-23 01:08:25 +0200250 PROCESS_SYSTEM_PARAM
251 (tuner_mute);
252 PROCESS_SYSTEM_PARAM
Markus Grabnere1a164d2010-08-23 01:08:25 +0200253 (tuner_pitch);
Markus Grabner705ecec2009-02-27 19:43:04 -0800254
255#undef PROCESS_SYSTEM_PARAM
256
Markus Grabnere1a164d2010-08-23 01:08:25 +0200257 default:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100258 dev_dbg(pod->line6.ifcdev,
259 "unknown tuner/system response %02X\n",
260 buf[6]);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200261 }
Markus Grabner705ecec2009-02-27 19:43:04 -0800262
Markus Grabnere1a164d2010-08-23 01:08:25 +0200263 break;
264 }
Markus Grabner705ecec2009-02-27 19:43:04 -0800265
266 case POD_SYSEX_FINISH:
267 /* do we need to respond to this? */
268 break;
269
270 case POD_SYSEX_SAVE:
271 pod_save_button_pressed(pod, buf[6], buf[7]);
272 break;
273
Markus Grabner705ecec2009-02-27 19:43:04 -0800274 case POD_SYSEX_STORE:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100275 dev_dbg(pod->line6.ifcdev,
276 "message %02X not yet implemented\n",
277 buf[5]);
Markus Grabner705ecec2009-02-27 19:43:04 -0800278 break;
279
280 default:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100281 dev_dbg(pod->line6.ifcdev,
282 "unknown sysex message %02X\n",
283 buf[5]);
Markus Grabner705ecec2009-02-27 19:43:04 -0800284 }
Markus Grabnere1a164d2010-08-23 01:08:25 +0200285 } else
286 if (memcmp
287 (buf, pod_version_header,
288 sizeof(pod_version_header)) == 0) {
289 pod->firmware_version =
290 buf[13] * 100 + buf[14] * 10 + buf[15];
291 pod->device_id =
292 ((int)buf[8] << 16) | ((int)buf[9] << 8) | (int)
293 buf[10];
Markus Grabner1027f472010-08-12 01:35:30 +0200294 pod_startup4(pod);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800295 } else
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100296 dev_dbg(pod->line6.ifcdev, "unknown sysex header\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800297
298 break;
299
300 case LINE6_SYSEX_END:
301 break;
302
303 default:
Stefan Hajnoczie00d33c2012-11-11 13:52:24 +0100304 dev_dbg(pod->line6.ifcdev, "POD: unknown message %02X\n",
305 buf[0]);
Markus Grabner705ecec2009-02-27 19:43:04 -0800306 }
307}
308
309/*
310 Detect some cases that require a channel dump after sending a command to the
311 device. Important notes:
312 *) The actual dump request can not be sent here since we are not allowed to
313 wait for the completion of the first message in this context, and sending
314 the dump request before completion of the previous message leaves the POD
315 in an undefined state. The dump request will be sent when the echoed
316 commands are received.
317 *) This method fails if a param change message is "chopped" after the first
318 byte.
319*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200320void line6_pod_midi_postprocess(struct usb_line6_pod *pod, unsigned char *data,
321 int length)
Markus Grabner705ecec2009-02-27 19:43:04 -0800322{
323 int i;
324
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800325 if (!pod->midi_postprocess)
Markus Grabner705ecec2009-02-27 19:43:04 -0800326 return;
327
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800328 for (i = 0; i < length; ++i) {
329 if (data[i] == (LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800330 line6_invalidate_current(&pod->dumpreq);
331 break;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200332 } else
333 if ((data[i] == (LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST))
334 && (i < length - 1))
335 if ((data[i + 1] == POD_amp_model_setup)
336 || (data[i + 1] == POD_effect_setup)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800337 line6_invalidate_current(&pod->dumpreq);
338 break;
339 }
340 }
341}
342
343/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800344 Transmit PODxt Pro control parameter.
345*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200346void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param,
Johannes Thumshirn5b9bd2a2012-06-27 21:25:57 +0200347 u8 value)
Markus Grabner705ecec2009-02-27 19:43:04 -0800348{
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800349 if (line6_transmit_parameter(&pod->line6, param, value) == 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800350 pod_store_parameter(pod, param, value);
351
Markus Grabnere1a164d2010-08-23 01:08:25 +0200352 if ((param == POD_amp_model_setup) || (param == POD_effect_setup)) /* these also affect other settings */
Markus Grabner705ecec2009-02-27 19:43:04 -0800353 line6_invalidate_current(&pod->dumpreq);
354}
355
356/*
Markus Grabner1027f472010-08-12 01:35:30 +0200357 Identify system parameters related to the tuner.
358*/
359static bool pod_is_tuner(int code)
360{
361 return
Markus Grabnere1a164d2010-08-23 01:08:25 +0200362 (code == POD_tuner_mute) ||
363 (code == POD_tuner_freq) ||
364 (code == POD_tuner_note) || (code == POD_tuner_pitch);
Markus Grabner1027f472010-08-12 01:35:30 +0200365}
366
367/*
368 Get system parameter (as integer).
Markus Grabner705ecec2009-02-27 19:43:04 -0800369 @param tuner non-zero, if code refers to a tuner parameter
370*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200371static int pod_get_system_param_int(struct usb_line6_pod *pod, int *value,
372 int code, struct ValueWait *param, int sign)
Markus Grabner705ecec2009-02-27 19:43:04 -0800373{
374 char *sysex;
Markus Grabner705ecec2009-02-27 19:43:04 -0800375 static const int size = 1;
376 int retval = 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800377
Markus Grabnere1a164d2010-08-23 01:08:25 +0200378 if (((pod->prog_data.control[POD_tuner] & 0x40) == 0)
379 && pod_is_tuner(code))
Markus Grabner705ecec2009-02-27 19:43:04 -0800380 return -ENODEV;
381
Markus Grabner1027f472010-08-12 01:35:30 +0200382 /* send value request to device: */
Markus Grabner705ecec2009-02-27 19:43:04 -0800383 param->value = POD_system_invalid;
384 sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEMREQ, size);
Markus Grabner1027f472010-08-12 01:35:30 +0200385
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800386 if (!sysex)
Markus Grabner1027f472010-08-12 01:35:30 +0200387 return -ENOMEM;
388
Markus Grabner705ecec2009-02-27 19:43:04 -0800389 sysex[SYSEX_DATA_OFS] = code;
390 line6_send_sysex_message(&pod->line6, sysex, size);
391 kfree(sysex);
392
Markus Grabner1027f472010-08-12 01:35:30 +0200393 /* wait for device to respond: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200394 retval =
395 wait_event_interruptible(param->wait,
396 param->value != POD_system_invalid);
Markus Grabner705ecec2009-02-27 19:43:04 -0800397
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800398 if (retval < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800399 return retval;
400
Markus Grabnere1a164d2010-08-23 01:08:25 +0200401 *value = sign ? (int)(signed short)param->value : (int)(unsigned short)
402 param->value;
Markus Grabner1027f472010-08-12 01:35:30 +0200403
Markus Grabnere1a164d2010-08-23 01:08:25 +0200404 if (*value == POD_system_invalid)
405 *value = 0; /* don't report uninitialized values */
Markus Grabner1027f472010-08-12 01:35:30 +0200406
407 return 0;
408}
409
410/*
411 Get system parameter (as string).
412 @param tuner non-zero, if code refers to a tuner parameter
413*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200414static ssize_t pod_get_system_param_string(struct usb_line6_pod *pod, char *buf,
415 int code, struct ValueWait *param,
416 int sign)
Markus Grabner1027f472010-08-12 01:35:30 +0200417{
418 int retval, value = 0;
419 retval = pod_get_system_param_int(pod, &value, code, param, sign);
420
Markus Grabnere1a164d2010-08-23 01:08:25 +0200421 if (retval < 0)
Markus Grabner1027f472010-08-12 01:35:30 +0200422 return retval;
423
Markus Grabner705ecec2009-02-27 19:43:04 -0800424 return sprintf(buf, "%d\n", value);
425}
426
427/*
Markus Grabner1027f472010-08-12 01:35:30 +0200428 Send system parameter (from integer).
Markus Grabner705ecec2009-02-27 19:43:04 -0800429 @param tuner non-zero, if code refers to a tuner parameter
430*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200431static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
432 int code)
Markus Grabner705ecec2009-02-27 19:43:04 -0800433{
434 char *sysex;
435 static const int size = 5;
Markus Grabner705ecec2009-02-27 19:43:04 -0800436
Markus Grabnere1a164d2010-08-23 01:08:25 +0200437 if (((pod->prog_data.control[POD_tuner] & 0x40) == 0)
438 && pod_is_tuner(code))
Markus Grabner705ecec2009-02-27 19:43:04 -0800439 return -EINVAL;
440
441 /* send value to tuner: */
442 sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800443 if (!sysex)
Markus Grabner1027f472010-08-12 01:35:30 +0200444 return -ENOMEM;
Markus Grabner705ecec2009-02-27 19:43:04 -0800445 sysex[SYSEX_DATA_OFS] = code;
446 sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200447 sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f;
448 sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f;
449 sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f;
Markus Grabner705ecec2009-02-27 19:43:04 -0800450 line6_send_sysex_message(&pod->line6, sysex, size);
451 kfree(sysex);
Markus Grabner1027f472010-08-12 01:35:30 +0200452 return 0;
453}
454
455/*
456 Send system parameter (from string).
457 @param tuner non-zero, if code refers to a tuner parameter
458*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200459static ssize_t pod_set_system_param_string(struct usb_line6_pod *pod,
460 const char *buf, int count, int code,
461 unsigned short mask)
Markus Grabner1027f472010-08-12 01:35:30 +0200462{
463 int retval;
464 unsigned short value = simple_strtoul(buf, NULL, 10) & mask;
465 retval = pod_set_system_param_int(pod, value, code);
466 return (retval < 0) ? retval : count;
Markus Grabner705ecec2009-02-27 19:43:04 -0800467}
468
469/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800470 "write" request on "finish" special file.
471*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800472static ssize_t pod_set_finish(struct device *dev,
473 struct device_attribute *attr,
474 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800475{
476 struct usb_interface *interface = to_usb_interface(dev);
477 struct usb_line6_pod *pod = usb_get_intfdata(interface);
478 int size = 0;
479 char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_FINISH, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800480 if (!sysex)
481 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800482 line6_send_sysex_message(&pod->line6, sysex, size);
483 kfree(sysex);
484 return count;
485}
486
487/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800488 "read" request on "midi_postprocess" special file.
489*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800490static ssize_t pod_get_midi_postprocess(struct device *dev,
491 struct device_attribute *attr,
492 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800493{
494 struct usb_interface *interface = to_usb_interface(dev);
495 struct usb_line6_pod *pod = usb_get_intfdata(interface);
496 return sprintf(buf, "%d\n", pod->midi_postprocess);
497}
498
499/*
500 "write" request on "midi_postprocess" special file.
501*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800502static ssize_t pod_set_midi_postprocess(struct device *dev,
503 struct device_attribute *attr,
504 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800505{
506 struct usb_interface *interface = to_usb_interface(dev);
507 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Johannes Thumshirn06501782012-06-27 21:26:03 +0200508 u8 value;
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600509 int ret;
510
Johannes Thumshirn06501782012-06-27 21:26:03 +0200511 ret = kstrtou8(buf, 10, &value);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600512 if (ret)
513 return ret;
514
Markus Grabner705ecec2009-02-27 19:43:04 -0800515 pod->midi_postprocess = value ? 1 : 0;
516 return count;
517}
518
519/*
520 "read" request on "serial_number" special file.
521*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800522static ssize_t pod_get_serial_number(struct device *dev,
523 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800524{
525 struct usb_interface *interface = to_usb_interface(dev);
526 struct usb_line6_pod *pod = usb_get_intfdata(interface);
527 return sprintf(buf, "%d\n", pod->serial_number);
528}
529
530/*
531 "read" request on "firmware_version" special file.
532*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800533static ssize_t pod_get_firmware_version(struct device *dev,
534 struct device_attribute *attr,
535 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800536{
537 struct usb_interface *interface = to_usb_interface(dev);
538 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800539 return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
540 pod->firmware_version % 100);
Markus Grabner705ecec2009-02-27 19:43:04 -0800541}
542
543/*
544 "read" request on "device_id" special file.
545*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800546static ssize_t pod_get_device_id(struct device *dev,
547 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800548{
549 struct usb_interface *interface = to_usb_interface(dev);
550 struct usb_line6_pod *pod = usb_get_intfdata(interface);
551 return sprintf(buf, "%d\n", pod->device_id);
552}
553
554/*
Markus Grabner1027f472010-08-12 01:35:30 +0200555 POD startup procedure.
556 This is a sequence of functions with special requirements (e.g., must
557 not run immediately after initialization, must not run in interrupt
558 context). After the last one has finished, the device is ready to use.
559*/
560
561static void pod_startup1(struct usb_line6_pod *pod)
562{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200563 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT);
Markus Grabner1027f472010-08-12 01:35:30 +0200564
565 /* delay startup procedure: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200566 line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
567 (unsigned long)pod);
Markus Grabner1027f472010-08-12 01:35:30 +0200568}
569
570static void pod_startup2(unsigned long data)
571{
572 struct usb_line6_pod *pod = (struct usb_line6_pod *)data;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200573
574 /* schedule another startup procedure until startup is complete: */
575 if (pod->startup_progress >= POD_STARTUP_LAST)
576 return;
577
578 pod->startup_progress = POD_STARTUP_DUMPREQ;
579 line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
580 (unsigned long)pod);
Markus Grabner1027f472010-08-12 01:35:30 +0200581
582 /* current channel dump: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200583 line6_dump_request_async(&pod->dumpreq, &pod->line6, 0,
584 LINE6_DUMP_CURRENT);
Markus Grabner1027f472010-08-12 01:35:30 +0200585}
586
587static void pod_startup3(struct usb_line6_pod *pod)
588{
589 struct usb_line6 *line6 = &pod->line6;
Markus Grabnere1a164d2010-08-23 01:08:25 +0200590 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ);
Markus Grabner1027f472010-08-12 01:35:30 +0200591
592 /* request firmware version: */
593 line6_version_request_async(line6);
594}
595
596static void pod_startup4(struct usb_line6_pod *pod)
597{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200598 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE);
Markus Grabner1027f472010-08-12 01:35:30 +0200599
600 /* schedule work for global work queue: */
601 schedule_work(&pod->startup_work);
602}
603
604static void pod_startup5(struct work_struct *work)
605{
Markus Grabnere1a164d2010-08-23 01:08:25 +0200606 struct usb_line6_pod *pod =
607 container_of(work, struct usb_line6_pod, startup_work);
Markus Grabner1027f472010-08-12 01:35:30 +0200608 struct usb_line6 *line6 = &pod->line6;
609
Markus Grabnere1a164d2010-08-23 01:08:25 +0200610 CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP);
Markus Grabner1027f472010-08-12 01:35:30 +0200611
612 /* serial number: */
613 line6_read_serial_number(&pod->line6, &pod->serial_number);
614
615 /* ALSA audio interface: */
616 line6_register_audio(line6);
617
618 /* device files: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200619 line6_pod_create_files(pod->firmware_version,
620 line6->properties->device_bit, line6->ifcdev);
Markus Grabner1027f472010-08-12 01:35:30 +0200621}
622
623#define POD_GET_SYSTEM_PARAM(code, sign) \
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800624static ssize_t pod_get_ ## code(struct device *dev, \
625 struct device_attribute *attr, char *buf) \
Markus Grabner705ecec2009-02-27 19:43:04 -0800626{ \
627 struct usb_interface *interface = to_usb_interface(dev); \
628 struct usb_line6_pod *pod = usb_get_intfdata(interface); \
Markus Grabner1027f472010-08-12 01:35:30 +0200629 return pod_get_system_param_string(pod, buf, POD_ ## code, \
630 &pod->code, sign); \
Markus Grabner705ecec2009-02-27 19:43:04 -0800631}
632
Markus Grabner1027f472010-08-12 01:35:30 +0200633#define POD_GET_SET_SYSTEM_PARAM(code, mask, sign) \
634POD_GET_SYSTEM_PARAM(code, sign) \
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800635static ssize_t pod_set_ ## code(struct device *dev, \
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800636 struct device_attribute *attr, \
637 const char *buf, size_t count) \
Markus Grabner705ecec2009-02-27 19:43:04 -0800638{ \
639 struct usb_interface *interface = to_usb_interface(dev); \
640 struct usb_line6_pod *pod = usb_get_intfdata(interface); \
Markus Grabner1027f472010-08-12 01:35:30 +0200641 return pod_set_system_param_string(pod, buf, count, POD_ ## code, mask); \
Markus Grabner705ecec2009-02-27 19:43:04 -0800642}
643
Markus Grabner1027f472010-08-12 01:35:30 +0200644POD_GET_SET_SYSTEM_PARAM(tuner_mute, 0x0001, 0);
Markus Grabner1027f472010-08-12 01:35:30 +0200645POD_GET_SYSTEM_PARAM(tuner_pitch, 1);
Markus Grabner705ecec2009-02-27 19:43:04 -0800646
647#undef GET_SET_SYSTEM_PARAM
648#undef GET_SYSTEM_PARAM
649
650/* POD special files: */
Markus Grabner705ecec2009-02-27 19:43:04 -0800651static DEVICE_ATTR(device_id, S_IRUGO, pod_get_device_id, line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800652static DEVICE_ATTR(finish, S_IWUSR, line6_nop_read, pod_set_finish);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200653static DEVICE_ATTR(firmware_version, S_IRUGO, pod_get_firmware_version,
654 line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800655static DEVICE_ATTR(midi_postprocess, S_IWUSR | S_IRUGO,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200656 pod_get_midi_postprocess, pod_set_midi_postprocess);
Markus Grabnere1a164d2010-08-23 01:08:25 +0200657static DEVICE_ATTR(serial_number, S_IRUGO, pod_get_serial_number,
658 line6_nop_write);
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800659static DEVICE_ATTR(tuner_mute, S_IWUSR | S_IRUGO, pod_get_tuner_mute,
Markus Grabnere1a164d2010-08-23 01:08:25 +0200660 pod_set_tuner_mute);
Markus Grabner705ecec2009-02-27 19:43:04 -0800661static DEVICE_ATTR(tuner_pitch, S_IRUGO, pod_get_tuner_pitch, line6_nop_write);
662
Markus Grabner1027f472010-08-12 01:35:30 +0200663#ifdef CONFIG_LINE6_USB_RAW
Greg Kroah-Hartmana3a972a2010-11-18 11:21:04 -0800664static DEVICE_ATTR(raw, S_IWUSR, line6_nop_read, line6_set_raw);
Markus Grabner705ecec2009-02-27 19:43:04 -0800665#endif
666
Markus Grabner1027f472010-08-12 01:35:30 +0200667/* control info callback */
668static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol,
669 struct snd_ctl_elem_info *uinfo)
670{
671 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
672 uinfo->count = 1;
673 uinfo->value.integer.min = 0;
674 uinfo->value.integer.max = 65535;
675 return 0;
676}
677
678/* control get callback */
679static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol,
680 struct snd_ctl_elem_value *ucontrol)
681{
682 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
683 struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
Stefan Hajnoczi2c35dc22012-11-22 20:48:47 +0100684 ucontrol->value.integer.value[0] = pod->monitor_level;
Markus Grabner1027f472010-08-12 01:35:30 +0200685 return 0;
686}
687
688/* control put callback */
689static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol,
690 struct snd_ctl_elem_value *ucontrol)
691{
692 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
693 struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
694
Stefan Hajnoczi2c35dc22012-11-22 20:48:47 +0100695 if (ucontrol->value.integer.value[0] == pod->monitor_level)
Markus Grabner1027f472010-08-12 01:35:30 +0200696 return 0;
697
Stefan Hajnoczi2c35dc22012-11-22 20:48:47 +0100698 pod->monitor_level = ucontrol->value.integer.value[0];
Markus Grabnere1a164d2010-08-23 01:08:25 +0200699 pod_set_system_param_int(pod, ucontrol->value.integer.value[0],
700 POD_monitor_level);
Markus Grabner1027f472010-08-12 01:35:30 +0200701 return 1;
702}
703
704/* control definition */
705static struct snd_kcontrol_new pod_control_monitor = {
706 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
707 .name = "Monitor Playback Volume",
708 .index = 0,
709 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
710 .info = snd_pod_control_monitor_info,
711 .get = snd_pod_control_monitor_get,
712 .put = snd_pod_control_monitor_put
713};
714
Markus Grabner705ecec2009-02-27 19:43:04 -0800715/*
716 POD destructor.
717*/
718static void pod_destruct(struct usb_interface *interface)
719{
720 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Markus Grabner705ecec2009-02-27 19:43:04 -0800721
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800722 if (pod == NULL)
723 return;
Stefan Hajnoczi188e6642011-12-10 02:12:30 +0100724 line6_cleanup_audio(&pod->line6);
Markus Grabner705ecec2009-02-27 19:43:04 -0800725
Markus Grabnere1a164d2010-08-23 01:08:25 +0200726 del_timer(&pod->startup_timer);
727 cancel_work_sync(&pod->startup_work);
728
Markus Grabner705ecec2009-02-27 19:43:04 -0800729 /* free dump request data: */
730 line6_dumpreq_destruct(&pod->dumpreq);
Markus Grabner705ecec2009-02-27 19:43:04 -0800731}
732
733/*
734 Create sysfs entries.
735*/
Greg Kroah-Hartmanb702ed252009-02-27 20:45:03 -0800736static int pod_create_files2(struct device *dev)
Markus Grabner705ecec2009-02-27 19:43:04 -0800737{
738 int err;
739
Markus Grabner705ecec2009-02-27 19:43:04 -0800740 CHECK_RETURN(device_create_file(dev, &dev_attr_device_id));
Markus Grabner705ecec2009-02-27 19:43:04 -0800741 CHECK_RETURN(device_create_file(dev, &dev_attr_finish));
742 CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version));
743 CHECK_RETURN(device_create_file(dev, &dev_attr_midi_postprocess));
Markus Grabner705ecec2009-02-27 19:43:04 -0800744 CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number));
Markus Grabner705ecec2009-02-27 19:43:04 -0800745 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_mute));
Markus Grabner705ecec2009-02-27 19:43:04 -0800746 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_pitch));
747
Markus Grabner1027f472010-08-12 01:35:30 +0200748#ifdef CONFIG_LINE6_USB_RAW
Markus Grabner705ecec2009-02-27 19:43:04 -0800749 CHECK_RETURN(device_create_file(dev, &dev_attr_raw));
750#endif
751
752 return 0;
753}
754
755/*
Markus Grabner1027f472010-08-12 01:35:30 +0200756 Try to init POD device.
Markus Grabner705ecec2009-02-27 19:43:04 -0800757*/
Markus Grabnere1a164d2010-08-23 01:08:25 +0200758static int pod_try_init(struct usb_interface *interface,
759 struct usb_line6_pod *pod)
Markus Grabner705ecec2009-02-27 19:43:04 -0800760{
761 int err;
762 struct usb_line6 *line6 = &pod->line6;
763
Markus Grabnere1a164d2010-08-23 01:08:25 +0200764 init_timer(&pod->startup_timer);
765 INIT_WORK(&pod->startup_work, pod_startup5);
766
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800767 if ((interface == NULL) || (pod == NULL))
768 return -ENODEV;
Markus Grabner705ecec2009-02-27 19:43:04 -0800769
Markus Grabner705ecec2009-02-27 19:43:04 -0800770 /* initialize wait queues: */
Markus Grabner705ecec2009-02-27 19:43:04 -0800771 init_waitqueue_head(&pod->tuner_mute.wait);
Markus Grabner705ecec2009-02-27 19:43:04 -0800772 init_waitqueue_head(&pod->tuner_pitch.wait);
Markus Grabner705ecec2009-02-27 19:43:04 -0800773
Markus Grabner705ecec2009-02-27 19:43:04 -0800774 /* initialize USB buffers: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800775 err = line6_dumpreq_init(&pod->dumpreq, pod_request_channel,
776 sizeof(pod_request_channel));
777 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800778 dev_err(&interface->dev, "Out of memory\n");
Markus Grabner705ecec2009-02-27 19:43:04 -0800779 return -ENOMEM;
780 }
781
Markus Grabner705ecec2009-02-27 19:43:04 -0800782 /* create sysfs entries: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800783 err = pod_create_files2(&interface->dev);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700784 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800785 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800786
787 /* initialize audio system: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800788 err = line6_init_audio(line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700789 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800790 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800791
792 /* initialize MIDI subsystem: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800793 err = line6_init_midi(line6);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700794 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800795 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800796
797 /* initialize PCM subsystem: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800798 err = line6_init_pcm(line6, &pod_pcm_properties);
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700799 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800800 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800801
Markus Grabner1027f472010-08-12 01:35:30 +0200802 /* register monitor control: */
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700803 err = snd_ctl_add(line6->card,
804 snd_ctl_new1(&pod_control_monitor, line6->line6pcm));
805 if (err < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800806 return err;
Markus Grabner705ecec2009-02-27 19:43:04 -0800807
Markus Grabner1027f472010-08-12 01:35:30 +0200808 /*
Markus Grabnere1a164d2010-08-23 01:08:25 +0200809 When the sound card is registered at this point, the PODxt Live
810 displays "Invalid Code Error 07", so we do it later in the event
811 handler.
812 */
Markus Grabner1027f472010-08-12 01:35:30 +0200813
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800814 if (pod->line6.properties->capabilities & LINE6_BIT_CONTROL) {
Stefan Hajnoczi2c35dc22012-11-22 20:48:47 +0100815 pod->monitor_level = POD_system_invalid;
Markus Grabner1027f472010-08-12 01:35:30 +0200816
817 /* initiate startup procedure: */
818 pod_startup1(pod);
Markus Grabner705ecec2009-02-27 19:43:04 -0800819 }
820
821 return 0;
822}
823
824/*
Markus Grabner1027f472010-08-12 01:35:30 +0200825 Init POD device (and clean up in case of failure).
826*/
827int line6_pod_init(struct usb_interface *interface, struct usb_line6_pod *pod)
828{
829 int err = pod_try_init(interface, pod);
830
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700831 if (err < 0)
Markus Grabner1027f472010-08-12 01:35:30 +0200832 pod_destruct(interface);
Markus Grabner1027f472010-08-12 01:35:30 +0200833
834 return err;
835}
836
837/*
Markus Grabner705ecec2009-02-27 19:43:04 -0800838 POD device disconnected.
839*/
Markus Grabner1027f472010-08-12 01:35:30 +0200840void line6_pod_disconnect(struct usb_interface *interface)
Markus Grabner705ecec2009-02-27 19:43:04 -0800841{
842 struct usb_line6_pod *pod;
843
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800844 if (interface == NULL)
845 return;
Markus Grabner705ecec2009-02-27 19:43:04 -0800846 pod = usb_get_intfdata(interface);
847
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800848 if (pod != NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800849 struct snd_line6_pcm *line6pcm = pod->line6.line6pcm;
850 struct device *dev = &interface->dev;
851
Greg Kroah-Hartman027360c2010-09-21 16:58:00 -0700852 if (line6pcm != NULL)
Markus Grabner1027f472010-08-12 01:35:30 +0200853 line6_pcm_disconnect(line6pcm);
Markus Grabner705ecec2009-02-27 19:43:04 -0800854
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800855 if (dev != NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800856 /* remove sysfs entries: */
Markus Grabnere1a164d2010-08-23 01:08:25 +0200857 line6_pod_remove_files(pod->firmware_version,
858 pod->line6.
859 properties->device_bit, dev);
Markus Grabner705ecec2009-02-27 19:43:04 -0800860
Markus Grabner705ecec2009-02-27 19:43:04 -0800861 device_remove_file(dev, &dev_attr_device_id);
Markus Grabner705ecec2009-02-27 19:43:04 -0800862 device_remove_file(dev, &dev_attr_finish);
863 device_remove_file(dev, &dev_attr_firmware_version);
864 device_remove_file(dev, &dev_attr_midi_postprocess);
Markus Grabner705ecec2009-02-27 19:43:04 -0800865 device_remove_file(dev, &dev_attr_serial_number);
Markus Grabner705ecec2009-02-27 19:43:04 -0800866 device_remove_file(dev, &dev_attr_tuner_mute);
Markus Grabner705ecec2009-02-27 19:43:04 -0800867 device_remove_file(dev, &dev_attr_tuner_pitch);
868
Markus Grabner1027f472010-08-12 01:35:30 +0200869#ifdef CONFIG_LINE6_USB_RAW
Markus Grabner705ecec2009-02-27 19:43:04 -0800870 device_remove_file(dev, &dev_attr_raw);
871#endif
872 }
873 }
874
875 pod_destruct(interface);
876}