Commit | Line | Data |
---|---|---|
705ececd | 1 | /* |
e1a164d7 | 2 | * Line6 Linux USB driver - 0.9.1beta |
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 | ||
705ececd MG |
12 | #include <linux/kernel.h> |
13 | #include <linux/module.h> | |
5a0e3ad6 | 14 | #include <linux/slab.h> |
705ececd MG |
15 | #include <linux/usb.h> |
16 | ||
17 | #include "audio.h" | |
18 | #include "capture.h" | |
1027f476 | 19 | #include "driver.h" |
705ececd MG |
20 | #include "midi.h" |
21 | #include "playback.h" | |
22 | #include "pod.h" | |
16dc1040 | 23 | #include "podhd.h" |
705ececd MG |
24 | #include "revision.h" |
25 | #include "toneport.h" | |
26 | #include "usbdefs.h" | |
27 | #include "variax.h" | |
28 | ||
705ececd MG |
29 | #define DRIVER_AUTHOR "Markus Grabner <grabner@icg.tugraz.at>" |
30 | #define DRIVER_DESC "Line6 USB Driver" | |
e1a164d7 | 31 | #define DRIVER_VERSION "0.9.1beta" DRIVER_REVISION |
705ececd MG |
32 | |
33 | /* table of devices that work with this driver */ | |
a457732b | 34 | static const struct usb_device_id line6_id_table[] = { |
e1a164d7 MG |
35 | {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXT)}, |
36 | {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXTLIVE)}, | |
37 | {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXTPRO)}, | |
38 | {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_GUITARPORT)}, | |
39 | {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_POCKETPOD)}, | |
4c6fb5fc MG |
40 | {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD300)}, |
41 | {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD500)}, | |
e1a164d7 MG |
42 | {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_GX)}, |
43 | {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_UX1)}, | |
44 | {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_UX2)}, | |
45 | {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODX3)}, | |
46 | {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODX3LIVE)}, | |
47 | {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXT)}, | |
48 | {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXTLIVE)}, | |
49 | {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXTPRO)}, | |
50 | {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_GX)}, | |
51 | {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_UX1)}, | |
52 | {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_UX2)}, | |
53 | {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_VARIAX)}, | |
54 | {}, | |
705ececd | 55 | }; |
e1a164d7 | 56 | |
36445bc1 | 57 | MODULE_DEVICE_TABLE(usb, line6_id_table); |
705ececd | 58 | |
e1a164d7 | 59 | /* *INDENT-OFF* */ |
705ececd | 60 | static struct line6_properties line6_properties_table[] = { |
4c6fb5fc MG |
61 | { LINE6_BIT_BASSPODXT, "BassPODxt", "BassPODxt", LINE6_BIT_CONTROL_PCM_HWMON }, |
62 | { LINE6_BIT_BASSPODXTLIVE, "BassPODxtLive", "BassPODxt Live", LINE6_BIT_CONTROL_PCM_HWMON }, | |
63 | { LINE6_BIT_BASSPODXTPRO, "BassPODxtPro", "BassPODxt Pro", LINE6_BIT_CONTROL_PCM_HWMON }, | |
64 | { LINE6_BIT_GUITARPORT, "GuitarPort", "GuitarPort", LINE6_BIT_PCM }, | |
65 | { LINE6_BIT_POCKETPOD, "PocketPOD", "Pocket POD", LINE6_BIT_CONTROL }, | |
66 | { LINE6_BIT_PODHD300, "PODHD300", "POD HD300", LINE6_BIT_CONTROL_PCM_HWMON }, | |
67 | { LINE6_BIT_PODHD500, "PODHD500", "POD HD500", LINE6_BIT_CONTROL_PCM_HWMON }, | |
68 | { LINE6_BIT_PODSTUDIO_GX, "PODStudioGX", "POD Studio GX", LINE6_BIT_PCM }, | |
69 | { LINE6_BIT_PODSTUDIO_UX1, "PODStudioUX1", "POD Studio UX1", LINE6_BIT_PCM }, | |
70 | { LINE6_BIT_PODSTUDIO_UX2, "PODStudioUX2", "POD Studio UX2", LINE6_BIT_PCM }, | |
71 | { LINE6_BIT_PODX3, "PODX3", "POD X3", LINE6_BIT_PCM }, | |
72 | { LINE6_BIT_PODX3LIVE, "PODX3Live", "POD X3 Live", LINE6_BIT_PCM }, | |
73 | { LINE6_BIT_PODXT, "PODxt", "PODxt", LINE6_BIT_CONTROL_PCM_HWMON }, | |
74 | { LINE6_BIT_PODXTLIVE, "PODxtLive", "PODxt Live", LINE6_BIT_CONTROL_PCM_HWMON }, | |
75 | { LINE6_BIT_PODXTPRO, "PODxtPro", "PODxt Pro", LINE6_BIT_CONTROL_PCM_HWMON }, | |
76 | { LINE6_BIT_TONEPORT_GX, "TonePortGX", "TonePort GX", LINE6_BIT_PCM }, | |
77 | { LINE6_BIT_TONEPORT_UX1, "TonePortUX1", "TonePort UX1", LINE6_BIT_PCM }, | |
78 | { LINE6_BIT_TONEPORT_UX2, "TonePortUX2", "TonePort UX2", LINE6_BIT_PCM }, | |
79 | { LINE6_BIT_VARIAX, "Variax", "Variax Workbench", LINE6_BIT_CONTROL }, | |
705ececd | 80 | }; |
e1a164d7 | 81 | /* *INDENT-ON* */ |
705ececd MG |
82 | |
83 | /* | |
84 | This is Line6's MIDI manufacturer ID. | |
85 | */ | |
1027f476 MG |
86 | const unsigned char line6_midi_id[] = { |
87 | 0x00, 0x01, 0x0c | |
88 | }; | |
89 | ||
90 | /* | |
91 | Code to request version of POD, Variax interface | |
92 | (and maybe other devices). | |
93 | */ | |
c46b8a65 | 94 | static const char line6_request_version[] = { |
1027f476 MG |
95 | 0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7 |
96 | }; | |
97 | ||
705ececd MG |
98 | /** |
99 | Class for asynchronous messages. | |
100 | */ | |
36445bc1 | 101 | struct message { |
705ececd MG |
102 | struct usb_line6 *line6; |
103 | const char *buffer; | |
104 | int size; | |
105 | int done; | |
106 | }; | |
107 | ||
705ececd MG |
108 | /* |
109 | Forward declarations. | |
110 | */ | |
0c7ab158 | 111 | static void line6_data_received(struct urb *urb); |
36445bc1 GKH |
112 | static int line6_send_raw_message_async_part(struct message *msg, |
113 | struct urb *urb); | |
705ececd | 114 | |
705ececd MG |
115 | /* |
116 | Start to listen on endpoint. | |
117 | */ | |
118 | static int line6_start_listen(struct usb_line6 *line6) | |
119 | { | |
1027f476 | 120 | int err; |
36445bc1 GKH |
121 | usb_fill_int_urb(line6->urb_listen, line6->usbdev, |
122 | usb_rcvintpipe(line6->usbdev, line6->ep_control_read), | |
123 | line6->buffer_listen, LINE6_BUFSIZE_LISTEN, | |
124 | line6_data_received, line6, line6->interval); | |
705ececd | 125 | line6->urb_listen->actual_length = 0; |
e1a164d7 | 126 | err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC); |
1027f476 MG |
127 | return err; |
128 | } | |
129 | ||
130 | /* | |
131 | Stop listening on endpoint. | |
132 | */ | |
133 | static void line6_stop_listen(struct usb_line6 *line6) | |
134 | { | |
135 | usb_kill_urb(line6->urb_listen); | |
705ececd MG |
136 | } |
137 | ||
1027f476 | 138 | #ifdef CONFIG_LINE6_USB_DUMP_ANY |
705ececd MG |
139 | /* |
140 | Write hexdump to syslog. | |
141 | */ | |
36445bc1 GKH |
142 | void line6_write_hexdump(struct usb_line6 *line6, char dir, |
143 | const unsigned char *buffer, int size) | |
705ececd MG |
144 | { |
145 | static const int BYTES_PER_LINE = 8; | |
146 | char hexdump[100]; | |
147 | char asc[BYTES_PER_LINE + 1]; | |
148 | int i, j; | |
149 | ||
36445bc1 | 150 | for (i = 0; i < size; i += BYTES_PER_LINE) { |
705ececd MG |
151 | int hexdumpsize = sizeof(hexdump); |
152 | char *p = hexdump; | |
153 | int n = min(size - i, BYTES_PER_LINE); | |
154 | asc[n] = 0; | |
155 | ||
36445bc1 | 156 | for (j = 0; j < BYTES_PER_LINE; ++j) { |
705ececd MG |
157 | int bytes; |
158 | ||
36445bc1 | 159 | if (j < n) { |
705ececd MG |
160 | unsigned char val = buffer[i + j]; |
161 | bytes = snprintf(p, hexdumpsize, " %02X", val); | |
e1a164d7 MG |
162 | asc[j] = ((val >= 0x20) |
163 | && (val < 0x7f)) ? val : '.'; | |
36445bc1 | 164 | } else |
705ececd MG |
165 | bytes = snprintf(p, hexdumpsize, " "); |
166 | ||
36445bc1 | 167 | if (bytes > hexdumpsize) |
e1a164d7 | 168 | break; /* buffer overflow */ |
705ececd MG |
169 | |
170 | p += bytes; | |
171 | hexdumpsize -= bytes; | |
172 | } | |
173 | ||
174 | dev_info(line6->ifcdev, "%c%04X:%s %s\n", dir, i, hexdump, asc); | |
175 | } | |
176 | } | |
177 | #endif | |
178 | ||
705ececd | 179 | /* |
1027f476 | 180 | Send raw message in pieces of wMaxPacketSize bytes. |
705ececd | 181 | */ |
36445bc1 GKH |
182 | int line6_send_raw_message(struct usb_line6 *line6, const char *buffer, |
183 | int size) | |
705ececd MG |
184 | { |
185 | int i, done = 0; | |
186 | ||
1027f476 MG |
187 | for (i = 0; i < size; i += line6->max_packet_size) { |
188 | int partial; | |
705ececd MG |
189 | const char *frag_buf = buffer + i; |
190 | int frag_size = min(line6->max_packet_size, size - i); | |
36445bc1 GKH |
191 | int retval; |
192 | ||
193 | retval = usb_interrupt_msg(line6->usbdev, | |
194 | usb_sndintpipe(line6->usbdev, | |
195 | line6->ep_control_write), | |
196 | (char *)frag_buf, frag_size, | |
1027f476 | 197 | &partial, LINE6_TIMEOUT * HZ); |
705ececd | 198 | |
36445bc1 GKH |
199 | if (retval) { |
200 | dev_err(line6->ifcdev, | |
201 | "usb_interrupt_msg failed (%d)\n", retval); | |
705ececd MG |
202 | break; |
203 | } | |
204 | ||
1027f476 | 205 | done += frag_size; |
705ececd MG |
206 | } |
207 | ||
208 | return done; | |
209 | } | |
210 | ||
211 | /* | |
212 | Notification of completion of asynchronous request transmission. | |
213 | */ | |
0c7ab158 | 214 | static void line6_async_request_sent(struct urb *urb) |
705ececd MG |
215 | { |
216 | struct message *msg = (struct message *)urb->context; | |
217 | ||
36445bc1 | 218 | if (msg->done >= msg->size) { |
705ececd MG |
219 | usb_free_urb(urb); |
220 | kfree(msg); | |
36445bc1 | 221 | } else |
705ececd MG |
222 | line6_send_raw_message_async_part(msg, urb); |
223 | } | |
224 | ||
225 | /* | |
226 | Asynchronously send part of a raw message. | |
227 | */ | |
36445bc1 GKH |
228 | static int line6_send_raw_message_async_part(struct message *msg, |
229 | struct urb *urb) | |
705ececd MG |
230 | { |
231 | int retval; | |
232 | struct usb_line6 *line6 = msg->line6; | |
233 | int done = msg->done; | |
234 | int bytes = min(msg->size - done, line6->max_packet_size); | |
235 | ||
36445bc1 GKH |
236 | usb_fill_int_urb(urb, line6->usbdev, |
237 | usb_sndintpipe(line6->usbdev, line6->ep_control_write), | |
238 | (char *)msg->buffer + done, bytes, | |
239 | line6_async_request_sent, msg, line6->interval); | |
705ececd | 240 | |
705ececd MG |
241 | msg->done += bytes; |
242 | retval = usb_submit_urb(urb, GFP_ATOMIC); | |
243 | ||
36445bc1 GKH |
244 | if (retval < 0) { |
245 | dev_err(line6->ifcdev, "%s: usb_submit_urb failed (%d)\n", | |
246 | __func__, retval); | |
705ececd MG |
247 | usb_free_urb(urb); |
248 | kfree(msg); | |
249 | return -EINVAL; | |
250 | } | |
251 | ||
252 | return 0; | |
253 | } | |
254 | ||
1027f476 MG |
255 | /* |
256 | Setup and start timer. | |
257 | */ | |
258 | void line6_start_timer(struct timer_list *timer, unsigned int msecs, | |
e1a164d7 | 259 | void (*function) (unsigned long), unsigned long data) |
1027f476 MG |
260 | { |
261 | setup_timer(timer, function, data); | |
262 | timer->expires = jiffies + msecs * HZ / 1000; | |
263 | add_timer(timer); | |
264 | } | |
265 | ||
705ececd MG |
266 | /* |
267 | Asynchronously send raw message. | |
268 | */ | |
36445bc1 GKH |
269 | int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer, |
270 | int size) | |
705ececd MG |
271 | { |
272 | struct message *msg; | |
273 | struct urb *urb; | |
274 | ||
275 | /* create message: */ | |
276 | msg = kmalloc(sizeof(struct message), GFP_ATOMIC); | |
277 | ||
36445bc1 | 278 | if (msg == NULL) { |
705ececd MG |
279 | dev_err(line6->ifcdev, "Out of memory\n"); |
280 | return -ENOMEM; | |
281 | } | |
282 | ||
283 | /* create URB: */ | |
284 | urb = usb_alloc_urb(0, GFP_ATOMIC); | |
285 | ||
36445bc1 | 286 | if (urb == NULL) { |
705ececd MG |
287 | kfree(msg); |
288 | dev_err(line6->ifcdev, "Out of memory\n"); | |
289 | return -ENOMEM; | |
290 | } | |
291 | ||
292 | /* set message data: */ | |
293 | msg->line6 = line6; | |
294 | msg->buffer = buffer; | |
295 | msg->size = size; | |
296 | msg->done = 0; | |
297 | ||
298 | /* start sending: */ | |
299 | return line6_send_raw_message_async_part(msg, urb); | |
300 | } | |
301 | ||
1027f476 MG |
302 | /* |
303 | Send asynchronous device version request. | |
304 | */ | |
305 | int line6_version_request_async(struct usb_line6 *line6) | |
306 | { | |
c46b8a65 GKH |
307 | char *buffer; |
308 | int retval; | |
309 | ||
77ecb6fe LN |
310 | buffer = kmemdup(line6_request_version, |
311 | sizeof(line6_request_version), GFP_ATOMIC); | |
c46b8a65 GKH |
312 | if (buffer == NULL) { |
313 | dev_err(line6->ifcdev, "Out of memory"); | |
314 | return -ENOMEM; | |
315 | } | |
316 | ||
c46b8a65 GKH |
317 | retval = line6_send_raw_message_async(line6, buffer, |
318 | sizeof(line6_request_version)); | |
319 | kfree(buffer); | |
320 | return retval; | |
1027f476 MG |
321 | } |
322 | ||
705ececd MG |
323 | /* |
324 | Send sysex message in pieces of wMaxPacketSize bytes. | |
325 | */ | |
36445bc1 GKH |
326 | int line6_send_sysex_message(struct usb_line6 *line6, const char *buffer, |
327 | int size) | |
705ececd | 328 | { |
e1a164d7 MG |
329 | return line6_send_raw_message(line6, buffer, |
330 | size + SYSEX_EXTRA_SIZE) - | |
331 | SYSEX_EXTRA_SIZE; | |
705ececd MG |
332 | } |
333 | ||
334 | /* | |
335 | Allocate buffer for sysex message and prepare header. | |
336 | @param code sysex message code | |
337 | @param size number of bytes between code and sysex end | |
338 | */ | |
36445bc1 GKH |
339 | char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2, |
340 | int size) | |
705ececd | 341 | { |
1027f476 | 342 | char *buffer = kmalloc(size + SYSEX_EXTRA_SIZE, GFP_ATOMIC); |
705ececd | 343 | |
36445bc1 | 344 | if (!buffer) { |
705ececd | 345 | dev_err(line6->ifcdev, "out of memory\n"); |
536165d8 | 346 | return NULL; |
705ececd MG |
347 | } |
348 | ||
349 | buffer[0] = LINE6_SYSEX_BEGIN; | |
350 | memcpy(buffer + 1, line6_midi_id, sizeof(line6_midi_id)); | |
351 | buffer[sizeof(line6_midi_id) + 1] = code1; | |
352 | buffer[sizeof(line6_midi_id) + 2] = code2; | |
353 | buffer[sizeof(line6_midi_id) + 3 + size] = LINE6_SYSEX_END; | |
354 | return buffer; | |
355 | } | |
356 | ||
357 | /* | |
358 | Notification of data received from the Line6 device. | |
359 | */ | |
0c7ab158 | 360 | static void line6_data_received(struct urb *urb) |
705ececd MG |
361 | { |
362 | struct usb_line6 *line6 = (struct usb_line6 *)urb->context; | |
363 | struct MidiBuffer *mb = &line6->line6midi->midibuf_in; | |
364 | int done; | |
365 | ||
36445bc1 | 366 | if (urb->status == -ESHUTDOWN) |
705ececd MG |
367 | return; |
368 | ||
e1a164d7 MG |
369 | done = |
370 | line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length); | |
705ececd | 371 | |
36445bc1 | 372 | if (done < urb->actual_length) { |
1027f476 | 373 | line6_midibuf_ignore(mb, done); |
e00d33cb SH |
374 | dev_dbg(line6->ifcdev, "%d %d buffer overflow - message skipped\n", |
375 | done, urb->actual_length); | |
705ececd MG |
376 | } |
377 | ||
36445bc1 | 378 | for (;;) { |
e1a164d7 MG |
379 | done = |
380 | line6_midibuf_read(mb, line6->buffer_message, | |
381 | LINE6_MESSAGE_MAXLEN); | |
705ececd | 382 | |
36445bc1 | 383 | if (done == 0) |
705ececd MG |
384 | break; |
385 | ||
705ececd | 386 | line6->message_length = done; |
705ececd MG |
387 | line6_midi_receive(line6, line6->buffer_message, done); |
388 | ||
36445bc1 | 389 | switch (line6->usbdev->descriptor.idProduct) { |
705ececd MG |
390 | case LINE6_DEVID_BASSPODXT: |
391 | case LINE6_DEVID_BASSPODXTLIVE: | |
392 | case LINE6_DEVID_BASSPODXTPRO: | |
393 | case LINE6_DEVID_PODXT: | |
394 | case LINE6_DEVID_PODXTPRO: | |
395 | case LINE6_DEVID_POCKETPOD: | |
e1a164d7 MG |
396 | line6_pod_process_message((struct usb_line6_pod *) |
397 | line6); | |
705ececd MG |
398 | break; |
399 | ||
16dc1040 | 400 | case LINE6_DEVID_PODHD300: |
4c6fb5fc | 401 | case LINE6_DEVID_PODHD500: |
16dc1040 SH |
402 | break; /* let userspace handle MIDI */ |
403 | ||
705ececd | 404 | case LINE6_DEVID_PODXTLIVE: |
36445bc1 | 405 | switch (line6->interface_number) { |
705ececd | 406 | case PODXTLIVE_INTERFACE_POD: |
e1a164d7 MG |
407 | line6_pod_process_message((struct usb_line6_pod |
408 | *)line6); | |
705ececd MG |
409 | break; |
410 | ||
411 | case PODXTLIVE_INTERFACE_VARIAX: | |
e1a164d7 MG |
412 | line6_variax_process_message((struct |
413 | usb_line6_variax | |
414 | *)line6); | |
705ececd MG |
415 | break; |
416 | ||
417 | default: | |
e1a164d7 MG |
418 | dev_err(line6->ifcdev, |
419 | "PODxt Live interface %d not supported\n", | |
420 | line6->interface_number); | |
705ececd MG |
421 | } |
422 | break; | |
423 | ||
424 | case LINE6_DEVID_VARIAX: | |
e1a164d7 MG |
425 | line6_variax_process_message((struct usb_line6_variax *) |
426 | line6); | |
705ececd MG |
427 | break; |
428 | ||
429 | default: | |
430 | MISSING_CASE; | |
431 | } | |
432 | } | |
433 | ||
434 | line6_start_listen(line6); | |
435 | } | |
436 | ||
437 | /* | |
438 | Send channel number (i.e., switch to a different sound). | |
439 | */ | |
317e188b | 440 | int line6_send_program(struct usb_line6 *line6, u8 value) |
705ececd | 441 | { |
1027f476 | 442 | int retval; |
705ececd | 443 | unsigned char *buffer; |
1027f476 MG |
444 | int partial; |
445 | ||
446 | buffer = kmalloc(2, GFP_KERNEL); | |
705ececd | 447 | |
36445bc1 | 448 | if (!buffer) { |
705ececd MG |
449 | dev_err(line6->ifcdev, "out of memory\n"); |
450 | return -ENOMEM; | |
451 | } | |
452 | ||
453 | buffer[0] = LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST; | |
454 | buffer[1] = value; | |
455 | ||
1027f476 MG |
456 | retval = usb_interrupt_msg(line6->usbdev, |
457 | usb_sndintpipe(line6->usbdev, | |
458 | line6->ep_control_write), | |
459 | buffer, 2, &partial, LINE6_TIMEOUT * HZ); | |
460 | ||
461 | if (retval) | |
e1a164d7 MG |
462 | dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n", |
463 | retval); | |
1027f476 MG |
464 | |
465 | kfree(buffer); | |
466 | return retval; | |
705ececd MG |
467 | } |
468 | ||
469 | /* | |
470 | Transmit Line6 control parameter. | |
471 | */ | |
2471c093 | 472 | int line6_transmit_parameter(struct usb_line6 *line6, int param, u8 value) |
705ececd | 473 | { |
1027f476 | 474 | int retval; |
705ececd | 475 | unsigned char *buffer; |
1027f476 MG |
476 | int partial; |
477 | ||
478 | buffer = kmalloc(3, GFP_KERNEL); | |
705ececd | 479 | |
36445bc1 | 480 | if (!buffer) { |
705ececd MG |
481 | dev_err(line6->ifcdev, "out of memory\n"); |
482 | return -ENOMEM; | |
483 | } | |
484 | ||
485 | buffer[0] = LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST; | |
486 | buffer[1] = param; | |
487 | buffer[2] = value; | |
488 | ||
1027f476 | 489 | retval = usb_interrupt_msg(line6->usbdev, |
e1a164d7 MG |
490 | usb_sndintpipe(line6->usbdev, |
491 | line6->ep_control_write), | |
1027f476 MG |
492 | buffer, 3, &partial, LINE6_TIMEOUT * HZ); |
493 | ||
494 | if (retval) | |
e1a164d7 MG |
495 | dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n", |
496 | retval); | |
1027f476 MG |
497 | |
498 | kfree(buffer); | |
499 | return retval; | |
705ececd MG |
500 | } |
501 | ||
502 | /* | |
503 | Read data from device. | |
504 | */ | |
e1a164d7 MG |
505 | int line6_read_data(struct usb_line6 *line6, int address, void *data, |
506 | size_t datalen) | |
705ececd MG |
507 | { |
508 | struct usb_device *usbdev = line6->usbdev; | |
509 | int ret; | |
510 | unsigned char len; | |
511 | ||
512 | /* query the serial number: */ | |
513 | ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, | |
1027f476 MG |
514 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, |
515 | (datalen << 8) | 0x21, address, | |
516 | NULL, 0, LINE6_TIMEOUT * HZ); | |
705ececd | 517 | |
36445bc1 | 518 | if (ret < 0) { |
705ececd MG |
519 | dev_err(line6->ifcdev, "read request failed (error %d)\n", ret); |
520 | return ret; | |
521 | } | |
522 | ||
bc776f27 | 523 | /* Wait for data length. We'll get 0xff until length arrives. */ |
705ececd MG |
524 | do { |
525 | ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, | |
36445bc1 GKH |
526 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | |
527 | USB_DIR_IN, | |
528 | 0x0012, 0x0000, &len, 1, | |
529 | LINE6_TIMEOUT * HZ); | |
530 | if (ret < 0) { | |
531 | dev_err(line6->ifcdev, | |
532 | "receive length failed (error %d)\n", ret); | |
705ececd MG |
533 | return ret; |
534 | } | |
d722a510 | 535 | } while (len == 0xff); |
36445bc1 GKH |
536 | |
537 | if (len != datalen) { | |
538 | /* should be equal or something went wrong */ | |
539 | dev_err(line6->ifcdev, | |
540 | "length mismatch (expected %d, got %d)\n", | |
541 | (int)datalen, (int)len); | |
705ececd MG |
542 | return -EINVAL; |
543 | } | |
544 | ||
545 | /* receive the result: */ | |
546 | ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67, | |
36445bc1 GKH |
547 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN, |
548 | 0x0013, 0x0000, data, datalen, | |
549 | LINE6_TIMEOUT * HZ); | |
705ececd | 550 | |
36445bc1 | 551 | if (ret < 0) { |
705ececd MG |
552 | dev_err(line6->ifcdev, "read failed (error %d)\n", ret); |
553 | return ret; | |
554 | } | |
555 | ||
556 | return 0; | |
557 | } | |
558 | ||
559 | /* | |
560 | Write data to device. | |
561 | */ | |
36445bc1 GKH |
562 | int line6_write_data(struct usb_line6 *line6, int address, void *data, |
563 | size_t datalen) | |
705ececd MG |
564 | { |
565 | struct usb_device *usbdev = line6->usbdev; | |
566 | int ret; | |
567 | unsigned char status; | |
568 | ||
36445bc1 GKH |
569 | ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, |
570 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | |
571 | 0x0022, address, data, datalen, | |
572 | LINE6_TIMEOUT * HZ); | |
705ececd | 573 | |
36445bc1 GKH |
574 | if (ret < 0) { |
575 | dev_err(line6->ifcdev, | |
576 | "write request failed (error %d)\n", ret); | |
705ececd MG |
577 | return ret; |
578 | } | |
579 | ||
580 | do { | |
36445bc1 GKH |
581 | ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), |
582 | 0x67, | |
583 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | | |
584 | USB_DIR_IN, | |
585 | 0x0012, 0x0000, | |
586 | &status, 1, LINE6_TIMEOUT * HZ); | |
587 | ||
588 | if (ret < 0) { | |
589 | dev_err(line6->ifcdev, | |
590 | "receiving status failed (error %d)\n", ret); | |
705ececd MG |
591 | return ret; |
592 | } | |
027360c5 | 593 | } while (status == 0xff); |
705ececd | 594 | |
36445bc1 | 595 | if (status != 0) { |
705ececd MG |
596 | dev_err(line6->ifcdev, "write failed (error %d)\n", ret); |
597 | return -EINVAL; | |
598 | } | |
599 | ||
600 | return 0; | |
601 | } | |
602 | ||
603 | /* | |
604 | Read Line6 device serial number. | |
605 | (POD, TonePort, GuitarPort) | |
606 | */ | |
607 | int line6_read_serial_number(struct usb_line6 *line6, int *serial_number) | |
608 | { | |
e1a164d7 MG |
609 | return line6_read_data(line6, 0x80d0, serial_number, |
610 | sizeof(*serial_number)); | |
705ececd MG |
611 | } |
612 | ||
613 | /* | |
614 | No operation (i.e., unsupported). | |
615 | */ | |
77491e52 GKH |
616 | ssize_t line6_nop_read(struct device *dev, struct device_attribute *attr, |
617 | char *buf) | |
705ececd MG |
618 | { |
619 | return 0; | |
620 | } | |
621 | ||
622 | /* | |
623 | No operation (i.e., unsupported). | |
624 | */ | |
027360c5 | 625 | ssize_t line6_nop_write(struct device *dev, struct device_attribute *attr, |
77491e52 | 626 | const char *buf, size_t count) |
705ececd MG |
627 | { |
628 | return count; | |
629 | } | |
630 | ||
705ececd MG |
631 | /* |
632 | Generic destructor. | |
633 | */ | |
634 | static void line6_destruct(struct usb_interface *interface) | |
635 | { | |
636 | struct usb_line6 *line6; | |
36445bc1 GKH |
637 | |
638 | if (interface == NULL) | |
639 | return; | |
705ececd | 640 | line6 = usb_get_intfdata(interface); |
36445bc1 GKH |
641 | if (line6 == NULL) |
642 | return; | |
705ececd MG |
643 | |
644 | /* free buffer memory first: */ | |
36445bc1 GKH |
645 | kfree(line6->buffer_message); |
646 | kfree(line6->buffer_listen); | |
705ececd MG |
647 | |
648 | /* then free URBs: */ | |
36445bc1 | 649 | usb_free_urb(line6->urb_listen); |
705ececd MG |
650 | |
651 | /* make sure the device isn't destructed twice: */ | |
652 | usb_set_intfdata(interface, NULL); | |
653 | ||
654 | /* free interface data: */ | |
655 | kfree(line6); | |
656 | } | |
657 | ||
705ececd MG |
658 | /* |
659 | Probe USB device. | |
660 | */ | |
e1a164d7 MG |
661 | static int line6_probe(struct usb_interface *interface, |
662 | const struct usb_device_id *id) | |
705ececd MG |
663 | { |
664 | int devtype; | |
4bd8b4de DC |
665 | struct usb_device *usbdev; |
666 | struct usb_line6 *line6; | |
705ececd | 667 | const struct line6_properties *properties; |
705ececd MG |
668 | int interface_number, alternate = 0; |
669 | int product; | |
670 | int size = 0; | |
671 | int ep_read = 0, ep_write = 0; | |
672 | int ret; | |
673 | ||
36445bc1 GKH |
674 | if (interface == NULL) |
675 | return -ENODEV; | |
705ececd | 676 | usbdev = interface_to_usbdev(interface); |
36445bc1 GKH |
677 | if (usbdev == NULL) |
678 | return -ENODEV; | |
705ececd | 679 | |
705ececd | 680 | /* we don't handle multiple configurations */ |
ab366c1a KV |
681 | if (usbdev->descriptor.bNumConfigurations != 1) { |
682 | ret = -ENODEV; | |
683 | goto err_put; | |
684 | } | |
705ececd MG |
685 | |
686 | /* check vendor and product id */ | |
d722a510 | 687 | for (devtype = ARRAY_SIZE(line6_id_table) - 1; devtype--;) { |
1e18c0d5 GKH |
688 | u16 idVendor = le16_to_cpu(usbdev->descriptor.idVendor); |
689 | u16 idProduct = le16_to_cpu(usbdev->descriptor.idProduct); | |
d722a510 | 690 | |
1027f476 MG |
691 | if (idVendor == line6_id_table[devtype].idVendor && |
692 | idProduct == line6_id_table[devtype].idProduct) | |
705ececd | 693 | break; |
d722a510 | 694 | } |
705ececd | 695 | |
ab366c1a KV |
696 | if (devtype < 0) { |
697 | ret = -ENODEV; | |
698 | goto err_put; | |
699 | } | |
705ececd | 700 | |
705ececd MG |
701 | /* initialize device info: */ |
702 | properties = &line6_properties_table[devtype]; | |
703 | dev_info(&interface->dev, "Line6 %s found\n", properties->name); | |
704 | product = le16_to_cpu(usbdev->descriptor.idProduct); | |
705 | ||
706 | /* query interface number */ | |
707 | interface_number = interface->cur_altsetting->desc.bInterfaceNumber; | |
708 | ||
36445bc1 | 709 | switch (product) { |
705ececd | 710 | case LINE6_DEVID_BASSPODXTLIVE: |
705ececd MG |
711 | case LINE6_DEVID_PODXTLIVE: |
712 | case LINE6_DEVID_VARIAX: | |
713 | alternate = 1; | |
714 | break; | |
715 | ||
1027f476 MG |
716 | case LINE6_DEVID_POCKETPOD: |
717 | switch (interface_number) { | |
718 | case 0: | |
e1a164d7 | 719 | return 0; /* this interface has no endpoints */ |
1027f476 MG |
720 | case 1: |
721 | alternate = 0; | |
722 | break; | |
723 | default: | |
724 | MISSING_CASE; | |
725 | } | |
726 | break; | |
727 | ||
4c6fb5fc | 728 | case LINE6_DEVID_PODHD500: |
705ececd MG |
729 | case LINE6_DEVID_PODX3: |
730 | case LINE6_DEVID_PODX3LIVE: | |
36445bc1 GKH |
731 | switch (interface_number) { |
732 | case 0: | |
733 | alternate = 1; | |
734 | break; | |
735 | case 1: | |
736 | alternate = 0; | |
737 | break; | |
738 | default: | |
739 | MISSING_CASE; | |
705ececd MG |
740 | } |
741 | break; | |
742 | ||
743 | case LINE6_DEVID_BASSPODXT: | |
744 | case LINE6_DEVID_BASSPODXTPRO: | |
745 | case LINE6_DEVID_PODXT: | |
746 | case LINE6_DEVID_PODXTPRO: | |
16dc1040 | 747 | case LINE6_DEVID_PODHD300: |
705ececd MG |
748 | alternate = 5; |
749 | break; | |
750 | ||
705ececd | 751 | case LINE6_DEVID_GUITARPORT: |
1027f476 MG |
752 | case LINE6_DEVID_PODSTUDIO_GX: |
753 | case LINE6_DEVID_PODSTUDIO_UX1: | |
754 | case LINE6_DEVID_TONEPORT_GX: | |
755 | case LINE6_DEVID_TONEPORT_UX1: | |
e1a164d7 | 756 | alternate = 2; /* 1..4 seem to be ok */ |
705ececd MG |
757 | break; |
758 | ||
705ececd | 759 | case LINE6_DEVID_TONEPORT_UX2: |
1027f476 | 760 | case LINE6_DEVID_PODSTUDIO_UX2: |
36445bc1 GKH |
761 | switch (interface_number) { |
762 | case 0: | |
763 | /* defaults to 44.1kHz, 16-bit */ | |
764 | alternate = 2; | |
765 | break; | |
766 | case 1: | |
1027f476 | 767 | /* don't know yet what this is ... |
e1a164d7 MG |
768 | alternate = 1; |
769 | break; | |
770 | */ | |
1027f476 | 771 | return -ENODEV; |
36445bc1 GKH |
772 | default: |
773 | MISSING_CASE; | |
705ececd MG |
774 | } |
775 | break; | |
776 | ||
777 | default: | |
778 | MISSING_CASE; | |
ab366c1a KV |
779 | ret = -ENODEV; |
780 | goto err_put; | |
705ececd MG |
781 | } |
782 | ||
36445bc1 GKH |
783 | ret = usb_set_interface(usbdev, interface_number, alternate); |
784 | if (ret < 0) { | |
705ececd | 785 | dev_err(&interface->dev, "set_interface failed\n"); |
ab366c1a | 786 | goto err_put; |
705ececd MG |
787 | } |
788 | ||
789 | /* initialize device data based on product id: */ | |
36445bc1 | 790 | switch (product) { |
705ececd MG |
791 | case LINE6_DEVID_BASSPODXT: |
792 | case LINE6_DEVID_BASSPODXTLIVE: | |
793 | case LINE6_DEVID_BASSPODXTPRO: | |
705ececd MG |
794 | case LINE6_DEVID_PODXT: |
795 | case LINE6_DEVID_PODXTPRO: | |
796 | size = sizeof(struct usb_line6_pod); | |
e1a164d7 | 797 | ep_read = 0x84; |
705ececd MG |
798 | ep_write = 0x03; |
799 | break; | |
800 | ||
16dc1040 SH |
801 | case LINE6_DEVID_PODHD300: |
802 | size = sizeof(struct usb_line6_podhd); | |
803 | ep_read = 0x84; | |
804 | ep_write = 0x03; | |
805 | break; | |
806 | ||
4c6fb5fc MG |
807 | case LINE6_DEVID_PODHD500: |
808 | size = sizeof(struct usb_line6_podhd); | |
809 | ep_read = 0x81; | |
810 | ep_write = 0x01; | |
811 | break; | |
812 | ||
1027f476 MG |
813 | case LINE6_DEVID_POCKETPOD: |
814 | size = sizeof(struct usb_line6_pod); | |
e1a164d7 | 815 | ep_read = 0x82; |
1027f476 MG |
816 | ep_write = 0x02; |
817 | break; | |
818 | ||
705ececd MG |
819 | case LINE6_DEVID_PODX3: |
820 | case LINE6_DEVID_PODX3LIVE: | |
821 | /* currently unused! */ | |
822 | size = sizeof(struct usb_line6_pod); | |
e1a164d7 | 823 | ep_read = 0x81; |
705ececd MG |
824 | ep_write = 0x01; |
825 | break; | |
826 | ||
1027f476 MG |
827 | case LINE6_DEVID_PODSTUDIO_GX: |
828 | case LINE6_DEVID_PODSTUDIO_UX1: | |
829 | case LINE6_DEVID_PODSTUDIO_UX2: | |
705ececd MG |
830 | case LINE6_DEVID_TONEPORT_GX: |
831 | case LINE6_DEVID_TONEPORT_UX1: | |
832 | case LINE6_DEVID_TONEPORT_UX2: | |
833 | case LINE6_DEVID_GUITARPORT: | |
834 | size = sizeof(struct usb_line6_toneport); | |
835 | /* these don't have a control channel */ | |
836 | break; | |
837 | ||
838 | case LINE6_DEVID_PODXTLIVE: | |
36445bc1 | 839 | switch (interface_number) { |
705ececd MG |
840 | case PODXTLIVE_INTERFACE_POD: |
841 | size = sizeof(struct usb_line6_pod); | |
e1a164d7 | 842 | ep_read = 0x84; |
705ececd MG |
843 | ep_write = 0x03; |
844 | break; | |
845 | ||
846 | case PODXTLIVE_INTERFACE_VARIAX: | |
847 | size = sizeof(struct usb_line6_variax); | |
e1a164d7 | 848 | ep_read = 0x86; |
705ececd MG |
849 | ep_write = 0x05; |
850 | break; | |
851 | ||
852 | default: | |
ab366c1a KV |
853 | ret = -ENODEV; |
854 | goto err_put; | |
705ececd MG |
855 | } |
856 | break; | |
857 | ||
858 | case LINE6_DEVID_VARIAX: | |
859 | size = sizeof(struct usb_line6_variax); | |
e1a164d7 | 860 | ep_read = 0x82; |
705ececd MG |
861 | ep_write = 0x01; |
862 | break; | |
863 | ||
864 | default: | |
865 | MISSING_CASE; | |
ab366c1a KV |
866 | ret = -ENODEV; |
867 | goto err_put; | |
705ececd MG |
868 | } |
869 | ||
36445bc1 | 870 | if (size == 0) { |
4bd8b4de | 871 | dev_err(&interface->dev, |
e1a164d7 | 872 | "driver bug: interface data size not set\n"); |
ab366c1a KV |
873 | ret = -ENODEV; |
874 | goto err_put; | |
705ececd MG |
875 | } |
876 | ||
877 | line6 = kzalloc(size, GFP_KERNEL); | |
878 | ||
36445bc1 | 879 | if (line6 == NULL) { |
705ececd | 880 | dev_err(&interface->dev, "Out of memory\n"); |
ab366c1a KV |
881 | ret = -ENODEV; |
882 | goto err_put; | |
705ececd MG |
883 | } |
884 | ||
885 | /* store basic data: */ | |
886 | line6->interface_number = interface_number; | |
887 | line6->properties = properties; | |
888 | line6->usbdev = usbdev; | |
889 | line6->ifcdev = &interface->dev; | |
890 | line6->ep_control_read = ep_read; | |
891 | line6->ep_control_write = ep_write; | |
892 | line6->product = product; | |
893 | ||
894 | /* get data from endpoint descriptor (see usb_maxpacket): */ | |
895 | { | |
896 | struct usb_host_endpoint *ep; | |
e1a164d7 MG |
897 | unsigned epnum = |
898 | usb_pipeendpoint(usb_rcvintpipe(usbdev, ep_read)); | |
705ececd MG |
899 | ep = usbdev->ep_in[epnum]; |
900 | ||
36445bc1 | 901 | if (ep != NULL) { |
705ececd | 902 | line6->interval = ep->desc.bInterval; |
e1a164d7 MG |
903 | line6->max_packet_size = |
904 | le16_to_cpu(ep->desc.wMaxPacketSize); | |
36445bc1 | 905 | } else { |
705ececd MG |
906 | line6->interval = LINE6_FALLBACK_INTERVAL; |
907 | line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE; | |
e1a164d7 MG |
908 | dev_err(line6->ifcdev, |
909 | "endpoint not available, using fallback values"); | |
705ececd MG |
910 | } |
911 | } | |
912 | ||
913 | usb_set_intfdata(interface, line6); | |
914 | ||
36445bc1 | 915 | if (properties->capabilities & LINE6_BIT_CONTROL) { |
705ececd | 916 | /* initialize USB buffers: */ |
e1a164d7 MG |
917 | line6->buffer_listen = |
918 | kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL); | |
705ececd | 919 | |
36445bc1 | 920 | if (line6->buffer_listen == NULL) { |
705ececd | 921 | dev_err(&interface->dev, "Out of memory\n"); |
ab366c1a KV |
922 | ret = -ENOMEM; |
923 | goto err_destruct; | |
705ececd MG |
924 | } |
925 | ||
e1a164d7 MG |
926 | line6->buffer_message = |
927 | kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL); | |
705ececd | 928 | |
36445bc1 | 929 | if (line6->buffer_message == NULL) { |
705ececd | 930 | dev_err(&interface->dev, "Out of memory\n"); |
ab366c1a KV |
931 | ret = -ENOMEM; |
932 | goto err_destruct; | |
705ececd MG |
933 | } |
934 | ||
935 | line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL); | |
936 | ||
36445bc1 | 937 | if (line6->urb_listen == NULL) { |
705ececd MG |
938 | dev_err(&interface->dev, "Out of memory\n"); |
939 | line6_destruct(interface); | |
ab366c1a KV |
940 | ret = -ENOMEM; |
941 | goto err_destruct; | |
705ececd MG |
942 | } |
943 | ||
36445bc1 GKH |
944 | ret = line6_start_listen(line6); |
945 | if (ret < 0) { | |
946 | dev_err(&interface->dev, "%s: usb_submit_urb failed\n", | |
947 | __func__); | |
ab366c1a | 948 | goto err_destruct; |
705ececd MG |
949 | } |
950 | } | |
951 | ||
952 | /* initialize device data based on product id: */ | |
36445bc1 | 953 | switch (product) { |
705ececd MG |
954 | case LINE6_DEVID_BASSPODXT: |
955 | case LINE6_DEVID_BASSPODXTLIVE: | |
956 | case LINE6_DEVID_BASSPODXTPRO: | |
957 | case LINE6_DEVID_POCKETPOD: | |
958 | case LINE6_DEVID_PODX3: | |
959 | case LINE6_DEVID_PODX3LIVE: | |
960 | case LINE6_DEVID_PODXT: | |
961 | case LINE6_DEVID_PODXTPRO: | |
1027f476 | 962 | ret = line6_pod_init(interface, (struct usb_line6_pod *)line6); |
705ececd MG |
963 | break; |
964 | ||
16dc1040 | 965 | case LINE6_DEVID_PODHD300: |
4c6fb5fc | 966 | case LINE6_DEVID_PODHD500: |
16dc1040 SH |
967 | ret = line6_podhd_init(interface, |
968 | (struct usb_line6_podhd *)line6); | |
969 | break; | |
970 | ||
705ececd | 971 | case LINE6_DEVID_PODXTLIVE: |
36445bc1 | 972 | switch (interface_number) { |
705ececd | 973 | case PODXTLIVE_INTERFACE_POD: |
e1a164d7 MG |
974 | ret = |
975 | line6_pod_init(interface, | |
976 | (struct usb_line6_pod *)line6); | |
705ececd MG |
977 | break; |
978 | ||
979 | case PODXTLIVE_INTERFACE_VARIAX: | |
e1a164d7 MG |
980 | ret = |
981 | line6_variax_init(interface, | |
982 | (struct usb_line6_variax *)line6); | |
705ececd MG |
983 | break; |
984 | ||
985 | default: | |
36445bc1 GKH |
986 | dev_err(&interface->dev, |
987 | "PODxt Live interface %d not supported\n", | |
988 | interface_number); | |
705ececd MG |
989 | ret = -ENODEV; |
990 | } | |
991 | ||
992 | break; | |
993 | ||
994 | case LINE6_DEVID_VARIAX: | |
e1a164d7 MG |
995 | ret = |
996 | line6_variax_init(interface, | |
997 | (struct usb_line6_variax *)line6); | |
705ececd MG |
998 | break; |
999 | ||
1027f476 MG |
1000 | case LINE6_DEVID_PODSTUDIO_GX: |
1001 | case LINE6_DEVID_PODSTUDIO_UX1: | |
1002 | case LINE6_DEVID_PODSTUDIO_UX2: | |
705ececd MG |
1003 | case LINE6_DEVID_TONEPORT_GX: |
1004 | case LINE6_DEVID_TONEPORT_UX1: | |
1005 | case LINE6_DEVID_TONEPORT_UX2: | |
1006 | case LINE6_DEVID_GUITARPORT: | |
e1a164d7 MG |
1007 | ret = |
1008 | line6_toneport_init(interface, | |
1009 | (struct usb_line6_toneport *)line6); | |
705ececd MG |
1010 | break; |
1011 | ||
1012 | default: | |
1013 | MISSING_CASE; | |
1014 | ret = -ENODEV; | |
1015 | } | |
1016 | ||
ab366c1a KV |
1017 | if (ret < 0) |
1018 | goto err_destruct; | |
705ececd | 1019 | |
36445bc1 GKH |
1020 | ret = sysfs_create_link(&interface->dev.kobj, &usbdev->dev.kobj, |
1021 | "usb_device"); | |
ab366c1a KV |
1022 | if (ret < 0) |
1023 | goto err_destruct; | |
705ececd | 1024 | |
1027f476 MG |
1025 | /* creation of additional special files should go here */ |
1026 | ||
36445bc1 GKH |
1027 | dev_info(&interface->dev, "Line6 %s now attached\n", |
1028 | line6->properties->name); | |
1027f476 | 1029 | |
e1a164d7 | 1030 | switch (product) { |
1027f476 MG |
1031 | case LINE6_DEVID_PODX3: |
1032 | case LINE6_DEVID_PODX3LIVE: | |
e1a164d7 MG |
1033 | dev_info(&interface->dev, |
1034 | "NOTE: the Line6 %s is detected, but not yet supported\n", | |
1027f476 MG |
1035 | line6->properties->name); |
1036 | } | |
1037 | ||
1038 | /* increment reference counters: */ | |
1039 | usb_get_intf(interface); | |
1040 | usb_get_dev(usbdev); | |
1041 | ||
ab366c1a KV |
1042 | return 0; |
1043 | ||
1044 | err_destruct: | |
1045 | line6_destruct(interface); | |
1046 | err_put: | |
705ececd MG |
1047 | return ret; |
1048 | } | |
1049 | ||
1050 | /* | |
1051 | Line6 device disconnected. | |
1052 | */ | |
1053 | static void line6_disconnect(struct usb_interface *interface) | |
1054 | { | |
1055 | struct usb_line6 *line6; | |
1056 | struct usb_device *usbdev; | |
b430b3db | 1057 | int interface_number; |
705ececd | 1058 | |
36445bc1 GKH |
1059 | if (interface == NULL) |
1060 | return; | |
705ececd | 1061 | usbdev = interface_to_usbdev(interface); |
36445bc1 GKH |
1062 | if (usbdev == NULL) |
1063 | return; | |
705ececd | 1064 | |
1027f476 MG |
1065 | /* removal of additional special files should go here */ |
1066 | ||
705ececd MG |
1067 | sysfs_remove_link(&interface->dev.kobj, "usb_device"); |
1068 | ||
1069 | interface_number = interface->cur_altsetting->desc.bInterfaceNumber; | |
1070 | line6 = usb_get_intfdata(interface); | |
1071 | ||
36445bc1 GKH |
1072 | if (line6 != NULL) { |
1073 | if (line6->urb_listen != NULL) | |
1027f476 | 1074 | line6_stop_listen(line6); |
705ececd | 1075 | |
36445bc1 GKH |
1076 | if (usbdev != line6->usbdev) |
1077 | dev_err(line6->ifcdev, | |
1078 | "driver bug: inconsistent usb device\n"); | |
705ececd | 1079 | |
36445bc1 | 1080 | switch (line6->usbdev->descriptor.idProduct) { |
705ececd MG |
1081 | case LINE6_DEVID_BASSPODXT: |
1082 | case LINE6_DEVID_BASSPODXTLIVE: | |
1083 | case LINE6_DEVID_BASSPODXTPRO: | |
1084 | case LINE6_DEVID_POCKETPOD: | |
1085 | case LINE6_DEVID_PODX3: | |
1086 | case LINE6_DEVID_PODX3LIVE: | |
1087 | case LINE6_DEVID_PODXT: | |
1088 | case LINE6_DEVID_PODXTPRO: | |
1027f476 | 1089 | line6_pod_disconnect(interface); |
705ececd MG |
1090 | break; |
1091 | ||
16dc1040 | 1092 | case LINE6_DEVID_PODHD300: |
4c6fb5fc | 1093 | case LINE6_DEVID_PODHD500: |
16dc1040 SH |
1094 | line6_podhd_disconnect(interface); |
1095 | break; | |
1096 | ||
705ececd | 1097 | case LINE6_DEVID_PODXTLIVE: |
36445bc1 | 1098 | switch (interface_number) { |
705ececd | 1099 | case PODXTLIVE_INTERFACE_POD: |
1027f476 | 1100 | line6_pod_disconnect(interface); |
705ececd MG |
1101 | break; |
1102 | ||
1103 | case PODXTLIVE_INTERFACE_VARIAX: | |
1027f476 | 1104 | line6_variax_disconnect(interface); |
705ececd MG |
1105 | break; |
1106 | } | |
1107 | ||
1108 | break; | |
1109 | ||
1110 | case LINE6_DEVID_VARIAX: | |
1027f476 | 1111 | line6_variax_disconnect(interface); |
705ececd MG |
1112 | break; |
1113 | ||
1027f476 MG |
1114 | case LINE6_DEVID_PODSTUDIO_GX: |
1115 | case LINE6_DEVID_PODSTUDIO_UX1: | |
1116 | case LINE6_DEVID_PODSTUDIO_UX2: | |
705ececd MG |
1117 | case LINE6_DEVID_TONEPORT_GX: |
1118 | case LINE6_DEVID_TONEPORT_UX1: | |
1119 | case LINE6_DEVID_TONEPORT_UX2: | |
1120 | case LINE6_DEVID_GUITARPORT: | |
1027f476 | 1121 | line6_toneport_disconnect(interface); |
705ececd MG |
1122 | break; |
1123 | ||
1124 | default: | |
1125 | MISSING_CASE; | |
1126 | } | |
1127 | ||
e1a164d7 MG |
1128 | dev_info(&interface->dev, "Line6 %s now disconnected\n", |
1129 | line6->properties->name); | |
705ececd MG |
1130 | } |
1131 | ||
1132 | line6_destruct(interface); | |
1133 | ||
1134 | /* decrement reference counters: */ | |
1135 | usb_put_intf(interface); | |
1136 | usb_put_dev(usbdev); | |
1027f476 MG |
1137 | } |
1138 | ||
1139 | #ifdef CONFIG_PM | |
1140 | ||
1141 | /* | |
1142 | Suspend Line6 device. | |
1143 | */ | |
1144 | static int line6_suspend(struct usb_interface *interface, pm_message_t message) | |
1145 | { | |
1146 | struct usb_line6 *line6 = usb_get_intfdata(interface); | |
1147 | struct snd_line6_pcm *line6pcm = line6->line6pcm; | |
1148 | ||
1149 | snd_power_change_state(line6->card, SNDRV_CTL_POWER_D3hot); | |
1150 | ||
1151 | if (line6->properties->capabilities & LINE6_BIT_CONTROL) | |
1152 | line6_stop_listen(line6); | |
1153 | ||
1154 | if (line6pcm != NULL) { | |
1155 | snd_pcm_suspend_all(line6pcm->pcm); | |
1156 | line6_pcm_disconnect(line6pcm); | |
1157 | line6pcm->flags = 0; | |
1158 | } | |
1159 | ||
1160 | return 0; | |
1161 | } | |
1162 | ||
1163 | /* | |
1164 | Resume Line6 device. | |
1165 | */ | |
1166 | static int line6_resume(struct usb_interface *interface) | |
1167 | { | |
1168 | struct usb_line6 *line6 = usb_get_intfdata(interface); | |
1169 | ||
1170 | if (line6->properties->capabilities & LINE6_BIT_CONTROL) | |
1171 | line6_start_listen(line6); | |
1172 | ||
1173 | snd_power_change_state(line6->card, SNDRV_CTL_POWER_D0); | |
1174 | return 0; | |
1175 | } | |
1176 | ||
1177 | /* | |
1178 | Resume Line6 device after reset. | |
1179 | */ | |
1180 | static int line6_reset_resume(struct usb_interface *interface) | |
1181 | { | |
1182 | struct usb_line6 *line6 = usb_get_intfdata(interface); | |
705ececd | 1183 | |
1027f476 MG |
1184 | switch (line6->usbdev->descriptor.idProduct) { |
1185 | case LINE6_DEVID_PODSTUDIO_GX: | |
1186 | case LINE6_DEVID_PODSTUDIO_UX1: | |
1187 | case LINE6_DEVID_PODSTUDIO_UX2: | |
1188 | case LINE6_DEVID_TONEPORT_GX: | |
1189 | case LINE6_DEVID_TONEPORT_UX1: | |
1190 | case LINE6_DEVID_TONEPORT_UX2: | |
1191 | case LINE6_DEVID_GUITARPORT: | |
1192 | line6_toneport_reset_resume((struct usb_line6_toneport *)line6); | |
1193 | } | |
1194 | ||
1195 | return line6_resume(interface); | |
705ececd MG |
1196 | } |
1197 | ||
e1a164d7 | 1198 | #endif /* CONFIG_PM */ |
1027f476 | 1199 | |
705ececd | 1200 | static struct usb_driver line6_driver = { |
705ececd MG |
1201 | .name = DRIVER_NAME, |
1202 | .probe = line6_probe, | |
1203 | .disconnect = line6_disconnect, | |
1027f476 MG |
1204 | #ifdef CONFIG_PM |
1205 | .suspend = line6_suspend, | |
1206 | .resume = line6_resume, | |
1207 | .reset_resume = line6_reset_resume, | |
1208 | #endif | |
705ececd MG |
1209 | .id_table = line6_id_table, |
1210 | }; | |
1211 | ||
4a631364 | 1212 | module_usb_driver(line6_driver); |
705ececd MG |
1213 | |
1214 | MODULE_AUTHOR(DRIVER_AUTHOR); | |
1215 | MODULE_DESCRIPTION(DRIVER_DESC); | |
1216 | MODULE_LICENSE("GPL"); | |
1217 | MODULE_VERSION(DRIVER_VERSION); |