162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Line 6 Linux USB driver
462306a36Sopenharmony_ci *
562306a36Sopenharmony_ci * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
662306a36Sopenharmony_ci */
762306a36Sopenharmony_ci
862306a36Sopenharmony_ci#include <linux/slab.h>
962306a36Sopenharmony_ci#include <linux/wait.h>
1062306a36Sopenharmony_ci#include <linux/interrupt.h>
1162306a36Sopenharmony_ci#include <linux/module.h>
1262306a36Sopenharmony_ci#include <linux/usb.h>
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci#include <sound/core.h>
1562306a36Sopenharmony_ci#include <sound/control.h>
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include "capture.h"
1862306a36Sopenharmony_ci#include "driver.h"
1962306a36Sopenharmony_ci#include "playback.h"
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/*
2262306a36Sopenharmony_ci	Locate name in binary program dump
2362306a36Sopenharmony_ci*/
2462306a36Sopenharmony_ci#define	POD_NAME_OFFSET 0
2562306a36Sopenharmony_ci#define	POD_NAME_LENGTH 16
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci/*
2862306a36Sopenharmony_ci	Other constants
2962306a36Sopenharmony_ci*/
3062306a36Sopenharmony_ci#define POD_CONTROL_SIZE 0x80
3162306a36Sopenharmony_ci#define POD_BUFSIZE_DUMPREQ 7
3262306a36Sopenharmony_ci#define POD_STARTUP_DELAY 1000
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_ci/*
3562306a36Sopenharmony_ci	Stages of POD startup procedure
3662306a36Sopenharmony_ci*/
3762306a36Sopenharmony_cienum {
3862306a36Sopenharmony_ci	POD_STARTUP_VERSIONREQ,
3962306a36Sopenharmony_ci	POD_STARTUP_SETUP,
4062306a36Sopenharmony_ci	POD_STARTUP_DONE,
4162306a36Sopenharmony_ci};
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_cienum {
4462306a36Sopenharmony_ci	LINE6_BASSPODXT,
4562306a36Sopenharmony_ci	LINE6_BASSPODXTLIVE,
4662306a36Sopenharmony_ci	LINE6_BASSPODXTPRO,
4762306a36Sopenharmony_ci	LINE6_POCKETPOD,
4862306a36Sopenharmony_ci	LINE6_PODXT,
4962306a36Sopenharmony_ci	LINE6_PODXTLIVE_POD,
5062306a36Sopenharmony_ci	LINE6_PODXTPRO,
5162306a36Sopenharmony_ci};
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_cistruct usb_line6_pod {
5462306a36Sopenharmony_ci	/* Generic Line 6 USB data */
5562306a36Sopenharmony_ci	struct usb_line6 line6;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	/* Instrument monitor level */
5862306a36Sopenharmony_ci	int monitor_level;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	/* Current progress in startup procedure */
6162306a36Sopenharmony_ci	int startup_progress;
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	/* Serial number of device */
6462306a36Sopenharmony_ci	u32 serial_number;
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	/* Firmware version (x 100) */
6762306a36Sopenharmony_ci	int firmware_version;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	/* Device ID */
7062306a36Sopenharmony_ci	int device_id;
7162306a36Sopenharmony_ci};
7262306a36Sopenharmony_ci
7362306a36Sopenharmony_ci#define line6_to_pod(x)		container_of(x, struct usb_line6_pod, line6)
7462306a36Sopenharmony_ci
7562306a36Sopenharmony_ci#define POD_SYSEX_CODE 3
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/* *INDENT-OFF* */
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_cienum {
8062306a36Sopenharmony_ci	POD_SYSEX_SAVE      = 0x24,
8162306a36Sopenharmony_ci	POD_SYSEX_SYSTEM    = 0x56,
8262306a36Sopenharmony_ci	POD_SYSEX_SYSTEMREQ = 0x57,
8362306a36Sopenharmony_ci	/* POD_SYSEX_UPDATE    = 0x6c, */  /* software update! */
8462306a36Sopenharmony_ci	POD_SYSEX_STORE     = 0x71,
8562306a36Sopenharmony_ci	POD_SYSEX_FINISH    = 0x72,
8662306a36Sopenharmony_ci	POD_SYSEX_DUMPMEM   = 0x73,
8762306a36Sopenharmony_ci	POD_SYSEX_DUMP      = 0x74,
8862306a36Sopenharmony_ci	POD_SYSEX_DUMPREQ   = 0x75
8962306a36Sopenharmony_ci
9062306a36Sopenharmony_ci	/* dumps entire internal memory of PODxt Pro */
9162306a36Sopenharmony_ci	/* POD_SYSEX_DUMPMEM2  = 0x76 */
9262306a36Sopenharmony_ci};
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_cienum {
9562306a36Sopenharmony_ci	POD_MONITOR_LEVEL  = 0x04,
9662306a36Sopenharmony_ci	POD_SYSTEM_INVALID = 0x10000
9762306a36Sopenharmony_ci};
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci/* *INDENT-ON* */
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cienum {
10262306a36Sopenharmony_ci	POD_DUMP_MEMORY = 2
10362306a36Sopenharmony_ci};
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_cienum {
10662306a36Sopenharmony_ci	POD_BUSY_READ,
10762306a36Sopenharmony_ci	POD_BUSY_WRITE,
10862306a36Sopenharmony_ci	POD_CHANNEL_DIRTY,
10962306a36Sopenharmony_ci	POD_SAVE_PRESSED,
11062306a36Sopenharmony_ci	POD_BUSY_MIDISEND
11162306a36Sopenharmony_ci};
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_cistatic const struct snd_ratden pod_ratden = {
11462306a36Sopenharmony_ci	.num_min = 78125,
11562306a36Sopenharmony_ci	.num_max = 78125,
11662306a36Sopenharmony_ci	.num_step = 1,
11762306a36Sopenharmony_ci	.den = 2
11862306a36Sopenharmony_ci};
11962306a36Sopenharmony_ci
12062306a36Sopenharmony_cistatic struct line6_pcm_properties pod_pcm_properties = {
12162306a36Sopenharmony_ci	.playback_hw = {
12262306a36Sopenharmony_ci				  .info = (SNDRV_PCM_INFO_MMAP |
12362306a36Sopenharmony_ci					   SNDRV_PCM_INFO_INTERLEAVED |
12462306a36Sopenharmony_ci					   SNDRV_PCM_INFO_BLOCK_TRANSFER |
12562306a36Sopenharmony_ci					   SNDRV_PCM_INFO_MMAP_VALID |
12662306a36Sopenharmony_ci					   SNDRV_PCM_INFO_PAUSE |
12762306a36Sopenharmony_ci					   SNDRV_PCM_INFO_SYNC_START),
12862306a36Sopenharmony_ci				  .formats = SNDRV_PCM_FMTBIT_S24_3LE,
12962306a36Sopenharmony_ci				  .rates = SNDRV_PCM_RATE_KNOT,
13062306a36Sopenharmony_ci				  .rate_min = 39062,
13162306a36Sopenharmony_ci				  .rate_max = 39063,
13262306a36Sopenharmony_ci				  .channels_min = 2,
13362306a36Sopenharmony_ci				  .channels_max = 2,
13462306a36Sopenharmony_ci				  .buffer_bytes_max = 60000,
13562306a36Sopenharmony_ci				  .period_bytes_min = 64,
13662306a36Sopenharmony_ci				  .period_bytes_max = 8192,
13762306a36Sopenharmony_ci				  .periods_min = 1,
13862306a36Sopenharmony_ci				  .periods_max = 1024},
13962306a36Sopenharmony_ci	.capture_hw = {
14062306a36Sopenharmony_ci				 .info = (SNDRV_PCM_INFO_MMAP |
14162306a36Sopenharmony_ci					  SNDRV_PCM_INFO_INTERLEAVED |
14262306a36Sopenharmony_ci					  SNDRV_PCM_INFO_BLOCK_TRANSFER |
14362306a36Sopenharmony_ci					  SNDRV_PCM_INFO_MMAP_VALID |
14462306a36Sopenharmony_ci					  SNDRV_PCM_INFO_SYNC_START),
14562306a36Sopenharmony_ci				 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
14662306a36Sopenharmony_ci				 .rates = SNDRV_PCM_RATE_KNOT,
14762306a36Sopenharmony_ci				 .rate_min = 39062,
14862306a36Sopenharmony_ci				 .rate_max = 39063,
14962306a36Sopenharmony_ci				 .channels_min = 2,
15062306a36Sopenharmony_ci				 .channels_max = 2,
15162306a36Sopenharmony_ci				 .buffer_bytes_max = 60000,
15262306a36Sopenharmony_ci				 .period_bytes_min = 64,
15362306a36Sopenharmony_ci				 .period_bytes_max = 8192,
15462306a36Sopenharmony_ci				 .periods_min = 1,
15562306a36Sopenharmony_ci				 .periods_max = 1024},
15662306a36Sopenharmony_ci	.rates = {
15762306a36Sopenharmony_ci			    .nrats = 1,
15862306a36Sopenharmony_ci			    .rats = &pod_ratden},
15962306a36Sopenharmony_ci	.bytes_per_channel = 3 /* SNDRV_PCM_FMTBIT_S24_3LE */
16062306a36Sopenharmony_ci};
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci
16362306a36Sopenharmony_cistatic const char pod_version_header[] = {
16462306a36Sopenharmony_ci	0xf0, 0x7e, 0x7f, 0x06, 0x02
16562306a36Sopenharmony_ci};
16662306a36Sopenharmony_ci
16762306a36Sopenharmony_cistatic char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code,
16862306a36Sopenharmony_ci				    int size)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code,
17162306a36Sopenharmony_ci					size);
17262306a36Sopenharmony_ci}
17362306a36Sopenharmony_ci
17462306a36Sopenharmony_ci/*
17562306a36Sopenharmony_ci	Process a completely received message.
17662306a36Sopenharmony_ci*/
17762306a36Sopenharmony_cistatic void line6_pod_process_message(struct usb_line6 *line6)
17862306a36Sopenharmony_ci{
17962306a36Sopenharmony_ci	struct usb_line6_pod *pod = line6_to_pod(line6);
18062306a36Sopenharmony_ci	const unsigned char *buf = pod->line6.buffer_message;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) {
18362306a36Sopenharmony_ci		pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15];
18462306a36Sopenharmony_ci		pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) |
18562306a36Sopenharmony_ci				 (int) buf[10];
18662306a36Sopenharmony_ci		if (pod->startup_progress == POD_STARTUP_VERSIONREQ) {
18762306a36Sopenharmony_ci			pod->startup_progress = POD_STARTUP_SETUP;
18862306a36Sopenharmony_ci			schedule_delayed_work(&line6->startup_work, 0);
18962306a36Sopenharmony_ci		}
19062306a36Sopenharmony_ci		return;
19162306a36Sopenharmony_ci	}
19262306a36Sopenharmony_ci
19362306a36Sopenharmony_ci	/* Only look for sysex messages from this device */
19462306a36Sopenharmony_ci	if (buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE) &&
19562306a36Sopenharmony_ci	    buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN)) {
19662306a36Sopenharmony_ci		return;
19762306a36Sopenharmony_ci	}
19862306a36Sopenharmony_ci	if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) != 0)
19962306a36Sopenharmony_ci		return;
20062306a36Sopenharmony_ci
20162306a36Sopenharmony_ci	if (buf[5] == POD_SYSEX_SYSTEM && buf[6] == POD_MONITOR_LEVEL) {
20262306a36Sopenharmony_ci		short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) |
20362306a36Sopenharmony_ci			      ((int)buf[9] << 4) | (int)buf[10];
20462306a36Sopenharmony_ci		pod->monitor_level = value;
20562306a36Sopenharmony_ci	}
20662306a36Sopenharmony_ci}
20762306a36Sopenharmony_ci
20862306a36Sopenharmony_ci/*
20962306a36Sopenharmony_ci	Send system parameter (from integer).
21062306a36Sopenharmony_ci*/
21162306a36Sopenharmony_cistatic int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
21262306a36Sopenharmony_ci				    int code)
21362306a36Sopenharmony_ci{
21462306a36Sopenharmony_ci	char *sysex;
21562306a36Sopenharmony_ci	static const int size = 5;
21662306a36Sopenharmony_ci
21762306a36Sopenharmony_ci	sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
21862306a36Sopenharmony_ci	if (!sysex)
21962306a36Sopenharmony_ci		return -ENOMEM;
22062306a36Sopenharmony_ci	sysex[SYSEX_DATA_OFS] = code;
22162306a36Sopenharmony_ci	sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f;
22262306a36Sopenharmony_ci	sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f;
22362306a36Sopenharmony_ci	sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f;
22462306a36Sopenharmony_ci	sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f;
22562306a36Sopenharmony_ci	line6_send_sysex_message(&pod->line6, sysex, size);
22662306a36Sopenharmony_ci	kfree(sysex);
22762306a36Sopenharmony_ci	return 0;
22862306a36Sopenharmony_ci}
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci/*
23162306a36Sopenharmony_ci	"read" request on "serial_number" special file.
23262306a36Sopenharmony_ci*/
23362306a36Sopenharmony_cistatic ssize_t serial_number_show(struct device *dev,
23462306a36Sopenharmony_ci				  struct device_attribute *attr, char *buf)
23562306a36Sopenharmony_ci{
23662306a36Sopenharmony_ci	struct snd_card *card = dev_to_snd_card(dev);
23762306a36Sopenharmony_ci	struct usb_line6_pod *pod = card->private_data;
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ci	return sysfs_emit(buf, "%u\n", pod->serial_number);
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci/*
24362306a36Sopenharmony_ci	"read" request on "firmware_version" special file.
24462306a36Sopenharmony_ci*/
24562306a36Sopenharmony_cistatic ssize_t firmware_version_show(struct device *dev,
24662306a36Sopenharmony_ci				     struct device_attribute *attr, char *buf)
24762306a36Sopenharmony_ci{
24862306a36Sopenharmony_ci	struct snd_card *card = dev_to_snd_card(dev);
24962306a36Sopenharmony_ci	struct usb_line6_pod *pod = card->private_data;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	return sysfs_emit(buf, "%d.%02d\n", pod->firmware_version / 100,
25262306a36Sopenharmony_ci			  pod->firmware_version % 100);
25362306a36Sopenharmony_ci}
25462306a36Sopenharmony_ci
25562306a36Sopenharmony_ci/*
25662306a36Sopenharmony_ci	"read" request on "device_id" special file.
25762306a36Sopenharmony_ci*/
25862306a36Sopenharmony_cistatic ssize_t device_id_show(struct device *dev,
25962306a36Sopenharmony_ci			      struct device_attribute *attr, char *buf)
26062306a36Sopenharmony_ci{
26162306a36Sopenharmony_ci	struct snd_card *card = dev_to_snd_card(dev);
26262306a36Sopenharmony_ci	struct usb_line6_pod *pod = card->private_data;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	return sysfs_emit(buf, "%d\n", pod->device_id);
26562306a36Sopenharmony_ci}
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci/*
26862306a36Sopenharmony_ci	POD startup procedure.
26962306a36Sopenharmony_ci	This is a sequence of functions with special requirements (e.g., must
27062306a36Sopenharmony_ci	not run immediately after initialization, must not run in interrupt
27162306a36Sopenharmony_ci	context). After the last one has finished, the device is ready to use.
27262306a36Sopenharmony_ci*/
27362306a36Sopenharmony_ci
27462306a36Sopenharmony_cistatic void pod_startup(struct usb_line6 *line6)
27562306a36Sopenharmony_ci{
27662306a36Sopenharmony_ci	struct usb_line6_pod *pod = line6_to_pod(line6);
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_ci	switch (pod->startup_progress) {
27962306a36Sopenharmony_ci	case POD_STARTUP_VERSIONREQ:
28062306a36Sopenharmony_ci		/* request firmware version: */
28162306a36Sopenharmony_ci		line6_version_request_async(line6);
28262306a36Sopenharmony_ci		break;
28362306a36Sopenharmony_ci	case POD_STARTUP_SETUP:
28462306a36Sopenharmony_ci		/* serial number: */
28562306a36Sopenharmony_ci		line6_read_serial_number(&pod->line6, &pod->serial_number);
28662306a36Sopenharmony_ci
28762306a36Sopenharmony_ci		/* ALSA audio interface: */
28862306a36Sopenharmony_ci		if (snd_card_register(line6->card))
28962306a36Sopenharmony_ci			dev_err(line6->ifcdev, "Failed to register POD card.\n");
29062306a36Sopenharmony_ci		pod->startup_progress = POD_STARTUP_DONE;
29162306a36Sopenharmony_ci		break;
29262306a36Sopenharmony_ci	default:
29362306a36Sopenharmony_ci		break;
29462306a36Sopenharmony_ci	}
29562306a36Sopenharmony_ci}
29662306a36Sopenharmony_ci
29762306a36Sopenharmony_ci/* POD special files: */
29862306a36Sopenharmony_cistatic DEVICE_ATTR_RO(device_id);
29962306a36Sopenharmony_cistatic DEVICE_ATTR_RO(firmware_version);
30062306a36Sopenharmony_cistatic DEVICE_ATTR_RO(serial_number);
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_cistatic struct attribute *pod_dev_attrs[] = {
30362306a36Sopenharmony_ci	&dev_attr_device_id.attr,
30462306a36Sopenharmony_ci	&dev_attr_firmware_version.attr,
30562306a36Sopenharmony_ci	&dev_attr_serial_number.attr,
30662306a36Sopenharmony_ci	NULL
30762306a36Sopenharmony_ci};
30862306a36Sopenharmony_ci
30962306a36Sopenharmony_cistatic const struct attribute_group pod_dev_attr_group = {
31062306a36Sopenharmony_ci	.name = "pod",
31162306a36Sopenharmony_ci	.attrs = pod_dev_attrs,
31262306a36Sopenharmony_ci};
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci/* control info callback */
31562306a36Sopenharmony_cistatic int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol,
31662306a36Sopenharmony_ci					struct snd_ctl_elem_info *uinfo)
31762306a36Sopenharmony_ci{
31862306a36Sopenharmony_ci	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
31962306a36Sopenharmony_ci	uinfo->count = 1;
32062306a36Sopenharmony_ci	uinfo->value.integer.min = 0;
32162306a36Sopenharmony_ci	uinfo->value.integer.max = 65535;
32262306a36Sopenharmony_ci	return 0;
32362306a36Sopenharmony_ci}
32462306a36Sopenharmony_ci
32562306a36Sopenharmony_ci/* control get callback */
32662306a36Sopenharmony_cistatic int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol,
32762306a36Sopenharmony_ci				       struct snd_ctl_elem_value *ucontrol)
32862306a36Sopenharmony_ci{
32962306a36Sopenharmony_ci	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
33062306a36Sopenharmony_ci	struct usb_line6_pod *pod = line6_to_pod(line6pcm->line6);
33162306a36Sopenharmony_ci
33262306a36Sopenharmony_ci	ucontrol->value.integer.value[0] = pod->monitor_level;
33362306a36Sopenharmony_ci	return 0;
33462306a36Sopenharmony_ci}
33562306a36Sopenharmony_ci
33662306a36Sopenharmony_ci/* control put callback */
33762306a36Sopenharmony_cistatic int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol,
33862306a36Sopenharmony_ci				       struct snd_ctl_elem_value *ucontrol)
33962306a36Sopenharmony_ci{
34062306a36Sopenharmony_ci	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
34162306a36Sopenharmony_ci	struct usb_line6_pod *pod = line6_to_pod(line6pcm->line6);
34262306a36Sopenharmony_ci
34362306a36Sopenharmony_ci	if (ucontrol->value.integer.value[0] == pod->monitor_level)
34462306a36Sopenharmony_ci		return 0;
34562306a36Sopenharmony_ci
34662306a36Sopenharmony_ci	pod->monitor_level = ucontrol->value.integer.value[0];
34762306a36Sopenharmony_ci	pod_set_system_param_int(pod, ucontrol->value.integer.value[0],
34862306a36Sopenharmony_ci				 POD_MONITOR_LEVEL);
34962306a36Sopenharmony_ci	return 1;
35062306a36Sopenharmony_ci}
35162306a36Sopenharmony_ci
35262306a36Sopenharmony_ci/* control definition */
35362306a36Sopenharmony_cistatic const struct snd_kcontrol_new pod_control_monitor = {
35462306a36Sopenharmony_ci	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
35562306a36Sopenharmony_ci	.name = "Monitor Playback Volume",
35662306a36Sopenharmony_ci	.index = 0,
35762306a36Sopenharmony_ci	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
35862306a36Sopenharmony_ci	.info = snd_pod_control_monitor_info,
35962306a36Sopenharmony_ci	.get = snd_pod_control_monitor_get,
36062306a36Sopenharmony_ci	.put = snd_pod_control_monitor_put
36162306a36Sopenharmony_ci};
36262306a36Sopenharmony_ci
36362306a36Sopenharmony_ci/*
36462306a36Sopenharmony_ci	 Try to init POD device.
36562306a36Sopenharmony_ci*/
36662306a36Sopenharmony_cistatic int pod_init(struct usb_line6 *line6,
36762306a36Sopenharmony_ci		    const struct usb_device_id *id)
36862306a36Sopenharmony_ci{
36962306a36Sopenharmony_ci	int err;
37062306a36Sopenharmony_ci	struct usb_line6_pod *pod = line6_to_pod(line6);
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	line6->process_message = line6_pod_process_message;
37362306a36Sopenharmony_ci	line6->startup = pod_startup;
37462306a36Sopenharmony_ci
37562306a36Sopenharmony_ci	/* create sysfs entries: */
37662306a36Sopenharmony_ci	err = snd_card_add_dev_attr(line6->card, &pod_dev_attr_group);
37762306a36Sopenharmony_ci	if (err < 0)
37862306a36Sopenharmony_ci		return err;
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci	/* initialize PCM subsystem: */
38162306a36Sopenharmony_ci	err = line6_init_pcm(line6, &pod_pcm_properties);
38262306a36Sopenharmony_ci	if (err < 0)
38362306a36Sopenharmony_ci		return err;
38462306a36Sopenharmony_ci
38562306a36Sopenharmony_ci	/* register monitor control: */
38662306a36Sopenharmony_ci	err = snd_ctl_add(line6->card,
38762306a36Sopenharmony_ci			  snd_ctl_new1(&pod_control_monitor, line6->line6pcm));
38862306a36Sopenharmony_ci	if (err < 0)
38962306a36Sopenharmony_ci		return err;
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	/*
39262306a36Sopenharmony_ci	   When the sound card is registered at this point, the PODxt Live
39362306a36Sopenharmony_ci	   displays "Invalid Code Error 07", so we do it later in the event
39462306a36Sopenharmony_ci	   handler.
39562306a36Sopenharmony_ci	 */
39662306a36Sopenharmony_ci
39762306a36Sopenharmony_ci	if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) {
39862306a36Sopenharmony_ci		pod->monitor_level = POD_SYSTEM_INVALID;
39962306a36Sopenharmony_ci
40062306a36Sopenharmony_ci		/* initiate startup procedure: */
40162306a36Sopenharmony_ci		schedule_delayed_work(&line6->startup_work,
40262306a36Sopenharmony_ci				      msecs_to_jiffies(POD_STARTUP_DELAY));
40362306a36Sopenharmony_ci	}
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_ci	return 0;
40662306a36Sopenharmony_ci}
40762306a36Sopenharmony_ci
40862306a36Sopenharmony_ci#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
40962306a36Sopenharmony_ci#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci/* table of devices that work with this driver */
41262306a36Sopenharmony_cistatic const struct usb_device_id pod_id_table[] = {
41362306a36Sopenharmony_ci	{ LINE6_DEVICE(0x4250),    .driver_info = LINE6_BASSPODXT },
41462306a36Sopenharmony_ci	{ LINE6_DEVICE(0x4642),    .driver_info = LINE6_BASSPODXTLIVE },
41562306a36Sopenharmony_ci	{ LINE6_DEVICE(0x4252),    .driver_info = LINE6_BASSPODXTPRO },
41662306a36Sopenharmony_ci	{ LINE6_IF_NUM(0x5051, 1), .driver_info = LINE6_POCKETPOD },
41762306a36Sopenharmony_ci	{ LINE6_DEVICE(0x5044),    .driver_info = LINE6_PODXT },
41862306a36Sopenharmony_ci	{ LINE6_IF_NUM(0x4650, 0), .driver_info = LINE6_PODXTLIVE_POD },
41962306a36Sopenharmony_ci	{ LINE6_DEVICE(0x5050),    .driver_info = LINE6_PODXTPRO },
42062306a36Sopenharmony_ci	{}
42162306a36Sopenharmony_ci};
42262306a36Sopenharmony_ci
42362306a36Sopenharmony_ciMODULE_DEVICE_TABLE(usb, pod_id_table);
42462306a36Sopenharmony_ci
42562306a36Sopenharmony_cistatic const struct line6_properties pod_properties_table[] = {
42662306a36Sopenharmony_ci	[LINE6_BASSPODXT] = {
42762306a36Sopenharmony_ci		.id = "BassPODxt",
42862306a36Sopenharmony_ci		.name = "BassPODxt",
42962306a36Sopenharmony_ci		.capabilities	= LINE6_CAP_CONTROL
43062306a36Sopenharmony_ci				| LINE6_CAP_CONTROL_MIDI
43162306a36Sopenharmony_ci				| LINE6_CAP_PCM
43262306a36Sopenharmony_ci				| LINE6_CAP_HWMON,
43362306a36Sopenharmony_ci		.altsetting = 5,
43462306a36Sopenharmony_ci		.ep_ctrl_r = 0x84,
43562306a36Sopenharmony_ci		.ep_ctrl_w = 0x03,
43662306a36Sopenharmony_ci		.ep_audio_r = 0x82,
43762306a36Sopenharmony_ci		.ep_audio_w = 0x01,
43862306a36Sopenharmony_ci	},
43962306a36Sopenharmony_ci	[LINE6_BASSPODXTLIVE] = {
44062306a36Sopenharmony_ci		.id = "BassPODxtLive",
44162306a36Sopenharmony_ci		.name = "BassPODxt Live",
44262306a36Sopenharmony_ci		.capabilities	= LINE6_CAP_CONTROL
44362306a36Sopenharmony_ci				| LINE6_CAP_CONTROL_MIDI
44462306a36Sopenharmony_ci				| LINE6_CAP_PCM
44562306a36Sopenharmony_ci				| LINE6_CAP_HWMON,
44662306a36Sopenharmony_ci		.altsetting = 1,
44762306a36Sopenharmony_ci		.ep_ctrl_r = 0x84,
44862306a36Sopenharmony_ci		.ep_ctrl_w = 0x03,
44962306a36Sopenharmony_ci		.ep_audio_r = 0x82,
45062306a36Sopenharmony_ci		.ep_audio_w = 0x01,
45162306a36Sopenharmony_ci	},
45262306a36Sopenharmony_ci	[LINE6_BASSPODXTPRO] = {
45362306a36Sopenharmony_ci		.id = "BassPODxtPro",
45462306a36Sopenharmony_ci		.name = "BassPODxt Pro",
45562306a36Sopenharmony_ci		.capabilities	= LINE6_CAP_CONTROL
45662306a36Sopenharmony_ci				| LINE6_CAP_CONTROL_MIDI
45762306a36Sopenharmony_ci				| LINE6_CAP_PCM
45862306a36Sopenharmony_ci				| LINE6_CAP_HWMON,
45962306a36Sopenharmony_ci		.altsetting = 5,
46062306a36Sopenharmony_ci		.ep_ctrl_r = 0x84,
46162306a36Sopenharmony_ci		.ep_ctrl_w = 0x03,
46262306a36Sopenharmony_ci		.ep_audio_r = 0x82,
46362306a36Sopenharmony_ci		.ep_audio_w = 0x01,
46462306a36Sopenharmony_ci	},
46562306a36Sopenharmony_ci	[LINE6_POCKETPOD] = {
46662306a36Sopenharmony_ci		.id = "PocketPOD",
46762306a36Sopenharmony_ci		.name = "Pocket POD",
46862306a36Sopenharmony_ci		.capabilities	= LINE6_CAP_CONTROL
46962306a36Sopenharmony_ci				| LINE6_CAP_CONTROL_MIDI,
47062306a36Sopenharmony_ci		.altsetting = 0,
47162306a36Sopenharmony_ci		.ep_ctrl_r = 0x82,
47262306a36Sopenharmony_ci		.ep_ctrl_w = 0x02,
47362306a36Sopenharmony_ci		/* no audio channel */
47462306a36Sopenharmony_ci	},
47562306a36Sopenharmony_ci	[LINE6_PODXT] = {
47662306a36Sopenharmony_ci		.id = "PODxt",
47762306a36Sopenharmony_ci		.name = "PODxt",
47862306a36Sopenharmony_ci		.capabilities	= LINE6_CAP_CONTROL
47962306a36Sopenharmony_ci				| LINE6_CAP_CONTROL_MIDI
48062306a36Sopenharmony_ci				| LINE6_CAP_PCM
48162306a36Sopenharmony_ci				| LINE6_CAP_HWMON,
48262306a36Sopenharmony_ci		.altsetting = 5,
48362306a36Sopenharmony_ci		.ep_ctrl_r = 0x84,
48462306a36Sopenharmony_ci		.ep_ctrl_w = 0x03,
48562306a36Sopenharmony_ci		.ep_audio_r = 0x82,
48662306a36Sopenharmony_ci		.ep_audio_w = 0x01,
48762306a36Sopenharmony_ci	},
48862306a36Sopenharmony_ci	[LINE6_PODXTLIVE_POD] = {
48962306a36Sopenharmony_ci		.id = "PODxtLive",
49062306a36Sopenharmony_ci		.name = "PODxt Live",
49162306a36Sopenharmony_ci		.capabilities	= LINE6_CAP_CONTROL
49262306a36Sopenharmony_ci				| LINE6_CAP_CONTROL_MIDI
49362306a36Sopenharmony_ci				| LINE6_CAP_PCM
49462306a36Sopenharmony_ci				| LINE6_CAP_HWMON,
49562306a36Sopenharmony_ci		.altsetting = 1,
49662306a36Sopenharmony_ci		.ep_ctrl_r = 0x84,
49762306a36Sopenharmony_ci		.ep_ctrl_w = 0x03,
49862306a36Sopenharmony_ci		.ep_audio_r = 0x82,
49962306a36Sopenharmony_ci		.ep_audio_w = 0x01,
50062306a36Sopenharmony_ci	},
50162306a36Sopenharmony_ci	[LINE6_PODXTPRO] = {
50262306a36Sopenharmony_ci		.id = "PODxtPro",
50362306a36Sopenharmony_ci		.name = "PODxt Pro",
50462306a36Sopenharmony_ci		.capabilities	= LINE6_CAP_CONTROL
50562306a36Sopenharmony_ci				| LINE6_CAP_CONTROL_MIDI
50662306a36Sopenharmony_ci				| LINE6_CAP_PCM
50762306a36Sopenharmony_ci				| LINE6_CAP_HWMON,
50862306a36Sopenharmony_ci		.altsetting = 5,
50962306a36Sopenharmony_ci		.ep_ctrl_r = 0x84,
51062306a36Sopenharmony_ci		.ep_ctrl_w = 0x03,
51162306a36Sopenharmony_ci		.ep_audio_r = 0x82,
51262306a36Sopenharmony_ci		.ep_audio_w = 0x01,
51362306a36Sopenharmony_ci	},
51462306a36Sopenharmony_ci};
51562306a36Sopenharmony_ci
51662306a36Sopenharmony_ci/*
51762306a36Sopenharmony_ci	Probe USB device.
51862306a36Sopenharmony_ci*/
51962306a36Sopenharmony_cistatic int pod_probe(struct usb_interface *interface,
52062306a36Sopenharmony_ci		     const struct usb_device_id *id)
52162306a36Sopenharmony_ci{
52262306a36Sopenharmony_ci	return line6_probe(interface, id, "Line6-POD",
52362306a36Sopenharmony_ci			   &pod_properties_table[id->driver_info],
52462306a36Sopenharmony_ci			   pod_init, sizeof(struct usb_line6_pod));
52562306a36Sopenharmony_ci}
52662306a36Sopenharmony_ci
52762306a36Sopenharmony_cistatic struct usb_driver pod_driver = {
52862306a36Sopenharmony_ci	.name = KBUILD_MODNAME,
52962306a36Sopenharmony_ci	.probe = pod_probe,
53062306a36Sopenharmony_ci	.disconnect = line6_disconnect,
53162306a36Sopenharmony_ci#ifdef CONFIG_PM
53262306a36Sopenharmony_ci	.suspend = line6_suspend,
53362306a36Sopenharmony_ci	.resume = line6_resume,
53462306a36Sopenharmony_ci	.reset_resume = line6_resume,
53562306a36Sopenharmony_ci#endif
53662306a36Sopenharmony_ci	.id_table = pod_id_table,
53762306a36Sopenharmony_ci};
53862306a36Sopenharmony_ci
53962306a36Sopenharmony_cimodule_usb_driver(pod_driver);
54062306a36Sopenharmony_ci
54162306a36Sopenharmony_ciMODULE_DESCRIPTION("Line 6 POD USB driver");
54262306a36Sopenharmony_ciMODULE_LICENSE("GPL");
543