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 | * Emil Myhrman (emil.myhrman@gmail.com) |
6 | * | |
7 | * This program is free software; you can redistribute it and/or | |
8 | * modify it under the terms of the GNU General Public License as | |
9 | * published by the Free Software Foundation, version 2. | |
10 | * | |
11 | */ | |
12 | ||
1027f476 | 13 | #include <linux/wait.h> |
ccddbe4a TI |
14 | #include <linux/usb.h> |
15 | #include <linux/slab.h> | |
16 | #include <linux/module.h> | |
17 | #include <sound/core.h> | |
1027f476 | 18 | #include <sound/control.h> |
705ececd | 19 | |
705ececd | 20 | #include "capture.h" |
1027f476 | 21 | #include "driver.h" |
705ececd | 22 | #include "playback.h" |
ccddbe4a TI |
23 | #include "usbdefs.h" |
24 | ||
25 | enum line6_device_type { | |
26 | LINE6_GUITARPORT, | |
27 | LINE6_PODSTUDIO_GX, | |
28 | LINE6_PODSTUDIO_UX1, | |
29 | LINE6_PODSTUDIO_UX2, | |
30 | LINE6_TONEPORT_GX, | |
31 | LINE6_TONEPORT_UX1, | |
32 | LINE6_TONEPORT_UX2, | |
33 | }; | |
34 | ||
35 | struct usb_line6_toneport { | |
36 | /** | |
37 | Generic Line6 USB data. | |
38 | */ | |
39 | struct usb_line6 line6; | |
40 | ||
41 | /** | |
42 | Source selector. | |
43 | */ | |
44 | int source; | |
45 | ||
46 | /** | |
47 | Serial number of device. | |
48 | */ | |
49 | int serial_number; | |
50 | ||
51 | /** | |
52 | Firmware version (x 100). | |
53 | */ | |
54 | int firmware_version; | |
55 | ||
56 | /** | |
57 | Timer for delayed PCM startup. | |
58 | */ | |
59 | struct timer_list timer; | |
60 | ||
61 | /** | |
62 | Device type. | |
63 | */ | |
64 | enum line6_device_type type; | |
65 | }; | |
705ececd | 66 | |
705ececd MG |
67 | static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2); |
68 | ||
1027f476 MG |
69 | #define TONEPORT_PCM_DELAY 1 |
70 | ||
705ececd MG |
71 | static struct snd_ratden toneport_ratden = { |
72 | .num_min = 44100, | |
73 | .num_max = 44100, | |
74 | .num_step = 1, | |
75 | .den = 1 | |
76 | }; | |
77 | ||
78 | static struct line6_pcm_properties toneport_pcm_properties = { | |
63a4a8ba | 79 | .snd_line6_playback_hw = { |
e1a164d7 MG |
80 | .info = (SNDRV_PCM_INFO_MMAP | |
81 | SNDRV_PCM_INFO_INTERLEAVED | | |
82 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | |
83 | SNDRV_PCM_INFO_MMAP_VALID | | |
84 | SNDRV_PCM_INFO_PAUSE | | |
e1a164d7 MG |
85 | SNDRV_PCM_INFO_SYNC_START), |
86 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | |
87 | .rates = SNDRV_PCM_RATE_KNOT, | |
88 | .rate_min = 44100, | |
89 | .rate_max = 44100, | |
90 | .channels_min = 2, | |
91 | .channels_max = 2, | |
92 | .buffer_bytes_max = 60000, | |
93 | .period_bytes_min = 64, | |
94 | .period_bytes_max = 8192, | |
95 | .periods_min = 1, | |
96 | .periods_max = 1024}, | |
63a4a8ba | 97 | .snd_line6_capture_hw = { |
e1a164d7 MG |
98 | .info = (SNDRV_PCM_INFO_MMAP | |
99 | SNDRV_PCM_INFO_INTERLEAVED | | |
100 | SNDRV_PCM_INFO_BLOCK_TRANSFER | | |
101 | SNDRV_PCM_INFO_MMAP_VALID | | |
e1a164d7 MG |
102 | SNDRV_PCM_INFO_SYNC_START), |
103 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | |
104 | .rates = SNDRV_PCM_RATE_KNOT, | |
105 | .rate_min = 44100, | |
106 | .rate_max = 44100, | |
107 | .channels_min = 2, | |
108 | .channels_max = 2, | |
109 | .buffer_bytes_max = 60000, | |
110 | .period_bytes_min = 64, | |
111 | .period_bytes_max = 8192, | |
112 | .periods_min = 1, | |
113 | .periods_max = 1024}, | |
705ececd | 114 | .snd_line6_rates = { |
e1a164d7 MG |
115 | .nrats = 1, |
116 | .rats = &toneport_ratden}, | |
705ececd MG |
117 | .bytes_per_frame = 4 |
118 | }; | |
119 | ||
120 | /* | |
121 | For the led on Guitarport. | |
6353773b GKH |
122 | Brightness goes from 0x00 to 0x26. Set a value above this to have led |
123 | blink. | |
705ececd MG |
124 | (void cmd_0x02(byte red, byte green) |
125 | */ | |
126 | static int led_red = 0x00; | |
127 | static int led_green = 0x26; | |
128 | ||
709b2fae | 129 | static const struct { |
1027f476 MG |
130 | const char *name; |
131 | int code; | |
709b2fae | 132 | } toneport_source_info[] = { |
e1a164d7 MG |
133 | {"Microphone", 0x0a01}, |
134 | {"Line", 0x0801}, | |
135 | {"Instrument", 0x0b01}, | |
136 | {"Inst & Mic", 0x0901} | |
1027f476 MG |
137 | }; |
138 | ||
a23a8bff | 139 | static bool toneport_has_led(enum line6_device_type type) |
1027f476 MG |
140 | { |
141 | return | |
a23a8bff CR |
142 | (type == LINE6_GUITARPORT) || |
143 | (type == LINE6_TONEPORT_GX); | |
1027f476 MG |
144 | /* add your device here if you are missing support for the LEDs */ |
145 | } | |
146 | ||
6353773b GKH |
147 | static void toneport_update_led(struct device *dev) |
148 | { | |
149 | struct usb_interface *interface = to_usb_interface(dev); | |
150 | struct usb_line6_toneport *tp = usb_get_intfdata(interface); | |
151 | struct usb_line6 *line6; | |
705ececd | 152 | |
6353773b GKH |
153 | if (!tp) |
154 | return; | |
155 | ||
156 | line6 = &tp->line6; | |
157 | if (line6) | |
158 | toneport_send_cmd(line6->usbdev, (led_red << 8) | 0x0002, | |
159 | led_green); | |
705ececd | 160 | } |
6353773b | 161 | |
77491e52 GKH |
162 | static ssize_t toneport_set_led_red(struct device *dev, |
163 | struct device_attribute *attr, | |
6353773b GKH |
164 | const char *buf, size_t count) |
165 | { | |
bb950a16 | 166 | int retval; |
bb950a16 | 167 | |
b07d9452 | 168 | retval = kstrtoint(buf, 10, &led_red); |
bb950a16 SB |
169 | if (retval) |
170 | return retval; | |
171 | ||
705ececd MG |
172 | toneport_update_led(dev); |
173 | return count; | |
174 | } | |
6353773b | 175 | |
77491e52 GKH |
176 | static ssize_t toneport_set_led_green(struct device *dev, |
177 | struct device_attribute *attr, | |
6353773b GKH |
178 | const char *buf, size_t count) |
179 | { | |
bb950a16 | 180 | int retval; |
bb950a16 | 181 | |
b07d9452 | 182 | retval = kstrtoint(buf, 10, &led_green); |
bb950a16 SB |
183 | if (retval) |
184 | return retval; | |
185 | ||
705ececd MG |
186 | toneport_update_led(dev); |
187 | return count; | |
188 | } | |
189 | ||
a3a972a0 | 190 | static DEVICE_ATTR(led_red, S_IWUSR | S_IRUGO, line6_nop_read, |
63a4a8ba | 191 | toneport_set_led_red); |
a3a972a0 | 192 | static DEVICE_ATTR(led_green, S_IWUSR | S_IRUGO, line6_nop_read, |
63a4a8ba | 193 | toneport_set_led_green); |
705ececd MG |
194 | |
195 | static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2) | |
196 | { | |
197 | int ret; | |
705ececd | 198 | |
6353773b GKH |
199 | ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67, |
200 | USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT, | |
201 | cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ); | |
202 | ||
203 | if (ret < 0) { | |
d86938fb | 204 | dev_err(&usbdev->dev, "send failed (error %d)\n", ret); |
705ececd MG |
205 | return ret; |
206 | } | |
207 | ||
208 | return 0; | |
209 | } | |
210 | ||
1027f476 MG |
211 | /* monitor info callback */ |
212 | static int snd_toneport_monitor_info(struct snd_kcontrol *kcontrol, | |
213 | struct snd_ctl_elem_info *uinfo) | |
214 | { | |
215 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | |
216 | uinfo->count = 1; | |
217 | uinfo->value.integer.min = 0; | |
218 | uinfo->value.integer.max = 256; | |
219 | return 0; | |
220 | } | |
221 | ||
222 | /* monitor get callback */ | |
223 | static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol, | |
224 | struct snd_ctl_elem_value *ucontrol) | |
225 | { | |
226 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | |
f3c5261e | 227 | |
1027f476 MG |
228 | ucontrol->value.integer.value[0] = line6pcm->volume_monitor; |
229 | return 0; | |
230 | } | |
231 | ||
232 | /* monitor put callback */ | |
233 | static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol, | |
234 | struct snd_ctl_elem_value *ucontrol) | |
235 | { | |
236 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | |
237 | ||
e1a164d7 | 238 | if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor) |
1027f476 MG |
239 | return 0; |
240 | ||
241 | line6pcm->volume_monitor = ucontrol->value.integer.value[0]; | |
e1a164d7 MG |
242 | |
243 | if (line6pcm->volume_monitor > 0) | |
0ca54888 | 244 | line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_MONITOR); |
e1a164d7 | 245 | else |
0ca54888 | 246 | line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR); |
e1a164d7 | 247 | |
1027f476 MG |
248 | return 1; |
249 | } | |
250 | ||
251 | /* source info callback */ | |
252 | static int snd_toneport_source_info(struct snd_kcontrol *kcontrol, | |
253 | struct snd_ctl_elem_info *uinfo) | |
254 | { | |
255 | const int size = ARRAY_SIZE(toneport_source_info); | |
a6b4699d | 256 | |
1027f476 MG |
257 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; |
258 | uinfo->count = 1; | |
259 | uinfo->value.enumerated.items = size; | |
260 | ||
e1a164d7 | 261 | if (uinfo->value.enumerated.item >= size) |
1027f476 MG |
262 | uinfo->value.enumerated.item = size - 1; |
263 | ||
264 | strcpy(uinfo->value.enumerated.name, | |
265 | toneport_source_info[uinfo->value.enumerated.item].name); | |
266 | ||
267 | return 0; | |
268 | } | |
269 | ||
270 | /* source get callback */ | |
271 | static int snd_toneport_source_get(struct snd_kcontrol *kcontrol, | |
272 | struct snd_ctl_elem_value *ucontrol) | |
273 | { | |
274 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | |
e1a164d7 MG |
275 | struct usb_line6_toneport *toneport = |
276 | (struct usb_line6_toneport *)line6pcm->line6; | |
1027f476 MG |
277 | ucontrol->value.enumerated.item[0] = toneport->source; |
278 | return 0; | |
279 | } | |
280 | ||
281 | /* source put callback */ | |
282 | static int snd_toneport_source_put(struct snd_kcontrol *kcontrol, | |
283 | struct snd_ctl_elem_value *ucontrol) | |
284 | { | |
285 | struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol); | |
e1a164d7 MG |
286 | struct usb_line6_toneport *toneport = |
287 | (struct usb_line6_toneport *)line6pcm->line6; | |
c3cb718a | 288 | unsigned int source; |
1027f476 | 289 | |
c3cb718a DC |
290 | source = ucontrol->value.enumerated.item[0]; |
291 | if (source >= ARRAY_SIZE(toneport_source_info)) | |
292 | return -EINVAL; | |
293 | if (source == toneport->source) | |
1027f476 MG |
294 | return 0; |
295 | ||
c3cb718a | 296 | toneport->source = source; |
e1a164d7 | 297 | toneport_send_cmd(toneport->line6.usbdev, |
c3cb718a | 298 | toneport_source_info[source].code, 0x0000); |
1027f476 MG |
299 | return 1; |
300 | } | |
301 | ||
302 | static void toneport_start_pcm(unsigned long arg) | |
303 | { | |
304 | struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg; | |
305 | struct usb_line6 *line6 = &toneport->line6; | |
f3c5261e | 306 | |
0ca54888 | 307 | line6_pcm_acquire(line6->line6pcm, LINE6_BITS_PCM_MONITOR); |
1027f476 MG |
308 | } |
309 | ||
310 | /* control definition */ | |
311 | static struct snd_kcontrol_new toneport_control_monitor = { | |
312 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
313 | .name = "Monitor Playback Volume", | |
314 | .index = 0, | |
315 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | |
316 | .info = snd_toneport_monitor_info, | |
317 | .get = snd_toneport_monitor_get, | |
318 | .put = snd_toneport_monitor_put | |
319 | }; | |
320 | ||
321 | /* source selector definition */ | |
322 | static struct snd_kcontrol_new toneport_control_source = { | |
323 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | |
324 | .name = "PCM Capture Source", | |
325 | .index = 0, | |
326 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, | |
327 | .info = snd_toneport_source_info, | |
328 | .get = snd_toneport_source_get, | |
329 | .put = snd_toneport_source_put | |
330 | }; | |
331 | ||
705ececd | 332 | /* |
1027f476 | 333 | Setup Toneport device. |
705ececd | 334 | */ |
1027f476 | 335 | static void toneport_setup(struct usb_line6_toneport *toneport) |
705ececd | 336 | { |
1027f476 | 337 | int ticks; |
705ececd | 338 | struct usb_line6 *line6 = &toneport->line6; |
1027f476 MG |
339 | struct usb_device *usbdev = line6->usbdev; |
340 | ||
341 | /* sync time on device with host: */ | |
342 | ticks = (int)get_seconds(); | |
343 | line6_write_data(line6, 0x80c6, &ticks, 4); | |
344 | ||
345 | /* enable device: */ | |
346 | toneport_send_cmd(usbdev, 0x0301, 0x0000); | |
347 | ||
348 | /* initialize source select: */ | |
ccddbe4a | 349 | switch (toneport->type) { |
a23a8bff CR |
350 | case LINE6_TONEPORT_UX1: |
351 | case LINE6_TONEPORT_UX2: | |
352 | case LINE6_PODSTUDIO_UX1: | |
353 | case LINE6_PODSTUDIO_UX2: | |
e1a164d7 MG |
354 | toneport_send_cmd(usbdev, |
355 | toneport_source_info[toneport->source].code, | |
356 | 0x0000); | |
a23a8bff CR |
357 | default: |
358 | break; | |
1027f476 MG |
359 | } |
360 | ||
ccddbe4a | 361 | if (toneport_has_led(toneport->type)) |
1027f476 MG |
362 | toneport_update_led(&usbdev->dev); |
363 | } | |
364 | ||
d29b854f CR |
365 | /* |
366 | Toneport device disconnected. | |
367 | */ | |
368 | static void line6_toneport_disconnect(struct usb_interface *interface) | |
369 | { | |
370 | struct usb_line6_toneport *toneport; | |
371 | u16 idProduct; | |
372 | ||
373 | if (interface == NULL) | |
374 | return; | |
375 | ||
376 | toneport = usb_get_intfdata(interface); | |
377 | del_timer_sync(&toneport->timer); | |
378 | idProduct = le16_to_cpu(toneport->line6.usbdev->descriptor.idProduct); | |
379 | ||
380 | if (toneport_has_led(idProduct)) { | |
381 | device_remove_file(&interface->dev, &dev_attr_led_red); | |
382 | device_remove_file(&interface->dev, &dev_attr_led_green); | |
383 | } | |
d29b854f CR |
384 | } |
385 | ||
386 | ||
1027f476 MG |
387 | /* |
388 | Try to init Toneport device. | |
389 | */ | |
85a9339b TI |
390 | static int toneport_init(struct usb_interface *interface, |
391 | struct usb_line6 *line6) | |
1027f476 MG |
392 | { |
393 | int err; | |
a221dd45 | 394 | struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6; |
705ececd | 395 | |
6353773b | 396 | if ((interface == NULL) || (toneport == NULL)) |
705ececd MG |
397 | return -ENODEV; |
398 | ||
a46c4672 CR |
399 | line6->disconnect = line6_toneport_disconnect; |
400 | ||
705ececd | 401 | /* initialize PCM subsystem: */ |
6353773b | 402 | err = line6_init_pcm(line6, &toneport_pcm_properties); |
027360c5 | 403 | if (err < 0) |
705ececd | 404 | return err; |
705ececd | 405 | |
1027f476 | 406 | /* register monitor control: */ |
027360c5 GKH |
407 | err = snd_ctl_add(line6->card, |
408 | snd_ctl_new1(&toneport_control_monitor, | |
409 | line6->line6pcm)); | |
410 | if (err < 0) | |
1027f476 | 411 | return err; |
1027f476 MG |
412 | |
413 | /* register source select control: */ | |
ccddbe4a | 414 | switch (toneport->type) { |
a23a8bff CR |
415 | case LINE6_TONEPORT_UX1: |
416 | case LINE6_TONEPORT_UX2: | |
417 | case LINE6_PODSTUDIO_UX1: | |
418 | case LINE6_PODSTUDIO_UX2: | |
e1a164d7 MG |
419 | err = |
420 | snd_ctl_add(line6->card, | |
421 | snd_ctl_new1(&toneport_control_source, | |
422 | line6->line6pcm)); | |
027360c5 | 423 | if (err < 0) |
1027f476 | 424 | return err; |
a23a8bff CR |
425 | |
426 | default: | |
427 | break; | |
1027f476 MG |
428 | } |
429 | ||
705ececd MG |
430 | line6_read_serial_number(line6, &toneport->serial_number); |
431 | line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1); | |
432 | ||
ccddbe4a | 433 | if (toneport_has_led(toneport->type)) { |
e1a164d7 MG |
434 | CHECK_RETURN(device_create_file |
435 | (&interface->dev, &dev_attr_led_red)); | |
436 | CHECK_RETURN(device_create_file | |
437 | (&interface->dev, &dev_attr_led_green)); | |
1027f476 | 438 | } |
705ececd | 439 | |
1027f476 | 440 | toneport_setup(toneport); |
705ececd | 441 | |
0f2524b3 TI |
442 | setup_timer(&toneport->timer, toneport_start_pcm, |
443 | (unsigned long)toneport); | |
444 | mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ); | |
705ececd | 445 | |
85a9339b TI |
446 | /* register audio system: */ |
447 | return snd_card_register(line6->card); | |
1027f476 MG |
448 | } |
449 | ||
ccddbe4a | 450 | #ifdef CONFIG_PM |
1027f476 MG |
451 | /* |
452 | Resume Toneport device after reset. | |
453 | */ | |
ccddbe4a | 454 | static int toneport_reset_resume(struct usb_interface *interface) |
1027f476 | 455 | { |
ccddbe4a TI |
456 | toneport_setup(usb_get_intfdata(interface)); |
457 | return line6_resume(interface); | |
1027f476 | 458 | } |
ccddbe4a TI |
459 | #endif |
460 | ||
461 | #define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod) | |
462 | #define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n) | |
463 | ||
464 | /* table of devices that work with this driver */ | |
465 | static const struct usb_device_id toneport_id_table[] = { | |
466 | { LINE6_DEVICE(0x4750), .driver_info = LINE6_GUITARPORT }, | |
467 | { LINE6_DEVICE(0x4153), .driver_info = LINE6_PODSTUDIO_GX }, | |
468 | { LINE6_DEVICE(0x4150), .driver_info = LINE6_PODSTUDIO_UX1 }, | |
469 | { LINE6_IF_NUM(0x4151, 0), .driver_info = LINE6_PODSTUDIO_UX2 }, | |
470 | { LINE6_DEVICE(0x4147), .driver_info = LINE6_TONEPORT_GX }, | |
471 | { LINE6_DEVICE(0x4141), .driver_info = LINE6_TONEPORT_UX1 }, | |
472 | { LINE6_IF_NUM(0x4142, 0), .driver_info = LINE6_TONEPORT_UX2 }, | |
473 | {} | |
474 | }; | |
475 | ||
476 | MODULE_DEVICE_TABLE(usb, toneport_id_table); | |
477 | ||
478 | static const struct line6_properties toneport_properties_table[] = { | |
479 | [LINE6_GUITARPORT] = { | |
480 | .id = "GuitarPort", | |
481 | .name = "GuitarPort", | |
482 | .capabilities = LINE6_CAP_PCM, | |
483 | .altsetting = 2, /* 1..4 seem to be ok */ | |
484 | /* no control channel */ | |
485 | .ep_audio_r = 0x82, | |
486 | .ep_audio_w = 0x01, | |
487 | }, | |
488 | [LINE6_PODSTUDIO_GX] = { | |
489 | .id = "PODStudioGX", | |
490 | .name = "POD Studio GX", | |
491 | .capabilities = LINE6_CAP_PCM, | |
492 | .altsetting = 2, /* 1..4 seem to be ok */ | |
493 | /* no control channel */ | |
494 | .ep_audio_r = 0x82, | |
495 | .ep_audio_w = 0x01, | |
496 | }, | |
497 | [LINE6_PODSTUDIO_UX1] = { | |
498 | .id = "PODStudioUX1", | |
499 | .name = "POD Studio UX1", | |
500 | .capabilities = LINE6_CAP_PCM, | |
501 | .altsetting = 2, /* 1..4 seem to be ok */ | |
502 | /* no control channel */ | |
503 | .ep_audio_r = 0x82, | |
504 | .ep_audio_w = 0x01, | |
505 | }, | |
506 | [LINE6_PODSTUDIO_UX2] = { | |
507 | .id = "PODStudioUX2", | |
508 | .name = "POD Studio UX2", | |
509 | .capabilities = LINE6_CAP_PCM, | |
510 | .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ | |
511 | /* no control channel */ | |
512 | .ep_audio_r = 0x82, | |
513 | .ep_audio_w = 0x01, | |
514 | }, | |
515 | [LINE6_TONEPORT_GX] = { | |
516 | .id = "TonePortGX", | |
517 | .name = "TonePort GX", | |
518 | .capabilities = LINE6_CAP_PCM, | |
519 | .altsetting = 2, /* 1..4 seem to be ok */ | |
520 | /* no control channel */ | |
521 | .ep_audio_r = 0x82, | |
522 | .ep_audio_w = 0x01, | |
523 | }, | |
524 | [LINE6_TONEPORT_UX1] = { | |
525 | .id = "TonePortUX1", | |
526 | .name = "TonePort UX1", | |
527 | .capabilities = LINE6_CAP_PCM, | |
528 | .altsetting = 2, /* 1..4 seem to be ok */ | |
529 | /* no control channel */ | |
530 | .ep_audio_r = 0x82, | |
531 | .ep_audio_w = 0x01, | |
532 | }, | |
533 | [LINE6_TONEPORT_UX2] = { | |
534 | .id = "TonePortUX2", | |
535 | .name = "TonePort UX2", | |
536 | .capabilities = LINE6_CAP_PCM, | |
537 | .altsetting = 2, /* defaults to 44.1kHz, 16-bit */ | |
538 | /* no control channel */ | |
539 | .ep_audio_r = 0x82, | |
540 | .ep_audio_w = 0x01, | |
541 | }, | |
542 | }; | |
543 | ||
544 | /* | |
545 | Probe USB device. | |
546 | */ | |
547 | static int toneport_probe(struct usb_interface *interface, | |
548 | const struct usb_device_id *id) | |
549 | { | |
550 | struct usb_line6_toneport *toneport; | |
ccddbe4a TI |
551 | |
552 | toneport = kzalloc(sizeof(*toneport), GFP_KERNEL); | |
553 | if (!toneport) | |
554 | return -ENODEV; | |
555 | toneport->type = id->driver_info; | |
85a9339b TI |
556 | return line6_probe(interface, &toneport->line6, |
557 | &toneport_properties_table[id->driver_info], | |
558 | toneport_init); | |
ccddbe4a TI |
559 | } |
560 | ||
561 | static struct usb_driver toneport_driver = { | |
562 | .name = KBUILD_MODNAME, | |
563 | .probe = toneport_probe, | |
564 | .disconnect = line6_disconnect, | |
565 | #ifdef CONFIG_PM | |
566 | .suspend = line6_suspend, | |
567 | .resume = line6_resume, | |
568 | .reset_resume = toneport_reset_resume, | |
569 | #endif | |
570 | .id_table = toneport_id_table, | |
571 | }; | |
572 | ||
573 | module_usb_driver(toneport_driver); | |
574 | ||
575 | MODULE_DESCRIPTION("TonePort USB driver"); | |
576 | MODULE_LICENSE("GPL"); |