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