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