xref: /OK3568_Linux_fs/kernel/sound/usb/line6/podhd.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  * Line 6 Pod HD
4*4882a593Smuzhiyun  *
5*4882a593Smuzhiyun  * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
6*4882a593Smuzhiyun  * Copyright (C) 2015 Andrej Krutak <dev@andree.sk>
7*4882a593Smuzhiyun  * Copyright (C) 2017 Hans P. Moller <hmoller@uc.cl>
8*4882a593Smuzhiyun  */
9*4882a593Smuzhiyun 
10*4882a593Smuzhiyun #include <linux/usb.h>
11*4882a593Smuzhiyun #include <linux/slab.h>
12*4882a593Smuzhiyun #include <linux/module.h>
13*4882a593Smuzhiyun #include <sound/core.h>
14*4882a593Smuzhiyun #include <sound/control.h>
15*4882a593Smuzhiyun #include <sound/pcm.h>
16*4882a593Smuzhiyun 
17*4882a593Smuzhiyun #include "driver.h"
18*4882a593Smuzhiyun #include "pcm.h"
19*4882a593Smuzhiyun 
20*4882a593Smuzhiyun #define PODHD_STARTUP_DELAY 500
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun enum {
23*4882a593Smuzhiyun 	LINE6_PODHD300,
24*4882a593Smuzhiyun 	LINE6_PODHD400,
25*4882a593Smuzhiyun 	LINE6_PODHD500,
26*4882a593Smuzhiyun 	LINE6_PODX3,
27*4882a593Smuzhiyun 	LINE6_PODX3LIVE,
28*4882a593Smuzhiyun 	LINE6_PODHD500X,
29*4882a593Smuzhiyun 	LINE6_PODHDDESKTOP
30*4882a593Smuzhiyun };
31*4882a593Smuzhiyun 
32*4882a593Smuzhiyun struct usb_line6_podhd {
33*4882a593Smuzhiyun 	/* Generic Line 6 USB data */
34*4882a593Smuzhiyun 	struct usb_line6 line6;
35*4882a593Smuzhiyun 
36*4882a593Smuzhiyun 	/* Serial number of device */
37*4882a593Smuzhiyun 	u32 serial_number;
38*4882a593Smuzhiyun 
39*4882a593Smuzhiyun 	/* Firmware version */
40*4882a593Smuzhiyun 	int firmware_version;
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun 	/* Monitor level */
43*4882a593Smuzhiyun 	int monitor_level;
44*4882a593Smuzhiyun };
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun #define line6_to_podhd(x)	container_of(x, struct usb_line6_podhd, line6)
47*4882a593Smuzhiyun 
48*4882a593Smuzhiyun static const struct snd_ratden podhd_ratden = {
49*4882a593Smuzhiyun 	.num_min = 48000,
50*4882a593Smuzhiyun 	.num_max = 48000,
51*4882a593Smuzhiyun 	.num_step = 1,
52*4882a593Smuzhiyun 	.den = 1,
53*4882a593Smuzhiyun };
54*4882a593Smuzhiyun 
55*4882a593Smuzhiyun static struct line6_pcm_properties podhd_pcm_properties = {
56*4882a593Smuzhiyun 	.playback_hw = {
57*4882a593Smuzhiyun 				  .info = (SNDRV_PCM_INFO_MMAP |
58*4882a593Smuzhiyun 					   SNDRV_PCM_INFO_INTERLEAVED |
59*4882a593Smuzhiyun 					   SNDRV_PCM_INFO_BLOCK_TRANSFER |
60*4882a593Smuzhiyun 					   SNDRV_PCM_INFO_MMAP_VALID |
61*4882a593Smuzhiyun 					   SNDRV_PCM_INFO_PAUSE |
62*4882a593Smuzhiyun 					   SNDRV_PCM_INFO_SYNC_START),
63*4882a593Smuzhiyun 				  .formats = SNDRV_PCM_FMTBIT_S24_3LE,
64*4882a593Smuzhiyun 				  .rates = SNDRV_PCM_RATE_48000,
65*4882a593Smuzhiyun 				  .rate_min = 48000,
66*4882a593Smuzhiyun 				  .rate_max = 48000,
67*4882a593Smuzhiyun 				  .channels_min = 2,
68*4882a593Smuzhiyun 				  .channels_max = 2,
69*4882a593Smuzhiyun 				  .buffer_bytes_max = 60000,
70*4882a593Smuzhiyun 				  .period_bytes_min = 64,
71*4882a593Smuzhiyun 				  .period_bytes_max = 8192,
72*4882a593Smuzhiyun 				  .periods_min = 1,
73*4882a593Smuzhiyun 				  .periods_max = 1024},
74*4882a593Smuzhiyun 	.capture_hw = {
75*4882a593Smuzhiyun 				 .info = (SNDRV_PCM_INFO_MMAP |
76*4882a593Smuzhiyun 					  SNDRV_PCM_INFO_INTERLEAVED |
77*4882a593Smuzhiyun 					  SNDRV_PCM_INFO_BLOCK_TRANSFER |
78*4882a593Smuzhiyun 					  SNDRV_PCM_INFO_MMAP_VALID |
79*4882a593Smuzhiyun 					  SNDRV_PCM_INFO_SYNC_START),
80*4882a593Smuzhiyun 				 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
81*4882a593Smuzhiyun 				 .rates = SNDRV_PCM_RATE_48000,
82*4882a593Smuzhiyun 				 .rate_min = 48000,
83*4882a593Smuzhiyun 				 .rate_max = 48000,
84*4882a593Smuzhiyun 				 .channels_min = 2,
85*4882a593Smuzhiyun 				 .channels_max = 2,
86*4882a593Smuzhiyun 				 .buffer_bytes_max = 60000,
87*4882a593Smuzhiyun 				 .period_bytes_min = 64,
88*4882a593Smuzhiyun 				 .period_bytes_max = 8192,
89*4882a593Smuzhiyun 				 .periods_min = 1,
90*4882a593Smuzhiyun 				 .periods_max = 1024},
91*4882a593Smuzhiyun 	.rates = {
92*4882a593Smuzhiyun 			    .nrats = 1,
93*4882a593Smuzhiyun 			    .rats = &podhd_ratden},
94*4882a593Smuzhiyun 	.bytes_per_channel = 3 /* SNDRV_PCM_FMTBIT_S24_3LE */
95*4882a593Smuzhiyun };
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun static struct line6_pcm_properties podx3_pcm_properties = {
98*4882a593Smuzhiyun 	.playback_hw = {
99*4882a593Smuzhiyun 				  .info = (SNDRV_PCM_INFO_MMAP |
100*4882a593Smuzhiyun 					   SNDRV_PCM_INFO_INTERLEAVED |
101*4882a593Smuzhiyun 					   SNDRV_PCM_INFO_BLOCK_TRANSFER |
102*4882a593Smuzhiyun 					   SNDRV_PCM_INFO_MMAP_VALID |
103*4882a593Smuzhiyun 					   SNDRV_PCM_INFO_PAUSE |
104*4882a593Smuzhiyun 					   SNDRV_PCM_INFO_SYNC_START),
105*4882a593Smuzhiyun 				  .formats = SNDRV_PCM_FMTBIT_S24_3LE,
106*4882a593Smuzhiyun 				  .rates = SNDRV_PCM_RATE_48000,
107*4882a593Smuzhiyun 				  .rate_min = 48000,
108*4882a593Smuzhiyun 				  .rate_max = 48000,
109*4882a593Smuzhiyun 				  .channels_min = 2,
110*4882a593Smuzhiyun 				  .channels_max = 2,
111*4882a593Smuzhiyun 				  .buffer_bytes_max = 60000,
112*4882a593Smuzhiyun 				  .period_bytes_min = 64,
113*4882a593Smuzhiyun 				  .period_bytes_max = 8192,
114*4882a593Smuzhiyun 				  .periods_min = 1,
115*4882a593Smuzhiyun 				  .periods_max = 1024},
116*4882a593Smuzhiyun 	.capture_hw = {
117*4882a593Smuzhiyun 				 .info = (SNDRV_PCM_INFO_MMAP |
118*4882a593Smuzhiyun 					  SNDRV_PCM_INFO_INTERLEAVED |
119*4882a593Smuzhiyun 					  SNDRV_PCM_INFO_BLOCK_TRANSFER |
120*4882a593Smuzhiyun 					  SNDRV_PCM_INFO_MMAP_VALID |
121*4882a593Smuzhiyun 					  SNDRV_PCM_INFO_SYNC_START),
122*4882a593Smuzhiyun 				 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
123*4882a593Smuzhiyun 				 .rates = SNDRV_PCM_RATE_48000,
124*4882a593Smuzhiyun 				 .rate_min = 48000,
125*4882a593Smuzhiyun 				 .rate_max = 48000,
126*4882a593Smuzhiyun 				 /* 1+2: Main signal (out), 3+4: Tone 1,
127*4882a593Smuzhiyun 				  * 5+6: Tone 2, 7+8: raw
128*4882a593Smuzhiyun 				  */
129*4882a593Smuzhiyun 				 .channels_min = 8,
130*4882a593Smuzhiyun 				 .channels_max = 8,
131*4882a593Smuzhiyun 				 .buffer_bytes_max = 60000,
132*4882a593Smuzhiyun 				 .period_bytes_min = 64,
133*4882a593Smuzhiyun 				 .period_bytes_max = 8192,
134*4882a593Smuzhiyun 				 .periods_min = 1,
135*4882a593Smuzhiyun 				 .periods_max = 1024},
136*4882a593Smuzhiyun 	.rates = {
137*4882a593Smuzhiyun 			    .nrats = 1,
138*4882a593Smuzhiyun 			    .rats = &podhd_ratden},
139*4882a593Smuzhiyun 	.bytes_per_channel = 3 /* SNDRV_PCM_FMTBIT_S24_3LE */
140*4882a593Smuzhiyun };
141*4882a593Smuzhiyun static struct usb_driver podhd_driver;
142*4882a593Smuzhiyun 
serial_number_show(struct device * dev,struct device_attribute * attr,char * buf)143*4882a593Smuzhiyun static ssize_t serial_number_show(struct device *dev,
144*4882a593Smuzhiyun 				  struct device_attribute *attr, char *buf)
145*4882a593Smuzhiyun {
146*4882a593Smuzhiyun 	struct snd_card *card = dev_to_snd_card(dev);
147*4882a593Smuzhiyun 	struct usb_line6_podhd *pod = card->private_data;
148*4882a593Smuzhiyun 
149*4882a593Smuzhiyun 	return sprintf(buf, "%u\n", pod->serial_number);
150*4882a593Smuzhiyun }
151*4882a593Smuzhiyun 
firmware_version_show(struct device * dev,struct device_attribute * attr,char * buf)152*4882a593Smuzhiyun static ssize_t firmware_version_show(struct device *dev,
153*4882a593Smuzhiyun 				     struct device_attribute *attr, char *buf)
154*4882a593Smuzhiyun {
155*4882a593Smuzhiyun 	struct snd_card *card = dev_to_snd_card(dev);
156*4882a593Smuzhiyun 	struct usb_line6_podhd *pod = card->private_data;
157*4882a593Smuzhiyun 
158*4882a593Smuzhiyun 	return sprintf(buf, "%06x\n", pod->firmware_version);
159*4882a593Smuzhiyun }
160*4882a593Smuzhiyun 
161*4882a593Smuzhiyun static DEVICE_ATTR_RO(firmware_version);
162*4882a593Smuzhiyun static DEVICE_ATTR_RO(serial_number);
163*4882a593Smuzhiyun 
164*4882a593Smuzhiyun static struct attribute *podhd_dev_attrs[] = {
165*4882a593Smuzhiyun 	&dev_attr_firmware_version.attr,
166*4882a593Smuzhiyun 	&dev_attr_serial_number.attr,
167*4882a593Smuzhiyun 	NULL
168*4882a593Smuzhiyun };
169*4882a593Smuzhiyun 
170*4882a593Smuzhiyun static const struct attribute_group podhd_dev_attr_group = {
171*4882a593Smuzhiyun 	.name = "podhd",
172*4882a593Smuzhiyun 	.attrs = podhd_dev_attrs,
173*4882a593Smuzhiyun };
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun /*
176*4882a593Smuzhiyun  * POD X3 startup procedure.
177*4882a593Smuzhiyun  *
178*4882a593Smuzhiyun  * May be compatible with other POD HD's, since it's also similar to the
179*4882a593Smuzhiyun  * previous POD setup. In any case, it doesn't seem to be required for the
180*4882a593Smuzhiyun  * audio nor bulk interfaces to work.
181*4882a593Smuzhiyun  */
182*4882a593Smuzhiyun 
podhd_dev_start(struct usb_line6_podhd * pod)183*4882a593Smuzhiyun static int podhd_dev_start(struct usb_line6_podhd *pod)
184*4882a593Smuzhiyun {
185*4882a593Smuzhiyun 	int ret;
186*4882a593Smuzhiyun 	u8 init_bytes[8];
187*4882a593Smuzhiyun 	int i;
188*4882a593Smuzhiyun 	struct usb_device *usbdev = pod->line6.usbdev;
189*4882a593Smuzhiyun 
190*4882a593Smuzhiyun 	ret = usb_control_msg_send(usbdev, 0,
191*4882a593Smuzhiyun 					0x67, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
192*4882a593Smuzhiyun 					0x11, 0,
193*4882a593Smuzhiyun 					NULL, 0, LINE6_TIMEOUT, GFP_KERNEL);
194*4882a593Smuzhiyun 	if (ret) {
195*4882a593Smuzhiyun 		dev_err(pod->line6.ifcdev, "read request failed (error %d)\n", ret);
196*4882a593Smuzhiyun 		goto exit;
197*4882a593Smuzhiyun 	}
198*4882a593Smuzhiyun 
199*4882a593Smuzhiyun 	/* NOTE: looks like some kind of ping message */
200*4882a593Smuzhiyun 	ret = usb_control_msg_recv(usbdev, 0, 0x67,
201*4882a593Smuzhiyun 					USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
202*4882a593Smuzhiyun 					0x11, 0x0,
203*4882a593Smuzhiyun 					init_bytes, 3, LINE6_TIMEOUT, GFP_KERNEL);
204*4882a593Smuzhiyun 	if (ret) {
205*4882a593Smuzhiyun 		dev_err(pod->line6.ifcdev,
206*4882a593Smuzhiyun 			"receive length failed (error %d)\n", ret);
207*4882a593Smuzhiyun 		goto exit;
208*4882a593Smuzhiyun 	}
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun 	pod->firmware_version =
211*4882a593Smuzhiyun 		(init_bytes[0] << 16) | (init_bytes[1] << 8) | (init_bytes[2] << 0);
212*4882a593Smuzhiyun 
213*4882a593Smuzhiyun 	for (i = 0; i <= 16; i++) {
214*4882a593Smuzhiyun 		ret = line6_read_data(&pod->line6, 0xf000 + 0x08 * i, init_bytes, 8);
215*4882a593Smuzhiyun 		if (ret < 0)
216*4882a593Smuzhiyun 			goto exit;
217*4882a593Smuzhiyun 	}
218*4882a593Smuzhiyun 
219*4882a593Smuzhiyun 	ret = usb_control_msg_send(usbdev, 0,
220*4882a593Smuzhiyun 					USB_REQ_SET_FEATURE,
221*4882a593Smuzhiyun 					USB_TYPE_STANDARD | USB_RECIP_DEVICE | USB_DIR_OUT,
222*4882a593Smuzhiyun 					1, 0,
223*4882a593Smuzhiyun 					NULL, 0, LINE6_TIMEOUT, GFP_KERNEL);
224*4882a593Smuzhiyun exit:
225*4882a593Smuzhiyun 	return ret;
226*4882a593Smuzhiyun }
227*4882a593Smuzhiyun 
podhd_startup(struct usb_line6 * line6)228*4882a593Smuzhiyun static void podhd_startup(struct usb_line6 *line6)
229*4882a593Smuzhiyun {
230*4882a593Smuzhiyun 	struct usb_line6_podhd *pod = line6_to_podhd(line6);
231*4882a593Smuzhiyun 
232*4882a593Smuzhiyun 	podhd_dev_start(pod);
233*4882a593Smuzhiyun 	line6_read_serial_number(&pod->line6, &pod->serial_number);
234*4882a593Smuzhiyun 	if (snd_card_register(line6->card))
235*4882a593Smuzhiyun 		dev_err(line6->ifcdev, "Failed to register POD HD card.\n");
236*4882a593Smuzhiyun }
237*4882a593Smuzhiyun 
podhd_disconnect(struct usb_line6 * line6)238*4882a593Smuzhiyun static void podhd_disconnect(struct usb_line6 *line6)
239*4882a593Smuzhiyun {
240*4882a593Smuzhiyun 	struct usb_line6_podhd *pod = line6_to_podhd(line6);
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO) {
243*4882a593Smuzhiyun 		struct usb_interface *intf;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 		intf = usb_ifnum_to_if(line6->usbdev,
246*4882a593Smuzhiyun 					pod->line6.properties->ctrl_if);
247*4882a593Smuzhiyun 		if (intf)
248*4882a593Smuzhiyun 			usb_driver_release_interface(&podhd_driver, intf);
249*4882a593Smuzhiyun 	}
250*4882a593Smuzhiyun }
251*4882a593Smuzhiyun 
252*4882a593Smuzhiyun static const unsigned int float_zero_to_one_lookup[] = {
253*4882a593Smuzhiyun 0x00000000, 0x3c23d70a, 0x3ca3d70a, 0x3cf5c28f, 0x3d23d70a, 0x3d4ccccd,
254*4882a593Smuzhiyun 0x3d75c28f, 0x3d8f5c29, 0x3da3d70a, 0x3db851ec, 0x3dcccccd, 0x3de147ae,
255*4882a593Smuzhiyun 0x3df5c28f, 0x3e051eb8, 0x3e0f5c29, 0x3e19999a, 0x3e23d70a, 0x3e2e147b,
256*4882a593Smuzhiyun 0x3e3851ec, 0x3e428f5c, 0x3e4ccccd, 0x3e570a3d, 0x3e6147ae, 0x3e6b851f,
257*4882a593Smuzhiyun 0x3e75c28f, 0x3e800000, 0x3e851eb8, 0x3e8a3d71, 0x3e8f5c29, 0x3e947ae1,
258*4882a593Smuzhiyun 0x3e99999a, 0x3e9eb852, 0x3ea3d70a, 0x3ea8f5c3, 0x3eae147b, 0x3eb33333,
259*4882a593Smuzhiyun 0x3eb851ec, 0x3ebd70a4, 0x3ec28f5c, 0x3ec7ae14, 0x3ecccccd, 0x3ed1eb85,
260*4882a593Smuzhiyun 0x3ed70a3d, 0x3edc28f6, 0x3ee147ae, 0x3ee66666, 0x3eeb851f, 0x3ef0a3d7,
261*4882a593Smuzhiyun 0x3ef5c28f, 0x3efae148, 0x3f000000, 0x3f028f5c, 0x3f051eb8, 0x3f07ae14,
262*4882a593Smuzhiyun 0x3f0a3d71, 0x3f0ccccd, 0x3f0f5c29, 0x3f11eb85, 0x3f147ae1, 0x3f170a3d,
263*4882a593Smuzhiyun 0x3f19999a, 0x3f1c28f6, 0x3f1eb852, 0x3f2147ae, 0x3f23d70a, 0x3f266666,
264*4882a593Smuzhiyun 0x3f28f5c3, 0x3f2b851f, 0x3f2e147b, 0x3f30a3d7, 0x3f333333, 0x3f35c28f,
265*4882a593Smuzhiyun 0x3f3851ec, 0x3f3ae148, 0x3f3d70a4, 0x3f400000, 0x3f428f5c, 0x3f451eb8,
266*4882a593Smuzhiyun 0x3f47ae14, 0x3f4a3d71, 0x3f4ccccd, 0x3f4f5c29, 0x3f51eb85, 0x3f547ae1,
267*4882a593Smuzhiyun 0x3f570a3d, 0x3f59999a, 0x3f5c28f6, 0x3f5eb852, 0x3f6147ae, 0x3f63d70a,
268*4882a593Smuzhiyun 0x3f666666, 0x3f68f5c3, 0x3f6b851f, 0x3f6e147b, 0x3f70a3d7, 0x3f733333,
269*4882a593Smuzhiyun 0x3f75c28f, 0x3f7851ec, 0x3f7ae148, 0x3f7d70a4, 0x3f800000
270*4882a593Smuzhiyun };
271*4882a593Smuzhiyun 
podhd_set_monitor_level(struct usb_line6_podhd * podhd,int value)272*4882a593Smuzhiyun static void podhd_set_monitor_level(struct usb_line6_podhd *podhd, int value)
273*4882a593Smuzhiyun {
274*4882a593Smuzhiyun 	unsigned int fl;
275*4882a593Smuzhiyun 	static const unsigned char msg[16] = {
276*4882a593Smuzhiyun 		/* Chunk is 0xc bytes (without first word) */
277*4882a593Smuzhiyun 		0x0c, 0x00,
278*4882a593Smuzhiyun 		/* First chunk in the message */
279*4882a593Smuzhiyun 		0x01, 0x00,
280*4882a593Smuzhiyun 		/* Message size is 2 4-byte words */
281*4882a593Smuzhiyun 		0x02, 0x00,
282*4882a593Smuzhiyun 		/* Unknown */
283*4882a593Smuzhiyun 		0x04, 0x41,
284*4882a593Smuzhiyun 		/* Unknown */
285*4882a593Smuzhiyun 		0x04, 0x00, 0x13, 0x00,
286*4882a593Smuzhiyun 		/* Volume, LE float32, 0.0 - 1.0 */
287*4882a593Smuzhiyun 		0x00, 0x00, 0x00, 0x00
288*4882a593Smuzhiyun 	};
289*4882a593Smuzhiyun 	unsigned char *buf;
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	buf = kmemdup(msg, sizeof(msg), GFP_KERNEL);
292*4882a593Smuzhiyun 	if (!buf)
293*4882a593Smuzhiyun 		return;
294*4882a593Smuzhiyun 
295*4882a593Smuzhiyun 	if (value < 0)
296*4882a593Smuzhiyun 		value = 0;
297*4882a593Smuzhiyun 
298*4882a593Smuzhiyun 	if (value >= ARRAY_SIZE(float_zero_to_one_lookup))
299*4882a593Smuzhiyun 		value = ARRAY_SIZE(float_zero_to_one_lookup) - 1;
300*4882a593Smuzhiyun 
301*4882a593Smuzhiyun 	fl = float_zero_to_one_lookup[value];
302*4882a593Smuzhiyun 
303*4882a593Smuzhiyun 	buf[12] = (fl >> 0) & 0xff;
304*4882a593Smuzhiyun 	buf[13] = (fl >> 8) & 0xff;
305*4882a593Smuzhiyun 	buf[14] = (fl >> 16) & 0xff;
306*4882a593Smuzhiyun 	buf[15] = (fl >> 24) & 0xff;
307*4882a593Smuzhiyun 
308*4882a593Smuzhiyun 	line6_send_raw_message(&podhd->line6, buf, sizeof(msg));
309*4882a593Smuzhiyun 	kfree(buf);
310*4882a593Smuzhiyun 
311*4882a593Smuzhiyun 	podhd->monitor_level = value;
312*4882a593Smuzhiyun }
313*4882a593Smuzhiyun 
314*4882a593Smuzhiyun /* control info callback */
snd_podhd_control_monitor_info(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)315*4882a593Smuzhiyun static int snd_podhd_control_monitor_info(struct snd_kcontrol *kcontrol,
316*4882a593Smuzhiyun 					struct snd_ctl_elem_info *uinfo)
317*4882a593Smuzhiyun {
318*4882a593Smuzhiyun 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
319*4882a593Smuzhiyun 	uinfo->count = 1;
320*4882a593Smuzhiyun 	uinfo->value.integer.min = 0;
321*4882a593Smuzhiyun 	uinfo->value.integer.max = 100;
322*4882a593Smuzhiyun 	uinfo->value.integer.step = 1;
323*4882a593Smuzhiyun 	return 0;
324*4882a593Smuzhiyun }
325*4882a593Smuzhiyun 
326*4882a593Smuzhiyun /* control get callback */
snd_podhd_control_monitor_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)327*4882a593Smuzhiyun static int snd_podhd_control_monitor_get(struct snd_kcontrol *kcontrol,
328*4882a593Smuzhiyun 				       struct snd_ctl_elem_value *ucontrol)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun 	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
331*4882a593Smuzhiyun 	struct usb_line6_podhd *podhd = line6_to_podhd(line6pcm->line6);
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	ucontrol->value.integer.value[0] = podhd->monitor_level;
334*4882a593Smuzhiyun 	return 0;
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun /* control put callback */
snd_podhd_control_monitor_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)338*4882a593Smuzhiyun static int snd_podhd_control_monitor_put(struct snd_kcontrol *kcontrol,
339*4882a593Smuzhiyun 				       struct snd_ctl_elem_value *ucontrol)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun 	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
342*4882a593Smuzhiyun 	struct usb_line6_podhd *podhd = line6_to_podhd(line6pcm->line6);
343*4882a593Smuzhiyun 
344*4882a593Smuzhiyun 	if (ucontrol->value.integer.value[0] == podhd->monitor_level)
345*4882a593Smuzhiyun 		return 0;
346*4882a593Smuzhiyun 
347*4882a593Smuzhiyun 	podhd_set_monitor_level(podhd, ucontrol->value.integer.value[0]);
348*4882a593Smuzhiyun 	return 1;
349*4882a593Smuzhiyun }
350*4882a593Smuzhiyun 
351*4882a593Smuzhiyun /* control definition */
352*4882a593Smuzhiyun static const struct snd_kcontrol_new podhd_control_monitor = {
353*4882a593Smuzhiyun 	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
354*4882a593Smuzhiyun 	.name = "Monitor Playback Volume",
355*4882a593Smuzhiyun 	.index = 0,
356*4882a593Smuzhiyun 	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
357*4882a593Smuzhiyun 	.info = snd_podhd_control_monitor_info,
358*4882a593Smuzhiyun 	.get = snd_podhd_control_monitor_get,
359*4882a593Smuzhiyun 	.put = snd_podhd_control_monitor_put
360*4882a593Smuzhiyun };
361*4882a593Smuzhiyun 
362*4882a593Smuzhiyun /*
363*4882a593Smuzhiyun 	Try to init POD HD device.
364*4882a593Smuzhiyun */
podhd_init(struct usb_line6 * line6,const struct usb_device_id * id)365*4882a593Smuzhiyun static int podhd_init(struct usb_line6 *line6,
366*4882a593Smuzhiyun 		      const struct usb_device_id *id)
367*4882a593Smuzhiyun {
368*4882a593Smuzhiyun 	int err;
369*4882a593Smuzhiyun 	struct usb_line6_podhd *pod = line6_to_podhd(line6);
370*4882a593Smuzhiyun 	struct usb_interface *intf;
371*4882a593Smuzhiyun 
372*4882a593Smuzhiyun 	line6->disconnect = podhd_disconnect;
373*4882a593Smuzhiyun 	line6->startup = podhd_startup;
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun 	if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) {
376*4882a593Smuzhiyun 		/* claim the data interface */
377*4882a593Smuzhiyun 		intf = usb_ifnum_to_if(line6->usbdev,
378*4882a593Smuzhiyun 					pod->line6.properties->ctrl_if);
379*4882a593Smuzhiyun 		if (!intf) {
380*4882a593Smuzhiyun 			dev_err(pod->line6.ifcdev, "interface %d not found\n",
381*4882a593Smuzhiyun 				pod->line6.properties->ctrl_if);
382*4882a593Smuzhiyun 			return -ENODEV;
383*4882a593Smuzhiyun 		}
384*4882a593Smuzhiyun 
385*4882a593Smuzhiyun 		err = usb_driver_claim_interface(&podhd_driver, intf, NULL);
386*4882a593Smuzhiyun 		if (err != 0) {
387*4882a593Smuzhiyun 			dev_err(pod->line6.ifcdev, "can't claim interface %d, error %d\n",
388*4882a593Smuzhiyun 				pod->line6.properties->ctrl_if, err);
389*4882a593Smuzhiyun 			return err;
390*4882a593Smuzhiyun 		}
391*4882a593Smuzhiyun 	}
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 	if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO) {
394*4882a593Smuzhiyun 		/* create sysfs entries: */
395*4882a593Smuzhiyun 		err = snd_card_add_dev_attr(line6->card, &podhd_dev_attr_group);
396*4882a593Smuzhiyun 		if (err < 0)
397*4882a593Smuzhiyun 			return err;
398*4882a593Smuzhiyun 	}
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 	if (pod->line6.properties->capabilities & LINE6_CAP_PCM) {
401*4882a593Smuzhiyun 		/* initialize PCM subsystem: */
402*4882a593Smuzhiyun 		err = line6_init_pcm(line6,
403*4882a593Smuzhiyun 			(id->driver_info == LINE6_PODX3 ||
404*4882a593Smuzhiyun 			id->driver_info == LINE6_PODX3LIVE) ? &podx3_pcm_properties :
405*4882a593Smuzhiyun 			&podhd_pcm_properties);
406*4882a593Smuzhiyun 		if (err < 0)
407*4882a593Smuzhiyun 			return err;
408*4882a593Smuzhiyun 	}
409*4882a593Smuzhiyun 
410*4882a593Smuzhiyun 	if (pod->line6.properties->capabilities & LINE6_CAP_HWMON_CTL) {
411*4882a593Smuzhiyun 		podhd_set_monitor_level(pod, 100);
412*4882a593Smuzhiyun 		err = snd_ctl_add(line6->card,
413*4882a593Smuzhiyun 				  snd_ctl_new1(&podhd_control_monitor,
414*4882a593Smuzhiyun 					       line6->line6pcm));
415*4882a593Smuzhiyun 		if (err < 0)
416*4882a593Smuzhiyun 			return err;
417*4882a593Smuzhiyun 	}
418*4882a593Smuzhiyun 
419*4882a593Smuzhiyun 	if (!(pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO)) {
420*4882a593Smuzhiyun 		/* register USB audio system directly */
421*4882a593Smuzhiyun 		return snd_card_register(line6->card);
422*4882a593Smuzhiyun 	}
423*4882a593Smuzhiyun 
424*4882a593Smuzhiyun 	/* init device and delay registering */
425*4882a593Smuzhiyun 	schedule_delayed_work(&line6->startup_work,
426*4882a593Smuzhiyun 			      msecs_to_jiffies(PODHD_STARTUP_DELAY));
427*4882a593Smuzhiyun 	return 0;
428*4882a593Smuzhiyun }
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun #define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
431*4882a593Smuzhiyun #define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun /* table of devices that work with this driver */
434*4882a593Smuzhiyun static const struct usb_device_id podhd_id_table[] = {
435*4882a593Smuzhiyun 	/* TODO: no need to alloc data interfaces when only audio is used */
436*4882a593Smuzhiyun 	{ LINE6_DEVICE(0x5057),    .driver_info = LINE6_PODHD300 },
437*4882a593Smuzhiyun 	{ LINE6_DEVICE(0x5058),    .driver_info = LINE6_PODHD400 },
438*4882a593Smuzhiyun 	{ LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500 },
439*4882a593Smuzhiyun 	{ LINE6_IF_NUM(0x414A, 0), .driver_info = LINE6_PODX3 },
440*4882a593Smuzhiyun 	{ LINE6_IF_NUM(0x414B, 0), .driver_info = LINE6_PODX3LIVE },
441*4882a593Smuzhiyun 	{ LINE6_IF_NUM(0x4159, 0), .driver_info = LINE6_PODHD500X },
442*4882a593Smuzhiyun 	{ LINE6_IF_NUM(0x4156, 0), .driver_info = LINE6_PODHDDESKTOP },
443*4882a593Smuzhiyun 	{}
444*4882a593Smuzhiyun };
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun MODULE_DEVICE_TABLE(usb, podhd_id_table);
447*4882a593Smuzhiyun 
448*4882a593Smuzhiyun static const struct line6_properties podhd_properties_table[] = {
449*4882a593Smuzhiyun 	[LINE6_PODHD300] = {
450*4882a593Smuzhiyun 		.id = "PODHD300",
451*4882a593Smuzhiyun 		.name = "POD HD300",
452*4882a593Smuzhiyun 		.capabilities	= LINE6_CAP_PCM
453*4882a593Smuzhiyun 				| LINE6_CAP_HWMON,
454*4882a593Smuzhiyun 		.altsetting = 5,
455*4882a593Smuzhiyun 		.ep_ctrl_r = 0x84,
456*4882a593Smuzhiyun 		.ep_ctrl_w = 0x03,
457*4882a593Smuzhiyun 		.ep_audio_r = 0x82,
458*4882a593Smuzhiyun 		.ep_audio_w = 0x01,
459*4882a593Smuzhiyun 	},
460*4882a593Smuzhiyun 	[LINE6_PODHD400] = {
461*4882a593Smuzhiyun 		.id = "PODHD400",
462*4882a593Smuzhiyun 		.name = "POD HD400",
463*4882a593Smuzhiyun 		.capabilities	= LINE6_CAP_PCM
464*4882a593Smuzhiyun 				| LINE6_CAP_HWMON,
465*4882a593Smuzhiyun 		.altsetting = 5,
466*4882a593Smuzhiyun 		.ep_ctrl_r = 0x84,
467*4882a593Smuzhiyun 		.ep_ctrl_w = 0x03,
468*4882a593Smuzhiyun 		.ep_audio_r = 0x82,
469*4882a593Smuzhiyun 		.ep_audio_w = 0x01,
470*4882a593Smuzhiyun 	},
471*4882a593Smuzhiyun 	[LINE6_PODHD500] = {
472*4882a593Smuzhiyun 		.id = "PODHD500",
473*4882a593Smuzhiyun 		.name = "POD HD500",
474*4882a593Smuzhiyun 		.capabilities	= LINE6_CAP_PCM | LINE6_CAP_CONTROL
475*4882a593Smuzhiyun 				| LINE6_CAP_HWMON | LINE6_CAP_HWMON_CTL,
476*4882a593Smuzhiyun 		.altsetting = 1,
477*4882a593Smuzhiyun 		.ctrl_if = 1,
478*4882a593Smuzhiyun 		.ep_ctrl_r = 0x81,
479*4882a593Smuzhiyun 		.ep_ctrl_w = 0x01,
480*4882a593Smuzhiyun 		.ep_audio_r = 0x86,
481*4882a593Smuzhiyun 		.ep_audio_w = 0x02,
482*4882a593Smuzhiyun 	},
483*4882a593Smuzhiyun 	[LINE6_PODX3] = {
484*4882a593Smuzhiyun 		.id = "PODX3",
485*4882a593Smuzhiyun 		.name = "POD X3",
486*4882a593Smuzhiyun 		.capabilities	= LINE6_CAP_CONTROL | LINE6_CAP_CONTROL_INFO
487*4882a593Smuzhiyun 				| LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT,
488*4882a593Smuzhiyun 		.altsetting = 1,
489*4882a593Smuzhiyun 		.ep_ctrl_r = 0x81,
490*4882a593Smuzhiyun 		.ep_ctrl_w = 0x01,
491*4882a593Smuzhiyun 		.ctrl_if = 1,
492*4882a593Smuzhiyun 		.ep_audio_r = 0x86,
493*4882a593Smuzhiyun 		.ep_audio_w = 0x02,
494*4882a593Smuzhiyun 	},
495*4882a593Smuzhiyun 	[LINE6_PODX3LIVE] = {
496*4882a593Smuzhiyun 		.id = "PODX3LIVE",
497*4882a593Smuzhiyun 		.name = "POD X3 LIVE",
498*4882a593Smuzhiyun 		.capabilities	= LINE6_CAP_CONTROL | LINE6_CAP_CONTROL_INFO
499*4882a593Smuzhiyun 				| LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT,
500*4882a593Smuzhiyun 		.altsetting = 1,
501*4882a593Smuzhiyun 		.ep_ctrl_r = 0x81,
502*4882a593Smuzhiyun 		.ep_ctrl_w = 0x01,
503*4882a593Smuzhiyun 		.ctrl_if = 1,
504*4882a593Smuzhiyun 		.ep_audio_r = 0x86,
505*4882a593Smuzhiyun 		.ep_audio_w = 0x02,
506*4882a593Smuzhiyun 	},
507*4882a593Smuzhiyun 	[LINE6_PODHD500X] = {
508*4882a593Smuzhiyun 		.id = "PODHD500X",
509*4882a593Smuzhiyun 		.name = "POD HD500X",
510*4882a593Smuzhiyun 		.capabilities	= LINE6_CAP_CONTROL
511*4882a593Smuzhiyun 				| LINE6_CAP_PCM | LINE6_CAP_HWMON,
512*4882a593Smuzhiyun 		.altsetting = 1,
513*4882a593Smuzhiyun 		.ep_ctrl_r = 0x81,
514*4882a593Smuzhiyun 		.ep_ctrl_w = 0x01,
515*4882a593Smuzhiyun 		.ctrl_if = 1,
516*4882a593Smuzhiyun 		.ep_audio_r = 0x86,
517*4882a593Smuzhiyun 		.ep_audio_w = 0x02,
518*4882a593Smuzhiyun 	},
519*4882a593Smuzhiyun 	[LINE6_PODHDDESKTOP] = {
520*4882a593Smuzhiyun 		.id = "PODHDDESKTOP",
521*4882a593Smuzhiyun 		.name = "POD HDDESKTOP",
522*4882a593Smuzhiyun 		.capabilities    = LINE6_CAP_CONTROL
523*4882a593Smuzhiyun 			| LINE6_CAP_PCM | LINE6_CAP_HWMON,
524*4882a593Smuzhiyun 		.altsetting = 1,
525*4882a593Smuzhiyun 		.ep_ctrl_r = 0x81,
526*4882a593Smuzhiyun 		.ep_ctrl_w = 0x01,
527*4882a593Smuzhiyun 		.ctrl_if = 1,
528*4882a593Smuzhiyun 		.ep_audio_r = 0x86,
529*4882a593Smuzhiyun 		.ep_audio_w = 0x02,
530*4882a593Smuzhiyun 	},
531*4882a593Smuzhiyun };
532*4882a593Smuzhiyun 
533*4882a593Smuzhiyun /*
534*4882a593Smuzhiyun 	Probe USB device.
535*4882a593Smuzhiyun */
podhd_probe(struct usb_interface * interface,const struct usb_device_id * id)536*4882a593Smuzhiyun static int podhd_probe(struct usb_interface *interface,
537*4882a593Smuzhiyun 		       const struct usb_device_id *id)
538*4882a593Smuzhiyun {
539*4882a593Smuzhiyun 	return line6_probe(interface, id, "Line6-PODHD",
540*4882a593Smuzhiyun 			   &podhd_properties_table[id->driver_info],
541*4882a593Smuzhiyun 			   podhd_init, sizeof(struct usb_line6_podhd));
542*4882a593Smuzhiyun }
543*4882a593Smuzhiyun 
544*4882a593Smuzhiyun static struct usb_driver podhd_driver = {
545*4882a593Smuzhiyun 	.name = KBUILD_MODNAME,
546*4882a593Smuzhiyun 	.probe = podhd_probe,
547*4882a593Smuzhiyun 	.disconnect = line6_disconnect,
548*4882a593Smuzhiyun #ifdef CONFIG_PM
549*4882a593Smuzhiyun 	.suspend = line6_suspend,
550*4882a593Smuzhiyun 	.resume = line6_resume,
551*4882a593Smuzhiyun 	.reset_resume = line6_resume,
552*4882a593Smuzhiyun #endif
553*4882a593Smuzhiyun 	.id_table = podhd_id_table,
554*4882a593Smuzhiyun };
555*4882a593Smuzhiyun 
556*4882a593Smuzhiyun module_usb_driver(podhd_driver);
557*4882a593Smuzhiyun 
558*4882a593Smuzhiyun MODULE_DESCRIPTION("Line 6 PODHD USB driver");
559*4882a593Smuzhiyun MODULE_LICENSE("GPL");
560