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