Commit | Line | Data |
---|---|---|
705ececd | 1 | /* |
1027f476 | 2 | * Line6 Linux USB driver - 0.9.0 |
705ececd | 3 | * |
1027f476 | 4 | * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) |
705ececd MG |
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 | ||
5a0e3ad6 | 12 | #include <linux/slab.h> |
1027f476 MG |
13 | #include <linux/wait.h> |
14 | #include <sound/control.h> | |
5a0e3ad6 | 15 | |
705ececd MG |
16 | #include "audio.h" |
17 | #include "capture.h" | |
18 | #include "control.h" | |
1027f476 | 19 | #include "driver.h" |
705ececd MG |
20 | #include "playback.h" |
21 | #include "pod.h" | |
22 | ||
23 | ||
24 | #define POD_SYSEX_CODE 3 | |
25 | #define POD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */ | |
26 | ||
27 | ||
28 | enum { | |
29 | POD_SYSEX_CLIP = 0x0f, | |
30 | POD_SYSEX_SAVE = 0x24, | |
31 | POD_SYSEX_SYSTEM = 0x56, | |
32 | POD_SYSEX_SYSTEMREQ = 0x57, | |
33 | /* POD_SYSEX_UPDATE = 0x6c, */ /* software update! */ | |
34 | POD_SYSEX_STORE = 0x71, | |
35 | POD_SYSEX_FINISH = 0x72, | |
36 | POD_SYSEX_DUMPMEM = 0x73, | |
37 | POD_SYSEX_DUMP = 0x74, | |
38 | POD_SYSEX_DUMPREQ = 0x75 | |
39 | /* POD_SYSEX_DUMPMEM2 = 0x76 */ /* dumps entire internal memory of PODxt Pro */ | |
40 | }; | |
41 | ||
42 | enum { | |
43 | POD_monitor_level = 0x04, | |
44 | POD_routing = 0x05, | |
45 | POD_tuner_mute = 0x13, | |
46 | POD_tuner_freq = 0x15, | |
47 | POD_tuner_note = 0x16, | |
48 | POD_tuner_pitch = 0x17, | |
1027f476 | 49 | POD_system_invalid = 0x10000 |
705ececd MG |
50 | }; |
51 | ||
52 | enum { | |
53 | POD_DUMP_MEMORY = 2 | |
54 | }; | |
55 | ||
56 | enum { | |
57 | POD_BUSY_READ, | |
58 | POD_BUSY_WRITE, | |
59 | POD_CHANNEL_DIRTY, | |
60 | POD_SAVE_PRESSED, | |
61 | POD_BUSY_MIDISEND | |
62 | }; | |
63 | ||
64 | ||
65 | static struct snd_ratden pod_ratden = { | |
66 | .num_min = 78125, | |
67 | .num_max = 78125, | |
68 | .num_step = 1, | |
69 | .den = 2 | |
70 | }; | |
71 | ||
72 | static struct line6_pcm_properties pod_pcm_properties = { | |
1027f476 | 73 | .snd_line6_playback_hw = { |
705ececd | 74 | .info = (SNDRV_PCM_INFO_MMAP | |
1027f476 MG |
75 | SNDRV_PCM_INFO_INTERLEAVED | |
76 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | |
77 | SNDRV_PCM_INFO_MMAP_VALID | | |
78 | SNDRV_PCM_INFO_PAUSE | | |
79 | #ifdef CONFIG_PM | |
80 | SNDRV_PCM_INFO_RESUME | | |
81 | #endif | |
82 | SNDRV_PCM_INFO_SYNC_START), | |
705ececd MG |
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, | |
1027f476 | 90 | .period_bytes_min = 64, |
705ececd MG |
91 | .period_bytes_max = 8192, |
92 | .periods_min = 1, | |
93 | .periods_max = 1024 | |
94 | }, | |
1027f476 | 95 | .snd_line6_capture_hw = { |
705ececd | 96 | .info = (SNDRV_PCM_INFO_MMAP | |
1027f476 MG |
97 | SNDRV_PCM_INFO_INTERLEAVED | |
98 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | |
99 | SNDRV_PCM_INFO_MMAP_VALID | | |
100 | #ifdef CONFIG_PM | |
101 | SNDRV_PCM_INFO_RESUME | | |
102 | #endif | |
103 | SNDRV_PCM_INFO_SYNC_START), | |
705ececd MG |
104 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, |
105 | .rates = SNDRV_PCM_RATE_KNOT, | |
106 | .rate_min = 39062, | |
107 | .rate_max = 39063, | |
108 | .channels_min = 2, | |
109 | .channels_max = 2, | |
110 | .buffer_bytes_max = 60000, | |
1027f476 | 111 | .period_bytes_min = 64, |
705ececd MG |
112 | .period_bytes_max = 8192, |
113 | .periods_min = 1, | |
114 | .periods_max = 1024 | |
115 | }, | |
116 | .snd_line6_rates = { | |
117 | .nrats = 1, | |
118 | .rats = &pod_ratden | |
119 | }, | |
120 | .bytes_per_frame = POD_BYTES_PER_FRAME | |
121 | }; | |
122 | ||
1027f476 MG |
123 | static const char pod_request_channel[] = { |
124 | 0xf0, 0x00, 0x01, 0x0c, 0x03, 0x75, 0xf7 | |
125 | }; | |
126 | ||
127 | static const char pod_version_header[] = { | |
128 | 0xf2, 0x7e, 0x7f, 0x06, 0x02 | |
129 | }; | |
130 | ||
131 | ||
132 | /* forward declarations: */ | |
133 | static void pod_startup2(unsigned long data); | |
134 | static void pod_startup3(struct usb_line6_pod *pod); | |
135 | static void pod_startup4(struct usb_line6_pod *pod); | |
705ececd MG |
136 | |
137 | ||
138 | /* | |
139 | Mark all parameters as dirty and notify waiting processes. | |
140 | */ | |
141 | static void pod_mark_batch_all_dirty(struct usb_line6_pod *pod) | |
142 | { | |
143 | int i; | |
144 | ||
e1769b3c | 145 | for (i = 0; i < POD_CONTROL_SIZE; i++) |
705ececd MG |
146 | set_bit(i, pod->param_dirty); |
147 | } | |
148 | ||
705ececd MG |
149 | static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code, int size) |
150 | { | |
151 | return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code, size); | |
152 | } | |
153 | ||
154 | /* | |
155 | Send channel dump data to the PODxt Pro. | |
156 | */ | |
157 | static void pod_dump(struct usb_line6_pod *pod, const unsigned char *data) | |
158 | { | |
159 | int size = 1 + sizeof(pod->prog_data); | |
160 | char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_DUMP, size); | |
0fdef36a GKH |
161 | if (!sysex) |
162 | return; | |
163 | /* Don't know what this is good for, but PODxt Pro transmits it, so we | |
164 | * also do... */ | |
165 | sysex[SYSEX_DATA_OFS] = 5; | |
705ececd MG |
166 | memcpy(sysex + SYSEX_DATA_OFS + 1, data, sizeof(pod->prog_data)); |
167 | line6_send_sysex_message(&pod->line6, sysex, size); | |
168 | memcpy(&pod->prog_data, data, sizeof(pod->prog_data)); | |
169 | pod_mark_batch_all_dirty(pod); | |
170 | kfree(sysex); | |
171 | } | |
172 | ||
173 | /* | |
174 | Store parameter value in driver memory and mark it as dirty. | |
175 | */ | |
176 | static void pod_store_parameter(struct usb_line6_pod *pod, int param, int value) | |
177 | { | |
178 | pod->prog_data.control[param] = value; | |
179 | set_bit(param, pod->param_dirty); | |
180 | pod->dirty = 1; | |
181 | } | |
182 | ||
183 | /* | |
1027f476 | 184 | Handle SAVE button. |
705ececd MG |
185 | */ |
186 | static void pod_save_button_pressed(struct usb_line6_pod *pod, int type, int index) | |
187 | { | |
188 | pod->dirty = 0; | |
189 | set_bit(POD_SAVE_PRESSED, &pod->atomic_flags); | |
190 | } | |
191 | ||
192 | /* | |
193 | Process a completely received message. | |
194 | */ | |
1027f476 | 195 | void line6_pod_process_message(struct usb_line6_pod *pod) |
705ececd MG |
196 | { |
197 | const unsigned char *buf = pod->line6.buffer_message; | |
198 | ||
199 | /* filter messages by type */ | |
0fdef36a | 200 | switch (buf[0] & 0xf0) { |
705ececd MG |
201 | case LINE6_PARAM_CHANGE: |
202 | case LINE6_PROGRAM_CHANGE: | |
203 | case LINE6_SYSEX_BEGIN: | |
204 | break; /* handle these further down */ | |
205 | ||
206 | default: | |
207 | return; /* ignore all others */ | |
208 | } | |
209 | ||
210 | /* process all remaining messages */ | |
0fdef36a | 211 | switch (buf[0]) { |
705ececd MG |
212 | case LINE6_PARAM_CHANGE | LINE6_CHANNEL_DEVICE: |
213 | pod_store_parameter(pod, buf[1], buf[2]); | |
214 | /* intentionally no break here! */ | |
215 | ||
216 | case LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST: | |
0fdef36a GKH |
217 | if ((buf[1] == POD_amp_model_setup) || |
218 | (buf[1] == POD_effect_setup)) | |
219 | /* these also affect other settings */ | |
1027f476 | 220 | line6_dump_request_async(&pod->dumpreq, &pod->line6, 0, LINE6_DUMP_CURRENT); |
705ececd MG |
221 | |
222 | break; | |
223 | ||
224 | case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_DEVICE: | |
225 | case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST: | |
226 | pod->channel_num = buf[1]; | |
227 | pod->dirty = 0; | |
228 | set_bit(POD_CHANNEL_DIRTY, &pod->atomic_flags); | |
1027f476 | 229 | line6_dump_request_async(&pod->dumpreq, &pod->line6, 0, LINE6_DUMP_CURRENT); |
705ececd MG |
230 | break; |
231 | ||
232 | case LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE: | |
233 | case LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN: | |
0fdef36a GKH |
234 | if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) == 0) { |
235 | switch (buf[5]) { | |
705ececd | 236 | case POD_SYSEX_DUMP: |
0fdef36a GKH |
237 | if (pod->line6.message_length == sizeof(pod->prog_data) + 7) { |
238 | switch (pod->dumpreq.in_progress) { | |
705ececd MG |
239 | case LINE6_DUMP_CURRENT: |
240 | memcpy(&pod->prog_data, buf + 7, sizeof(pod->prog_data)); | |
241 | pod_mark_batch_all_dirty(pod); | |
705ececd MG |
242 | break; |
243 | ||
244 | case POD_DUMP_MEMORY: | |
245 | memcpy(&pod->prog_data_buf, buf + 7, sizeof(pod->prog_data_buf)); | |
246 | break; | |
247 | ||
248 | default: | |
249 | DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "unknown dump code %02X\n", pod->dumpreq.in_progress)); | |
250 | } | |
251 | ||
252 | line6_dump_finished(&pod->dumpreq); | |
1027f476 | 253 | pod_startup3(pod); |
0fdef36a | 254 | } else |
705ececd MG |
255 | DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "wrong size of channel dump message (%d instead of %d)\n", |
256 | pod->line6.message_length, (int)sizeof(pod->prog_data) + 7)); | |
257 | ||
258 | break; | |
259 | ||
260 | case POD_SYSEX_SYSTEM: { | |
261 | short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) | ((int)buf[9] << 4) | (int)buf[10]; | |
262 | ||
263 | #define PROCESS_SYSTEM_PARAM(x) \ | |
264 | case POD_ ## x: \ | |
265 | pod->x.value = value; \ | |
1027f476 | 266 | wake_up(&pod->x.wait); \ |
705ececd MG |
267 | break; |
268 | ||
0fdef36a | 269 | switch (buf[6]) { |
705ececd MG |
270 | PROCESS_SYSTEM_PARAM(monitor_level); |
271 | PROCESS_SYSTEM_PARAM(routing); | |
272 | PROCESS_SYSTEM_PARAM(tuner_mute); | |
273 | PROCESS_SYSTEM_PARAM(tuner_freq); | |
274 | PROCESS_SYSTEM_PARAM(tuner_note); | |
275 | PROCESS_SYSTEM_PARAM(tuner_pitch); | |
276 | ||
277 | #undef PROCESS_SYSTEM_PARAM | |
278 | ||
279 | default: | |
280 | DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "unknown tuner/system response %02X\n", buf[6])); | |
281 | } | |
282 | ||
283 | break; | |
284 | } | |
285 | ||
286 | case POD_SYSEX_FINISH: | |
287 | /* do we need to respond to this? */ | |
288 | break; | |
289 | ||
290 | case POD_SYSEX_SAVE: | |
291 | pod_save_button_pressed(pod, buf[6], buf[7]); | |
292 | break; | |
293 | ||
294 | case POD_SYSEX_CLIP: | |
295 | DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "audio clipped\n")); | |
296 | pod->clipping.value = 1; | |
1027f476 | 297 | wake_up(&pod->clipping.wait); |
705ececd MG |
298 | break; |
299 | ||
300 | case POD_SYSEX_STORE: | |
301 | DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "message %02X not yet implemented\n", buf[5])); | |
302 | break; | |
303 | ||
304 | default: | |
305 | DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "unknown sysex message %02X\n", buf[5])); | |
306 | } | |
0fdef36a | 307 | } else if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) { |
1027f476 MG |
308 | pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15]; |
309 | pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) | (int)buf[10]; | |
310 | pod_startup4(pod); | |
0fdef36a | 311 | } else |
705ececd MG |
312 | DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "unknown sysex header\n")); |
313 | ||
314 | break; | |
315 | ||
316 | case LINE6_SYSEX_END: | |
317 | break; | |
318 | ||
319 | default: | |
320 | DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "POD: unknown message %02X\n", buf[0])); | |
321 | } | |
322 | } | |
323 | ||
324 | /* | |
325 | Detect some cases that require a channel dump after sending a command to the | |
326 | device. Important notes: | |
327 | *) The actual dump request can not be sent here since we are not allowed to | |
328 | wait for the completion of the first message in this context, and sending | |
329 | the dump request before completion of the previous message leaves the POD | |
330 | in an undefined state. The dump request will be sent when the echoed | |
331 | commands are received. | |
332 | *) This method fails if a param change message is "chopped" after the first | |
333 | byte. | |
334 | */ | |
1027f476 | 335 | void line6_pod_midi_postprocess(struct usb_line6_pod *pod, unsigned char *data, int length) |
705ececd MG |
336 | { |
337 | int i; | |
338 | ||
0fdef36a | 339 | if (!pod->midi_postprocess) |
705ececd MG |
340 | return; |
341 | ||
0fdef36a GKH |
342 | for (i = 0; i < length; ++i) { |
343 | if (data[i] == (LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST)) { | |
705ececd MG |
344 | line6_invalidate_current(&pod->dumpreq); |
345 | break; | |
0fdef36a GKH |
346 | } else if ((data[i] == (LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST)) && (i < length - 1)) |
347 | if ((data[i + 1] == POD_amp_model_setup) || (data[i + 1] == POD_effect_setup)) { | |
705ececd MG |
348 | line6_invalidate_current(&pod->dumpreq); |
349 | break; | |
350 | } | |
351 | } | |
352 | } | |
353 | ||
354 | /* | |
355 | Send channel number (i.e., switch to a different sound). | |
356 | */ | |
b702ed25 | 357 | static void pod_send_channel(struct usb_line6_pod *pod, int value) |
705ececd MG |
358 | { |
359 | line6_invalidate_current(&pod->dumpreq); | |
360 | ||
0fdef36a | 361 | if (line6_send_program(&pod->line6, value) == 0) |
705ececd MG |
362 | pod->channel_num = value; |
363 | else | |
364 | line6_dump_finished(&pod->dumpreq); | |
365 | } | |
366 | ||
367 | /* | |
368 | Transmit PODxt Pro control parameter. | |
369 | */ | |
1027f476 | 370 | void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param, int value) |
705ececd | 371 | { |
0fdef36a | 372 | if (line6_transmit_parameter(&pod->line6, param, value) == 0) |
705ececd MG |
373 | pod_store_parameter(pod, param, value); |
374 | ||
0fdef36a | 375 | if ((param == POD_amp_model_setup) || (param == POD_effect_setup)) /* these also affect other settings */ |
705ececd MG |
376 | line6_invalidate_current(&pod->dumpreq); |
377 | } | |
378 | ||
379 | /* | |
380 | Resolve value to memory location. | |
381 | */ | |
7e4d5c13 | 382 | static int pod_resolve(const char *buf, short block0, short block1, unsigned char *location) |
705ececd | 383 | { |
7e4d5c13 SB |
384 | unsigned long value; |
385 | short block; | |
386 | int ret; | |
387 | ||
388 | ret = strict_strtoul(buf, 10, &value); | |
389 | if (ret) | |
390 | return ret; | |
391 | ||
392 | block = (value < 0x40) ? block0 : block1; | |
705ececd MG |
393 | value &= 0x3f; |
394 | location[0] = block >> 7; | |
395 | location[1] = value | (block & 0x7f); | |
7e4d5c13 | 396 | return 0; |
705ececd MG |
397 | } |
398 | ||
399 | /* | |
400 | Send command to store channel/effects setup/amp setup to PODxt Pro. | |
401 | */ | |
402 | static ssize_t pod_send_store_command(struct device *dev, const char *buf, size_t count, short block0, short block1) | |
403 | { | |
404 | struct usb_interface *interface = to_usb_interface(dev); | |
405 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | |
7e4d5c13 | 406 | int ret; |
705ececd MG |
407 | int size = 3 + sizeof(pod->prog_data_buf); |
408 | char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_STORE, size); | |
7e4d5c13 | 409 | |
0fdef36a GKH |
410 | if (!sysex) |
411 | return 0; | |
705ececd MG |
412 | |
413 | sysex[SYSEX_DATA_OFS] = 5; /* see pod_dump() */ | |
7e4d5c13 SB |
414 | ret = pod_resolve(buf, block0, block1, sysex + SYSEX_DATA_OFS + 1); |
415 | if (ret) { | |
416 | kfree(sysex); | |
417 | return ret; | |
418 | } | |
419 | ||
705ececd MG |
420 | memcpy(sysex + SYSEX_DATA_OFS + 3, &pod->prog_data_buf, sizeof(pod->prog_data_buf)); |
421 | ||
422 | line6_send_sysex_message(&pod->line6, sysex, size); | |
423 | kfree(sysex); | |
424 | /* needs some delay here on AMD64 platform */ | |
425 | return count; | |
426 | } | |
427 | ||
428 | /* | |
429 | Send command to retrieve channel/effects setup/amp setup to PODxt Pro. | |
430 | */ | |
431 | static ssize_t pod_send_retrieve_command(struct device *dev, const char *buf, size_t count, short block0, short block1) | |
432 | { | |
433 | struct usb_interface *interface = to_usb_interface(dev); | |
434 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | |
7e4d5c13 | 435 | int ret; |
705ececd MG |
436 | int size = 4; |
437 | char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_DUMPMEM, size); | |
0fdef36a GKH |
438 | |
439 | if (!sysex) | |
440 | return 0; | |
705ececd | 441 | |
7e4d5c13 SB |
442 | ret = pod_resolve(buf, block0, block1, sysex + SYSEX_DATA_OFS); |
443 | if (ret) { | |
444 | kfree(sysex); | |
445 | return ret; | |
446 | } | |
705ececd MG |
447 | sysex[SYSEX_DATA_OFS + 2] = 0; |
448 | sysex[SYSEX_DATA_OFS + 3] = 0; | |
449 | line6_dump_started(&pod->dumpreq, POD_DUMP_MEMORY); | |
450 | ||
0fdef36a | 451 | if (line6_send_sysex_message(&pod->line6, sysex, size) < size) |
705ececd MG |
452 | line6_dump_finished(&pod->dumpreq); |
453 | ||
454 | kfree(sysex); | |
455 | /* needs some delay here on AMD64 platform */ | |
456 | return count; | |
457 | } | |
458 | ||
459 | /* | |
460 | Generic get name function. | |
461 | */ | |
462 | static ssize_t get_name_generic(struct usb_line6_pod *pod, const char *str, char *buf) | |
463 | { | |
464 | int length = 0; | |
465 | const char *p1; | |
466 | char *p2; | |
467 | char *last_non_space = buf; | |
468 | ||
1027f476 | 469 | int retval = line6_dump_wait_interruptible(&pod->dumpreq); |
0fdef36a GKH |
470 | if (retval < 0) |
471 | return retval; | |
705ececd | 472 | |
0fdef36a | 473 | for (p1 = str, p2 = buf; *p1; ++p1, ++p2) { |
705ececd | 474 | *p2 = *p1; |
0fdef36a GKH |
475 | if (*p2 != ' ') |
476 | last_non_space = p2; | |
477 | if (++length == POD_NAME_LENGTH) | |
478 | break; | |
705ececd MG |
479 | } |
480 | ||
481 | *(last_non_space + 1) = '\n'; | |
482 | return last_non_space - buf + 2; | |
483 | } | |
484 | ||
485 | /* | |
486 | "read" request on "channel" special file. | |
487 | */ | |
77491e52 GKH |
488 | static ssize_t pod_get_channel(struct device *dev, |
489 | struct device_attribute *attr, char *buf) | |
705ececd MG |
490 | { |
491 | struct usb_interface *interface = to_usb_interface(dev); | |
492 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | |
493 | return sprintf(buf, "%d\n", pod->channel_num); | |
494 | } | |
495 | ||
496 | /* | |
497 | "write" request on "channel" special file. | |
498 | */ | |
77491e52 GKH |
499 | static ssize_t pod_set_channel(struct device *dev, |
500 | struct device_attribute *attr, | |
501 | const char *buf, size_t count) | |
705ececd MG |
502 | { |
503 | struct usb_interface *interface = to_usb_interface(dev); | |
504 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | |
7e4d5c13 SB |
505 | unsigned long value; |
506 | int ret; | |
507 | ||
508 | ret = strict_strtoul(buf, 10, &value); | |
509 | if (ret) | |
510 | return ret; | |
511 | ||
705ececd MG |
512 | pod_send_channel(pod, value); |
513 | return count; | |
514 | } | |
515 | ||
516 | /* | |
517 | "read" request on "name" special file. | |
518 | */ | |
77491e52 GKH |
519 | static ssize_t pod_get_name(struct device *dev, struct device_attribute *attr, |
520 | char *buf) | |
705ececd MG |
521 | { |
522 | struct usb_interface *interface = to_usb_interface(dev); | |
523 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | |
524 | return get_name_generic(pod, pod->prog_data.header + POD_NAME_OFFSET, buf); | |
525 | } | |
526 | ||
527 | /* | |
528 | "read" request on "name" special file. | |
529 | */ | |
77491e52 GKH |
530 | static ssize_t pod_get_name_buf(struct device *dev, |
531 | struct device_attribute *attr, char *buf) | |
705ececd MG |
532 | { |
533 | struct usb_interface *interface = to_usb_interface(dev); | |
534 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | |
535 | return get_name_generic(pod, pod->prog_data_buf.header + POD_NAME_OFFSET, buf); | |
536 | } | |
537 | ||
538 | /* | |
539 | "read" request on "dump" special file. | |
540 | */ | |
77491e52 GKH |
541 | static ssize_t pod_get_dump(struct device *dev, struct device_attribute *attr, |
542 | char *buf) | |
705ececd MG |
543 | { |
544 | struct usb_interface *interface = to_usb_interface(dev); | |
545 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | |
1027f476 | 546 | int retval = line6_dump_wait_interruptible(&pod->dumpreq); |
0fdef36a GKH |
547 | if (retval < 0) |
548 | return retval; | |
705ececd MG |
549 | memcpy(buf, &pod->prog_data, sizeof(pod->prog_data)); |
550 | return sizeof(pod->prog_data); | |
551 | } | |
552 | ||
553 | /* | |
554 | "write" request on "dump" special file. | |
555 | */ | |
77491e52 GKH |
556 | static ssize_t pod_set_dump(struct device *dev, struct device_attribute *attr, |
557 | const char *buf, size_t count) | |
705ececd MG |
558 | { |
559 | struct usb_interface *interface = to_usb_interface(dev); | |
560 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | |
561 | ||
0fdef36a | 562 | if (count != sizeof(pod->prog_data)) { |
705ececd | 563 | dev_err(pod->line6.ifcdev, |
1027f476 MG |
564 | "data block must be exactly %d bytes\n", |
565 | (int)sizeof(pod->prog_data)); | |
705ececd MG |
566 | return -EINVAL; |
567 | } | |
568 | ||
569 | pod_dump(pod, buf); | |
570 | return sizeof(pod->prog_data); | |
571 | } | |
572 | ||
573 | /* | |
1027f476 MG |
574 | Identify system parameters related to the tuner. |
575 | */ | |
576 | static bool pod_is_tuner(int code) | |
577 | { | |
578 | return | |
579 | (code == POD_tuner_mute) || | |
580 | (code == POD_tuner_freq) || | |
581 | (code == POD_tuner_note) || | |
582 | (code == POD_tuner_pitch); | |
583 | } | |
584 | ||
585 | /* | |
586 | Get system parameter (as integer). | |
705ececd MG |
587 | @param tuner non-zero, if code refers to a tuner parameter |
588 | */ | |
1027f476 MG |
589 | static int pod_get_system_param_int(struct usb_line6_pod *pod, int *value, int code, |
590 | struct ValueWait *param, int sign) | |
705ececd MG |
591 | { |
592 | char *sysex; | |
705ececd MG |
593 | static const int size = 1; |
594 | int retval = 0; | |
705ececd | 595 | |
1027f476 | 596 | if (((pod->prog_data.control[POD_tuner] & 0x40) == 0) && pod_is_tuner(code)) |
705ececd MG |
597 | return -ENODEV; |
598 | ||
1027f476 | 599 | /* send value request to device: */ |
705ececd MG |
600 | param->value = POD_system_invalid; |
601 | sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEMREQ, size); | |
1027f476 | 602 | |
0fdef36a | 603 | if (!sysex) |
1027f476 MG |
604 | return -ENOMEM; |
605 | ||
705ececd MG |
606 | sysex[SYSEX_DATA_OFS] = code; |
607 | line6_send_sysex_message(&pod->line6, sysex, size); | |
608 | kfree(sysex); | |
609 | ||
1027f476 MG |
610 | /* wait for device to respond: */ |
611 | retval = wait_event_interruptible(param->wait, param->value != POD_system_invalid); | |
705ececd | 612 | |
1027f476 MG |
613 | if (retval < 0) |
614 | return retval; | |
705ececd | 615 | |
1027f476 | 616 | *value = sign ? (int)(signed short)param->value : (int)(unsigned short)param->value; |
705ececd | 617 | |
1027f476 MG |
618 | if(*value == POD_system_invalid) |
619 | *value = 0; /* don't report uninitialized values */ | |
620 | ||
621 | return 0; | |
622 | } | |
623 | ||
624 | /* | |
625 | Get system parameter (as string). | |
626 | @param tuner non-zero, if code refers to a tuner parameter | |
627 | */ | |
628 | static ssize_t pod_get_system_param_string(struct usb_line6_pod *pod, char *buf, int code, | |
629 | struct ValueWait *param, int sign) | |
630 | { | |
631 | int retval, value = 0; | |
632 | retval = pod_get_system_param_int(pod, &value, code, param, sign); | |
633 | ||
634 | if(retval < 0) | |
705ececd MG |
635 | return retval; |
636 | ||
705ececd MG |
637 | return sprintf(buf, "%d\n", value); |
638 | } | |
639 | ||
640 | /* | |
1027f476 | 641 | Send system parameter (from integer). |
705ececd MG |
642 | @param tuner non-zero, if code refers to a tuner parameter |
643 | */ | |
1027f476 | 644 | static int pod_set_system_param_int(struct usb_line6_pod *pod, int value, int code) |
705ececd MG |
645 | { |
646 | char *sysex; | |
647 | static const int size = 5; | |
705ececd | 648 | |
1027f476 | 649 | if (((pod->prog_data.control[POD_tuner] & 0x40) == 0) && pod_is_tuner(code)) |
705ececd MG |
650 | return -EINVAL; |
651 | ||
652 | /* send value to tuner: */ | |
653 | sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size); | |
0fdef36a | 654 | if (!sysex) |
1027f476 | 655 | return -ENOMEM; |
705ececd MG |
656 | sysex[SYSEX_DATA_OFS] = code; |
657 | sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f; | |
658 | sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f; | |
659 | sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f; | |
660 | sysex[SYSEX_DATA_OFS + 4] = (value ) & 0x0f; | |
661 | line6_send_sysex_message(&pod->line6, sysex, size); | |
662 | kfree(sysex); | |
1027f476 MG |
663 | return 0; |
664 | } | |
665 | ||
666 | /* | |
667 | Send system parameter (from string). | |
668 | @param tuner non-zero, if code refers to a tuner parameter | |
669 | */ | |
670 | static ssize_t pod_set_system_param_string(struct usb_line6_pod *pod, const char *buf, | |
671 | int count, int code, unsigned short mask) | |
672 | { | |
673 | int retval; | |
674 | unsigned short value = simple_strtoul(buf, NULL, 10) & mask; | |
675 | retval = pod_set_system_param_int(pod, value, code); | |
676 | return (retval < 0) ? retval : count; | |
705ececd MG |
677 | } |
678 | ||
679 | /* | |
680 | "read" request on "dump_buf" special file. | |
681 | */ | |
77491e52 GKH |
682 | static ssize_t pod_get_dump_buf(struct device *dev, |
683 | struct device_attribute *attr, char *buf) | |
705ececd MG |
684 | { |
685 | struct usb_interface *interface = to_usb_interface(dev); | |
686 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | |
1027f476 | 687 | int retval = line6_dump_wait_interruptible(&pod->dumpreq); |
0fdef36a GKH |
688 | if (retval < 0) |
689 | return retval; | |
705ececd MG |
690 | memcpy(buf, &pod->prog_data_buf, sizeof(pod->prog_data_buf)); |
691 | return sizeof(pod->prog_data_buf); | |
692 | } | |
693 | ||
694 | /* | |
695 | "write" request on "dump_buf" special file. | |
696 | */ | |
77491e52 GKH |
697 | static ssize_t pod_set_dump_buf(struct device *dev, |
698 | struct device_attribute *attr, | |
699 | const char *buf, size_t count) | |
705ececd MG |
700 | { |
701 | struct usb_interface *interface = to_usb_interface(dev); | |
702 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | |
703 | ||
0fdef36a | 704 | if (count != sizeof(pod->prog_data)) { |
705ececd | 705 | dev_err(pod->line6.ifcdev, |
1027f476 MG |
706 | "data block must be exactly %d bytes\n", |
707 | (int)sizeof(pod->prog_data)); | |
705ececd MG |
708 | return -EINVAL; |
709 | } | |
710 | ||
711 | memcpy(&pod->prog_data_buf, buf, sizeof(pod->prog_data)); | |
712 | return sizeof(pod->prog_data); | |
713 | } | |
714 | ||
715 | /* | |
716 | "write" request on "finish" special file. | |
717 | */ | |
77491e52 GKH |
718 | static ssize_t pod_set_finish(struct device *dev, |
719 | struct device_attribute *attr, | |
720 | const char *buf, size_t count) | |
705ececd MG |
721 | { |
722 | struct usb_interface *interface = to_usb_interface(dev); | |
723 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | |
724 | int size = 0; | |
725 | char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_FINISH, size); | |
0fdef36a GKH |
726 | if (!sysex) |
727 | return 0; | |
705ececd MG |
728 | line6_send_sysex_message(&pod->line6, sysex, size); |
729 | kfree(sysex); | |
730 | return count; | |
731 | } | |
732 | ||
733 | /* | |
734 | "write" request on "store_channel" special file. | |
735 | */ | |
77491e52 GKH |
736 | static ssize_t pod_set_store_channel(struct device *dev, |
737 | struct device_attribute *attr, | |
738 | const char *buf, size_t count) | |
705ececd MG |
739 | { |
740 | return pod_send_store_command(dev, buf, count, 0x0000, 0x00c0); | |
741 | } | |
742 | ||
743 | /* | |
744 | "write" request on "store_effects_setup" special file. | |
745 | */ | |
77491e52 GKH |
746 | static ssize_t pod_set_store_effects_setup(struct device *dev, |
747 | struct device_attribute *attr, | |
748 | const char *buf, size_t count) | |
705ececd MG |
749 | { |
750 | return pod_send_store_command(dev, buf, count, 0x0080, 0x0080); | |
751 | } | |
752 | ||
753 | /* | |
754 | "write" request on "store_amp_setup" special file. | |
755 | */ | |
77491e52 GKH |
756 | static ssize_t pod_set_store_amp_setup(struct device *dev, |
757 | struct device_attribute *attr, | |
758 | const char *buf, size_t count) | |
705ececd MG |
759 | { |
760 | return pod_send_store_command(dev, buf, count, 0x0040, 0x0100); | |
761 | } | |
762 | ||
763 | /* | |
764 | "write" request on "retrieve_channel" special file. | |
765 | */ | |
77491e52 GKH |
766 | static ssize_t pod_set_retrieve_channel(struct device *dev, |
767 | struct device_attribute *attr, | |
768 | const char *buf, size_t count) | |
705ececd MG |
769 | { |
770 | return pod_send_retrieve_command(dev, buf, count, 0x0000, 0x00c0); | |
771 | } | |
772 | ||
773 | /* | |
774 | "write" request on "retrieve_effects_setup" special file. | |
775 | */ | |
77491e52 GKH |
776 | static ssize_t pod_set_retrieve_effects_setup(struct device *dev, |
777 | struct device_attribute *attr, | |
778 | const char *buf, size_t count) | |
705ececd MG |
779 | { |
780 | return pod_send_retrieve_command(dev, buf, count, 0x0080, 0x0080); | |
781 | } | |
782 | ||
783 | /* | |
784 | "write" request on "retrieve_amp_setup" special file. | |
785 | */ | |
77491e52 GKH |
786 | static ssize_t pod_set_retrieve_amp_setup(struct device *dev, |
787 | struct device_attribute *attr, | |
788 | const char *buf, size_t count) | |
705ececd MG |
789 | { |
790 | return pod_send_retrieve_command(dev, buf, count, 0x0040, 0x0100); | |
791 | } | |
792 | ||
793 | /* | |
794 | "read" request on "dirty" special file. | |
795 | */ | |
77491e52 GKH |
796 | static ssize_t pod_get_dirty(struct device *dev, struct device_attribute *attr, |
797 | char *buf) | |
705ececd MG |
798 | { |
799 | struct usb_interface *interface = to_usb_interface(dev); | |
800 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | |
801 | buf[0] = pod->dirty ? '1' : '0'; | |
802 | buf[1] = '\n'; | |
803 | return 2; | |
804 | } | |
805 | ||
806 | /* | |
807 | "read" request on "midi_postprocess" special file. | |
808 | */ | |
77491e52 GKH |
809 | static ssize_t pod_get_midi_postprocess(struct device *dev, |
810 | struct device_attribute *attr, | |
811 | char *buf) | |
705ececd MG |
812 | { |
813 | struct usb_interface *interface = to_usb_interface(dev); | |
814 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | |
815 | return sprintf(buf, "%d\n", pod->midi_postprocess); | |
816 | } | |
817 | ||
818 | /* | |
819 | "write" request on "midi_postprocess" special file. | |
820 | */ | |
77491e52 GKH |
821 | static ssize_t pod_set_midi_postprocess(struct device *dev, |
822 | struct device_attribute *attr, | |
823 | const char *buf, size_t count) | |
705ececd MG |
824 | { |
825 | struct usb_interface *interface = to_usb_interface(dev); | |
826 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | |
7e4d5c13 SB |
827 | unsigned long value; |
828 | int ret; | |
829 | ||
830 | ret = strict_strtoul(buf, 10, &value); | |
831 | if (ret) | |
832 | return ret; | |
833 | ||
705ececd MG |
834 | pod->midi_postprocess = value ? 1 : 0; |
835 | return count; | |
836 | } | |
837 | ||
838 | /* | |
839 | "read" request on "serial_number" special file. | |
840 | */ | |
77491e52 GKH |
841 | static ssize_t pod_get_serial_number(struct device *dev, |
842 | struct device_attribute *attr, char *buf) | |
705ececd MG |
843 | { |
844 | struct usb_interface *interface = to_usb_interface(dev); | |
845 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | |
846 | return sprintf(buf, "%d\n", pod->serial_number); | |
847 | } | |
848 | ||
849 | /* | |
850 | "read" request on "firmware_version" special file. | |
851 | */ | |
77491e52 GKH |
852 | static ssize_t pod_get_firmware_version(struct device *dev, |
853 | struct device_attribute *attr, | |
854 | char *buf) | |
705ececd MG |
855 | { |
856 | struct usb_interface *interface = to_usb_interface(dev); | |
857 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | |
0fdef36a GKH |
858 | return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100, |
859 | pod->firmware_version % 100); | |
705ececd MG |
860 | } |
861 | ||
862 | /* | |
863 | "read" request on "device_id" special file. | |
864 | */ | |
77491e52 GKH |
865 | static ssize_t pod_get_device_id(struct device *dev, |
866 | struct device_attribute *attr, char *buf) | |
705ececd MG |
867 | { |
868 | struct usb_interface *interface = to_usb_interface(dev); | |
869 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | |
870 | return sprintf(buf, "%d\n", pod->device_id); | |
871 | } | |
872 | ||
873 | /* | |
874 | "read" request on "clip" special file. | |
875 | */ | |
77491e52 GKH |
876 | static ssize_t pod_wait_for_clip(struct device *dev, |
877 | struct device_attribute *attr, char *buf) | |
705ececd MG |
878 | { |
879 | struct usb_interface *interface = to_usb_interface(dev); | |
880 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | |
1027f476 MG |
881 | return wait_event_interruptible(pod->clipping.wait, pod->clipping.value != 0); |
882 | } | |
705ececd | 883 | |
1027f476 MG |
884 | /* |
885 | POD startup procedure. | |
886 | This is a sequence of functions with special requirements (e.g., must | |
887 | not run immediately after initialization, must not run in interrupt | |
888 | context). After the last one has finished, the device is ready to use. | |
889 | */ | |
890 | ||
891 | static void pod_startup1(struct usb_line6_pod *pod) | |
892 | { | |
893 | CHECK_STARTUP_PROGRESS(pod->startup_progress, 1); | |
894 | ||
895 | /* delay startup procedure: */ | |
896 | line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2, (unsigned long)pod); | |
897 | } | |
898 | ||
899 | static void pod_startup2(unsigned long data) | |
900 | { | |
901 | struct usb_line6_pod *pod = (struct usb_line6_pod *)data; | |
902 | CHECK_STARTUP_PROGRESS(pod->startup_progress, 2); | |
903 | ||
904 | /* current channel dump: */ | |
905 | line6_dump_request_async(&pod->dumpreq, &pod->line6, 0, LINE6_DUMP_CURRENT); | |
906 | } | |
907 | ||
908 | static void pod_startup3(struct usb_line6_pod *pod) | |
909 | { | |
910 | struct usb_line6 *line6 = &pod->line6; | |
911 | CHECK_STARTUP_PROGRESS(pod->startup_progress, 3); | |
912 | ||
913 | /* request firmware version: */ | |
914 | line6_version_request_async(line6); | |
705ececd MG |
915 | } |
916 | ||
1027f476 MG |
917 | static void pod_startup4(struct usb_line6_pod *pod) |
918 | { | |
919 | CHECK_STARTUP_PROGRESS(pod->startup_progress, 4); | |
920 | ||
921 | /* schedule work for global work queue: */ | |
922 | schedule_work(&pod->startup_work); | |
923 | } | |
924 | ||
925 | static void pod_startup5(struct work_struct *work) | |
926 | { | |
927 | struct usb_line6_pod *pod = container_of(work, struct usb_line6_pod, startup_work); | |
928 | struct usb_line6 *line6 = &pod->line6; | |
929 | ||
930 | CHECK_STARTUP_PROGRESS(pod->startup_progress, 5); | |
931 | ||
932 | /* serial number: */ | |
933 | line6_read_serial_number(&pod->line6, &pod->serial_number); | |
934 | ||
935 | /* ALSA audio interface: */ | |
936 | line6_register_audio(line6); | |
937 | ||
938 | /* device files: */ | |
939 | line6_pod_create_files(pod->firmware_version, line6->properties->device_bit, line6->ifcdev); | |
940 | } | |
941 | ||
942 | #define POD_GET_SYSTEM_PARAM(code, sign) \ | |
77491e52 GKH |
943 | static ssize_t pod_get_ ## code(struct device *dev, \ |
944 | struct device_attribute *attr, char *buf) \ | |
705ececd MG |
945 | { \ |
946 | struct usb_interface *interface = to_usb_interface(dev); \ | |
947 | struct usb_line6_pod *pod = usb_get_intfdata(interface); \ | |
1027f476 MG |
948 | return pod_get_system_param_string(pod, buf, POD_ ## code, \ |
949 | &pod->code, sign); \ | |
705ececd MG |
950 | } |
951 | ||
1027f476 MG |
952 | #define POD_GET_SET_SYSTEM_PARAM(code, mask, sign) \ |
953 | POD_GET_SYSTEM_PARAM(code, sign) \ | |
77491e52 | 954 | static ssize_t pod_set_ ## code(struct device *dev, \ |
0fdef36a GKH |
955 | struct device_attribute *attr, \ |
956 | const char *buf, size_t count) \ | |
705ececd MG |
957 | { \ |
958 | struct usb_interface *interface = to_usb_interface(dev); \ | |
959 | struct usb_line6_pod *pod = usb_get_intfdata(interface); \ | |
1027f476 | 960 | return pod_set_system_param_string(pod, buf, count, POD_ ## code, mask); \ |
705ececd MG |
961 | } |
962 | ||
1027f476 MG |
963 | POD_GET_SET_SYSTEM_PARAM(monitor_level, 0xffff, 0); |
964 | POD_GET_SET_SYSTEM_PARAM(routing, 0x0003, 0); | |
965 | POD_GET_SET_SYSTEM_PARAM(tuner_mute, 0x0001, 0); | |
966 | POD_GET_SET_SYSTEM_PARAM(tuner_freq, 0xffff, 0); | |
967 | POD_GET_SYSTEM_PARAM(tuner_note, 1); | |
968 | POD_GET_SYSTEM_PARAM(tuner_pitch, 1); | |
705ececd MG |
969 | |
970 | #undef GET_SET_SYSTEM_PARAM | |
971 | #undef GET_SYSTEM_PARAM | |
972 | ||
973 | /* POD special files: */ | |
974 | static DEVICE_ATTR(channel, S_IWUGO | S_IRUGO, pod_get_channel, pod_set_channel); | |
975 | static DEVICE_ATTR(clip, S_IRUGO, pod_wait_for_clip, line6_nop_write); | |
976 | static DEVICE_ATTR(device_id, S_IRUGO, pod_get_device_id, line6_nop_write); | |
977 | static DEVICE_ATTR(dirty, S_IRUGO, pod_get_dirty, line6_nop_write); | |
978 | static DEVICE_ATTR(dump, S_IWUGO | S_IRUGO, pod_get_dump, pod_set_dump); | |
979 | static DEVICE_ATTR(dump_buf, S_IWUGO | S_IRUGO, pod_get_dump_buf, pod_set_dump_buf); | |
980 | static DEVICE_ATTR(finish, S_IWUGO, line6_nop_read, pod_set_finish); | |
981 | static DEVICE_ATTR(firmware_version, S_IRUGO, pod_get_firmware_version, line6_nop_write); | |
982 | static DEVICE_ATTR(midi_postprocess, S_IWUGO | S_IRUGO, pod_get_midi_postprocess, pod_set_midi_postprocess); | |
983 | static DEVICE_ATTR(monitor_level, S_IWUGO | S_IRUGO, pod_get_monitor_level, pod_set_monitor_level); | |
984 | static DEVICE_ATTR(name, S_IRUGO, pod_get_name, line6_nop_write); | |
985 | static DEVICE_ATTR(name_buf, S_IRUGO, pod_get_name_buf, line6_nop_write); | |
986 | static DEVICE_ATTR(retrieve_amp_setup, S_IWUGO, line6_nop_read, pod_set_retrieve_amp_setup); | |
987 | static DEVICE_ATTR(retrieve_channel, S_IWUGO, line6_nop_read, pod_set_retrieve_channel); | |
988 | static DEVICE_ATTR(retrieve_effects_setup, S_IWUGO, line6_nop_read, pod_set_retrieve_effects_setup); | |
989 | static DEVICE_ATTR(routing, S_IWUGO | S_IRUGO, pod_get_routing, pod_set_routing); | |
990 | static DEVICE_ATTR(serial_number, S_IRUGO, pod_get_serial_number, line6_nop_write); | |
991 | static DEVICE_ATTR(store_amp_setup, S_IWUGO, line6_nop_read, pod_set_store_amp_setup); | |
992 | static DEVICE_ATTR(store_channel, S_IWUGO, line6_nop_read, pod_set_store_channel); | |
993 | static DEVICE_ATTR(store_effects_setup, S_IWUGO, line6_nop_read, pod_set_store_effects_setup); | |
994 | static DEVICE_ATTR(tuner_freq, S_IWUGO | S_IRUGO, pod_get_tuner_freq, pod_set_tuner_freq); | |
995 | static DEVICE_ATTR(tuner_mute, S_IWUGO | S_IRUGO, pod_get_tuner_mute, pod_set_tuner_mute); | |
996 | static DEVICE_ATTR(tuner_note, S_IRUGO, pod_get_tuner_note, line6_nop_write); | |
997 | static DEVICE_ATTR(tuner_pitch, S_IRUGO, pod_get_tuner_pitch, line6_nop_write); | |
998 | ||
1027f476 | 999 | #ifdef CONFIG_LINE6_USB_RAW |
705ececd MG |
1000 | static DEVICE_ATTR(raw, S_IWUGO, line6_nop_read, line6_set_raw); |
1001 | #endif | |
1002 | ||
1027f476 MG |
1003 | /* control info callback */ |
1004 | static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol, | |
1005 | struct snd_ctl_elem_info *uinfo) | |
1006 | { | |
1007 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |
1008 | uinfo->count = 1; | |
1009 | uinfo->value.integer.min = 0; | |
1010 | uinfo->value.integer.max = 65535; | |
1011 | return 0; | |
1012 | } | |
1013 | ||
1014 | /* control get callback */ | |
1015 | static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol, | |
1016 | struct snd_ctl_elem_value *ucontrol) | |
1017 | { | |
1018 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | |
1019 | struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6; | |
1020 | ucontrol->value.integer.value[0] = pod->monitor_level.value; | |
1021 | return 0; | |
1022 | } | |
1023 | ||
1024 | /* control put callback */ | |
1025 | static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol, | |
1026 | struct snd_ctl_elem_value *ucontrol) | |
1027 | { | |
1028 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | |
1029 | struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6; | |
1030 | ||
1031 | if(ucontrol->value.integer.value[0] == pod->monitor_level.value) | |
1032 | return 0; | |
1033 | ||
1034 | pod->monitor_level.value = ucontrol->value.integer.value[0]; | |
1035 | pod_set_system_param_int(pod, ucontrol->value.integer.value[0], POD_monitor_level); | |
1036 | return 1; | |
1037 | } | |
1038 | ||
1039 | /* control definition */ | |
1040 | static struct snd_kcontrol_new pod_control_monitor = { | |
1041 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
1042 | .name = "Monitor Playback Volume", | |
1043 | .index = 0, | |
1044 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | |
1045 | .info = snd_pod_control_monitor_info, | |
1046 | .get = snd_pod_control_monitor_get, | |
1047 | .put = snd_pod_control_monitor_put | |
1048 | }; | |
1049 | ||
705ececd MG |
1050 | /* |
1051 | POD destructor. | |
1052 | */ | |
1053 | static void pod_destruct(struct usb_interface *interface) | |
1054 | { | |
1055 | struct usb_line6_pod *pod = usb_get_intfdata(interface); | |
1056 | struct usb_line6 *line6; | |
1057 | ||
0fdef36a GKH |
1058 | if (pod == NULL) |
1059 | return; | |
705ececd | 1060 | line6 = &pod->line6; |
0fdef36a GKH |
1061 | if (line6 == NULL) |
1062 | return; | |
705ececd MG |
1063 | line6_cleanup_audio(line6); |
1064 | ||
1065 | /* free dump request data: */ | |
1066 | line6_dumpreq_destruct(&pod->dumpreq); | |
705ececd MG |
1067 | } |
1068 | ||
1069 | /* | |
1070 | Create sysfs entries. | |
1071 | */ | |
b702ed25 | 1072 | static int pod_create_files2(struct device *dev) |
705ececd MG |
1073 | { |
1074 | int err; | |
1075 | ||
1076 | CHECK_RETURN(device_create_file(dev, &dev_attr_channel)); | |
1077 | CHECK_RETURN(device_create_file(dev, &dev_attr_clip)); | |
1078 | CHECK_RETURN(device_create_file(dev, &dev_attr_device_id)); | |
1079 | CHECK_RETURN(device_create_file(dev, &dev_attr_dirty)); | |
1080 | CHECK_RETURN(device_create_file(dev, &dev_attr_dump)); | |
1081 | CHECK_RETURN(device_create_file(dev, &dev_attr_dump_buf)); | |
1082 | CHECK_RETURN(device_create_file(dev, &dev_attr_finish)); | |
1083 | CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version)); | |
1084 | CHECK_RETURN(device_create_file(dev, &dev_attr_midi_postprocess)); | |
1085 | CHECK_RETURN(device_create_file(dev, &dev_attr_monitor_level)); | |
1086 | CHECK_RETURN(device_create_file(dev, &dev_attr_name)); | |
1087 | CHECK_RETURN(device_create_file(dev, &dev_attr_name_buf)); | |
1088 | CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_amp_setup)); | |
1089 | CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_channel)); | |
1090 | CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_effects_setup)); | |
1091 | CHECK_RETURN(device_create_file(dev, &dev_attr_routing)); | |
1092 | CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number)); | |
1093 | CHECK_RETURN(device_create_file(dev, &dev_attr_store_amp_setup)); | |
1094 | CHECK_RETURN(device_create_file(dev, &dev_attr_store_channel)); | |
1095 | CHECK_RETURN(device_create_file(dev, &dev_attr_store_effects_setup)); | |
1096 | CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_freq)); | |
1097 | CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_mute)); | |
1098 | CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_note)); | |
1099 | CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_pitch)); | |
1100 | ||
1027f476 | 1101 | #ifdef CONFIG_LINE6_USB_RAW |
705ececd MG |
1102 | CHECK_RETURN(device_create_file(dev, &dev_attr_raw)); |
1103 | #endif | |
1104 | ||
1105 | return 0; | |
1106 | } | |
1107 | ||
1108 | /* | |
1027f476 | 1109 | Try to init POD device. |
705ececd | 1110 | */ |
1027f476 | 1111 | static int pod_try_init(struct usb_interface *interface, struct usb_line6_pod *pod) |
705ececd MG |
1112 | { |
1113 | int err; | |
1114 | struct usb_line6 *line6 = &pod->line6; | |
1115 | ||
0fdef36a GKH |
1116 | if ((interface == NULL) || (pod == NULL)) |
1117 | return -ENODEV; | |
705ececd MG |
1118 | |
1119 | pod->channel_num = 255; | |
1120 | ||
1121 | /* initialize wait queues: */ | |
1122 | init_waitqueue_head(&pod->monitor_level.wait); | |
1123 | init_waitqueue_head(&pod->routing.wait); | |
1124 | init_waitqueue_head(&pod->tuner_mute.wait); | |
1125 | init_waitqueue_head(&pod->tuner_freq.wait); | |
1126 | init_waitqueue_head(&pod->tuner_note.wait); | |
1127 | init_waitqueue_head(&pod->tuner_pitch.wait); | |
1128 | init_waitqueue_head(&pod->clipping.wait); | |
1027f476 MG |
1129 | init_timer(&pod->startup_timer); |
1130 | INIT_WORK(&pod->startup_work, pod_startup5); | |
705ececd MG |
1131 | |
1132 | memset(pod->param_dirty, 0xff, sizeof(pod->param_dirty)); | |
1133 | ||
1134 | /* initialize USB buffers: */ | |
0fdef36a GKH |
1135 | err = line6_dumpreq_init(&pod->dumpreq, pod_request_channel, |
1136 | sizeof(pod_request_channel)); | |
1137 | if (err < 0) { | |
705ececd | 1138 | dev_err(&interface->dev, "Out of memory\n"); |
705ececd MG |
1139 | return -ENOMEM; |
1140 | } | |
1141 | ||
705ececd | 1142 | /* create sysfs entries: */ |
0fdef36a GKH |
1143 | err = pod_create_files2(&interface->dev); |
1144 | if (err < 0) { | |
705ececd MG |
1145 | return err; |
1146 | } | |
1147 | ||
1148 | /* initialize audio system: */ | |
0fdef36a GKH |
1149 | err = line6_init_audio(line6); |
1150 | if (err < 0) { | |
705ececd MG |
1151 | return err; |
1152 | } | |
1153 | ||
1154 | /* initialize MIDI subsystem: */ | |
0fdef36a GKH |
1155 | err = line6_init_midi(line6); |
1156 | if (err < 0) { | |
705ececd MG |
1157 | return err; |
1158 | } | |
1159 | ||
1160 | /* initialize PCM subsystem: */ | |
0fdef36a GKH |
1161 | err = line6_init_pcm(line6, &pod_pcm_properties); |
1162 | if (err < 0) { | |
705ececd MG |
1163 | return err; |
1164 | } | |
1165 | ||
1027f476 MG |
1166 | /* register monitor control: */ |
1167 | err = snd_ctl_add(line6->card, snd_ctl_new1(&pod_control_monitor, line6->line6pcm)); | |
0fdef36a | 1168 | if (err < 0) { |
705ececd MG |
1169 | return err; |
1170 | } | |
1171 | ||
1027f476 MG |
1172 | /* |
1173 | When the sound card is registered at this point, the PODxt Live | |
1174 | displays "Invalid Code Error 07", so we do it later in the event | |
1175 | handler. | |
1176 | */ | |
1177 | ||
0fdef36a | 1178 | if (pod->line6.properties->capabilities & LINE6_BIT_CONTROL) { |
1027f476 MG |
1179 | pod->monitor_level.value = POD_system_invalid; |
1180 | ||
1181 | /* initiate startup procedure: */ | |
1182 | pod_startup1(pod); | |
705ececd MG |
1183 | } |
1184 | ||
1185 | return 0; | |
1186 | } | |
1187 | ||
1027f476 MG |
1188 | /* |
1189 | Init POD device (and clean up in case of failure). | |
1190 | */ | |
1191 | int line6_pod_init(struct usb_interface *interface, struct usb_line6_pod *pod) | |
1192 | { | |
1193 | int err = pod_try_init(interface, pod); | |
1194 | ||
1195 | if (err < 0) { | |
1196 | pod_destruct(interface); | |
1197 | } | |
1198 | ||
1199 | return err; | |
1200 | } | |
1201 | ||
705ececd MG |
1202 | /* |
1203 | POD device disconnected. | |
1204 | */ | |
1027f476 | 1205 | void line6_pod_disconnect(struct usb_interface *interface) |
705ececd MG |
1206 | { |
1207 | struct usb_line6_pod *pod; | |
1208 | ||
0fdef36a GKH |
1209 | if (interface == NULL) |
1210 | return; | |
705ececd MG |
1211 | pod = usb_get_intfdata(interface); |
1212 | ||
0fdef36a | 1213 | if (pod != NULL) { |
705ececd MG |
1214 | struct snd_line6_pcm *line6pcm = pod->line6.line6pcm; |
1215 | struct device *dev = &interface->dev; | |
1216 | ||
0fdef36a | 1217 | if (line6pcm != NULL) { |
1027f476 | 1218 | line6_pcm_disconnect(line6pcm); |
705ececd MG |
1219 | } |
1220 | ||
0fdef36a | 1221 | if (dev != NULL) { |
705ececd | 1222 | /* remove sysfs entries: */ |
1027f476 | 1223 | line6_pod_remove_files(pod->firmware_version, pod->line6.properties->device_bit, dev); |
705ececd MG |
1224 | |
1225 | device_remove_file(dev, &dev_attr_channel); | |
1226 | device_remove_file(dev, &dev_attr_clip); | |
1227 | device_remove_file(dev, &dev_attr_device_id); | |
1228 | device_remove_file(dev, &dev_attr_dirty); | |
1229 | device_remove_file(dev, &dev_attr_dump); | |
1230 | device_remove_file(dev, &dev_attr_dump_buf); | |
1231 | device_remove_file(dev, &dev_attr_finish); | |
1232 | device_remove_file(dev, &dev_attr_firmware_version); | |
1233 | device_remove_file(dev, &dev_attr_midi_postprocess); | |
1234 | device_remove_file(dev, &dev_attr_monitor_level); | |
1235 | device_remove_file(dev, &dev_attr_name); | |
1236 | device_remove_file(dev, &dev_attr_name_buf); | |
1237 | device_remove_file(dev, &dev_attr_retrieve_amp_setup); | |
1238 | device_remove_file(dev, &dev_attr_retrieve_channel); | |
1239 | device_remove_file(dev, &dev_attr_retrieve_effects_setup); | |
1240 | device_remove_file(dev, &dev_attr_routing); | |
1241 | device_remove_file(dev, &dev_attr_serial_number); | |
1242 | device_remove_file(dev, &dev_attr_store_amp_setup); | |
1243 | device_remove_file(dev, &dev_attr_store_channel); | |
1244 | device_remove_file(dev, &dev_attr_store_effects_setup); | |
1245 | device_remove_file(dev, &dev_attr_tuner_freq); | |
1246 | device_remove_file(dev, &dev_attr_tuner_mute); | |
1247 | device_remove_file(dev, &dev_attr_tuner_note); | |
1248 | device_remove_file(dev, &dev_attr_tuner_pitch); | |
1249 | ||
1027f476 | 1250 | #ifdef CONFIG_LINE6_USB_RAW |
705ececd MG |
1251 | device_remove_file(dev, &dev_attr_raw); |
1252 | #endif | |
1253 | } | |
1254 | } | |
1255 | ||
1256 | pod_destruct(interface); | |
1257 | } |