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