Blame view

sound/usb/line6/podhd.c 15.1 KB
a10e763b8   Thomas Gleixner   treewide: Replace...
1
  // SPDX-License-Identifier: GPL-2.0-only
16dc10401   Stefan Hajnoczi   staging: line6: a...
2
  /*
c6fffce92   Chris Rorvick   ALSA: line6: Refe...
3
   * Line 6 Pod HD
16dc10401   Stefan Hajnoczi   staging: line6: a...
4
5
   *
   * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
790869dac   Andrej Krutak   ALSA: line6: Add ...
6
   * Copyright (C) 2015 Andrej Krutak <dev@andree.sk>
c1d25075f   Hans P. Möller Ebner   ALSA: line6: add ...
7
   * Copyright (C) 2017 Hans P. Moller <hmoller@uc.cl>
16dc10401   Stefan Hajnoczi   staging: line6: a...
8
   */
ccddbe4a9   Takashi Iwai   ALSA: line6: Spli...
9
10
11
  #include <linux/usb.h>
  #include <linux/slab.h>
  #include <linux/module.h>
16dc10401   Stefan Hajnoczi   staging: line6: a...
12
  #include <sound/core.h>
0afff876d   Vasily Khoruzhick   ALSA: line6: add ...
13
  #include <sound/control.h>
16dc10401   Stefan Hajnoczi   staging: line6: a...
14
  #include <sound/pcm.h>
16dc10401   Stefan Hajnoczi   staging: line6: a...
15
16
  #include "driver.h"
  #include "pcm.h"
ccddbe4a9   Takashi Iwai   ALSA: line6: Spli...
17

790869dac   Andrej Krutak   ALSA: line6: Add ...
18
  #define PODHD_STARTUP_DELAY 500
ccddbe4a9   Takashi Iwai   ALSA: line6: Spli...
19
20
21
  enum {
  	LINE6_PODHD300,
  	LINE6_PODHD400,
cc18b2f4f   Vasily Khoruzhick   ALSA: line6: Fix ...
22
  	LINE6_PODHD500,
790869dac   Andrej Krutak   ALSA: line6: Add ...
23
  	LINE6_PODX3,
c1d25075f   Hans P. Möller Ebner   ALSA: line6: add ...
24
  	LINE6_PODX3LIVE,
729fbfc92   Hans P. Möller Ebner   ALSA: line6: add ...
25
26
  	LINE6_PODHD500X,
  	LINE6_PODHDDESKTOP
790869dac   Andrej Krutak   ALSA: line6: Add ...
27
28
29
30
31
  };
  
  struct usb_line6_podhd {
  	/* Generic Line 6 USB data */
  	struct usb_line6 line6;
790869dac   Andrej Krutak   ALSA: line6: Add ...
32
33
34
35
36
  	/* Serial number of device */
  	u32 serial_number;
  
  	/* Firmware version */
  	int firmware_version;
0afff876d   Vasily Khoruzhick   ALSA: line6: add ...
37
38
39
  
  	/* Monitor level */
  	int monitor_level;
ccddbe4a9   Takashi Iwai   ALSA: line6: Spli...
40
  };
f23a09eea   Takashi Iwai   ALSA: line6: Use ...
41
  #define line6_to_podhd(x)	container_of(x, struct usb_line6_podhd, line6)
37cc306b7   Takashi Iwai   ALSA: line6: Cons...
42
  static const struct snd_ratden podhd_ratden = {
16dc10401   Stefan Hajnoczi   staging: line6: a...
43
44
45
46
47
48
49
  	.num_min = 48000,
  	.num_max = 48000,
  	.num_step = 1,
  	.den = 1,
  };
  
  static struct line6_pcm_properties podhd_pcm_properties = {
1263f6117   Takashi Iwai   ALSA: line6: Remo...
50
  	.playback_hw = {
16dc10401   Stefan Hajnoczi   staging: line6: a...
51
52
53
54
55
  				  .info = (SNDRV_PCM_INFO_MMAP |
  					   SNDRV_PCM_INFO_INTERLEAVED |
  					   SNDRV_PCM_INFO_BLOCK_TRANSFER |
  					   SNDRV_PCM_INFO_MMAP_VALID |
  					   SNDRV_PCM_INFO_PAUSE |
16dc10401   Stefan Hajnoczi   staging: line6: a...
56
57
58
59
60
61
62
63
64
65
66
67
  					   SNDRV_PCM_INFO_SYNC_START),
  				  .formats = SNDRV_PCM_FMTBIT_S24_3LE,
  				  .rates = SNDRV_PCM_RATE_48000,
  				  .rate_min = 48000,
  				  .rate_max = 48000,
  				  .channels_min = 2,
  				  .channels_max = 2,
  				  .buffer_bytes_max = 60000,
  				  .period_bytes_min = 64,
  				  .period_bytes_max = 8192,
  				  .periods_min = 1,
  				  .periods_max = 1024},
1263f6117   Takashi Iwai   ALSA: line6: Remo...
68
  	.capture_hw = {
16dc10401   Stefan Hajnoczi   staging: line6: a...
69
70
71
72
  				 .info = (SNDRV_PCM_INFO_MMAP |
  					  SNDRV_PCM_INFO_INTERLEAVED |
  					  SNDRV_PCM_INFO_BLOCK_TRANSFER |
  					  SNDRV_PCM_INFO_MMAP_VALID |
16dc10401   Stefan Hajnoczi   staging: line6: a...
73
74
75
76
77
78
79
80
81
82
83
84
  					  SNDRV_PCM_INFO_SYNC_START),
  				 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
  				 .rates = SNDRV_PCM_RATE_48000,
  				 .rate_min = 48000,
  				 .rate_max = 48000,
  				 .channels_min = 2,
  				 .channels_max = 2,
  				 .buffer_bytes_max = 60000,
  				 .period_bytes_min = 64,
  				 .period_bytes_max = 8192,
  				 .periods_min = 1,
  				 .periods_max = 1024},
1263f6117   Takashi Iwai   ALSA: line6: Remo...
85
  	.rates = {
16dc10401   Stefan Hajnoczi   staging: line6: a...
86
87
  			    .nrats = 1,
  			    .rats = &podhd_ratden},
790869dac   Andrej Krutak   ALSA: line6: Add ...
88
  	.bytes_per_channel = 3 /* SNDRV_PCM_FMTBIT_S24_3LE */
16dc10401   Stefan Hajnoczi   staging: line6: a...
89
  };
790869dac   Andrej Krutak   ALSA: line6: Add ...
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
  static struct line6_pcm_properties podx3_pcm_properties = {
  	.playback_hw = {
  				  .info = (SNDRV_PCM_INFO_MMAP |
  					   SNDRV_PCM_INFO_INTERLEAVED |
  					   SNDRV_PCM_INFO_BLOCK_TRANSFER |
  					   SNDRV_PCM_INFO_MMAP_VALID |
  					   SNDRV_PCM_INFO_PAUSE |
  					   SNDRV_PCM_INFO_SYNC_START),
  				  .formats = SNDRV_PCM_FMTBIT_S24_3LE,
  				  .rates = SNDRV_PCM_RATE_48000,
  				  .rate_min = 48000,
  				  .rate_max = 48000,
  				  .channels_min = 2,
  				  .channels_max = 2,
  				  .buffer_bytes_max = 60000,
  				  .period_bytes_min = 64,
  				  .period_bytes_max = 8192,
  				  .periods_min = 1,
  				  .periods_max = 1024},
  	.capture_hw = {
  				 .info = (SNDRV_PCM_INFO_MMAP |
  					  SNDRV_PCM_INFO_INTERLEAVED |
  					  SNDRV_PCM_INFO_BLOCK_TRANSFER |
  					  SNDRV_PCM_INFO_MMAP_VALID |
  					  SNDRV_PCM_INFO_SYNC_START),
  				 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
  				 .rates = SNDRV_PCM_RATE_48000,
  				 .rate_min = 48000,
  				 .rate_max = 48000,
  				 /* 1+2: Main signal (out), 3+4: Tone 1,
  				  * 5+6: Tone 2, 7+8: raw
  				  */
  				 .channels_min = 8,
  				 .channels_max = 8,
  				 .buffer_bytes_max = 60000,
  				 .period_bytes_min = 64,
  				 .period_bytes_max = 8192,
  				 .periods_min = 1,
  				 .periods_max = 1024},
  	.rates = {
  			    .nrats = 1,
  			    .rats = &podhd_ratden},
  	.bytes_per_channel = 3 /* SNDRV_PCM_FMTBIT_S24_3LE */
  };
fc90172ba   Andrej Krutak   ALSA: line6: Clai...
134
  static struct usb_driver podhd_driver;
790869dac   Andrej Krutak   ALSA: line6: Add ...
135

790869dac   Andrej Krutak   ALSA: line6: Add ...
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
  static ssize_t serial_number_show(struct device *dev,
  				  struct device_attribute *attr, char *buf)
  {
  	struct snd_card *card = dev_to_snd_card(dev);
  	struct usb_line6_podhd *pod = card->private_data;
  
  	return sprintf(buf, "%u
  ", pod->serial_number);
  }
  
  static ssize_t firmware_version_show(struct device *dev,
  				     struct device_attribute *attr, char *buf)
  {
  	struct snd_card *card = dev_to_snd_card(dev);
  	struct usb_line6_podhd *pod = card->private_data;
  
  	return sprintf(buf, "%06x
  ", pod->firmware_version);
  }
  
  static DEVICE_ATTR_RO(firmware_version);
  static DEVICE_ATTR_RO(serial_number);
  
  static struct attribute *podhd_dev_attrs[] = {
  	&dev_attr_firmware_version.attr,
  	&dev_attr_serial_number.attr,
  	NULL
  };
  
  static const struct attribute_group podhd_dev_attr_group = {
  	.name = "podhd",
  	.attrs = podhd_dev_attrs,
  };
  
  /*
   * POD X3 startup procedure.
   *
   * May be compatible with other POD HD's, since it's also similar to the
   * previous POD setup. In any case, it doesn't seem to be required for the
   * audio nor bulk interfaces to work.
   */
790869dac   Andrej Krutak   ALSA: line6: Add ...
177
178
179
  static int podhd_dev_start(struct usb_line6_podhd *pod)
  {
  	int ret;
6d2d427e3   Greg Kroah-Hartman   sound: line6: mov...
180
  	u8 init_bytes[8];
790869dac   Andrej Krutak   ALSA: line6: Add ...
181
182
  	int i;
  	struct usb_device *usbdev = pod->line6.usbdev;
6d2d427e3   Greg Kroah-Hartman   sound: line6: mov...
183
  	ret = usb_control_msg_send(usbdev, 0,
790869dac   Andrej Krutak   ALSA: line6: Add ...
184
185
  					0x67, USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
  					0x11, 0,
6d2d427e3   Greg Kroah-Hartman   sound: line6: mov...
186
187
  					NULL, 0, LINE6_TIMEOUT * HZ, GFP_KERNEL);
  	if (ret) {
790869dac   Andrej Krutak   ALSA: line6: Add ...
188
189
  		dev_err(pod->line6.ifcdev, "read request failed (error %d)
  ", ret);
e5c812e84   Greg Kroah-Hartman   ALSA: line6: use ...
190
  		goto exit;
790869dac   Andrej Krutak   ALSA: line6: Add ...
191
192
193
  	}
  
  	/* NOTE: looks like some kind of ping message */
6d2d427e3   Greg Kroah-Hartman   sound: line6: mov...
194
  	ret = usb_control_msg_recv(usbdev, 0, 0x67,
790869dac   Andrej Krutak   ALSA: line6: Add ...
195
196
  					USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
  					0x11, 0x0,
6d2d427e3   Greg Kroah-Hartman   sound: line6: mov...
197
198
  					init_bytes, 3, LINE6_TIMEOUT * HZ, GFP_KERNEL);
  	if (ret) {
790869dac   Andrej Krutak   ALSA: line6: Add ...
199
200
201
  		dev_err(pod->line6.ifcdev,
  			"receive length failed (error %d)
  ", ret);
e5c812e84   Greg Kroah-Hartman   ALSA: line6: use ...
202
  		goto exit;
790869dac   Andrej Krutak   ALSA: line6: Add ...
203
204
205
206
207
208
209
210
  	}
  
  	pod->firmware_version =
  		(init_bytes[0] << 16) | (init_bytes[1] << 8) | (init_bytes[2] << 0);
  
  	for (i = 0; i <= 16; i++) {
  		ret = line6_read_data(&pod->line6, 0xf000 + 0x08 * i, init_bytes, 8);
  		if (ret < 0)
e5c812e84   Greg Kroah-Hartman   ALSA: line6: use ...
211
  			goto exit;
790869dac   Andrej Krutak   ALSA: line6: Add ...
212
  	}
6d2d427e3   Greg Kroah-Hartman   sound: line6: mov...
213
  	ret = usb_control_msg_send(usbdev, 0,
790869dac   Andrej Krutak   ALSA: line6: Add ...
214
215
216
  					USB_REQ_SET_FEATURE,
  					USB_TYPE_STANDARD | USB_RECIP_DEVICE | USB_DIR_OUT,
  					1, 0,
6d2d427e3   Greg Kroah-Hartman   sound: line6: mov...
217
  					NULL, 0, LINE6_TIMEOUT * HZ, GFP_KERNEL);
e5c812e84   Greg Kroah-Hartman   ALSA: line6: use ...
218
  exit:
e5c812e84   Greg Kroah-Hartman   ALSA: line6: use ...
219
  	return ret;
790869dac   Andrej Krutak   ALSA: line6: Add ...
220
  }
a91c1da77   Takashi Iwai   ALSA: line6: podh...
221
  static void podhd_startup(struct usb_line6 *line6)
790869dac   Andrej Krutak   ALSA: line6: Add ...
222
  {
f23a09eea   Takashi Iwai   ALSA: line6: Use ...
223
  	struct usb_line6_podhd *pod = line6_to_podhd(line6);
790869dac   Andrej Krutak   ALSA: line6: Add ...
224
225
226
  
  	podhd_dev_start(pod);
  	line6_read_serial_number(&pod->line6, &pod->serial_number);
a91c1da77   Takashi Iwai   ALSA: line6: podh...
227
228
229
  	if (snd_card_register(line6->card))
  		dev_err(line6->ifcdev, "Failed to register POD HD card.
  ");
790869dac   Andrej Krutak   ALSA: line6: Add ...
230
231
232
233
  }
  
  static void podhd_disconnect(struct usb_line6 *line6)
  {
f23a09eea   Takashi Iwai   ALSA: line6: Use ...
234
  	struct usb_line6_podhd *pod = line6_to_podhd(line6);
790869dac   Andrej Krutak   ALSA: line6: Add ...
235

8cad7a3db   Hans P. Möller Ebner   ALSA: line6: remo...
236
  	if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO) {
fc90172ba   Andrej Krutak   ALSA: line6: Clai...
237
  		struct usb_interface *intf;
fc90172ba   Andrej Krutak   ALSA: line6: Clai...
238
239
  		intf = usb_ifnum_to_if(line6->usbdev,
  					pod->line6.properties->ctrl_if);
54a4b2b45   Takashi Iwai   ALSA: line6: Fix ...
240
241
  		if (intf)
  			usb_driver_release_interface(&podhd_driver, intf);
790869dac   Andrej Krutak   ALSA: line6: Add ...
242
243
  	}
  }
0afff876d   Vasily Khoruzhick   ALSA: line6: add ...
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
  static const unsigned int float_zero_to_one_lookup[] = {
  0x00000000, 0x3c23d70a, 0x3ca3d70a, 0x3cf5c28f, 0x3d23d70a, 0x3d4ccccd,
  0x3d75c28f, 0x3d8f5c29, 0x3da3d70a, 0x3db851ec, 0x3dcccccd, 0x3de147ae,
  0x3df5c28f, 0x3e051eb8, 0x3e0f5c29, 0x3e19999a, 0x3e23d70a, 0x3e2e147b,
  0x3e3851ec, 0x3e428f5c, 0x3e4ccccd, 0x3e570a3d, 0x3e6147ae, 0x3e6b851f,
  0x3e75c28f, 0x3e800000, 0x3e851eb8, 0x3e8a3d71, 0x3e8f5c29, 0x3e947ae1,
  0x3e99999a, 0x3e9eb852, 0x3ea3d70a, 0x3ea8f5c3, 0x3eae147b, 0x3eb33333,
  0x3eb851ec, 0x3ebd70a4, 0x3ec28f5c, 0x3ec7ae14, 0x3ecccccd, 0x3ed1eb85,
  0x3ed70a3d, 0x3edc28f6, 0x3ee147ae, 0x3ee66666, 0x3eeb851f, 0x3ef0a3d7,
  0x3ef5c28f, 0x3efae148, 0x3f000000, 0x3f028f5c, 0x3f051eb8, 0x3f07ae14,
  0x3f0a3d71, 0x3f0ccccd, 0x3f0f5c29, 0x3f11eb85, 0x3f147ae1, 0x3f170a3d,
  0x3f19999a, 0x3f1c28f6, 0x3f1eb852, 0x3f2147ae, 0x3f23d70a, 0x3f266666,
  0x3f28f5c3, 0x3f2b851f, 0x3f2e147b, 0x3f30a3d7, 0x3f333333, 0x3f35c28f,
  0x3f3851ec, 0x3f3ae148, 0x3f3d70a4, 0x3f400000, 0x3f428f5c, 0x3f451eb8,
  0x3f47ae14, 0x3f4a3d71, 0x3f4ccccd, 0x3f4f5c29, 0x3f51eb85, 0x3f547ae1,
  0x3f570a3d, 0x3f59999a, 0x3f5c28f6, 0x3f5eb852, 0x3f6147ae, 0x3f63d70a,
  0x3f666666, 0x3f68f5c3, 0x3f6b851f, 0x3f6e147b, 0x3f70a3d7, 0x3f733333,
  0x3f75c28f, 0x3f7851ec, 0x3f7ae148, 0x3f7d70a4, 0x3f800000
  };
  
  static void podhd_set_monitor_level(struct usb_line6_podhd *podhd, int value)
  {
  	unsigned int fl;
  	static const unsigned char msg[16] = {
  		/* Chunk is 0xc bytes (without first word) */
  		0x0c, 0x00,
  		/* First chunk in the message */
  		0x01, 0x00,
  		/* Message size is 2 4-byte words */
  		0x02, 0x00,
  		/* Unknown */
  		0x04, 0x41,
  		/* Unknown */
  		0x04, 0x00, 0x13, 0x00,
  		/* Volume, LE float32, 0.0 - 1.0 */
  		0x00, 0x00, 0x00, 0x00
  	};
  	unsigned char *buf;
71ea8eebd   YueHaibing   ALSA: line6: Use ...
282
  	buf = kmemdup(msg, sizeof(msg), GFP_KERNEL);
0afff876d   Vasily Khoruzhick   ALSA: line6: add ...
283
284
  	if (!buf)
  		return;
0afff876d   Vasily Khoruzhick   ALSA: line6: add ...
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
  	if (value < 0)
  		value = 0;
  
  	if (value >= ARRAY_SIZE(float_zero_to_one_lookup))
  		value = ARRAY_SIZE(float_zero_to_one_lookup) - 1;
  
  	fl = float_zero_to_one_lookup[value];
  
  	buf[12] = (fl >> 0) & 0xff;
  	buf[13] = (fl >> 8) & 0xff;
  	buf[14] = (fl >> 16) & 0xff;
  	buf[15] = (fl >> 24) & 0xff;
  
  	line6_send_raw_message(&podhd->line6, buf, sizeof(msg));
  	kfree(buf);
  
  	podhd->monitor_level = value;
  }
  
  /* control info callback */
  static int snd_podhd_control_monitor_info(struct snd_kcontrol *kcontrol,
  					struct snd_ctl_elem_info *uinfo)
  {
  	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
  	uinfo->count = 1;
  	uinfo->value.integer.min = 0;
  	uinfo->value.integer.max = 100;
  	uinfo->value.integer.step = 1;
  	return 0;
  }
  
  /* control get callback */
  static int snd_podhd_control_monitor_get(struct snd_kcontrol *kcontrol,
  				       struct snd_ctl_elem_value *ucontrol)
  {
  	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
  	struct usb_line6_podhd *podhd = line6_to_podhd(line6pcm->line6);
  
  	ucontrol->value.integer.value[0] = podhd->monitor_level;
  	return 0;
  }
  
  /* control put callback */
  static int snd_podhd_control_monitor_put(struct snd_kcontrol *kcontrol,
  				       struct snd_ctl_elem_value *ucontrol)
  {
  	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
  	struct usb_line6_podhd *podhd = line6_to_podhd(line6pcm->line6);
  
  	if (ucontrol->value.integer.value[0] == podhd->monitor_level)
  		return 0;
  
  	podhd_set_monitor_level(podhd, ucontrol->value.integer.value[0]);
  	return 1;
  }
  
  /* control definition */
  static const struct snd_kcontrol_new podhd_control_monitor = {
  	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
  	.name = "Monitor Playback Volume",
  	.index = 0,
  	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
  	.info = snd_podhd_control_monitor_info,
  	.get = snd_podhd_control_monitor_get,
  	.put = snd_podhd_control_monitor_put
  };
16dc10401   Stefan Hajnoczi   staging: line6: a...
351
  /*
16dc10401   Stefan Hajnoczi   staging: line6: a...
352
353
  	Try to init POD HD device.
  */
f66fd990c   Takashi Iwai   ALSA: line6: Drop...
354
355
  static int podhd_init(struct usb_line6 *line6,
  		      const struct usb_device_id *id)
16dc10401   Stefan Hajnoczi   staging: line6: a...
356
357
  {
  	int err;
f23a09eea   Takashi Iwai   ALSA: line6: Use ...
358
  	struct usb_line6_podhd *pod = line6_to_podhd(line6);
fc90172ba   Andrej Krutak   ALSA: line6: Clai...
359
  	struct usb_interface *intf;
790869dac   Andrej Krutak   ALSA: line6: Add ...
360
361
  
  	line6->disconnect = podhd_disconnect;
a91c1da77   Takashi Iwai   ALSA: line6: podh...
362
  	line6->startup = podhd_startup;
cb02ffc76   Takashi Iwai   ALSA: line6: Fix ...
363

790869dac   Andrej Krutak   ALSA: line6: Add ...
364
  	if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL) {
fc90172ba   Andrej Krutak   ALSA: line6: Clai...
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
  		/* claim the data interface */
  		intf = usb_ifnum_to_if(line6->usbdev,
  					pod->line6.properties->ctrl_if);
  		if (!intf) {
  			dev_err(pod->line6.ifcdev, "interface %d not found
  ",
  				pod->line6.properties->ctrl_if);
  			return -ENODEV;
  		}
  
  		err = usb_driver_claim_interface(&podhd_driver, intf, NULL);
  		if (err != 0) {
  			dev_err(pod->line6.ifcdev, "can't claim interface %d, error %d
  ",
  				pod->line6.properties->ctrl_if, err);
  			return err;
  		}
8cad7a3db   Hans P. Möller Ebner   ALSA: line6: remo...
382
  	}
fc90172ba   Andrej Krutak   ALSA: line6: Clai...
383

8cad7a3db   Hans P. Möller Ebner   ALSA: line6: remo...
384
  	if (pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO) {
790869dac   Andrej Krutak   ALSA: line6: Add ...
385
386
387
388
389
  		/* create sysfs entries: */
  		err = snd_card_add_dev_attr(line6->card, &podhd_dev_attr_group);
  		if (err < 0)
  			return err;
  	}
16dc10401   Stefan Hajnoczi   staging: line6: a...
390

cfa769695   Andrej Krutak   ALSA: line6: Clea...
391
392
393
  	if (pod->line6.properties->capabilities & LINE6_CAP_PCM) {
  		/* initialize PCM subsystem: */
  		err = line6_init_pcm(line6,
b907900ec   Andrej Krutak   ALSA: line6: Fix ...
394
395
  			(id->driver_info == LINE6_PODX3 ||
  			id->driver_info == LINE6_PODX3LIVE) ? &podx3_pcm_properties :
cfa769695   Andrej Krutak   ALSA: line6: Clea...
396
397
398
399
  			&podhd_pcm_properties);
  		if (err < 0)
  			return err;
  	}
16dc10401   Stefan Hajnoczi   staging: line6: a...
400

0afff876d   Vasily Khoruzhick   ALSA: line6: add ...
401
402
403
404
405
406
407
408
  	if (pod->line6.properties->capabilities & LINE6_CAP_HWMON_CTL) {
  		podhd_set_monitor_level(pod, 100);
  		err = snd_ctl_add(line6->card,
  				  snd_ctl_new1(&podhd_control_monitor,
  					       line6->line6pcm));
  		if (err < 0)
  			return err;
  	}
8cad7a3db   Hans P. Möller Ebner   ALSA: line6: remo...
409
  	if (!(pod->line6.properties->capabilities & LINE6_CAP_CONTROL_INFO)) {
790869dac   Andrej Krutak   ALSA: line6: Add ...
410
  		/* register USB audio system directly */
a91c1da77   Takashi Iwai   ALSA: line6: podh...
411
  		return snd_card_register(line6->card);
790869dac   Andrej Krutak   ALSA: line6: Add ...
412
413
414
  	}
  
  	/* init device and delay registering */
a91c1da77   Takashi Iwai   ALSA: line6: podh...
415
416
  	schedule_delayed_work(&line6->startup_work,
  			      msecs_to_jiffies(PODHD_STARTUP_DELAY));
790869dac   Andrej Krutak   ALSA: line6: Add ...
417
  	return 0;
16dc10401   Stefan Hajnoczi   staging: line6: a...
418
  }
ccddbe4a9   Takashi Iwai   ALSA: line6: Spli...
419
420
421
422
423
  #define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
  #define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
  
  /* table of devices that work with this driver */
  static const struct usb_device_id podhd_id_table[] = {
790869dac   Andrej Krutak   ALSA: line6: Add ...
424
  	/* TODO: no need to alloc data interfaces when only audio is used */
ccddbe4a9   Takashi Iwai   ALSA: line6: Spli...
425
426
  	{ LINE6_DEVICE(0x5057),    .driver_info = LINE6_PODHD300 },
  	{ LINE6_DEVICE(0x5058),    .driver_info = LINE6_PODHD400 },
cc18b2f4f   Vasily Khoruzhick   ALSA: line6: Fix ...
427
  	{ LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500 },
790869dac   Andrej Krutak   ALSA: line6: Add ...
428
  	{ LINE6_IF_NUM(0x414A, 0), .driver_info = LINE6_PODX3 },
c039aaa77   Andrej Krutak   ALSA: line6: Add ...
429
  	{ LINE6_IF_NUM(0x414B, 0), .driver_info = LINE6_PODX3LIVE },
c1d25075f   Hans P. Möller Ebner   ALSA: line6: add ...
430
  	{ LINE6_IF_NUM(0x4159, 0), .driver_info = LINE6_PODHD500X },
729fbfc92   Hans P. Möller Ebner   ALSA: line6: add ...
431
  	{ LINE6_IF_NUM(0x4156, 0), .driver_info = LINE6_PODHDDESKTOP },
ccddbe4a9   Takashi Iwai   ALSA: line6: Spli...
432
433
434
435
436
437
438
439
440
  	{}
  };
  
  MODULE_DEVICE_TABLE(usb, podhd_id_table);
  
  static const struct line6_properties podhd_properties_table[] = {
  	[LINE6_PODHD300] = {
  		.id = "PODHD300",
  		.name = "POD HD300",
790869dac   Andrej Krutak   ALSA: line6: Add ...
441
  		.capabilities	= LINE6_CAP_PCM
ccddbe4a9   Takashi Iwai   ALSA: line6: Spli...
442
443
444
445
446
447
448
449
450
451
  				| LINE6_CAP_HWMON,
  		.altsetting = 5,
  		.ep_ctrl_r = 0x84,
  		.ep_ctrl_w = 0x03,
  		.ep_audio_r = 0x82,
  		.ep_audio_w = 0x01,
  	},
  	[LINE6_PODHD400] = {
  		.id = "PODHD400",
  		.name = "POD HD400",
790869dac   Andrej Krutak   ALSA: line6: Add ...
452
  		.capabilities	= LINE6_CAP_PCM
ccddbe4a9   Takashi Iwai   ALSA: line6: Spli...
453
454
455
456
457
458
459
  				| LINE6_CAP_HWMON,
  		.altsetting = 5,
  		.ep_ctrl_r = 0x84,
  		.ep_ctrl_w = 0x03,
  		.ep_audio_r = 0x82,
  		.ep_audio_w = 0x01,
  	},
cc18b2f4f   Vasily Khoruzhick   ALSA: line6: Fix ...
460
  	[LINE6_PODHD500] = {
ccddbe4a9   Takashi Iwai   ALSA: line6: Spli...
461
462
  		.id = "PODHD500",
  		.name = "POD HD500",
cc18b2f4f   Vasily Khoruzhick   ALSA: line6: Fix ...
463
  		.capabilities	= LINE6_CAP_PCM | LINE6_CAP_CONTROL
0afff876d   Vasily Khoruzhick   ALSA: line6: add ...
464
  				| LINE6_CAP_HWMON | LINE6_CAP_HWMON_CTL,
ccddbe4a9   Takashi Iwai   ALSA: line6: Spli...
465
  		.altsetting = 1,
cc18b2f4f   Vasily Khoruzhick   ALSA: line6: Fix ...
466
  		.ctrl_if = 1,
ccddbe4a9   Takashi Iwai   ALSA: line6: Spli...
467
468
469
470
471
  		.ep_ctrl_r = 0x81,
  		.ep_ctrl_w = 0x01,
  		.ep_audio_r = 0x86,
  		.ep_audio_w = 0x02,
  	},
790869dac   Andrej Krutak   ALSA: line6: Add ...
472
473
474
  	[LINE6_PODX3] = {
  		.id = "PODX3",
  		.name = "POD X3",
8cad7a3db   Hans P. Möller Ebner   ALSA: line6: remo...
475
  		.capabilities	= LINE6_CAP_CONTROL | LINE6_CAP_CONTROL_INFO
790869dac   Andrej Krutak   ALSA: line6: Add ...
476
477
478
479
  				| LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT,
  		.altsetting = 1,
  		.ep_ctrl_r = 0x81,
  		.ep_ctrl_w = 0x01,
fc90172ba   Andrej Krutak   ALSA: line6: Clai...
480
  		.ctrl_if = 1,
790869dac   Andrej Krutak   ALSA: line6: Add ...
481
482
483
  		.ep_audio_r = 0x86,
  		.ep_audio_w = 0x02,
  	},
c039aaa77   Andrej Krutak   ALSA: line6: Add ...
484
485
486
  	[LINE6_PODX3LIVE] = {
  		.id = "PODX3LIVE",
  		.name = "POD X3 LIVE",
8cad7a3db   Hans P. Möller Ebner   ALSA: line6: remo...
487
  		.capabilities	= LINE6_CAP_CONTROL | LINE6_CAP_CONTROL_INFO
c039aaa77   Andrej Krutak   ALSA: line6: Add ...
488
489
490
491
  				| LINE6_CAP_PCM | LINE6_CAP_HWMON | LINE6_CAP_IN_NEEDS_OUT,
  		.altsetting = 1,
  		.ep_ctrl_r = 0x81,
  		.ep_ctrl_w = 0x01,
fc90172ba   Andrej Krutak   ALSA: line6: Clai...
492
  		.ctrl_if = 1,
c039aaa77   Andrej Krutak   ALSA: line6: Add ...
493
494
495
  		.ep_audio_r = 0x86,
  		.ep_audio_w = 0x02,
  	},
c1d25075f   Hans P. Möller Ebner   ALSA: line6: add ...
496
497
498
499
500
501
502
503
504
505
506
507
  	[LINE6_PODHD500X] = {
  		.id = "PODHD500X",
  		.name = "POD HD500X",
  		.capabilities	= LINE6_CAP_CONTROL
  				| LINE6_CAP_PCM | LINE6_CAP_HWMON,
  		.altsetting = 1,
  		.ep_ctrl_r = 0x81,
  		.ep_ctrl_w = 0x01,
  		.ctrl_if = 1,
  		.ep_audio_r = 0x86,
  		.ep_audio_w = 0x02,
  	},
729fbfc92   Hans P. Möller Ebner   ALSA: line6: add ...
508
509
510
511
512
513
514
515
516
517
518
519
  	[LINE6_PODHDDESKTOP] = {
  		.id = "PODHDDESKTOP",
  		.name = "POD HDDESKTOP",
  		.capabilities    = LINE6_CAP_CONTROL
  			| LINE6_CAP_PCM | LINE6_CAP_HWMON,
  		.altsetting = 1,
  		.ep_ctrl_r = 0x81,
  		.ep_ctrl_w = 0x01,
  		.ctrl_if = 1,
  		.ep_audio_r = 0x86,
  		.ep_audio_w = 0x02,
  	},
ccddbe4a9   Takashi Iwai   ALSA: line6: Spli...
520
  };
16dc10401   Stefan Hajnoczi   staging: line6: a...
521
  /*
ccddbe4a9   Takashi Iwai   ALSA: line6: Spli...
522
523
524
525
526
  	Probe USB device.
  */
  static int podhd_probe(struct usb_interface *interface,
  		       const struct usb_device_id *id)
  {
12865cac3   Chris Rorvick   ALSA: line6: Pass...
527
  	return line6_probe(interface, id, "Line6-PODHD",
85a9339be   Takashi Iwai   ALSA: line6: Reor...
528
  			   &podhd_properties_table[id->driver_info],
790869dac   Andrej Krutak   ALSA: line6: Add ...
529
  			   podhd_init, sizeof(struct usb_line6_podhd));
ccddbe4a9   Takashi Iwai   ALSA: line6: Spli...
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
  }
  
  static struct usb_driver podhd_driver = {
  	.name = KBUILD_MODNAME,
  	.probe = podhd_probe,
  	.disconnect = line6_disconnect,
  #ifdef CONFIG_PM
  	.suspend = line6_suspend,
  	.resume = line6_resume,
  	.reset_resume = line6_resume,
  #endif
  	.id_table = podhd_id_table,
  };
  
  module_usb_driver(podhd_driver);
c6fffce92   Chris Rorvick   ALSA: line6: Refe...
545
  MODULE_DESCRIPTION("Line 6 PODHD USB driver");
ccddbe4a9   Takashi Iwai   ALSA: line6: Spli...
546
  MODULE_LICENSE("GPL");