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