blob: 685c529950eb56541683a2439b9dfd1a71702354 [file] [log] [blame]
Markus Grabner705ecec2009-02-27 19:43:04 -08001/*
2 * Line6 Linux USB driver - 0.8.0
3 *
4 * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
5 *
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
12#include "driver.h"
13
14#include "audio.h"
15#include "capture.h"
16#include "control.h"
17#include "playback.h"
18#include "pod.h"
19
20
21#define POD_SYSEX_CODE 3
22#define POD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */
23
24
25enum {
26 POD_SYSEX_CLIP = 0x0f,
27 POD_SYSEX_SAVE = 0x24,
28 POD_SYSEX_SYSTEM = 0x56,
29 POD_SYSEX_SYSTEMREQ = 0x57,
30 /* POD_SYSEX_UPDATE = 0x6c, */ /* software update! */
31 POD_SYSEX_STORE = 0x71,
32 POD_SYSEX_FINISH = 0x72,
33 POD_SYSEX_DUMPMEM = 0x73,
34 POD_SYSEX_DUMP = 0x74,
35 POD_SYSEX_DUMPREQ = 0x75
36 /* POD_SYSEX_DUMPMEM2 = 0x76 */ /* dumps entire internal memory of PODxt Pro */
37};
38
39enum {
40 POD_monitor_level = 0x04,
41 POD_routing = 0x05,
42 POD_tuner_mute = 0x13,
43 POD_tuner_freq = 0x15,
44 POD_tuner_note = 0x16,
45 POD_tuner_pitch = 0x17,
46 POD_system_invalid = 0x7fff
47};
48
49enum {
50 POD_DUMP_MEMORY = 2
51};
52
53enum {
54 POD_BUSY_READ,
55 POD_BUSY_WRITE,
56 POD_CHANNEL_DIRTY,
57 POD_SAVE_PRESSED,
58 POD_BUSY_MIDISEND
59};
60
61
62static struct snd_ratden pod_ratden = {
63 .num_min = 78125,
64 .num_max = 78125,
65 .num_step = 1,
66 .den = 2
67};
68
69static struct line6_pcm_properties pod_pcm_properties = {
70 .snd_line6_playback_hw = {
71 .info = (SNDRV_PCM_INFO_MMAP |
72 SNDRV_PCM_INFO_INTERLEAVED |
73 SNDRV_PCM_INFO_BLOCK_TRANSFER |
74 SNDRV_PCM_INFO_MMAP_VALID |
75 SNDRV_PCM_INFO_PAUSE |
76 SNDRV_PCM_INFO_SYNC_START),
77 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
78 .rates = SNDRV_PCM_RATE_KNOT,
79 .rate_min = 39062,
80 .rate_max = 39063,
81 .channels_min = 2,
82 .channels_max = 2,
83 .buffer_bytes_max = 60000,
84 .period_bytes_min = LINE6_ISO_PACKET_SIZE_MAX * POD_BYTES_PER_FRAME, /* at least one URB must fit into one period */
85 .period_bytes_max = 8192,
86 .periods_min = 1,
87 .periods_max = 1024
88 },
89 .snd_line6_capture_hw = {
90 .info = (SNDRV_PCM_INFO_MMAP |
91 SNDRV_PCM_INFO_INTERLEAVED |
92 SNDRV_PCM_INFO_BLOCK_TRANSFER |
93 SNDRV_PCM_INFO_MMAP_VALID |
94 SNDRV_PCM_INFO_SYNC_START),
95 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
96 .rates = SNDRV_PCM_RATE_KNOT,
97 .rate_min = 39062,
98 .rate_max = 39063,
99 .channels_min = 2,
100 .channels_max = 2,
101 .buffer_bytes_max = 60000,
102 .period_bytes_min = LINE6_ISO_PACKET_SIZE_MAX * POD_BYTES_PER_FRAME, /* at least one URB must fit into one period */
103 .period_bytes_max = 8192,
104 .periods_min = 1,
105 .periods_max = 1024
106 },
107 .snd_line6_rates = {
108 .nrats = 1,
109 .rats = &pod_ratden
110 },
111 .bytes_per_frame = POD_BYTES_PER_FRAME
112};
113
114static const char pod_request_version[] = { 0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7 };
115static const char pod_request_channel[] = { 0xf0, 0x00, 0x01, 0x0c, 0x03, 0x75, 0xf7 };
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800116static const char pod_version_header[] = { 0xf2, 0x7e, 0x7f, 0x06, 0x02 };
Markus Grabner705ecec2009-02-27 19:43:04 -0800117
118
119/*
120 Mark all parameters as dirty and notify waiting processes.
121*/
122static void pod_mark_batch_all_dirty(struct usb_line6_pod *pod)
123{
124 int i;
125
Frederik Deweerdte1769b32009-09-14 08:51:38 +0000126 for (i = 0; i < POD_CONTROL_SIZE; i++)
Markus Grabner705ecec2009-02-27 19:43:04 -0800127 set_bit(i, pod->param_dirty);
128}
129
130/*
131 Send an asynchronous request for the POD firmware version and device ID.
132*/
133static int pod_version_request_async(struct usb_line6_pod *pod)
134{
135 return line6_send_raw_message_async(&pod->line6, pod->buffer_versionreq, sizeof(pod_request_version));
136}
137
Markus Grabner705ecec2009-02-27 19:43:04 -0800138static void pod_create_files_work(struct work_struct *work)
139{
140 struct usb_line6_pod *pod = container_of(work, struct usb_line6_pod, create_files_work);
Markus Grabner705ecec2009-02-27 19:43:04 -0800141
142 pod_create_files(pod->firmware_version, pod->line6.properties->device_bit, pod->line6.ifcdev);
143}
144
145static void pod_startup_timeout(unsigned long arg)
146{
147 enum {
148 REQUEST_NONE,
149 REQUEST_DUMP,
150 REQUEST_VERSION
151 };
152
153 int request = REQUEST_NONE;
154 struct usb_line6_pod *pod = (struct usb_line6_pod *)arg;
155
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800156 if (pod->dumpreq.ok) {
157 if (!pod->versionreq_ok)
Markus Grabner705ecec2009-02-27 19:43:04 -0800158 request = REQUEST_VERSION;
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800159 } else {
160 if (pod->versionreq_ok)
Markus Grabner705ecec2009-02-27 19:43:04 -0800161 request = REQUEST_DUMP;
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800162 else if (pod->startup_count++ & 1)
Markus Grabner705ecec2009-02-27 19:43:04 -0800163 request = REQUEST_DUMP;
164 else
165 request = REQUEST_VERSION;
166 }
167
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800168 switch (request) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800169 case REQUEST_DUMP:
170 line6_dump_request_async(&pod->dumpreq, &pod->line6, 0);
171 break;
172
173 case REQUEST_VERSION:
174 pod_version_request_async(pod);
175 break;
176
177 default:
178 return;
179 }
180
181 line6_startup_delayed(&pod->dumpreq, 1, pod_startup_timeout, pod);
182}
183
184static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code, int size)
185{
186 return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code, size);
187}
188
189/*
190 Send channel dump data to the PODxt Pro.
191*/
192static void pod_dump(struct usb_line6_pod *pod, const unsigned char *data)
193{
194 int size = 1 + sizeof(pod->prog_data);
195 char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_DUMP, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800196 if (!sysex)
197 return;
198 /* Don't know what this is good for, but PODxt Pro transmits it, so we
199 * also do... */
200 sysex[SYSEX_DATA_OFS] = 5;
Markus Grabner705ecec2009-02-27 19:43:04 -0800201 memcpy(sysex + SYSEX_DATA_OFS + 1, data, sizeof(pod->prog_data));
202 line6_send_sysex_message(&pod->line6, sysex, size);
203 memcpy(&pod->prog_data, data, sizeof(pod->prog_data));
204 pod_mark_batch_all_dirty(pod);
205 kfree(sysex);
206}
207
208/*
209 Store parameter value in driver memory and mark it as dirty.
210*/
211static void pod_store_parameter(struct usb_line6_pod *pod, int param, int value)
212{
213 pod->prog_data.control[param] = value;
214 set_bit(param, pod->param_dirty);
215 pod->dirty = 1;
216}
217
218/*
219 Handle SAVE button
220*/
221static void pod_save_button_pressed(struct usb_line6_pod *pod, int type, int index)
222{
223 pod->dirty = 0;
224 set_bit(POD_SAVE_PRESSED, &pod->atomic_flags);
225}
226
227/*
228 Process a completely received message.
229*/
230void pod_process_message(struct usb_line6_pod *pod)
231{
232 const unsigned char *buf = pod->line6.buffer_message;
233
234 /* filter messages by type */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800235 switch (buf[0] & 0xf0) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800236 case LINE6_PARAM_CHANGE:
237 case LINE6_PROGRAM_CHANGE:
238 case LINE6_SYSEX_BEGIN:
239 break; /* handle these further down */
240
241 default:
242 return; /* ignore all others */
243 }
244
245 /* process all remaining messages */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800246 switch (buf[0]) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800247 case LINE6_PARAM_CHANGE | LINE6_CHANNEL_DEVICE:
248 pod_store_parameter(pod, buf[1], buf[2]);
249 /* intentionally no break here! */
250
251 case LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST:
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800252 if ((buf[1] == POD_amp_model_setup) ||
253 (buf[1] == POD_effect_setup))
254 /* these also affect other settings */
Markus Grabner705ecec2009-02-27 19:43:04 -0800255 line6_dump_request_async(&pod->dumpreq, &pod->line6, 0);
256
257 break;
258
259 case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_DEVICE:
260 case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST:
261 pod->channel_num = buf[1];
262 pod->dirty = 0;
263 set_bit(POD_CHANNEL_DIRTY, &pod->atomic_flags);
264 line6_dump_request_async(&pod->dumpreq, &pod->line6, 0);
265 break;
266
267 case LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE:
268 case LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN:
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800269 if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) == 0) {
270 switch (buf[5]) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800271 case POD_SYSEX_DUMP:
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800272 if (pod->line6.message_length == sizeof(pod->prog_data) + 7) {
273 switch (pod->dumpreq.in_progress) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800274 case LINE6_DUMP_CURRENT:
275 memcpy(&pod->prog_data, buf + 7, sizeof(pod->prog_data));
276 pod_mark_batch_all_dirty(pod);
277 pod->dumpreq.ok = 1;
278 break;
279
280 case POD_DUMP_MEMORY:
281 memcpy(&pod->prog_data_buf, buf + 7, sizeof(pod->prog_data_buf));
282 break;
283
284 default:
285 DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "unknown dump code %02X\n", pod->dumpreq.in_progress));
286 }
287
288 line6_dump_finished(&pod->dumpreq);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800289 } else
Markus Grabner705ecec2009-02-27 19:43:04 -0800290 DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "wrong size of channel dump message (%d instead of %d)\n",
291 pod->line6.message_length, (int)sizeof(pod->prog_data) + 7));
292
293 break;
294
295 case POD_SYSEX_SYSTEM: {
296 short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) | ((int)buf[9] << 4) | (int)buf[10];
297
298#define PROCESS_SYSTEM_PARAM(x) \
299 case POD_ ## x: \
300 pod->x.value = value; \
301 wake_up_interruptible(&pod->x.wait); \
302 break;
303
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800304 switch (buf[6]) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800305 PROCESS_SYSTEM_PARAM(monitor_level);
306 PROCESS_SYSTEM_PARAM(routing);
307 PROCESS_SYSTEM_PARAM(tuner_mute);
308 PROCESS_SYSTEM_PARAM(tuner_freq);
309 PROCESS_SYSTEM_PARAM(tuner_note);
310 PROCESS_SYSTEM_PARAM(tuner_pitch);
311
312#undef PROCESS_SYSTEM_PARAM
313
314 default:
315 DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "unknown tuner/system response %02X\n", buf[6]));
316 }
317
318 break;
319 }
320
321 case POD_SYSEX_FINISH:
322 /* do we need to respond to this? */
323 break;
324
325 case POD_SYSEX_SAVE:
326 pod_save_button_pressed(pod, buf[6], buf[7]);
327 break;
328
329 case POD_SYSEX_CLIP:
330 DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "audio clipped\n"));
331 pod->clipping.value = 1;
332 wake_up_interruptible(&pod->clipping.wait);
333 break;
334
335 case POD_SYSEX_STORE:
336 DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "message %02X not yet implemented\n", buf[5]));
337 break;
338
339 default:
340 DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "unknown sysex message %02X\n", buf[5]));
341 }
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800342 } else if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) {
343 if (pod->versionreq_ok == 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800344 pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15];
345 pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) | (int)buf[10];
346 pod->versionreq_ok = 1;
347
348 /* Now we know the firmware version, so we schedule a bottom half
349 handler to create the special files: */
Markus Grabner705ecec2009-02-27 19:43:04 -0800350 INIT_WORK(&pod->create_files_work, pod_create_files_work);
Markus Grabner705ecec2009-02-27 19:43:04 -0800351 queue_work(line6_workqueue, &pod->create_files_work);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800352 } else
Markus Grabner705ecec2009-02-27 19:43:04 -0800353 DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "multiple firmware version message\n"));
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800354 } else
Markus Grabner705ecec2009-02-27 19:43:04 -0800355 DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "unknown sysex header\n"));
356
357 break;
358
359 case LINE6_SYSEX_END:
360 break;
361
362 default:
363 DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "POD: unknown message %02X\n", buf[0]));
364 }
365}
366
367/*
368 Detect some cases that require a channel dump after sending a command to the
369 device. Important notes:
370 *) The actual dump request can not be sent here since we are not allowed to
371 wait for the completion of the first message in this context, and sending
372 the dump request before completion of the previous message leaves the POD
373 in an undefined state. The dump request will be sent when the echoed
374 commands are received.
375 *) This method fails if a param change message is "chopped" after the first
376 byte.
377*/
378void pod_midi_postprocess(struct usb_line6_pod *pod, unsigned char *data, int length)
379{
380 int i;
381
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800382 if (!pod->midi_postprocess)
Markus Grabner705ecec2009-02-27 19:43:04 -0800383 return;
384
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800385 for (i = 0; i < length; ++i) {
386 if (data[i] == (LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800387 line6_invalidate_current(&pod->dumpreq);
388 break;
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800389 } else if ((data[i] == (LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST)) && (i < length - 1))
390 if ((data[i + 1] == POD_amp_model_setup) || (data[i + 1] == POD_effect_setup)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800391 line6_invalidate_current(&pod->dumpreq);
392 break;
393 }
394 }
395}
396
397/*
398 Send channel number (i.e., switch to a different sound).
399*/
Greg Kroah-Hartmanb702ed252009-02-27 20:45:03 -0800400static void pod_send_channel(struct usb_line6_pod *pod, int value)
Markus Grabner705ecec2009-02-27 19:43:04 -0800401{
402 line6_invalidate_current(&pod->dumpreq);
403
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800404 if (line6_send_program(&pod->line6, value) == 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800405 pod->channel_num = value;
406 else
407 line6_dump_finished(&pod->dumpreq);
408}
409
410/*
411 Transmit PODxt Pro control parameter.
412*/
413void pod_transmit_parameter(struct usb_line6_pod *pod, int param, int value)
414{
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800415 if (line6_transmit_parameter(&pod->line6, param, value) == 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800416 pod_store_parameter(pod, param, value);
417
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800418 if ((param == POD_amp_model_setup) || (param == POD_effect_setup)) /* these also affect other settings */
Markus Grabner705ecec2009-02-27 19:43:04 -0800419 line6_invalidate_current(&pod->dumpreq);
420}
421
422/*
423 Resolve value to memory location.
424*/
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600425static int pod_resolve(const char *buf, short block0, short block1, unsigned char *location)
Markus Grabner705ecec2009-02-27 19:43:04 -0800426{
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600427 unsigned long value;
428 short block;
429 int ret;
430
431 ret = strict_strtoul(buf, 10, &value);
432 if (ret)
433 return ret;
434
435 block = (value < 0x40) ? block0 : block1;
Markus Grabner705ecec2009-02-27 19:43:04 -0800436 value &= 0x3f;
437 location[0] = block >> 7;
438 location[1] = value | (block & 0x7f);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600439 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800440}
441
442/*
443 Send command to store channel/effects setup/amp setup to PODxt Pro.
444*/
445static ssize_t pod_send_store_command(struct device *dev, const char *buf, size_t count, short block0, short block1)
446{
447 struct usb_interface *interface = to_usb_interface(dev);
448 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600449 int ret;
Markus Grabner705ecec2009-02-27 19:43:04 -0800450 int size = 3 + sizeof(pod->prog_data_buf);
451 char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_STORE, size);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600452
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800453 if (!sysex)
454 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800455
456 sysex[SYSEX_DATA_OFS] = 5; /* see pod_dump() */
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600457 ret = pod_resolve(buf, block0, block1, sysex + SYSEX_DATA_OFS + 1);
458 if (ret) {
459 kfree(sysex);
460 return ret;
461 }
462
Markus Grabner705ecec2009-02-27 19:43:04 -0800463 memcpy(sysex + SYSEX_DATA_OFS + 3, &pod->prog_data_buf, sizeof(pod->prog_data_buf));
464
465 line6_send_sysex_message(&pod->line6, sysex, size);
466 kfree(sysex);
467 /* needs some delay here on AMD64 platform */
468 return count;
469}
470
471/*
472 Send command to retrieve channel/effects setup/amp setup to PODxt Pro.
473*/
474static ssize_t pod_send_retrieve_command(struct device *dev, const char *buf, size_t count, short block0, short block1)
475{
476 struct usb_interface *interface = to_usb_interface(dev);
477 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600478 int ret;
Markus Grabner705ecec2009-02-27 19:43:04 -0800479 int size = 4;
480 char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_DUMPMEM, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800481
482 if (!sysex)
483 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800484
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600485 ret = pod_resolve(buf, block0, block1, sysex + SYSEX_DATA_OFS);
486 if (ret) {
487 kfree(sysex);
488 return ret;
489 }
Markus Grabner705ecec2009-02-27 19:43:04 -0800490 sysex[SYSEX_DATA_OFS + 2] = 0;
491 sysex[SYSEX_DATA_OFS + 3] = 0;
492 line6_dump_started(&pod->dumpreq, POD_DUMP_MEMORY);
493
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800494 if (line6_send_sysex_message(&pod->line6, sysex, size) < size)
Markus Grabner705ecec2009-02-27 19:43:04 -0800495 line6_dump_finished(&pod->dumpreq);
496
497 kfree(sysex);
498 /* needs some delay here on AMD64 platform */
499 return count;
500}
501
502/*
503 Generic get name function.
504*/
505static ssize_t get_name_generic(struct usb_line6_pod *pod, const char *str, char *buf)
506{
507 int length = 0;
508 const char *p1;
509 char *p2;
510 char *last_non_space = buf;
511
512 int retval = line6_wait_dump(&pod->dumpreq, 0);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800513 if (retval < 0)
514 return retval;
Markus Grabner705ecec2009-02-27 19:43:04 -0800515
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800516 for (p1 = str, p2 = buf; *p1; ++p1, ++p2) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800517 *p2 = *p1;
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800518 if (*p2 != ' ')
519 last_non_space = p2;
520 if (++length == POD_NAME_LENGTH)
521 break;
Markus Grabner705ecec2009-02-27 19:43:04 -0800522 }
523
524 *(last_non_space + 1) = '\n';
525 return last_non_space - buf + 2;
526}
527
528/*
529 "read" request on "channel" special file.
530*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800531static ssize_t pod_get_channel(struct device *dev,
532 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800533{
534 struct usb_interface *interface = to_usb_interface(dev);
535 struct usb_line6_pod *pod = usb_get_intfdata(interface);
536 return sprintf(buf, "%d\n", pod->channel_num);
537}
538
539/*
540 "write" request on "channel" special file.
541*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800542static ssize_t pod_set_channel(struct device *dev,
543 struct device_attribute *attr,
544 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800545{
546 struct usb_interface *interface = to_usb_interface(dev);
547 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600548 unsigned long value;
549 int ret;
550
551 ret = strict_strtoul(buf, 10, &value);
552 if (ret)
553 return ret;
554
Markus Grabner705ecec2009-02-27 19:43:04 -0800555 pod_send_channel(pod, value);
556 return count;
557}
558
559/*
560 "read" request on "name" special file.
561*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800562static ssize_t pod_get_name(struct device *dev, struct device_attribute *attr,
563 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800564{
565 struct usb_interface *interface = to_usb_interface(dev);
566 struct usb_line6_pod *pod = usb_get_intfdata(interface);
567 return get_name_generic(pod, pod->prog_data.header + POD_NAME_OFFSET, buf);
568}
569
570/*
571 "read" request on "name" special file.
572*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800573static ssize_t pod_get_name_buf(struct device *dev,
574 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800575{
576 struct usb_interface *interface = to_usb_interface(dev);
577 struct usb_line6_pod *pod = usb_get_intfdata(interface);
578 return get_name_generic(pod, pod->prog_data_buf.header + POD_NAME_OFFSET, buf);
579}
580
581/*
582 "read" request on "dump" special file.
583*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800584static ssize_t pod_get_dump(struct device *dev, struct device_attribute *attr,
585 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800586{
587 struct usb_interface *interface = to_usb_interface(dev);
588 struct usb_line6_pod *pod = usb_get_intfdata(interface);
589 int retval = line6_wait_dump(&pod->dumpreq, 0);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800590 if (retval < 0)
591 return retval;
Markus Grabner705ecec2009-02-27 19:43:04 -0800592 memcpy(buf, &pod->prog_data, sizeof(pod->prog_data));
593 return sizeof(pod->prog_data);
594}
595
596/*
597 "write" request on "dump" special file.
598*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800599static ssize_t pod_set_dump(struct device *dev, struct device_attribute *attr,
600 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800601{
602 struct usb_interface *interface = to_usb_interface(dev);
603 struct usb_line6_pod *pod = usb_get_intfdata(interface);
604
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800605 if (count != sizeof(pod->prog_data)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800606 dev_err(pod->line6.ifcdev,
Randy Dunlap034f5852009-11-12 15:46:01 -0800607 "data block must be exactly %zu bytes\n",
Frederik Deweerdte1769b32009-09-14 08:51:38 +0000608 sizeof(pod->prog_data));
Markus Grabner705ecec2009-02-27 19:43:04 -0800609 return -EINVAL;
610 }
611
612 pod_dump(pod, buf);
613 return sizeof(pod->prog_data);
614}
615
616/*
617 Request system parameter.
618 @param tuner non-zero, if code refers to a tuner parameter
619*/
620static ssize_t pod_get_system_param(struct usb_line6_pod *pod, char *buf, int code, struct ValueWait *param, int tuner, int sign)
621{
622 char *sysex;
623 int value;
624 static const int size = 1;
625 int retval = 0;
626 DECLARE_WAITQUEUE(wait, current);
627
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800628 if (((pod->prog_data.control[POD_tuner] & 0x40) == 0) && tuner)
Markus Grabner705ecec2009-02-27 19:43:04 -0800629 return -ENODEV;
630
631 /* send value request to tuner: */
632 param->value = POD_system_invalid;
633 sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEMREQ, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800634 if (!sysex)
635 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800636 sysex[SYSEX_DATA_OFS] = code;
637 line6_send_sysex_message(&pod->line6, sysex, size);
638 kfree(sysex);
639
640 /* wait for tuner to respond: */
641 add_wait_queue(&param->wait, &wait);
642 current->state = TASK_INTERRUPTIBLE;
643
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800644 while (param->value == POD_system_invalid) {
645 if (signal_pending(current)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800646 retval = -ERESTARTSYS;
647 break;
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800648 } else
Markus Grabner705ecec2009-02-27 19:43:04 -0800649 schedule();
650 }
651
652 current->state = TASK_RUNNING;
653 remove_wait_queue(&param->wait, &wait);
654
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800655 if (retval < 0)
Markus Grabner705ecec2009-02-27 19:43:04 -0800656 return retval;
657
658 value = sign ? (int)(signed short)param->value : (int)(unsigned short)param->value;
659 return sprintf(buf, "%d\n", value);
660}
661
662/*
663 Send system parameter.
664 @param tuner non-zero, if code refers to a tuner parameter
665*/
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800666static ssize_t pod_set_system_param(struct usb_line6_pod *pod, const char *buf,
667 int count, int code, unsigned short mask,
668 int tuner)
Markus Grabner705ecec2009-02-27 19:43:04 -0800669{
670 char *sysex;
671 static const int size = 5;
672 unsigned short value;
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600673 unsigned long result;
674 int ret;
Markus Grabner705ecec2009-02-27 19:43:04 -0800675
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800676 if (((pod->prog_data.control[POD_tuner] & 0x40) == 0) && tuner)
Markus Grabner705ecec2009-02-27 19:43:04 -0800677 return -EINVAL;
678
679 /* send value to tuner: */
680 sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800681 if (!sysex)
682 return 0;
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600683
684 ret = strict_strtoul(buf, 10, &result);
685 if (ret)
686 return ret;
687
688 value = result & mask;
Markus Grabner705ecec2009-02-27 19:43:04 -0800689 sysex[SYSEX_DATA_OFS] = code;
690 sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f;
691 sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f;
692 sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f;
693 sysex[SYSEX_DATA_OFS + 4] = (value ) & 0x0f;
694 line6_send_sysex_message(&pod->line6, sysex, size);
695 kfree(sysex);
696 return count;
697}
698
699/*
700 "read" request on "dump_buf" special file.
701*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800702static ssize_t pod_get_dump_buf(struct device *dev,
703 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800704{
705 struct usb_interface *interface = to_usb_interface(dev);
706 struct usb_line6_pod *pod = usb_get_intfdata(interface);
707 int retval = line6_wait_dump(&pod->dumpreq, 0);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800708 if (retval < 0)
709 return retval;
Markus Grabner705ecec2009-02-27 19:43:04 -0800710 memcpy(buf, &pod->prog_data_buf, sizeof(pod->prog_data_buf));
711 return sizeof(pod->prog_data_buf);
712}
713
714/*
715 "write" request on "dump_buf" special file.
716*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800717static ssize_t pod_set_dump_buf(struct device *dev,
718 struct device_attribute *attr,
719 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800720{
721 struct usb_interface *interface = to_usb_interface(dev);
722 struct usb_line6_pod *pod = usb_get_intfdata(interface);
723
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800724 if (count != sizeof(pod->prog_data)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800725 dev_err(pod->line6.ifcdev,
Randy Dunlap034f5852009-11-12 15:46:01 -0800726 "data block must be exactly %zu bytes\n",
Frederik Deweerdte1769b32009-09-14 08:51:38 +0000727 sizeof(pod->prog_data));
Markus Grabner705ecec2009-02-27 19:43:04 -0800728 return -EINVAL;
729 }
730
731 memcpy(&pod->prog_data_buf, buf, sizeof(pod->prog_data));
732 return sizeof(pod->prog_data);
733}
734
735/*
736 "write" request on "finish" special file.
737*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800738static ssize_t pod_set_finish(struct device *dev,
739 struct device_attribute *attr,
740 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800741{
742 struct usb_interface *interface = to_usb_interface(dev);
743 struct usb_line6_pod *pod = usb_get_intfdata(interface);
744 int size = 0;
745 char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_FINISH, size);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800746 if (!sysex)
747 return 0;
Markus Grabner705ecec2009-02-27 19:43:04 -0800748 line6_send_sysex_message(&pod->line6, sysex, size);
749 kfree(sysex);
750 return count;
751}
752
753/*
754 "write" request on "store_channel" special file.
755*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800756static ssize_t pod_set_store_channel(struct device *dev,
757 struct device_attribute *attr,
758 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800759{
760 return pod_send_store_command(dev, buf, count, 0x0000, 0x00c0);
761}
762
763/*
764 "write" request on "store_effects_setup" special file.
765*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800766static ssize_t pod_set_store_effects_setup(struct device *dev,
767 struct device_attribute *attr,
768 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800769{
770 return pod_send_store_command(dev, buf, count, 0x0080, 0x0080);
771}
772
773/*
774 "write" request on "store_amp_setup" special file.
775*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800776static ssize_t pod_set_store_amp_setup(struct device *dev,
777 struct device_attribute *attr,
778 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800779{
780 return pod_send_store_command(dev, buf, count, 0x0040, 0x0100);
781}
782
783/*
784 "write" request on "retrieve_channel" special file.
785*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800786static ssize_t pod_set_retrieve_channel(struct device *dev,
787 struct device_attribute *attr,
788 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800789{
790 return pod_send_retrieve_command(dev, buf, count, 0x0000, 0x00c0);
791}
792
793/*
794 "write" request on "retrieve_effects_setup" special file.
795*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800796static ssize_t pod_set_retrieve_effects_setup(struct device *dev,
797 struct device_attribute *attr,
798 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800799{
800 return pod_send_retrieve_command(dev, buf, count, 0x0080, 0x0080);
801}
802
803/*
804 "write" request on "retrieve_amp_setup" special file.
805*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800806static ssize_t pod_set_retrieve_amp_setup(struct device *dev,
807 struct device_attribute *attr,
808 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800809{
810 return pod_send_retrieve_command(dev, buf, count, 0x0040, 0x0100);
811}
812
813/*
814 "read" request on "dirty" special file.
815*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800816static ssize_t pod_get_dirty(struct device *dev, struct device_attribute *attr,
817 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800818{
819 struct usb_interface *interface = to_usb_interface(dev);
820 struct usb_line6_pod *pod = usb_get_intfdata(interface);
821 buf[0] = pod->dirty ? '1' : '0';
822 buf[1] = '\n';
823 return 2;
824}
825
826/*
827 "read" request on "midi_postprocess" special file.
828*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800829static ssize_t pod_get_midi_postprocess(struct device *dev,
830 struct device_attribute *attr,
831 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800832{
833 struct usb_interface *interface = to_usb_interface(dev);
834 struct usb_line6_pod *pod = usb_get_intfdata(interface);
835 return sprintf(buf, "%d\n", pod->midi_postprocess);
836}
837
838/*
839 "write" request on "midi_postprocess" special file.
840*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800841static ssize_t pod_set_midi_postprocess(struct device *dev,
842 struct device_attribute *attr,
843 const char *buf, size_t count)
Markus Grabner705ecec2009-02-27 19:43:04 -0800844{
845 struct usb_interface *interface = to_usb_interface(dev);
846 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Shawn Bohrer7e4d5c12009-11-15 22:18:01 -0600847 unsigned long value;
848 int ret;
849
850 ret = strict_strtoul(buf, 10, &value);
851 if (ret)
852 return ret;
853
Markus Grabner705ecec2009-02-27 19:43:04 -0800854 pod->midi_postprocess = value ? 1 : 0;
855 return count;
856}
857
858/*
859 "read" request on "serial_number" special file.
860*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800861static ssize_t pod_get_serial_number(struct device *dev,
862 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800863{
864 struct usb_interface *interface = to_usb_interface(dev);
865 struct usb_line6_pod *pod = usb_get_intfdata(interface);
866 return sprintf(buf, "%d\n", pod->serial_number);
867}
868
869/*
870 "read" request on "firmware_version" special file.
871*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800872static ssize_t pod_get_firmware_version(struct device *dev,
873 struct device_attribute *attr,
874 char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800875{
876 struct usb_interface *interface = to_usb_interface(dev);
877 struct usb_line6_pod *pod = usb_get_intfdata(interface);
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800878 return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
879 pod->firmware_version % 100);
Markus Grabner705ecec2009-02-27 19:43:04 -0800880}
881
882/*
883 "read" request on "device_id" special file.
884*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800885static ssize_t pod_get_device_id(struct device *dev,
886 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800887{
888 struct usb_interface *interface = to_usb_interface(dev);
889 struct usb_line6_pod *pod = usb_get_intfdata(interface);
890 return sprintf(buf, "%d\n", pod->device_id);
891}
892
893/*
894 "read" request on "clip" special file.
895*/
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800896static ssize_t pod_wait_for_clip(struct device *dev,
897 struct device_attribute *attr, char *buf)
Markus Grabner705ecec2009-02-27 19:43:04 -0800898{
899 struct usb_interface *interface = to_usb_interface(dev);
900 struct usb_line6_pod *pod = usb_get_intfdata(interface);
901 int err = 0;
902 DECLARE_WAITQUEUE(wait, current);
903 pod->clipping.value = 0;
904 add_wait_queue(&pod->clipping.wait, &wait);
905 current->state = TASK_INTERRUPTIBLE;
906
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800907 while (pod->clipping.value == 0) {
908 if (signal_pending(current)) {
Markus Grabner705ecec2009-02-27 19:43:04 -0800909 err = -ERESTARTSYS;
910 break;
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800911 } else
Markus Grabner705ecec2009-02-27 19:43:04 -0800912 schedule();
913 }
914
915 current->state = TASK_RUNNING;
916 remove_wait_queue(&pod->clipping.wait, &wait);
917 return err;
918}
919
920#define POD_GET_SYSTEM_PARAM(code, tuner, sign) \
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800921static ssize_t pod_get_ ## code(struct device *dev, \
922 struct device_attribute *attr, char *buf) \
Markus Grabner705ecec2009-02-27 19:43:04 -0800923{ \
924 struct usb_interface *interface = to_usb_interface(dev); \
925 struct usb_line6_pod *pod = usb_get_intfdata(interface); \
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800926 return pod_get_system_param(pod, buf, POD_ ## code, &pod->code, \
927 tuner, sign); \
Markus Grabner705ecec2009-02-27 19:43:04 -0800928}
929
930#define POD_GET_SET_SYSTEM_PARAM(code, mask, tuner, sign) \
931POD_GET_SYSTEM_PARAM(code, tuner, sign) \
Greg Kroah-Hartman77491e52009-02-27 20:25:43 -0800932static ssize_t pod_set_ ## code(struct device *dev, \
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800933 struct device_attribute *attr, \
934 const char *buf, size_t count) \
Markus Grabner705ecec2009-02-27 19:43:04 -0800935{ \
936 struct usb_interface *interface = to_usb_interface(dev); \
937 struct usb_line6_pod *pod = usb_get_intfdata(interface); \
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800938 return pod_set_system_param(pod, buf, count, POD_ ## code, mask, \
939 tuner); \
Markus Grabner705ecec2009-02-27 19:43:04 -0800940}
941
942POD_GET_SET_SYSTEM_PARAM(monitor_level, 0xffff, 0, 0);
943POD_GET_SET_SYSTEM_PARAM(routing, 0x0003, 0, 0);
944POD_GET_SET_SYSTEM_PARAM(tuner_mute, 0x0001, 1, 0);
945POD_GET_SET_SYSTEM_PARAM(tuner_freq, 0xffff, 1, 0);
946POD_GET_SYSTEM_PARAM(tuner_note, 1, 1);
947POD_GET_SYSTEM_PARAM(tuner_pitch, 1, 1);
948
949#undef GET_SET_SYSTEM_PARAM
950#undef GET_SYSTEM_PARAM
951
952/* POD special files: */
953static DEVICE_ATTR(channel, S_IWUGO | S_IRUGO, pod_get_channel, pod_set_channel);
954static DEVICE_ATTR(clip, S_IRUGO, pod_wait_for_clip, line6_nop_write);
955static DEVICE_ATTR(device_id, S_IRUGO, pod_get_device_id, line6_nop_write);
956static DEVICE_ATTR(dirty, S_IRUGO, pod_get_dirty, line6_nop_write);
957static DEVICE_ATTR(dump, S_IWUGO | S_IRUGO, pod_get_dump, pod_set_dump);
958static DEVICE_ATTR(dump_buf, S_IWUGO | S_IRUGO, pod_get_dump_buf, pod_set_dump_buf);
959static DEVICE_ATTR(finish, S_IWUGO, line6_nop_read, pod_set_finish);
960static DEVICE_ATTR(firmware_version, S_IRUGO, pod_get_firmware_version, line6_nop_write);
961static DEVICE_ATTR(midi_postprocess, S_IWUGO | S_IRUGO, pod_get_midi_postprocess, pod_set_midi_postprocess);
962static DEVICE_ATTR(monitor_level, S_IWUGO | S_IRUGO, pod_get_monitor_level, pod_set_monitor_level);
963static DEVICE_ATTR(name, S_IRUGO, pod_get_name, line6_nop_write);
964static DEVICE_ATTR(name_buf, S_IRUGO, pod_get_name_buf, line6_nop_write);
965static DEVICE_ATTR(retrieve_amp_setup, S_IWUGO, line6_nop_read, pod_set_retrieve_amp_setup);
966static DEVICE_ATTR(retrieve_channel, S_IWUGO, line6_nop_read, pod_set_retrieve_channel);
967static DEVICE_ATTR(retrieve_effects_setup, S_IWUGO, line6_nop_read, pod_set_retrieve_effects_setup);
968static DEVICE_ATTR(routing, S_IWUGO | S_IRUGO, pod_get_routing, pod_set_routing);
969static DEVICE_ATTR(serial_number, S_IRUGO, pod_get_serial_number, line6_nop_write);
970static DEVICE_ATTR(store_amp_setup, S_IWUGO, line6_nop_read, pod_set_store_amp_setup);
971static DEVICE_ATTR(store_channel, S_IWUGO, line6_nop_read, pod_set_store_channel);
972static DEVICE_ATTR(store_effects_setup, S_IWUGO, line6_nop_read, pod_set_store_effects_setup);
973static DEVICE_ATTR(tuner_freq, S_IWUGO | S_IRUGO, pod_get_tuner_freq, pod_set_tuner_freq);
974static DEVICE_ATTR(tuner_mute, S_IWUGO | S_IRUGO, pod_get_tuner_mute, pod_set_tuner_mute);
975static DEVICE_ATTR(tuner_note, S_IRUGO, pod_get_tuner_note, line6_nop_write);
976static DEVICE_ATTR(tuner_pitch, S_IRUGO, pod_get_tuner_pitch, line6_nop_write);
977
978#if CREATE_RAW_FILE
979static DEVICE_ATTR(raw, S_IWUGO, line6_nop_read, line6_set_raw);
980#endif
981
982/*
983 POD destructor.
984*/
985static void pod_destruct(struct usb_interface *interface)
986{
987 struct usb_line6_pod *pod = usb_get_intfdata(interface);
988 struct usb_line6 *line6;
989
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800990 if (pod == NULL)
991 return;
Markus Grabner705ecec2009-02-27 19:43:04 -0800992 line6 = &pod->line6;
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -0800993 if (line6 == NULL)
994 return;
Markus Grabner705ecec2009-02-27 19:43:04 -0800995 line6_cleanup_audio(line6);
996
997 /* free dump request data: */
998 line6_dumpreq_destruct(&pod->dumpreq);
999
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001000 kfree(pod->buffer_versionreq);
Markus Grabner705ecec2009-02-27 19:43:04 -08001001}
1002
1003/*
1004 Create sysfs entries.
1005*/
Greg Kroah-Hartmanb702ed252009-02-27 20:45:03 -08001006static int pod_create_files2(struct device *dev)
Markus Grabner705ecec2009-02-27 19:43:04 -08001007{
1008 int err;
1009
1010 CHECK_RETURN(device_create_file(dev, &dev_attr_channel));
1011 CHECK_RETURN(device_create_file(dev, &dev_attr_clip));
1012 CHECK_RETURN(device_create_file(dev, &dev_attr_device_id));
1013 CHECK_RETURN(device_create_file(dev, &dev_attr_dirty));
1014 CHECK_RETURN(device_create_file(dev, &dev_attr_dump));
1015 CHECK_RETURN(device_create_file(dev, &dev_attr_dump_buf));
1016 CHECK_RETURN(device_create_file(dev, &dev_attr_finish));
1017 CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version));
1018 CHECK_RETURN(device_create_file(dev, &dev_attr_midi_postprocess));
1019 CHECK_RETURN(device_create_file(dev, &dev_attr_monitor_level));
1020 CHECK_RETURN(device_create_file(dev, &dev_attr_name));
1021 CHECK_RETURN(device_create_file(dev, &dev_attr_name_buf));
1022 CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_amp_setup));
1023 CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_channel));
1024 CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_effects_setup));
1025 CHECK_RETURN(device_create_file(dev, &dev_attr_routing));
1026 CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number));
1027 CHECK_RETURN(device_create_file(dev, &dev_attr_store_amp_setup));
1028 CHECK_RETURN(device_create_file(dev, &dev_attr_store_channel));
1029 CHECK_RETURN(device_create_file(dev, &dev_attr_store_effects_setup));
1030 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_freq));
1031 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_mute));
1032 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_note));
1033 CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_pitch));
1034
1035#if CREATE_RAW_FILE
1036 CHECK_RETURN(device_create_file(dev, &dev_attr_raw));
1037#endif
1038
1039 return 0;
1040}
1041
1042/*
1043 Init POD device.
1044*/
1045int pod_init(struct usb_interface *interface, struct usb_line6_pod *pod)
1046{
1047 int err;
1048 struct usb_line6 *line6 = &pod->line6;
1049
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001050 if ((interface == NULL) || (pod == NULL))
1051 return -ENODEV;
Markus Grabner705ecec2009-02-27 19:43:04 -08001052
1053 pod->channel_num = 255;
1054
1055 /* initialize wait queues: */
1056 init_waitqueue_head(&pod->monitor_level.wait);
1057 init_waitqueue_head(&pod->routing.wait);
1058 init_waitqueue_head(&pod->tuner_mute.wait);
1059 init_waitqueue_head(&pod->tuner_freq.wait);
1060 init_waitqueue_head(&pod->tuner_note.wait);
1061 init_waitqueue_head(&pod->tuner_pitch.wait);
1062 init_waitqueue_head(&pod->clipping.wait);
1063
1064 memset(pod->param_dirty, 0xff, sizeof(pod->param_dirty));
1065
1066 /* initialize USB buffers: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001067 err = line6_dumpreq_init(&pod->dumpreq, pod_request_channel,
1068 sizeof(pod_request_channel));
1069 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001070 dev_err(&interface->dev, "Out of memory\n");
1071 pod_destruct(interface);
1072 return -ENOMEM;
1073 }
1074
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001075 pod->buffer_versionreq = kmalloc(sizeof(pod_request_version),
1076 GFP_KERNEL);
Markus Grabner705ecec2009-02-27 19:43:04 -08001077
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001078 if (pod->buffer_versionreq == NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001079 dev_err(&interface->dev, "Out of memory\n");
1080 pod_destruct(interface);
1081 return -ENOMEM;
1082 }
1083
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001084 memcpy(pod->buffer_versionreq, pod_request_version,
1085 sizeof(pod_request_version));
Markus Grabner705ecec2009-02-27 19:43:04 -08001086
1087 /* create sysfs entries: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001088 err = pod_create_files2(&interface->dev);
1089 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001090 pod_destruct(interface);
1091 return err;
1092 }
1093
1094 /* initialize audio system: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001095 err = line6_init_audio(line6);
1096 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001097 pod_destruct(interface);
1098 return err;
1099 }
1100
1101 /* initialize MIDI subsystem: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001102 err = line6_init_midi(line6);
1103 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001104 pod_destruct(interface);
1105 return err;
1106 }
1107
1108 /* initialize PCM subsystem: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001109 err = line6_init_pcm(line6, &pod_pcm_properties);
1110 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001111 pod_destruct(interface);
1112 return err;
1113 }
1114
1115 /* register audio system: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001116 err = line6_register_audio(line6);
1117 if (err < 0) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001118 pod_destruct(interface);
1119 return err;
1120 }
1121
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001122 if (pod->line6.properties->capabilities & LINE6_BIT_CONTROL) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001123 /* query some data: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001124 line6_startup_delayed(&pod->dumpreq, POD_STARTUP_DELAY,
1125 pod_startup_timeout, pod);
Markus Grabner705ecec2009-02-27 19:43:04 -08001126 line6_read_serial_number(&pod->line6, &pod->serial_number);
1127 }
1128
1129 return 0;
1130}
1131
1132/*
1133 POD device disconnected.
1134*/
1135void pod_disconnect(struct usb_interface *interface)
1136{
1137 struct usb_line6_pod *pod;
1138
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001139 if (interface == NULL)
1140 return;
Markus Grabner705ecec2009-02-27 19:43:04 -08001141 pod = usb_get_intfdata(interface);
1142
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001143 if (pod != NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001144 struct snd_line6_pcm *line6pcm = pod->line6.line6pcm;
1145 struct device *dev = &interface->dev;
1146
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001147 if (line6pcm != NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001148 unlink_wait_clear_audio_out_urbs(line6pcm);
1149 unlink_wait_clear_audio_in_urbs(line6pcm);
1150 }
1151
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001152 if (dev != NULL) {
Markus Grabner705ecec2009-02-27 19:43:04 -08001153 /* remove sysfs entries: */
Greg Kroah-Hartman0fdef362009-02-27 22:41:29 -08001154 if (pod->versionreq_ok)
Markus Grabner705ecec2009-02-27 19:43:04 -08001155 pod_remove_files(pod->firmware_version, pod->line6.properties->device_bit, dev);
1156
1157 device_remove_file(dev, &dev_attr_channel);
1158 device_remove_file(dev, &dev_attr_clip);
1159 device_remove_file(dev, &dev_attr_device_id);
1160 device_remove_file(dev, &dev_attr_dirty);
1161 device_remove_file(dev, &dev_attr_dump);
1162 device_remove_file(dev, &dev_attr_dump_buf);
1163 device_remove_file(dev, &dev_attr_finish);
1164 device_remove_file(dev, &dev_attr_firmware_version);
1165 device_remove_file(dev, &dev_attr_midi_postprocess);
1166 device_remove_file(dev, &dev_attr_monitor_level);
1167 device_remove_file(dev, &dev_attr_name);
1168 device_remove_file(dev, &dev_attr_name_buf);
1169 device_remove_file(dev, &dev_attr_retrieve_amp_setup);
1170 device_remove_file(dev, &dev_attr_retrieve_channel);
1171 device_remove_file(dev, &dev_attr_retrieve_effects_setup);
1172 device_remove_file(dev, &dev_attr_routing);
1173 device_remove_file(dev, &dev_attr_serial_number);
1174 device_remove_file(dev, &dev_attr_store_amp_setup);
1175 device_remove_file(dev, &dev_attr_store_channel);
1176 device_remove_file(dev, &dev_attr_store_effects_setup);
1177 device_remove_file(dev, &dev_attr_tuner_freq);
1178 device_remove_file(dev, &dev_attr_tuner_mute);
1179 device_remove_file(dev, &dev_attr_tuner_note);
1180 device_remove_file(dev, &dev_attr_tuner_pitch);
1181
1182#if CREATE_RAW_FILE
1183 device_remove_file(dev, &dev_attr_raw);
1184#endif
1185 }
1186 }
1187
1188 pod_destruct(interface);
1189}