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