1 | // SPDX-License-Identifier: GPL-2.0-only |
2 | /* |
3 | * Line 6 Linux USB driver |
4 | * |
5 | * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) |
6 | */ |
7 | |
8 | #include <linux/slab.h> |
9 | #include <linux/wait.h> |
10 | #include <linux/interrupt.h> |
11 | #include <linux/module.h> |
12 | #include <linux/usb.h> |
13 | |
14 | #include <sound/core.h> |
15 | #include <sound/control.h> |
16 | |
17 | #include "capture.h" |
18 | #include "driver.h" |
19 | #include "playback.h" |
20 | |
21 | /* |
22 | Locate name in binary program dump |
23 | */ |
24 | #define POD_NAME_OFFSET 0 |
25 | #define POD_NAME_LENGTH 16 |
26 | |
27 | /* |
28 | Other constants |
29 | */ |
30 | #define POD_CONTROL_SIZE 0x80 |
31 | #define POD_BUFSIZE_DUMPREQ 7 |
32 | #define POD_STARTUP_DELAY 1000 |
33 | |
34 | /* |
35 | Stages of POD startup procedure |
36 | */ |
37 | enum { |
38 | POD_STARTUP_VERSIONREQ, |
39 | POD_STARTUP_SETUP, |
40 | POD_STARTUP_DONE, |
41 | }; |
42 | |
43 | enum { |
44 | LINE6_BASSPODXT, |
45 | LINE6_BASSPODXTLIVE, |
46 | LINE6_BASSPODXTPRO, |
47 | LINE6_POCKETPOD, |
48 | LINE6_PODXT, |
49 | LINE6_PODXTLIVE_POD, |
50 | LINE6_PODXTPRO, |
51 | }; |
52 | |
53 | struct usb_line6_pod { |
54 | /* Generic Line 6 USB data */ |
55 | struct usb_line6 line6; |
56 | |
57 | /* Instrument monitor level */ |
58 | int monitor_level; |
59 | |
60 | /* Current progress in startup procedure */ |
61 | int startup_progress; |
62 | |
63 | /* Serial number of device */ |
64 | u32 serial_number; |
65 | |
66 | /* Firmware version (x 100) */ |
67 | int firmware_version; |
68 | |
69 | /* Device ID */ |
70 | int device_id; |
71 | }; |
72 | |
73 | #define line6_to_pod(x) container_of(x, struct usb_line6_pod, line6) |
74 | |
75 | #define POD_SYSEX_CODE 3 |
76 | |
77 | /* *INDENT-OFF* */ |
78 | |
79 | enum { |
80 | POD_SYSEX_SAVE = 0x24, |
81 | POD_SYSEX_SYSTEM = 0x56, |
82 | POD_SYSEX_SYSTEMREQ = 0x57, |
83 | /* POD_SYSEX_UPDATE = 0x6c, */ /* software update! */ |
84 | POD_SYSEX_STORE = 0x71, |
85 | POD_SYSEX_FINISH = 0x72, |
86 | POD_SYSEX_DUMPMEM = 0x73, |
87 | POD_SYSEX_DUMP = 0x74, |
88 | POD_SYSEX_DUMPREQ = 0x75 |
89 | |
90 | /* dumps entire internal memory of PODxt Pro */ |
91 | /* POD_SYSEX_DUMPMEM2 = 0x76 */ |
92 | }; |
93 | |
94 | enum { |
95 | POD_MONITOR_LEVEL = 0x04, |
96 | POD_SYSTEM_INVALID = 0x10000 |
97 | }; |
98 | |
99 | /* *INDENT-ON* */ |
100 | |
101 | enum { |
102 | POD_DUMP_MEMORY = 2 |
103 | }; |
104 | |
105 | enum { |
106 | POD_BUSY_READ, |
107 | POD_BUSY_WRITE, |
108 | POD_CHANNEL_DIRTY, |
109 | POD_SAVE_PRESSED, |
110 | POD_BUSY_MIDISEND |
111 | }; |
112 | |
113 | static const struct snd_ratden pod_ratden = { |
114 | .num_min = 78125, |
115 | .num_max = 78125, |
116 | .num_step = 1, |
117 | .den = 2 |
118 | }; |
119 | |
120 | static struct line6_pcm_properties pod_pcm_properties = { |
121 | .playback_hw = { |
122 | .info = (SNDRV_PCM_INFO_MMAP | |
123 | SNDRV_PCM_INFO_INTERLEAVED | |
124 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
125 | SNDRV_PCM_INFO_MMAP_VALID | |
126 | SNDRV_PCM_INFO_PAUSE | |
127 | SNDRV_PCM_INFO_SYNC_START), |
128 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, |
129 | .rates = SNDRV_PCM_RATE_KNOT, |
130 | .rate_min = 39062, |
131 | .rate_max = 39063, |
132 | .channels_min = 2, |
133 | .channels_max = 2, |
134 | .buffer_bytes_max = 60000, |
135 | .period_bytes_min = 64, |
136 | .period_bytes_max = 8192, |
137 | .periods_min = 1, |
138 | .periods_max = 1024}, |
139 | .capture_hw = { |
140 | .info = (SNDRV_PCM_INFO_MMAP | |
141 | SNDRV_PCM_INFO_INTERLEAVED | |
142 | SNDRV_PCM_INFO_BLOCK_TRANSFER | |
143 | SNDRV_PCM_INFO_MMAP_VALID | |
144 | SNDRV_PCM_INFO_SYNC_START), |
145 | .formats = SNDRV_PCM_FMTBIT_S24_3LE, |
146 | .rates = SNDRV_PCM_RATE_KNOT, |
147 | .rate_min = 39062, |
148 | .rate_max = 39063, |
149 | .channels_min = 2, |
150 | .channels_max = 2, |
151 | .buffer_bytes_max = 60000, |
152 | .period_bytes_min = 64, |
153 | .period_bytes_max = 8192, |
154 | .periods_min = 1, |
155 | .periods_max = 1024}, |
156 | .rates = { |
157 | .nrats = 1, |
158 | .rats = &pod_ratden}, |
159 | .bytes_per_channel = 3 /* SNDRV_PCM_FMTBIT_S24_3LE */ |
160 | }; |
161 | |
162 | |
163 | static const char [] = { |
164 | 0xf0, 0x7e, 0x7f, 0x06, 0x02 |
165 | }; |
166 | |
167 | static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code, |
168 | int size) |
169 | { |
170 | return line6_alloc_sysex_buffer(line6: &pod->line6, POD_SYSEX_CODE, code2: code, |
171 | size); |
172 | } |
173 | |
174 | /* |
175 | Process a completely received message. |
176 | */ |
177 | static void line6_pod_process_message(struct usb_line6 *line6) |
178 | { |
179 | struct usb_line6_pod *pod = line6_to_pod(line6); |
180 | const unsigned char *buf = pod->line6.buffer_message; |
181 | |
182 | if (memcmp(p: buf, q: pod_version_header, size: sizeof(pod_version_header)) == 0) { |
183 | pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15]; |
184 | pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) | |
185 | (int) buf[10]; |
186 | if (pod->startup_progress == POD_STARTUP_VERSIONREQ) { |
187 | pod->startup_progress = POD_STARTUP_SETUP; |
188 | schedule_delayed_work(dwork: &line6->startup_work, delay: 0); |
189 | } |
190 | return; |
191 | } |
192 | |
193 | /* Only look for sysex messages from this device */ |
194 | if (buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE) && |
195 | buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN)) { |
196 | return; |
197 | } |
198 | if (memcmp(p: buf + 1, q: line6_midi_id, size: sizeof(line6_midi_id)) != 0) |
199 | return; |
200 | |
201 | if (buf[5] == POD_SYSEX_SYSTEM && buf[6] == POD_MONITOR_LEVEL) { |
202 | short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) | |
203 | ((int)buf[9] << 4) | (int)buf[10]; |
204 | pod->monitor_level = value; |
205 | } |
206 | } |
207 | |
208 | /* |
209 | Send system parameter (from integer). |
210 | */ |
211 | static int pod_set_system_param_int(struct usb_line6_pod *pod, int value, |
212 | int code) |
213 | { |
214 | char *sysex; |
215 | static const int size = 5; |
216 | |
217 | sysex = pod_alloc_sysex_buffer(pod, code: POD_SYSEX_SYSTEM, size); |
218 | if (!sysex) |
219 | return -ENOMEM; |
220 | sysex[SYSEX_DATA_OFS] = code; |
221 | sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f; |
222 | sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f; |
223 | sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f; |
224 | sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f; |
225 | line6_send_sysex_message(line6: &pod->line6, buffer: sysex, size); |
226 | kfree(objp: sysex); |
227 | return 0; |
228 | } |
229 | |
230 | /* |
231 | "read" request on "serial_number" special file. |
232 | */ |
233 | static ssize_t serial_number_show(struct device *dev, |
234 | struct device_attribute *attr, char *buf) |
235 | { |
236 | struct snd_card *card = dev_to_snd_card(dev); |
237 | struct usb_line6_pod *pod = card->private_data; |
238 | |
239 | return sysfs_emit(buf, fmt: "%u\n" , pod->serial_number); |
240 | } |
241 | |
242 | /* |
243 | "read" request on "firmware_version" special file. |
244 | */ |
245 | static ssize_t firmware_version_show(struct device *dev, |
246 | struct device_attribute *attr, char *buf) |
247 | { |
248 | struct snd_card *card = dev_to_snd_card(dev); |
249 | struct usb_line6_pod *pod = card->private_data; |
250 | |
251 | return sysfs_emit(buf, fmt: "%d.%02d\n" , pod->firmware_version / 100, |
252 | pod->firmware_version % 100); |
253 | } |
254 | |
255 | /* |
256 | "read" request on "device_id" special file. |
257 | */ |
258 | static ssize_t device_id_show(struct device *dev, |
259 | struct device_attribute *attr, char *buf) |
260 | { |
261 | struct snd_card *card = dev_to_snd_card(dev); |
262 | struct usb_line6_pod *pod = card->private_data; |
263 | |
264 | return sysfs_emit(buf, fmt: "%d\n" , pod->device_id); |
265 | } |
266 | |
267 | /* |
268 | POD startup procedure. |
269 | This is a sequence of functions with special requirements (e.g., must |
270 | not run immediately after initialization, must not run in interrupt |
271 | context). After the last one has finished, the device is ready to use. |
272 | */ |
273 | |
274 | static void pod_startup(struct usb_line6 *line6) |
275 | { |
276 | struct usb_line6_pod *pod = line6_to_pod(line6); |
277 | |
278 | switch (pod->startup_progress) { |
279 | case POD_STARTUP_VERSIONREQ: |
280 | /* request firmware version: */ |
281 | line6_version_request_async(line6); |
282 | break; |
283 | case POD_STARTUP_SETUP: |
284 | /* serial number: */ |
285 | line6_read_serial_number(line6: &pod->line6, serial_number: &pod->serial_number); |
286 | |
287 | /* ALSA audio interface: */ |
288 | if (snd_card_register(card: line6->card)) |
289 | dev_err(line6->ifcdev, "Failed to register POD card.\n" ); |
290 | pod->startup_progress = POD_STARTUP_DONE; |
291 | break; |
292 | default: |
293 | break; |
294 | } |
295 | } |
296 | |
297 | /* POD special files: */ |
298 | static DEVICE_ATTR_RO(device_id); |
299 | static DEVICE_ATTR_RO(firmware_version); |
300 | static DEVICE_ATTR_RO(serial_number); |
301 | |
302 | static struct attribute *pod_dev_attrs[] = { |
303 | &dev_attr_device_id.attr, |
304 | &dev_attr_firmware_version.attr, |
305 | &dev_attr_serial_number.attr, |
306 | NULL |
307 | }; |
308 | |
309 | static const struct attribute_group pod_dev_attr_group = { |
310 | .name = "pod" , |
311 | .attrs = pod_dev_attrs, |
312 | }; |
313 | |
314 | /* control info callback */ |
315 | static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol, |
316 | struct snd_ctl_elem_info *uinfo) |
317 | { |
318 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; |
319 | uinfo->count = 1; |
320 | uinfo->value.integer.min = 0; |
321 | uinfo->value.integer.max = 65535; |
322 | return 0; |
323 | } |
324 | |
325 | /* control get callback */ |
326 | static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol, |
327 | struct snd_ctl_elem_value *ucontrol) |
328 | { |
329 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); |
330 | struct usb_line6_pod *pod = line6_to_pod(line6pcm->line6); |
331 | |
332 | ucontrol->value.integer.value[0] = pod->monitor_level; |
333 | return 0; |
334 | } |
335 | |
336 | /* control put callback */ |
337 | static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol, |
338 | struct snd_ctl_elem_value *ucontrol) |
339 | { |
340 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); |
341 | struct usb_line6_pod *pod = line6_to_pod(line6pcm->line6); |
342 | |
343 | if (ucontrol->value.integer.value[0] == pod->monitor_level) |
344 | return 0; |
345 | |
346 | pod->monitor_level = ucontrol->value.integer.value[0]; |
347 | pod_set_system_param_int(pod, value: ucontrol->value.integer.value[0], |
348 | code: POD_MONITOR_LEVEL); |
349 | return 1; |
350 | } |
351 | |
352 | /* control definition */ |
353 | static const struct snd_kcontrol_new pod_control_monitor = { |
354 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
355 | .name = "Monitor Playback Volume" , |
356 | .index = 0, |
357 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, |
358 | .info = snd_pod_control_monitor_info, |
359 | .get = snd_pod_control_monitor_get, |
360 | .put = snd_pod_control_monitor_put |
361 | }; |
362 | |
363 | /* |
364 | Try to init POD device. |
365 | */ |
366 | static int pod_init(struct usb_line6 *line6, |
367 | const struct usb_device_id *id) |
368 | { |
369 | int err; |
370 | struct usb_line6_pod *pod = line6_to_pod(line6); |
371 | |
372 | line6->process_message = line6_pod_process_message; |
373 | line6->startup = pod_startup; |
374 | |
375 | /* create sysfs entries: */ |
376 | err = snd_card_add_dev_attr(card: line6->card, group: &pod_dev_attr_group); |
377 | if (err < 0) |
378 | return err; |
379 | |
380 | /* initialize PCM subsystem: */ |
381 | err = line6_init_pcm(line6, properties: &pod_pcm_properties); |
382 | if (err < 0) |
383 | return err; |
384 | |
385 | /* register monitor control: */ |
386 | err = snd_ctl_add(card: line6->card, |
387 | kcontrol: snd_ctl_new1(kcontrolnew: &pod_control_monitor, private_data: line6->line6pcm)); |
388 | if (err < 0) |
389 | return err; |
390 | |
391 | /* |
392 | When the sound card is registered at this point, the PODxt Live |
393 | displays "Invalid Code Error 07", so we do it later in the event |
394 | handler. |
395 | */ |
396 | |
397 | if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) { |
398 | pod->monitor_level = POD_SYSTEM_INVALID; |
399 | |
400 | /* initiate startup procedure: */ |
401 | schedule_delayed_work(dwork: &line6->startup_work, |
402 | delay: msecs_to_jiffies(POD_STARTUP_DELAY)); |
403 | } |
404 | |
405 | return 0; |
406 | } |
407 | |
408 | #define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) |
409 | #define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n) |
410 | |
411 | /* table of devices that work with this driver */ |
412 | static const struct usb_device_id pod_id_table[] = { |
413 | { LINE6_DEVICE(0x4250), .driver_info = LINE6_BASSPODXT }, |
414 | { LINE6_DEVICE(0x4642), .driver_info = LINE6_BASSPODXTLIVE }, |
415 | { LINE6_DEVICE(0x4252), .driver_info = LINE6_BASSPODXTPRO }, |
416 | { LINE6_IF_NUM(0x5051, 1), .driver_info = LINE6_POCKETPOD }, |
417 | { LINE6_DEVICE(0x5044), .driver_info = LINE6_PODXT }, |
418 | { LINE6_IF_NUM(0x4650, 0), .driver_info = LINE6_PODXTLIVE_POD }, |
419 | { LINE6_DEVICE(0x5050), .driver_info = LINE6_PODXTPRO }, |
420 | {} |
421 | }; |
422 | |
423 | MODULE_DEVICE_TABLE(usb, pod_id_table); |
424 | |
425 | static const struct line6_properties pod_properties_table[] = { |
426 | [LINE6_BASSPODXT] = { |
427 | .id = "BassPODxt" , |
428 | .name = "BassPODxt" , |
429 | .capabilities = LINE6_CAP_CONTROL |
430 | | LINE6_CAP_CONTROL_MIDI |
431 | | LINE6_CAP_PCM |
432 | | LINE6_CAP_HWMON, |
433 | .altsetting = 5, |
434 | .ep_ctrl_r = 0x84, |
435 | .ep_ctrl_w = 0x03, |
436 | .ep_audio_r = 0x82, |
437 | .ep_audio_w = 0x01, |
438 | }, |
439 | [LINE6_BASSPODXTLIVE] = { |
440 | .id = "BassPODxtLive" , |
441 | .name = "BassPODxt Live" , |
442 | .capabilities = LINE6_CAP_CONTROL |
443 | | LINE6_CAP_CONTROL_MIDI |
444 | | LINE6_CAP_PCM |
445 | | LINE6_CAP_HWMON, |
446 | .altsetting = 1, |
447 | .ep_ctrl_r = 0x84, |
448 | .ep_ctrl_w = 0x03, |
449 | .ep_audio_r = 0x82, |
450 | .ep_audio_w = 0x01, |
451 | }, |
452 | [LINE6_BASSPODXTPRO] = { |
453 | .id = "BassPODxtPro" , |
454 | .name = "BassPODxt Pro" , |
455 | .capabilities = LINE6_CAP_CONTROL |
456 | | LINE6_CAP_CONTROL_MIDI |
457 | | LINE6_CAP_PCM |
458 | | LINE6_CAP_HWMON, |
459 | .altsetting = 5, |
460 | .ep_ctrl_r = 0x84, |
461 | .ep_ctrl_w = 0x03, |
462 | .ep_audio_r = 0x82, |
463 | .ep_audio_w = 0x01, |
464 | }, |
465 | [LINE6_POCKETPOD] = { |
466 | .id = "PocketPOD" , |
467 | .name = "Pocket POD" , |
468 | .capabilities = LINE6_CAP_CONTROL |
469 | | LINE6_CAP_CONTROL_MIDI, |
470 | .altsetting = 0, |
471 | .ep_ctrl_r = 0x82, |
472 | .ep_ctrl_w = 0x02, |
473 | /* no audio channel */ |
474 | }, |
475 | [LINE6_PODXT] = { |
476 | .id = "PODxt" , |
477 | .name = "PODxt" , |
478 | .capabilities = LINE6_CAP_CONTROL |
479 | | LINE6_CAP_CONTROL_MIDI |
480 | | LINE6_CAP_PCM |
481 | | LINE6_CAP_HWMON, |
482 | .altsetting = 5, |
483 | .ep_ctrl_r = 0x84, |
484 | .ep_ctrl_w = 0x03, |
485 | .ep_audio_r = 0x82, |
486 | .ep_audio_w = 0x01, |
487 | }, |
488 | [LINE6_PODXTLIVE_POD] = { |
489 | .id = "PODxtLive" , |
490 | .name = "PODxt Live" , |
491 | .capabilities = LINE6_CAP_CONTROL |
492 | | LINE6_CAP_CONTROL_MIDI |
493 | | LINE6_CAP_PCM |
494 | | LINE6_CAP_HWMON, |
495 | .altsetting = 1, |
496 | .ep_ctrl_r = 0x84, |
497 | .ep_ctrl_w = 0x03, |
498 | .ep_audio_r = 0x82, |
499 | .ep_audio_w = 0x01, |
500 | }, |
501 | [LINE6_PODXTPRO] = { |
502 | .id = "PODxtPro" , |
503 | .name = "PODxt Pro" , |
504 | .capabilities = LINE6_CAP_CONTROL |
505 | | LINE6_CAP_CONTROL_MIDI |
506 | | LINE6_CAP_PCM |
507 | | LINE6_CAP_HWMON, |
508 | .altsetting = 5, |
509 | .ep_ctrl_r = 0x84, |
510 | .ep_ctrl_w = 0x03, |
511 | .ep_audio_r = 0x82, |
512 | .ep_audio_w = 0x01, |
513 | }, |
514 | }; |
515 | |
516 | /* |
517 | Probe USB device. |
518 | */ |
519 | static int pod_probe(struct usb_interface *interface, |
520 | const struct usb_device_id *id) |
521 | { |
522 | return line6_probe(interface, id, driver_name: "Line6-POD" , |
523 | properties: &pod_properties_table[id->driver_info], |
524 | private_init: pod_init, data_size: sizeof(struct usb_line6_pod)); |
525 | } |
526 | |
527 | static struct usb_driver pod_driver = { |
528 | .name = KBUILD_MODNAME, |
529 | .probe = pod_probe, |
530 | .disconnect = line6_disconnect, |
531 | #ifdef CONFIG_PM |
532 | .suspend = line6_suspend, |
533 | .resume = line6_resume, |
534 | .reset_resume = line6_resume, |
535 | #endif |
536 | .id_table = pod_id_table, |
537 | }; |
538 | |
539 | module_usb_driver(pod_driver); |
540 | |
541 | MODULE_DESCRIPTION("Line 6 POD USB driver" ); |
542 | MODULE_LICENSE("GPL" ); |
543 | |