blob: 9352a44ae6e4a5dcb4230c7192ec75f9a788e5d1 [file] [log] [blame]
Stefan Hajnoczi16dc1042011-11-23 08:20:42 +00001/*
Chris Rorvickc6fffce2015-01-20 02:20:49 -06002 * Line 6 Pod HD
Stefan Hajnoczi16dc1042011-11-23 08:20:42 +00003 *
4 * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
Andrej Krutak790869d2016-09-18 20:59:28 +02005 * Copyright (C) 2015 Andrej Krutak <dev@andree.sk>
Stefan Hajnoczi16dc1042011-11-23 08:20:42 +00006 *
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
Takashi Iwaiccddbe42015-01-15 08:22:31 +010013#include <linux/usb.h>
14#include <linux/slab.h>
15#include <linux/module.h>
Stefan Hajnoczi16dc1042011-11-23 08:20:42 +000016#include <sound/core.h>
17#include <sound/pcm.h>
18
Stefan Hajnoczi16dc1042011-11-23 08:20:42 +000019#include "driver.h"
20#include "pcm.h"
Takashi Iwaiccddbe42015-01-15 08:22:31 +010021
Andrej Krutak790869d2016-09-18 20:59:28 +020022#define PODHD_STARTUP_DELAY 500
23
24/*
25 * Stages of POD startup procedure
26 */
27enum {
28 PODHD_STARTUP_INIT = 1,
29 PODHD_STARTUP_SCHEDULE_WORKQUEUE,
30 PODHD_STARTUP_SETUP,
31 PODHD_STARTUP_LAST = PODHD_STARTUP_SETUP - 1
32};
33
Takashi Iwaiccddbe42015-01-15 08:22:31 +010034enum {
35 LINE6_PODHD300,
36 LINE6_PODHD400,
37 LINE6_PODHD500_0,
38 LINE6_PODHD500_1,
Andrej Krutak790869d2016-09-18 20:59:28 +020039 LINE6_PODX3,
Andrej Krutakc039aaa2016-09-18 20:59:29 +020040 LINE6_PODX3LIVE
Andrej Krutak790869d2016-09-18 20:59:28 +020041};
42
43struct usb_line6_podhd {
44 /* Generic Line 6 USB data */
45 struct usb_line6 line6;
46
47 /* Timer for device initialization */
48 struct timer_list startup_timer;
49
50 /* Work handler for device initialization */
51 struct work_struct startup_work;
52
53 /* Current progress in startup procedure */
54 int startup_progress;
55
56 /* Serial number of device */
57 u32 serial_number;
58
59 /* Firmware version */
60 int firmware_version;
Takashi Iwaiccddbe42015-01-15 08:22:31 +010061};
62
Stefan Hajnoczi16dc1042011-11-23 08:20:42 +000063static struct snd_ratden podhd_ratden = {
64 .num_min = 48000,
65 .num_max = 48000,
66 .num_step = 1,
67 .den = 1,
68};
69
70static struct line6_pcm_properties podhd_pcm_properties = {
Takashi Iwai1263f612015-01-28 15:08:59 +010071 .playback_hw = {
Stefan Hajnoczi16dc1042011-11-23 08:20:42 +000072 .info = (SNDRV_PCM_INFO_MMAP |
73 SNDRV_PCM_INFO_INTERLEAVED |
74 SNDRV_PCM_INFO_BLOCK_TRANSFER |
75 SNDRV_PCM_INFO_MMAP_VALID |
76 SNDRV_PCM_INFO_PAUSE |
Stefan Hajnoczi16dc1042011-11-23 08:20:42 +000077 SNDRV_PCM_INFO_SYNC_START),
78 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
79 .rates = SNDRV_PCM_RATE_48000,
80 .rate_min = 48000,
81 .rate_max = 48000,
82 .channels_min = 2,
83 .channels_max = 2,
84 .buffer_bytes_max = 60000,
85 .period_bytes_min = 64,
86 .period_bytes_max = 8192,
87 .periods_min = 1,
88 .periods_max = 1024},
Takashi Iwai1263f612015-01-28 15:08:59 +010089 .capture_hw = {
Stefan Hajnoczi16dc1042011-11-23 08:20:42 +000090 .info = (SNDRV_PCM_INFO_MMAP |
91 SNDRV_PCM_INFO_INTERLEAVED |
92 SNDRV_PCM_INFO_BLOCK_TRANSFER |
93 SNDRV_PCM_INFO_MMAP_VALID |
Stefan Hajnoczi16dc1042011-11-23 08:20:42 +000094 SNDRV_PCM_INFO_SYNC_START),
95 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
96 .rates = SNDRV_PCM_RATE_48000,
97 .rate_min = 48000,
98 .rate_max = 48000,
99 .channels_min = 2,
100 .channels_max = 2,
101 .buffer_bytes_max = 60000,
102 .period_bytes_min = 64,
103 .period_bytes_max = 8192,
104 .periods_min = 1,
105 .periods_max = 1024},
Takashi Iwai1263f612015-01-28 15:08:59 +0100106 .rates = {
Stefan Hajnoczi16dc1042011-11-23 08:20:42 +0000107 .nrats = 1,
108 .rats = &podhd_ratden},
Andrej Krutak790869d2016-09-18 20:59:28 +0200109 .bytes_per_channel = 3 /* SNDRV_PCM_FMTBIT_S24_3LE */
Stefan Hajnoczi16dc1042011-11-23 08:20:42 +0000110};
111
Andrej Krutak790869d2016-09-18 20:59:28 +0200112static struct line6_pcm_properties podx3_pcm_properties = {
113 .playback_hw = {
114 .info = (SNDRV_PCM_INFO_MMAP |
115 SNDRV_PCM_INFO_INTERLEAVED |
116 SNDRV_PCM_INFO_BLOCK_TRANSFER |
117 SNDRV_PCM_INFO_MMAP_VALID |
118 SNDRV_PCM_INFO_PAUSE |
119 SNDRV_PCM_INFO_SYNC_START),
120 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
121 .rates = SNDRV_PCM_RATE_48000,
122 .rate_min = 48000,
123 .rate_max = 48000,
124 .channels_min = 2,
125 .channels_max = 2,
126 .buffer_bytes_max = 60000,
127 .period_bytes_min = 64,
128 .period_bytes_max = 8192,
129 .periods_min = 1,
130 .periods_max = 1024},
131 .capture_hw = {
132 .info = (SNDRV_PCM_INFO_MMAP |
133 SNDRV_PCM_INFO_INTERLEAVED |
134 SNDRV_PCM_INFO_BLOCK_TRANSFER |
135 SNDRV_PCM_INFO_MMAP_VALID |
136 SNDRV_PCM_INFO_SYNC_START),
137 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
138 .rates = SNDRV_PCM_RATE_48000,
139 .rate_min = 48000,
140 .rate_max = 48000,
141 /* 1+2: Main signal (out), 3+4: Tone 1,
142 * 5+6: Tone 2, 7+8: raw
143 */
144 .channels_min = 8,
145 .channels_max = 8,
146 .buffer_bytes_max = 60000,
147 .period_bytes_min = 64,
148 .period_bytes_max = 8192,
149 .periods_min = 1,
150 .periods_max = 1024},
151 .rates = {
152 .nrats = 1,
153 .rats = &podhd_ratden},
154 .bytes_per_channel = 3 /* SNDRV_PCM_FMTBIT_S24_3LE */
155};
156
157static void podhd_startup_start_workqueue(unsigned long data);
158static void podhd_startup_workqueue(struct work_struct *work);
159static int podhd_startup_finalize(struct usb_line6_podhd *pod);
160
161static ssize_t serial_number_show(struct device *dev,
162 struct device_attribute *attr, char *buf)
163{
164 struct snd_card *card = dev_to_snd_card(dev);
165 struct usb_line6_podhd *pod = card->private_data;
166
167 return sprintf(buf, "%u\n", pod->serial_number);
168}
169
170static ssize_t firmware_version_show(struct device *dev,
171 struct device_attribute *attr, char *buf)
172{
173 struct snd_card *card = dev_to_snd_card(dev);
174 struct usb_line6_podhd *pod = card->private_data;
175
176 return sprintf(buf, "%06x\n", pod->firmware_version);
177}
178
179static DEVICE_ATTR_RO(firmware_version);
180static DEVICE_ATTR_RO(serial_number);
181
182static struct attribute *podhd_dev_attrs[] = {
183 &dev_attr_firmware_version.attr,
184 &dev_attr_serial_number.attr,
185 NULL
186};
187
188static const struct attribute_group podhd_dev_attr_group = {
189 .name = "podhd",
190 .attrs = podhd_dev_attrs,
191};
192
193/*
194 * POD X3 startup procedure.
195 *
196 * May be compatible with other POD HD's, since it's also similar to the
197 * previous POD setup. In any case, it doesn't seem to be required for the
198 * audio nor bulk interfaces to work.
199 */
200
201static void podhd_startup(struct usb_line6_podhd *pod)
202{
203 CHECK_STARTUP_PROGRESS(pod->startup_progress, PODHD_STARTUP_INIT);
204
205 /* delay startup procedure: */
206 line6_start_timer(&pod->startup_timer, PODHD_STARTUP_DELAY,
207 podhd_startup_start_workqueue, (unsigned long)pod);
208}
209
210static void podhd_startup_start_workqueue(unsigned long data)
211{
212 struct usb_line6_podhd *pod = (struct usb_line6_podhd *)data;
213
214 CHECK_STARTUP_PROGRESS(pod->startup_progress,
215 PODHD_STARTUP_SCHEDULE_WORKQUEUE);
216
217 /* schedule work for global work queue: */
218 schedule_work(&pod->startup_work);
219}
220
221static int podhd_dev_start(struct usb_line6_podhd *pod)
222{
223 int ret;
224 u8 init_bytes[8];
225 int i;
226 struct usb_device *usbdev = pod->line6.usbdev;
227
228 ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0),
229 0x67, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
230 0x11, 0,
231 NULL, 0, LINE6_TIMEOUT * HZ);
232 if (ret < 0) {
233 dev_err(pod->line6.ifcdev, "read request failed (error %d)\n", ret);
234 return ret;
235 }
236
237 /* NOTE: looks like some kind of ping message */
238 ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67,
239 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
240 0x11, 0x0,
241 &init_bytes, 3, LINE6_TIMEOUT * HZ);
242 if (ret < 0) {
243 dev_err(pod->line6.ifcdev,
244 "receive length failed (error %d)\n", ret);
245 return ret;
246 }
247
248 pod->firmware_version =
249 (init_bytes[0] << 16) | (init_bytes[1] << 8) | (init_bytes[2] << 0);
250
251 for (i = 0; i <= 16; i++) {
252 ret = line6_read_data(&pod->line6, 0xf000 + 0x08 * i, init_bytes, 8);
253 if (ret < 0)
254 return ret;
255 }
256
257 ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0),
258 USB_REQ_SET_FEATURE,
259 USB_TYPE_STANDARD | USB_RECIP_DEVICE | USB_DIR_OUT,
260 1, 0,
261 NULL, 0, LINE6_TIMEOUT * HZ);
262 if (ret < 0)
263 return ret;
264
265 return 0;
266}
267
268static void podhd_startup_workqueue(struct work_struct *work)
269{
270 struct usb_line6_podhd *pod =
271 container_of(work, struct usb_line6_podhd, startup_work);
272
273 CHECK_STARTUP_PROGRESS(pod->startup_progress, PODHD_STARTUP_SETUP);
274
275 podhd_dev_start(pod);
276 line6_read_serial_number(&pod->line6, &pod->serial_number);
277
278 podhd_startup_finalize(pod);
279}
280
281static int podhd_startup_finalize(struct usb_line6_podhd *pod)
282{
283 struct usb_line6 *line6 = &pod->line6;
284
285 /* ALSA audio interface: */
286 return snd_card_register(line6->card);
287}
288
289static void podhd_disconnect(struct usb_line6 *line6)
290{
291 struct usb_line6_podhd *pod = (struct usb_line6_podhd *)line6;
292
293 if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) {
294 del_timer_sync(&pod->startup_timer);
295 cancel_work_sync(&pod->startup_work);
296 }
297}
298
Stefan Hajnoczi16dc1042011-11-23 08:20:42 +0000299/*
Stefan Hajnoczi16dc1042011-11-23 08:20:42 +0000300 Try to init POD HD device.
301*/
Takashi Iwaif66fd992015-01-25 18:22:58 +0100302static int podhd_init(struct usb_line6 *line6,
303 const struct usb_device_id *id)
Stefan Hajnoczi16dc1042011-11-23 08:20:42 +0000304{
305 int err;
Andrej Krutak790869d2016-09-18 20:59:28 +0200306 struct usb_line6_podhd *pod = (struct usb_line6_podhd *) line6;
307
308 line6->disconnect = podhd_disconnect;
309
310 if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) {
311 /* create sysfs entries: */
312 err = snd_card_add_dev_attr(line6->card, &podhd_dev_attr_group);
313 if (err < 0)
314 return err;
315 }
Stefan Hajnoczi16dc1042011-11-23 08:20:42 +0000316
Andrej Krutakcfa76962016-09-18 20:59:31 +0200317 if (pod->line6.properties->capabilities & LINE6_CAP_PCM) {
318 /* initialize PCM subsystem: */
319 err = line6_init_pcm(line6,
320 (id->driver_info == LINE6_PODX3) ? &podx3_pcm_properties :
321 &podhd_pcm_properties);
322 if (err < 0)
323 return err;
324 }
Stefan Hajnoczi16dc1042011-11-23 08:20:42 +0000325
Andrej Krutak790869d2016-09-18 20:59:28 +0200326 if (!(pod->line6.properties->capabilities & LINE6_CAP_CONTROL)) {
327 /* register USB audio system directly */
328 return podhd_startup_finalize(pod);
329 }
330
331 /* init device and delay registering */
332 init_timer(&pod->startup_timer);
333 INIT_WORK(&pod->startup_work, podhd_startup_workqueue);
334 podhd_startup(pod);
335 return 0;
Stefan Hajnoczi16dc1042011-11-23 08:20:42 +0000336}
337
Takashi Iwaiccddbe42015-01-15 08:22:31 +0100338#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
339#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
340
341/* table of devices that work with this driver */
342static const struct usb_device_id podhd_id_table[] = {
Andrej Krutak790869d2016-09-18 20:59:28 +0200343 /* TODO: no need to alloc data interfaces when only audio is used */
Takashi Iwaiccddbe42015-01-15 08:22:31 +0100344 { LINE6_DEVICE(0x5057), .driver_info = LINE6_PODHD300 },
345 { LINE6_DEVICE(0x5058), .driver_info = LINE6_PODHD400 },
346 { LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500_0 },
347 { LINE6_IF_NUM(0x414D, 1), .driver_info = LINE6_PODHD500_1 },
Andrej Krutak790869d2016-09-18 20:59:28 +0200348 { LINE6_IF_NUM(0x414A, 0), .driver_info = LINE6_PODX3 },
Andrej Krutakc039aaa2016-09-18 20:59:29 +0200349 { LINE6_IF_NUM(0x414B, 0), .driver_info = LINE6_PODX3LIVE },
Takashi Iwaiccddbe42015-01-15 08:22:31 +0100350 {}
351};
352
353MODULE_DEVICE_TABLE(usb, podhd_id_table);
354
355static const struct line6_properties podhd_properties_table[] = {
356 [LINE6_PODHD300] = {
357 .id = "PODHD300",
358 .name = "POD HD300",
Andrej Krutak790869d2016-09-18 20:59:28 +0200359 .capabilities = LINE6_CAP_PCM
Takashi Iwaiccddbe42015-01-15 08:22:31 +0100360 | LINE6_CAP_HWMON,
361 .altsetting = 5,
362 .ep_ctrl_r = 0x84,
363 .ep_ctrl_w = 0x03,
364 .ep_audio_r = 0x82,
365 .ep_audio_w = 0x01,
366 },
367 [LINE6_PODHD400] = {
368 .id = "PODHD400",
369 .name = "POD HD400",
Andrej Krutak790869d2016-09-18 20:59:28 +0200370 .capabilities = LINE6_CAP_PCM
Takashi Iwaiccddbe42015-01-15 08:22:31 +0100371 | LINE6_CAP_HWMON,
372 .altsetting = 5,
373 .ep_ctrl_r = 0x84,
374 .ep_ctrl_w = 0x03,
375 .ep_audio_r = 0x82,
376 .ep_audio_w = 0x01,
377 },
378 [LINE6_PODHD500_0] = {
379 .id = "PODHD500",
380 .name = "POD HD500",
Andrej Krutak790869d2016-09-18 20:59:28 +0200381 .capabilities = LINE6_CAP_PCM
Takashi Iwaiccddbe42015-01-15 08:22:31 +0100382 | LINE6_CAP_HWMON,
383 .altsetting = 1,
384 .ep_ctrl_r = 0x81,
385 .ep_ctrl_w = 0x01,
386 .ep_audio_r = 0x86,
387 .ep_audio_w = 0x02,
388 },
389 [LINE6_PODHD500_1] = {
390 .id = "PODHD500",
391 .name = "POD HD500",
Andrej Krutak790869d2016-09-18 20:59:28 +0200392 .capabilities = LINE6_CAP_PCM
Takashi Iwaiccddbe42015-01-15 08:22:31 +0100393 | LINE6_CAP_HWMON,
394 .altsetting = 1,
395 .ep_ctrl_r = 0x81,
396 .ep_ctrl_w = 0x01,
397 .ep_audio_r = 0x86,
398 .ep_audio_w = 0x02,
399 },
Andrej Krutak790869d2016-09-18 20:59:28 +0200400 [LINE6_PODX3] = {
401 .id = "PODX3",
402 .name = "POD X3",
403 .capabilities = LINE6_CAP_CONTROL
404 | LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT,
405 .altsetting = 1,
406 .ep_ctrl_r = 0x81,
407 .ep_ctrl_w = 0x01,
408 .ep_audio_r = 0x86,
409 .ep_audio_w = 0x02,
410 },
Andrej Krutakc039aaa2016-09-18 20:59:29 +0200411 [LINE6_PODX3LIVE] = {
412 .id = "PODX3LIVE",
413 .name = "POD X3 LIVE",
414 .capabilities = LINE6_CAP_CONTROL
415 | LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT,
416 .altsetting = 1,
417 .ep_ctrl_r = 0x81,
418 .ep_ctrl_w = 0x01,
419 .ep_audio_r = 0x86,
420 .ep_audio_w = 0x02,
421 },
Takashi Iwaiccddbe42015-01-15 08:22:31 +0100422};
423
Stefan Hajnoczi16dc1042011-11-23 08:20:42 +0000424/*
Takashi Iwaiccddbe42015-01-15 08:22:31 +0100425 Probe USB device.
426*/
427static int podhd_probe(struct usb_interface *interface,
428 const struct usb_device_id *id)
429{
Chris Rorvick12865ca2015-02-07 10:43:19 -0600430 return line6_probe(interface, id, "Line6-PODHD",
Takashi Iwai85a93392015-01-19 15:54:00 +0100431 &podhd_properties_table[id->driver_info],
Andrej Krutak790869d2016-09-18 20:59:28 +0200432 podhd_init, sizeof(struct usb_line6_podhd));
Takashi Iwaiccddbe42015-01-15 08:22:31 +0100433}
434
435static struct usb_driver podhd_driver = {
436 .name = KBUILD_MODNAME,
437 .probe = podhd_probe,
438 .disconnect = line6_disconnect,
439#ifdef CONFIG_PM
440 .suspend = line6_suspend,
441 .resume = line6_resume,
442 .reset_resume = line6_resume,
443#endif
444 .id_table = podhd_id_table,
445};
446
447module_usb_driver(podhd_driver);
448
Chris Rorvickc6fffce2015-01-20 02:20:49 -0600449MODULE_DESCRIPTION("Line 6 PODHD USB driver");
Takashi Iwaiccddbe42015-01-15 08:22:31 +0100450MODULE_LICENSE("GPL");