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