1 // SPDX-License-Identifier: GPL-2.0-only
5 * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
6 * Copyright (C) 2015 Andrej Krutak <dev@andree.sk>
7 * Copyright (C) 2017 Hans P. Moller <hmoller@uc.cl>
10 #include <linux/usb.h>
11 #include <linux/slab.h>
12 #include <linux/module.h>
13 #include <sound/core.h>
14 #include <sound/control.h>
15 #include <sound/pcm.h>
20 #define PODHD_STARTUP_DELAY 500
32 struct usb_line6_podhd {
33 /* Generic Line 6 USB data */
34 struct usb_line6 line6;
36 /* Serial number of device */
39 /* Firmware version */
46 #define line6_to_podhd(x) container_of(x, struct usb_line6_podhd, line6)
48 static const struct snd_ratden podhd_ratden = {
55 static struct line6_pcm_properties podhd_pcm_properties = {
57 .info = (SNDRV_PCM_INFO_MMAP |
58 SNDRV_PCM_INFO_INTERLEAVED |
59 SNDRV_PCM_INFO_BLOCK_TRANSFER |
60 SNDRV_PCM_INFO_MMAP_VALID |
61 SNDRV_PCM_INFO_PAUSE |
62 SNDRV_PCM_INFO_SYNC_START),
63 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
64 .rates = SNDRV_PCM_RATE_48000,
69 .buffer_bytes_max = 60000,
70 .period_bytes_min = 64,
71 .period_bytes_max = 8192,
75 .info = (SNDRV_PCM_INFO_MMAP |
76 SNDRV_PCM_INFO_INTERLEAVED |
77 SNDRV_PCM_INFO_BLOCK_TRANSFER |
78 SNDRV_PCM_INFO_MMAP_VALID |
79 SNDRV_PCM_INFO_SYNC_START),
80 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
81 .rates = SNDRV_PCM_RATE_48000,
86 .buffer_bytes_max = 60000,
87 .period_bytes_min = 64,
88 .period_bytes_max = 8192,
93 .rats = &podhd_ratden},
94 .bytes_per_channel = 3 /* SNDRV_PCM_FMTBIT_S24_3LE */
97 static struct line6_pcm_properties podx3_pcm_properties = {
99 .info = (SNDRV_PCM_INFO_MMAP |
100 SNDRV_PCM_INFO_INTERLEAVED |
101 SNDRV_PCM_INFO_BLOCK_TRANSFER |
102 SNDRV_PCM_INFO_MMAP_VALID |
103 SNDRV_PCM_INFO_PAUSE |
104 SNDRV_PCM_INFO_SYNC_START),
105 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
106 .rates = SNDRV_PCM_RATE_48000,
111 .buffer_bytes_max = 60000,
112 .period_bytes_min = 64,
113 .period_bytes_max = 8192,
115 .periods_max = 1024},
117 .info = (SNDRV_PCM_INFO_MMAP |
118 SNDRV_PCM_INFO_INTERLEAVED |
119 SNDRV_PCM_INFO_BLOCK_TRANSFER |
120 SNDRV_PCM_INFO_MMAP_VALID |
121 SNDRV_PCM_INFO_SYNC_START),
122 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
123 .rates = SNDRV_PCM_RATE_48000,
126 /* 1+2: Main signal (out), 3+4: Tone 1,
127 * 5+6: Tone 2, 7+8: raw
131 .buffer_bytes_max = 60000,
132 .period_bytes_min = 64,
133 .period_bytes_max = 8192,
135 .periods_max = 1024},
138 .rats = &podhd_ratden},
139 .bytes_per_channel = 3 /* SNDRV_PCM_FMTBIT_S24_3LE */
141 static struct usb_driver podhd_driver;
143 static ssize_t serial_number_show(struct device *dev,
144 struct device_attribute *attr, char *buf)
146 struct snd_card *card = dev_to_snd_card(dev);
147 struct usb_line6_podhd *pod = card->private_data;
149 return sprintf(buf, "%u\n", pod->serial_number);
152 static ssize_t firmware_version_show(struct device *dev,
153 struct device_attribute *attr, char *buf)
155 struct snd_card *card = dev_to_snd_card(dev);
156 struct usb_line6_podhd *pod = card->private_data;
158 return sprintf(buf, "%06x\n", pod->firmware_version);
161 static DEVICE_ATTR_RO(firmware_version);
162 static DEVICE_ATTR_RO(serial_number);
164 static struct attribute *podhd_dev_attrs[] = {
165 &dev_attr_firmware_version.attr,
166 &dev_attr_serial_number.attr,
170 static const struct attribute_group podhd_dev_attr_group = {
172 .attrs = podhd_dev_attrs,
176 * POD X3 startup procedure.
178 * May be compatible with other POD HD's, since it's also similar to the
179 * previous POD setup. In any case, it doesn't seem to be required for the
180 * audio nor bulk interfaces to work.
183 static int podhd_dev_start(struct usb_line6_podhd *pod)
188 struct usb_device *usbdev = pod->line6.usbdev;
190 ret = usb_control_msg_send(usbdev, 0,
191 0x67, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
193 NULL, 0, LINE6_TIMEOUT * HZ, GFP_KERNEL);
195 dev_err(pod->line6.ifcdev, "read request failed (error %d)\n", ret);
199 /* NOTE: looks like some kind of ping message */
200 ret = usb_control_msg_recv(usbdev, 0, 0x67,
201 USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
203 init_bytes, 3, LINE6_TIMEOUT * HZ, GFP_KERNEL);
205 dev_err(pod->line6.ifcdev,
206 "receive length failed (error %d)\n", ret);
210 pod->firmware_version =
211 (init_bytes[0] << 16) | (init_bytes[1] << 8) | (init_bytes[2] << 0);
213 for (i = 0; i <= 16; i++) {
214 ret = line6_read_data(&pod->line6, 0xf000 + 0x08 * i, init_bytes, 8);
219 ret = usb_control_msg_send(usbdev, 0,
221 USB_TYPE_STANDARD | USB_RECIP_DEVICE | USB_DIR_OUT,
223 NULL, 0, LINE6_TIMEOUT * HZ, GFP_KERNEL);
228 static void podhd_startup(struct usb_line6 *line6)
230 struct usb_line6_podhd *pod = line6_to_podhd(line6);
232 podhd_dev_start(pod);
233 line6_read_serial_number(&pod->line6, &pod->serial_number);
234 if (snd_card_register(line6->card))
235 dev_err(line6->ifcdev, "Failed to register POD HD card.\n");
238 static void podhd_disconnect(struct usb_line6 *line6)
240 struct usb_line6_podhd *pod = line6_to_podhd(line6);
242 if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO) {
243 struct usb_interface *intf;
245 intf = usb_ifnum_to_if(line6->usbdev,
246 pod->line6.properties->ctrl_if);
248 usb_driver_release_interface(&podhd_driver, intf);
252 static const unsigned int float_zero_to_one_lookup[] = {
253 0x00000000, 0x3c23d70a, 0x3ca3d70a, 0x3cf5c28f, 0x3d23d70a, 0x3d4ccccd,
254 0x3d75c28f, 0x3d8f5c29, 0x3da3d70a, 0x3db851ec, 0x3dcccccd, 0x3de147ae,
255 0x3df5c28f, 0x3e051eb8, 0x3e0f5c29, 0x3e19999a, 0x3e23d70a, 0x3e2e147b,
256 0x3e3851ec, 0x3e428f5c, 0x3e4ccccd, 0x3e570a3d, 0x3e6147ae, 0x3e6b851f,
257 0x3e75c28f, 0x3e800000, 0x3e851eb8, 0x3e8a3d71, 0x3e8f5c29, 0x3e947ae1,
258 0x3e99999a, 0x3e9eb852, 0x3ea3d70a, 0x3ea8f5c3, 0x3eae147b, 0x3eb33333,
259 0x3eb851ec, 0x3ebd70a4, 0x3ec28f5c, 0x3ec7ae14, 0x3ecccccd, 0x3ed1eb85,
260 0x3ed70a3d, 0x3edc28f6, 0x3ee147ae, 0x3ee66666, 0x3eeb851f, 0x3ef0a3d7,
261 0x3ef5c28f, 0x3efae148, 0x3f000000, 0x3f028f5c, 0x3f051eb8, 0x3f07ae14,
262 0x3f0a3d71, 0x3f0ccccd, 0x3f0f5c29, 0x3f11eb85, 0x3f147ae1, 0x3f170a3d,
263 0x3f19999a, 0x3f1c28f6, 0x3f1eb852, 0x3f2147ae, 0x3f23d70a, 0x3f266666,
264 0x3f28f5c3, 0x3f2b851f, 0x3f2e147b, 0x3f30a3d7, 0x3f333333, 0x3f35c28f,
265 0x3f3851ec, 0x3f3ae148, 0x3f3d70a4, 0x3f400000, 0x3f428f5c, 0x3f451eb8,
266 0x3f47ae14, 0x3f4a3d71, 0x3f4ccccd, 0x3f4f5c29, 0x3f51eb85, 0x3f547ae1,
267 0x3f570a3d, 0x3f59999a, 0x3f5c28f6, 0x3f5eb852, 0x3f6147ae, 0x3f63d70a,
268 0x3f666666, 0x3f68f5c3, 0x3f6b851f, 0x3f6e147b, 0x3f70a3d7, 0x3f733333,
269 0x3f75c28f, 0x3f7851ec, 0x3f7ae148, 0x3f7d70a4, 0x3f800000
272 static void podhd_set_monitor_level(struct usb_line6_podhd *podhd, int value)
275 static const unsigned char msg[16] = {
276 /* Chunk is 0xc bytes (without first word) */
278 /* First chunk in the message */
280 /* Message size is 2 4-byte words */
285 0x04, 0x00, 0x13, 0x00,
286 /* Volume, LE float32, 0.0 - 1.0 */
287 0x00, 0x00, 0x00, 0x00
291 buf = kmemdup(msg, sizeof(msg), GFP_KERNEL);
298 if (value >= ARRAY_SIZE(float_zero_to_one_lookup))
299 value = ARRAY_SIZE(float_zero_to_one_lookup) - 1;
301 fl = float_zero_to_one_lookup[value];
303 buf[12] = (fl >> 0) & 0xff;
304 buf[13] = (fl >> 8) & 0xff;
305 buf[14] = (fl >> 16) & 0xff;
306 buf[15] = (fl >> 24) & 0xff;
308 line6_send_raw_message(&podhd->line6, buf, sizeof(msg));
311 podhd->monitor_level = value;
314 /* control info callback */
315 static int snd_podhd_control_monitor_info(struct snd_kcontrol *kcontrol,
316 struct snd_ctl_elem_info *uinfo)
318 uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
320 uinfo->value.integer.min = 0;
321 uinfo->value.integer.max = 100;
322 uinfo->value.integer.step = 1;
326 /* control get callback */
327 static int snd_podhd_control_monitor_get(struct snd_kcontrol *kcontrol,
328 struct snd_ctl_elem_value *ucontrol)
330 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
331 struct usb_line6_podhd *podhd = line6_to_podhd(line6pcm->line6);
333 ucontrol->value.integer.value[0] = podhd->monitor_level;
337 /* control put callback */
338 static int snd_podhd_control_monitor_put(struct snd_kcontrol *kcontrol,
339 struct snd_ctl_elem_value *ucontrol)
341 struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
342 struct usb_line6_podhd *podhd = line6_to_podhd(line6pcm->line6);
344 if (ucontrol->value.integer.value[0] == podhd->monitor_level)
347 podhd_set_monitor_level(podhd, ucontrol->value.integer.value[0]);
351 /* control definition */
352 static const struct snd_kcontrol_new podhd_control_monitor = {
353 .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
354 .name = "Monitor Playback Volume",
356 .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
357 .info = snd_podhd_control_monitor_info,
358 .get = snd_podhd_control_monitor_get,
359 .put = snd_podhd_control_monitor_put
363 Try to init POD HD device.
365 static int podhd_init(struct usb_line6 *line6,
366 const struct usb_device_id *id)
369 struct usb_line6_podhd *pod = line6_to_podhd(line6);
370 struct usb_interface *intf;
372 line6->disconnect = podhd_disconnect;
373 line6->startup = podhd_startup;
375 if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) {
376 /* claim the data interface */
377 intf = usb_ifnum_to_if(line6->usbdev,
378 pod->line6.properties->ctrl_if);
380 dev_err(pod->line6.ifcdev, "interface %d not found\n",
381 pod->line6.properties->ctrl_if);
385 err = usb_driver_claim_interface(&podhd_driver, intf, NULL);
387 dev_err(pod->line6.ifcdev, "can't claim interface %d, error %d\n",
388 pod->line6.properties->ctrl_if, err);
393 if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO) {
394 /* create sysfs entries: */
395 err = snd_card_add_dev_attr(line6->card, &podhd_dev_attr_group);
400 if (pod->line6.properties->capabilities & LINE6_CAP_PCM) {
401 /* initialize PCM subsystem: */
402 err = line6_init_pcm(line6,
403 (id->driver_info == LINE6_PODX3 ||
404 id->driver_info == LINE6_PODX3LIVE) ? &podx3_pcm_properties :
405 &podhd_pcm_properties);
410 if (pod->line6.properties->capabilities & LINE6_CAP_HWMON_CTL) {
411 podhd_set_monitor_level(pod, 100);
412 err = snd_ctl_add(line6->card,
413 snd_ctl_new1(&podhd_control_monitor,
419 if (!(pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO)) {
420 /* register USB audio system directly */
421 return snd_card_register(line6->card);
424 /* init device and delay registering */
425 schedule_delayed_work(&line6->startup_work,
426 msecs_to_jiffies(PODHD_STARTUP_DELAY));
430 #define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
431 #define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
433 /* table of devices that work with this driver */
434 static const struct usb_device_id podhd_id_table[] = {
435 /* TODO: no need to alloc data interfaces when only audio is used */
436 { LINE6_DEVICE(0x5057), .driver_info = LINE6_PODHD300 },
437 { LINE6_DEVICE(0x5058), .driver_info = LINE6_PODHD400 },
438 { LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500 },
439 { LINE6_IF_NUM(0x414A, 0), .driver_info = LINE6_PODX3 },
440 { LINE6_IF_NUM(0x414B, 0), .driver_info = LINE6_PODX3LIVE },
441 { LINE6_IF_NUM(0x4159, 0), .driver_info = LINE6_PODHD500X },
442 { LINE6_IF_NUM(0x4156, 0), .driver_info = LINE6_PODHDDESKTOP },
446 MODULE_DEVICE_TABLE(usb, podhd_id_table);
448 static const struct line6_properties podhd_properties_table[] = {
452 .capabilities = LINE6_CAP_PCM
463 .capabilities = LINE6_CAP_PCM
474 .capabilities = LINE6_CAP_PCM | LINE6_CAP_CONTROL
475 | LINE6_CAP_HWMON | LINE6_CAP_HWMON_CTL,
486 .capabilities = LINE6_CAP_CONTROL | LINE6_CAP_CONTROL_INFO
487 | LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT,
495 [LINE6_PODX3LIVE] = {
497 .name = "POD X3 LIVE",
498 .capabilities = LINE6_CAP_CONTROL | LINE6_CAP_CONTROL_INFO
499 | LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT,
507 [LINE6_PODHD500X] = {
509 .name = "POD HD500X",
510 .capabilities = LINE6_CAP_CONTROL
511 | LINE6_CAP_PCM | LINE6_CAP_HWMON,
519 [LINE6_PODHDDESKTOP] = {
520 .id = "PODHDDESKTOP",
521 .name = "POD HDDESKTOP",
522 .capabilities = LINE6_CAP_CONTROL
523 | LINE6_CAP_PCM | LINE6_CAP_HWMON,
536 static int podhd_probe(struct usb_interface *interface,
537 const struct usb_device_id *id)
539 return line6_probe(interface, id, "Line6-PODHD",
540 &podhd_properties_table[id->driver_info],
541 podhd_init, sizeof(struct usb_line6_podhd));
544 static struct usb_driver podhd_driver = {
545 .name = KBUILD_MODNAME,
546 .probe = podhd_probe,
547 .disconnect = line6_disconnect,
549 .suspend = line6_suspend,
550 .resume = line6_resume,
551 .reset_resume = line6_resume,
553 .id_table = podhd_id_table,
556 module_usb_driver(podhd_driver);
558 MODULE_DESCRIPTION("Line 6 PODHD USB driver");
559 MODULE_LICENSE("GPL");