Merge branch 'topic/line6' into for-next
diff --git a/sound/usb/Makefile b/sound/usb/Makefile
index 54045b7..2d2d122 100644
--- a/sound/usb/Makefile
+++ b/sound/usb/Makefile
@@ -25,4 +25,4 @@
 obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o
 
 obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/
-obj-$(CONFIG_LINE6_USB)		+= line6/
+obj-$(CONFIG_SND_USB_LINE6)	+= line6/
diff --git a/sound/usb/line6/Kconfig b/sound/usb/line6/Kconfig
index 4f1219b..af20947 100644
--- a/sound/usb/line6/Kconfig
+++ b/sound/usb/line6/Kconfig
@@ -1,12 +1,14 @@
-menuconfig LINE6_USB
-	tristate "Line6 USB support"
-	depends on USB && SND
+config SND_USB_LINE6
+	tristate
 	select SND_RAWMIDI
 	select SND_PCM
+
+config SND_USB_POD
+	tristate "Line 6 POD USB support"
+	select SND_USB_LINE6
 	help
-	  This is a driver for the guitar amp, cab, and effects modeller
-	  PODxt Pro by Line6 (and similar devices), supporting the
-	  following features:
+	  This is a driver for PODxt and other similar devices,
+	  supporting the following features:
 	    * Reading/writing individual parameters
 	    * Reading/writing complete channel, effects setup, and amp
 	      setup data
@@ -18,21 +20,21 @@
 	    * Signal routing (record clean/processed guitar signal,
 	      re-amping)
 
-	  Preliminary support for the Variax Workbench and TonePort
-	  devices is included.
-
-if LINE6_USB
-
-config LINE6_USB_IMPULSE_RESPONSE
-	bool "measure impulse response"
-	default n
+config SND_USB_PODHD
+	tristate "Line 6 POD HD300/400/500 USB support"
+	select SND_USB_LINE6
 	help
-	  Say Y here to add code to measure the impulse response of a Line6
-	  device. This is more accurate than user-space methods since it
-	  bypasses any PCM data buffering (e.g., by ALSA or jack). This is
-	  useful for assessing the performance of new devices, but is not
-	  required for normal operation.
+	  This is a driver for POD HD300, 400 and 500 devices.
 
-	  If unsure, say N.
+config SND_USB_TONEPORT
+	tristate "TonePort GX, UX1 and UX2 USB support"
+	select SND_USB_LINE6
+	help
+	  This is a driver for TonePort GX, UX1 and UX2 devices.
 
-endif # LINE6_USB
+config SND_USB_VARIAX
+	tristate "Variax Workbench USB support"
+	select SND_USB_LINE6
+	help
+	  This is a driver for Variax Workbench device.
+
diff --git a/sound/usb/line6/Makefile b/sound/usb/line6/Makefile
index ae5c374..b8b3b2a 100644
--- a/sound/usb/line6/Makefile
+++ b/sound/usb/line6/Makefile
@@ -1,14 +1,18 @@
-obj-$(CONFIG_LINE6_USB)		+= line6usb.o
-
-line6usb-y := 		\
-		audio.o		\
+snd-usb-line6-y := 		\
 		capture.o	\
 		driver.o	\
 		midi.o		\
 		midibuf.o	\
 		pcm.o		\
-		playback.o	\
-		pod.o		\
-		toneport.o	\
-		variax.o	\
-		podhd.o
+		playback.o
+
+snd-usb-pod-y := pod.o
+snd-usb-podhd-y := podhd.o
+snd-usb-toneport-y := toneport.o
+snd-usb-variax-y := variax.o
+
+obj-$(CONFIG_SND_USB_LINE6)	+= snd-usb-line6.o
+obj-$(CONFIG_SND_USB_POD)	+= snd-usb-pod.o
+obj-$(CONFIG_SND_USB_PODHD)	+= snd-usb-podhd.o
+obj-$(CONFIG_SND_USB_TONEPORT)	+= snd-usb-toneport.o
+obj-$(CONFIG_SND_USB_VARIAX)	+= snd-usb-variax.o
diff --git a/sound/usb/line6/audio.c b/sound/usb/line6/audio.c
deleted file mode 100644
index 171d80c..0000000
--- a/sound/usb/line6/audio.c
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License as
- *	published by the Free Software Foundation, version 2.
- *
- */
-
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <linux/export.h>
-
-#include "driver.h"
-#include "audio.h"
-
-/*
-	Initialize the Line6 USB audio system.
-*/
-int line6_init_audio(struct usb_line6 *line6)
-{
-	struct snd_card *card;
-	int err;
-
-	err = snd_card_new(line6->ifcdev,
-			   SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
-			   THIS_MODULE, 0, &card);
-	if (err < 0)
-		return err;
-
-	line6->card = card;
-
-	strcpy(card->id, line6->properties->id);
-	strcpy(card->driver, DRIVER_NAME);
-	strcpy(card->shortname, line6->properties->name);
-	/* longname is 80 chars - see asound.h */
-	sprintf(card->longname, "Line6 %s at USB %s", line6->properties->name,
-		dev_name(line6->ifcdev));
-	return 0;
-}
-
-/*
-	Register the Line6 USB audio system.
-*/
-int line6_register_audio(struct usb_line6 *line6)
-{
-	int err;
-
-	err = snd_card_register(line6->card);
-	if (err < 0)
-		return err;
-
-	return 0;
-}
-
-/*
-	Cleanup the Line6 USB audio system.
-*/
-void line6_cleanup_audio(struct usb_line6 *line6)
-{
-	struct snd_card *card = line6->card;
-
-	if (card == NULL)
-		return;
-
-	snd_card_disconnect(card);
-	snd_card_free(card);
-	line6->card = NULL;
-}
diff --git a/sound/usb/line6/audio.h b/sound/usb/line6/audio.h
deleted file mode 100644
index 5f8a09a..0000000
--- a/sound/usb/line6/audio.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License as
- *	published by the Free Software Foundation, version 2.
- *
- */
-
-#ifndef AUDIO_H
-#define AUDIO_H
-
-#include "driver.h"
-
-extern void line6_cleanup_audio(struct usb_line6 *);
-extern int line6_init_audio(struct usb_line6 *);
-extern int line6_register_audio(struct usb_line6 *);
-
-#endif
diff --git a/sound/usb/line6/capture.c b/sound/usb/line6/capture.c
index f24c7c5..5a010ba 100644
--- a/sound/usb/line6/capture.c
+++ b/sound/usb/line6/capture.c
@@ -1,5 +1,5 @@
 /*
- * Line6 Linux USB driver - 0.9.1beta
+ * Line 6 Linux USB driver
  *
  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
  *
@@ -14,11 +14,9 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 
-#include "audio.h"
 #include "capture.h"
 #include "driver.h"
 #include "pcm.h"
-#include "pod.h"
 
 /*
 	Find a free URB and submit it.
@@ -245,9 +243,7 @@
 		line6pcm->prev_fbuf = fbuf;
 		line6pcm->prev_fsize = fsize;
 
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
 		if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
-#endif
 			if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
 				     &line6pcm->flags) && (fsize > 0))
 				line6_capture_copy(line6pcm, fbuf, fsize);
@@ -263,9 +259,7 @@
 	if (!shutdown) {
 		submit_audio_in_urb(line6pcm);
 
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
 		if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
-#endif
 			if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
 				     &line6pcm->flags))
 				line6_capture_check_period(line6pcm, length);
@@ -347,9 +341,7 @@
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
-#ifdef CONFIG_PM
 	case SNDRV_PCM_TRIGGER_RESUME:
-#endif
 		err = line6_pcm_acquire(line6pcm,
 					LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
 
@@ -359,9 +351,7 @@
 		break;
 
 	case SNDRV_PCM_TRIGGER_STOP:
-#ifdef CONFIG_PM
 	case SNDRV_PCM_TRIGGER_SUSPEND:
-#endif
 		err = line6_pcm_release(line6pcm,
 					LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
 
@@ -411,10 +401,8 @@
 		urb = line6pcm->urb_audio_in[i] =
 		    usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
 
-		if (urb == NULL) {
-			dev_err(line6->ifcdev, "Out of memory\n");
+		if (urb == NULL)
 			return -ENOMEM;
-		}
 
 		urb->dev = line6->usbdev;
 		urb->pipe =
diff --git a/sound/usb/line6/capture.h b/sound/usb/line6/capture.h
index 4157bcb..0939f40 100644
--- a/sound/usb/line6/capture.h
+++ b/sound/usb/line6/capture.h
@@ -1,5 +1,5 @@
 /*
- * Line6 Linux USB driver - 0.9.1beta
+ * Line 6 Linux USB driver
  *
  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
  *
diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c
index fc852f6..93cd4da 100644
--- a/sound/usb/line6/driver.c
+++ b/sound/usb/line6/driver.c
@@ -1,5 +1,5 @@
 /*
- * Line6 Linux USB driver - 0.9.1beta
+ * Line 6 Linux USB driver
  *
  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
  *
@@ -11,277 +11,30 @@
 
 #include <linux/kernel.h>
 #include <linux/module.h>
+#include <linux/export.h>
 #include <linux/slab.h>
 #include <linux/usb.h>
 
-#include "audio.h"
+#include <sound/core.h>
+#include <sound/initval.h>
+
 #include "capture.h"
 #include "driver.h"
 #include "midi.h"
 #include "playback.h"
-#include "pod.h"
-#include "podhd.h"
 #include "revision.h"
-#include "toneport.h"
 #include "usbdefs.h"
-#include "variax.h"
 
 #define DRIVER_AUTHOR  "Markus Grabner <grabner@icg.tugraz.at>"
-#define DRIVER_DESC    "Line6 USB Driver"
-#define DRIVER_VERSION "0.9.1beta" DRIVER_REVISION
-
-#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 line6_id_table[] = {
-	{ LINE6_DEVICE(0x4250),    .driver_info = LINE6_BASSPODXT },
-	{ LINE6_DEVICE(0x4642),    .driver_info = LINE6_BASSPODXTLIVE },
-	{ LINE6_DEVICE(0x4252),    .driver_info = LINE6_BASSPODXTPRO },
-	{ LINE6_DEVICE(0x4750),    .driver_info = LINE6_GUITARPORT },
-	{ LINE6_IF_NUM(0x5051, 1), .driver_info = LINE6_POCKETPOD },
-	{ LINE6_DEVICE(0x5057),    .driver_info = LINE6_PODHD300 },
-	{ LINE6_DEVICE(0x5058),    .driver_info = LINE6_PODHD400 },
-	{ LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500_0 },
-	{ LINE6_IF_NUM(0x414D, 1), .driver_info = LINE6_PODHD500_1 },
-	{ LINE6_DEVICE(0x4153),    .driver_info = LINE6_PODSTUDIO_GX },
-	{ LINE6_DEVICE(0x4150),    .driver_info = LINE6_PODSTUDIO_UX1 },
-	{ LINE6_IF_NUM(0x4151, 0), .driver_info = LINE6_PODSTUDIO_UX2 },
-	{ LINE6_DEVICE(0x5044),    .driver_info = LINE6_PODXT },
-	{ LINE6_IF_NUM(0x4650, 0), .driver_info = LINE6_PODXTLIVE_POD },
-	{ LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX },
-	{ LINE6_DEVICE(0x5050),    .driver_info = LINE6_PODXTPRO },
-	{ LINE6_DEVICE(0x4147),    .driver_info = LINE6_TONEPORT_GX },
-	{ LINE6_DEVICE(0x4141),    .driver_info = LINE6_TONEPORT_UX1 },
-	{ LINE6_IF_NUM(0x4142, 0), .driver_info = LINE6_TONEPORT_UX2 },
-	{ LINE6_DEVICE(0x534d),    .driver_info = LINE6_VARIAX },
-	{}
-};
-
-MODULE_DEVICE_TABLE(usb, line6_id_table);
-
-static const struct line6_properties line6_properties_table[] = {
-	[LINE6_BASSPODXT] = {
-		.id = "BassPODxt",
-		.name = "BassPODxt",
-		.capabilities	= LINE6_CAP_CONTROL
-				| LINE6_CAP_PCM
-				| LINE6_CAP_HWMON,
-		.altsetting = 5,
-		.ep_ctrl_r = 0x84,
-		.ep_ctrl_w = 0x03,
-		.ep_audio_r = 0x82,
-		.ep_audio_w = 0x01,
-	},
-	[LINE6_BASSPODXTLIVE] = {
-		.id = "BassPODxtLive",
-		.name = "BassPODxt Live",
-		.capabilities	= LINE6_CAP_CONTROL
-				| LINE6_CAP_PCM
-				| LINE6_CAP_HWMON,
-		.altsetting = 1,
-		.ep_ctrl_r = 0x84,
-		.ep_ctrl_w = 0x03,
-		.ep_audio_r = 0x82,
-		.ep_audio_w = 0x01,
-	},
-	[LINE6_BASSPODXTPRO] = {
-		.id = "BassPODxtPro",
-		.name = "BassPODxt Pro",
-		.capabilities	= LINE6_CAP_CONTROL
-				| LINE6_CAP_PCM
-				| LINE6_CAP_HWMON,
-		.altsetting = 5,
-		.ep_ctrl_r = 0x84,
-		.ep_ctrl_w = 0x03,
-		.ep_audio_r = 0x82,
-		.ep_audio_w = 0x01,
-	},
-	[LINE6_GUITARPORT] = {
-		.id = "GuitarPort",
-		.name = "GuitarPort",
-		.capabilities	= LINE6_CAP_PCM,
-		.altsetting = 2,  /* 1..4 seem to be ok */
-		/* no control channel */
-		.ep_audio_r = 0x82,
-		.ep_audio_w = 0x01,
-	},
-	[LINE6_POCKETPOD] = {
-		.id = "PocketPOD",
-		.name = "Pocket POD",
-		.capabilities	= LINE6_CAP_CONTROL,
-		.altsetting = 0,
-		.ep_ctrl_r = 0x82,
-		.ep_ctrl_w = 0x02,
-		/* no audio channel */
-	},
-	[LINE6_PODHD300] = {
-		.id = "PODHD300",
-		.name = "POD HD300",
-		.capabilities	= LINE6_CAP_CONTROL
-				| LINE6_CAP_PCM
-				| 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",
-		.capabilities	= LINE6_CAP_CONTROL
-				| LINE6_CAP_PCM
-				| LINE6_CAP_HWMON,
-		.altsetting = 5,
-		.ep_ctrl_r = 0x84,
-		.ep_ctrl_w = 0x03,
-		.ep_audio_r = 0x82,
-		.ep_audio_w = 0x01,
-	},
-	[LINE6_PODHD500_0] = {
-		.id = "PODHD500",
-		.name = "POD HD500",
-		.capabilities	= LINE6_CAP_CONTROL
-				| LINE6_CAP_PCM
-				| LINE6_CAP_HWMON,
-		.altsetting = 1,
-		.ep_ctrl_r = 0x81,
-		.ep_ctrl_w = 0x01,
-		.ep_audio_r = 0x86,
-		.ep_audio_w = 0x02,
-	},
-	[LINE6_PODHD500_1] = {
-		.id = "PODHD500",
-		.name = "POD HD500",
-		.capabilities	= LINE6_CAP_CONTROL
-				| LINE6_CAP_PCM
-				| LINE6_CAP_HWMON,
-		.altsetting = 1,
-		.ep_ctrl_r = 0x81,
-		.ep_ctrl_w = 0x01,
-		.ep_audio_r = 0x86,
-		.ep_audio_w = 0x02,
-	},
-	[LINE6_PODSTUDIO_GX] = {
-		.id = "PODStudioGX",
-		.name = "POD Studio GX",
-		.capabilities	= LINE6_CAP_PCM,
-		.altsetting = 2,  /* 1..4 seem to be ok */
-		/* no control channel */
-		.ep_audio_r = 0x82,
-		.ep_audio_w = 0x01,
-	},
-	[LINE6_PODSTUDIO_UX1] = {
-		.id = "PODStudioUX1",
-		.name = "POD Studio UX1",
-		.capabilities	= LINE6_CAP_PCM,
-		.altsetting = 2,  /* 1..4 seem to be ok */
-		/* no control channel */
-		.ep_audio_r = 0x82,
-		.ep_audio_w = 0x01,
-	},
-	[LINE6_PODSTUDIO_UX2] = {
-		.id = "PODStudioUX2",
-		.name = "POD Studio UX2",
-		.capabilities	= LINE6_CAP_PCM,
-		.altsetting = 2,  /* defaults to 44.1kHz, 16-bit */
-		/* no control channel */
-		.ep_audio_r = 0x82,
-		.ep_audio_w = 0x01,
-	},
-	[LINE6_PODXT] = {
-		.id = "PODxt",
-		.name = "PODxt",
-		.capabilities	= LINE6_CAP_CONTROL
-				| LINE6_CAP_PCM
-				| LINE6_CAP_HWMON,
-		.altsetting = 5,
-		.ep_ctrl_r = 0x84,
-		.ep_ctrl_w = 0x03,
-		.ep_audio_r = 0x82,
-		.ep_audio_w = 0x01,
-	},
-	[LINE6_PODXTLIVE_POD] = {
-		.id = "PODxtLive",
-		.name = "PODxt Live",
-		.capabilities	= LINE6_CAP_CONTROL
-				| LINE6_CAP_PCM
-				| LINE6_CAP_HWMON,
-		.altsetting = 1,
-		.ep_ctrl_r = 0x84,
-		.ep_ctrl_w = 0x03,
-		.ep_audio_r = 0x82,
-		.ep_audio_w = 0x01,
-	},
-	[LINE6_PODXTLIVE_VARIAX] = {
-		.id = "PODxtLive",
-		.name = "PODxt Live",
-		.capabilities	= LINE6_CAP_CONTROL
-				| LINE6_CAP_PCM
-				| LINE6_CAP_HWMON,
-		.altsetting = 1,
-		.ep_ctrl_r = 0x86,
-		.ep_ctrl_w = 0x05,
-		.ep_audio_r = 0x82,
-		.ep_audio_w = 0x01,
-	},
-	[LINE6_PODXTPRO] = {
-		.id = "PODxtPro",
-		.name = "PODxt Pro",
-		.capabilities	= LINE6_CAP_CONTROL
-				| LINE6_CAP_PCM
-				| LINE6_CAP_HWMON,
-		.altsetting = 5,
-		.ep_ctrl_r = 0x84,
-		.ep_ctrl_w = 0x03,
-		.ep_audio_r = 0x82,
-		.ep_audio_w = 0x01,
-	},
-	[LINE6_TONEPORT_GX] = {
-		.id = "TonePortGX",
-		.name = "TonePort GX",
-		.capabilities	= LINE6_CAP_PCM,
-		.altsetting = 2,  /* 1..4 seem to be ok */
-		/* no control channel */
-		.ep_audio_r = 0x82,
-		.ep_audio_w = 0x01,
-	},
-	[LINE6_TONEPORT_UX1] = {
-		.id = "TonePortUX1",
-		.name = "TonePort UX1",
-		.capabilities	= LINE6_CAP_PCM,
-		.altsetting = 2,  /* 1..4 seem to be ok */
-		/* no control channel */
-		.ep_audio_r = 0x82,
-		.ep_audio_w = 0x01,
-	},
-	[LINE6_TONEPORT_UX2] = {
-		.id = "TonePortUX2",
-		.name = "TonePort UX2",
-		.capabilities	= LINE6_CAP_PCM,
-		.altsetting = 2,  /* defaults to 44.1kHz, 16-bit */
-		/* no control channel */
-		.ep_audio_r = 0x82,
-		.ep_audio_w = 0x01,
-	},
-	[LINE6_VARIAX] = {
-		.id = "Variax",
-		.name = "Variax Workbench",
-		.capabilities	= LINE6_CAP_CONTROL,
-		.altsetting = 1,
-		.ep_ctrl_r = 0x82,
-		.ep_ctrl_w = 0x01,
-		/* no audio channel */
-	}
-};
+#define DRIVER_DESC    "Line 6 USB Driver"
 
 /*
-	This is Line6's MIDI manufacturer ID.
+	This is Line 6's MIDI manufacturer ID.
 */
 const unsigned char line6_midi_id[] = {
 	0x00, 0x01, 0x0c
 };
+EXPORT_SYMBOL_GPL(line6_midi_id);
 
 /*
 	Code to request version of POD, Variax interface
@@ -335,8 +88,8 @@
 /*
 	Send raw message in pieces of wMaxPacketSize bytes.
 */
-int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
-			   int size)
+static int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
+				  int size)
 {
 	int i, done = 0;
 
@@ -415,9 +168,9 @@
 		       void (*function)(unsigned long), unsigned long data)
 {
 	setup_timer(timer, function, data);
-	timer->expires = jiffies + msecs * HZ / 1000;
-	add_timer(timer);
+	mod_timer(timer, jiffies + msecs * HZ / 1000);
 }
+EXPORT_SYMBOL_GPL(line6_start_timer);
 
 /*
 	Asynchronously send raw message.
@@ -438,7 +191,6 @@
 
 	if (urb == NULL) {
 		kfree(msg);
-		dev_err(line6->ifcdev, "Out of memory\n");
 		return -ENOMEM;
 	}
 
@@ -451,6 +203,7 @@
 	/* start sending: */
 	return line6_send_raw_message_async_part(msg, urb);
 }
+EXPORT_SYMBOL_GPL(line6_send_raw_message_async);
 
 /*
 	Send asynchronous device version request.
@@ -462,16 +215,15 @@
 
 	buffer = kmemdup(line6_request_version,
 			sizeof(line6_request_version), GFP_ATOMIC);
-	if (buffer == NULL) {
-		dev_err(line6->ifcdev, "Out of memory");
+	if (buffer == NULL)
 		return -ENOMEM;
-	}
 
 	retval = line6_send_raw_message_async(line6, buffer,
 					      sizeof(line6_request_version));
 	kfree(buffer);
 	return retval;
 }
+EXPORT_SYMBOL_GPL(line6_version_request_async);
 
 /*
 	Send sysex message in pieces of wMaxPacketSize bytes.
@@ -483,6 +235,7 @@
 				      size + SYSEX_EXTRA_SIZE) -
 	    SYSEX_EXTRA_SIZE;
 }
+EXPORT_SYMBOL_GPL(line6_send_sysex_message);
 
 /*
 	Allocate buffer for sysex message and prepare header.
@@ -504,9 +257,10 @@
 	buffer[sizeof(line6_midi_id) + 3 + size] = LINE6_SYSEX_END;
 	return buffer;
 }
+EXPORT_SYMBOL_GPL(line6_alloc_sysex_buffer);
 
 /*
-	Notification of data received from the Line6 device.
+	Notification of data received from the Line 6 device.
 */
 static void line6_data_received(struct urb *urb)
 {
@@ -545,65 +299,6 @@
 }
 
 /*
-	Send channel number (i.e., switch to a different sound).
-*/
-int line6_send_program(struct usb_line6 *line6, u8 value)
-{
-	int retval;
-	unsigned char *buffer;
-	int partial;
-
-	buffer = kmalloc(2, GFP_KERNEL);
-	if (!buffer)
-		return -ENOMEM;
-
-	buffer[0] = LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST;
-	buffer[1] = value;
-
-	retval = usb_interrupt_msg(line6->usbdev,
-				   usb_sndintpipe(line6->usbdev,
-						  line6->properties->ep_ctrl_w),
-				   buffer, 2, &partial, LINE6_TIMEOUT * HZ);
-
-	if (retval)
-		dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n",
-			retval);
-
-	kfree(buffer);
-	return retval;
-}
-
-/*
-	Transmit Line6 control parameter.
-*/
-int line6_transmit_parameter(struct usb_line6 *line6, int param, u8 value)
-{
-	int retval;
-	unsigned char *buffer;
-	int partial;
-
-	buffer = kmalloc(3, GFP_KERNEL);
-	if (!buffer)
-		return -ENOMEM;
-
-	buffer[0] = LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST;
-	buffer[1] = param;
-	buffer[2] = value;
-
-	retval = usb_interrupt_msg(line6->usbdev,
-				   usb_sndintpipe(line6->usbdev,
-						  line6->properties->ep_ctrl_w),
-				   buffer, 3, &partial, LINE6_TIMEOUT * HZ);
-
-	if (retval)
-		dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n",
-			retval);
-
-	kfree(buffer);
-	return retval;
-}
-
-/*
 	Read data from device.
 */
 int line6_read_data(struct usb_line6 *line6, int address, void *data,
@@ -659,6 +354,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(line6_read_data);
 
 /*
 	Write data to device.
@@ -703,9 +399,10 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(line6_write_data);
 
 /*
-	Read Line6 device serial number.
+	Read Line 6 device serial number.
 	(POD, TonePort, GuitarPort)
 */
 int line6_read_serial_number(struct usb_line6 *line6, int *serial_number)
@@ -713,6 +410,7 @@
 	return line6_read_data(line6, 0x80d0, serial_number,
 			       sizeof(*serial_number));
 }
+EXPORT_SYMBOL_GPL(line6_read_serial_number);
 
 /*
 	No operation (i.e., unsupported).
@@ -722,19 +420,19 @@
 {
 	return 0;
 }
+EXPORT_SYMBOL_GPL(line6_nop_read);
 
 /*
-	Generic destructor.
+	Card destructor.
 */
-static void line6_destruct(struct usb_interface *interface)
+static void line6_destruct(struct snd_card *card)
 {
-	struct usb_line6 *line6;
+	struct usb_line6 *line6 = card->private_data;
+	struct usb_device *usbdev;
 
-	if (interface == NULL)
+	if (!line6)
 		return;
-	line6 = usb_get_intfdata(interface);
-	if (line6 == NULL)
-		return;
+	usbdev = line6->usbdev;
 
 	/* free buffer memory first: */
 	kfree(line6->buffer_message);
@@ -743,44 +441,34 @@
 	/* then free URBs: */
 	usb_free_urb(line6->urb_listen);
 
-	/* make sure the device isn't destructed twice: */
-	usb_set_intfdata(interface, NULL);
-
 	/* free interface data: */
 	kfree(line6);
+
+	/* decrement reference counters: */
+	usb_put_dev(usbdev);
 }
 
 /*
 	Probe USB device.
 */
-static int line6_probe(struct usb_interface *interface,
-		       const struct usb_device_id *id)
+int line6_probe(struct usb_interface *interface,
+		struct usb_line6 *line6,
+		const struct line6_properties *properties,
+		int (*private_init)(struct usb_interface *, struct usb_line6 *))
 {
-	enum line6_device_type devtype;
-	struct usb_device *usbdev;
-	struct usb_line6 *line6;
-	const struct line6_properties *properties;
+	struct usb_device *usbdev = interface_to_usbdev(interface);
+	struct snd_card *card;
 	int interface_number;
-	int size = 0;
 	int ret;
 
-	if (interface == NULL)
-		return -ENODEV;
-	usbdev = interface_to_usbdev(interface);
-	if (usbdev == NULL)
-		return -ENODEV;
-
 	/* we don't handle multiple configurations */
 	if (usbdev->descriptor.bNumConfigurations != 1) {
 		ret = -ENODEV;
 		goto err_put;
 	}
 
-	devtype = id->driver_info;
-
 	/* initialize device info: */
-	properties = &line6_properties_table[devtype];
-	dev_info(&interface->dev, "Line6 %s found\n", properties->name);
+	dev_info(&interface->dev, "Line 6 %s found\n", properties->name);
 
 	/* query interface number */
 	interface_number = interface->cur_altsetting->desc.bInterfaceNumber;
@@ -792,76 +480,10 @@
 		goto err_put;
 	}
 
-	/* initialize device data based on device: */
-	switch (devtype) {
-	case LINE6_BASSPODXT:
-	case LINE6_BASSPODXTLIVE:
-	case LINE6_BASSPODXTPRO:
-	case LINE6_PODXT:
-	case LINE6_PODXTPRO:
-		size = sizeof(struct usb_line6_pod);
-		break;
-
-	case LINE6_PODHD300:
-	case LINE6_PODHD400:
-		size = sizeof(struct usb_line6_podhd);
-		break;
-
-	case LINE6_PODHD500_0:
-	case LINE6_PODHD500_1:
-		size = sizeof(struct usb_line6_podhd);
-		break;
-
-	case LINE6_POCKETPOD:
-		size = sizeof(struct usb_line6_pod);
-		break;
-
-	case LINE6_PODSTUDIO_GX:
-	case LINE6_PODSTUDIO_UX1:
-	case LINE6_PODSTUDIO_UX2:
-	case LINE6_TONEPORT_GX:
-	case LINE6_TONEPORT_UX1:
-	case LINE6_TONEPORT_UX2:
-	case LINE6_GUITARPORT:
-		size = sizeof(struct usb_line6_toneport);
-		break;
-
-	case LINE6_PODXTLIVE_POD:
-		size = sizeof(struct usb_line6_pod);
-		break;
-
-	case LINE6_PODXTLIVE_VARIAX:
-		size = sizeof(struct usb_line6_variax);
-		break;
-
-	case LINE6_VARIAX:
-		size = sizeof(struct usb_line6_variax);
-		break;
-
-	default:
-		MISSING_CASE;
-		ret = -ENODEV;
-		goto err_put;
-	}
-
-	if (size == 0) {
-		dev_err(&interface->dev,
-			"driver bug: interface data size not set\n");
-		ret = -ENODEV;
-		goto err_put;
-	}
-
-	line6 = kzalloc(size, GFP_KERNEL);
-	if (line6 == NULL) {
-		ret = -ENODEV;
-		goto err_put;
-	}
-
 	/* store basic data: */
 	line6->properties = properties;
 	line6->usbdev = usbdev;
 	line6->ifcdev = &interface->dev;
-	line6->type = devtype;
 
 	/* get data from endpoint descriptor (see usb_maxpacket): */
 	{
@@ -882,8 +504,26 @@
 		}
 	}
 
+	ret = snd_card_new(line6->ifcdev,
+			   SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
+			   THIS_MODULE, 0, &card);
+	if (ret < 0)
+		goto err_put;
+
+	line6->card = card;
+	strcpy(card->id, line6->properties->id);
+	strcpy(card->driver, DRIVER_NAME);
+	strcpy(card->shortname, line6->properties->name);
+	sprintf(card->longname, "Line 6 %s at USB %s", line6->properties->name,
+		dev_name(line6->ifcdev));
+	card->private_data = line6;
+	card->private_free = line6_destruct;
+
 	usb_set_intfdata(interface, line6);
 
+	/* increment reference counters: */
+	usb_get_dev(usbdev);
+
 	if (properties->capabilities & LINE6_CAP_CONTROL) {
 		/* initialize USB buffers: */
 		line6->buffer_listen =
@@ -903,8 +543,6 @@
 		line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL);
 
 		if (line6->urb_listen == NULL) {
-			dev_err(&interface->dev, "Out of memory\n");
-			line6_destruct(interface);
 			ret = -ENOMEM;
 			goto err_destruct;
 		}
@@ -918,79 +556,28 @@
 	}
 
 	/* initialize device data based on device: */
-	switch (devtype) {
-	case LINE6_BASSPODXT:
-	case LINE6_BASSPODXTLIVE:
-	case LINE6_BASSPODXTPRO:
-	case LINE6_POCKETPOD:
-	case LINE6_PODXT:
-	case LINE6_PODXTPRO:
-		ret = line6_pod_init(interface, line6);
-		break;
-
-	case LINE6_PODHD300:
-	case LINE6_PODHD400:
-	case LINE6_PODHD500_0:
-	case LINE6_PODHD500_1:
-		ret = line6_podhd_init(interface, line6);
-		break;
-
-	case LINE6_PODXTLIVE_POD:
-		ret = line6_pod_init(interface, line6);
-		break;
-
-	case LINE6_PODXTLIVE_VARIAX:
-		ret = line6_variax_init(interface, line6);
-		break;
-
-	case LINE6_VARIAX:
-		ret = line6_variax_init(interface, line6);
-		break;
-
-	case LINE6_PODSTUDIO_GX:
-	case LINE6_PODSTUDIO_UX1:
-	case LINE6_PODSTUDIO_UX2:
-	case LINE6_TONEPORT_GX:
-	case LINE6_TONEPORT_UX1:
-	case LINE6_TONEPORT_UX2:
-	case LINE6_GUITARPORT:
-		ret = line6_toneport_init(interface, line6);
-		break;
-
-	default:
-		MISSING_CASE;
-		ret = -ENODEV;
-	}
-
-	if (ret < 0)
-		goto err_destruct;
-
-	ret = sysfs_create_link(&interface->dev.kobj, &usbdev->dev.kobj,
-				"usb_device");
+	ret = private_init(interface, line6);
 	if (ret < 0)
 		goto err_destruct;
 
 	/* creation of additional special files should go here */
 
-	dev_info(&interface->dev, "Line6 %s now attached\n",
+	dev_info(&interface->dev, "Line 6 %s now attached\n",
 		 line6->properties->name);
 
-	/* increment reference counters: */
-	usb_get_intf(interface);
-	usb_get_dev(usbdev);
-
 	return 0;
 
-err_destruct:
-	line6_destruct(interface);
-err_put:
+ err_destruct:
+	snd_card_free(card);
+ err_put:
 	return ret;
 }
+EXPORT_SYMBOL_GPL(line6_probe);
 
 /*
-	Line6 device disconnected.
+	Line 6 device disconnected.
 */
-static void line6_disconnect(struct usb_interface *interface)
+void line6_disconnect(struct usb_interface *interface)
 {
 	struct usb_line6 *line6;
 	struct usb_device *usbdev;
@@ -1002,40 +589,39 @@
 	if (usbdev == NULL)
 		return;
 
-	/* removal of additional special files should go here */
-
-	sysfs_remove_link(&interface->dev.kobj, "usb_device");
-
 	interface_number = interface->cur_altsetting->desc.bInterfaceNumber;
 	line6 = usb_get_intfdata(interface);
+	if (!line6)
+		return;
 
-	if (line6 != NULL) {
-		if (line6->urb_listen != NULL)
-			line6_stop_listen(line6);
+	if (line6->urb_listen != NULL)
+		line6_stop_listen(line6);
 
-		if (usbdev != line6->usbdev)
-			dev_err(line6->ifcdev,
-				"driver bug: inconsistent usb device\n");
+	if (usbdev != line6->usbdev)
+		dev_err(line6->ifcdev, "driver bug: inconsistent usb device\n");
 
+	snd_card_disconnect(line6->card);
+	if (line6->line6pcm)
+		line6_pcm_disconnect(line6->line6pcm);
+	if (line6->disconnect)
 		line6->disconnect(interface);
 
-		dev_info(&interface->dev, "Line6 %s now disconnected\n",
-			 line6->properties->name);
-	}
+	dev_info(&interface->dev, "Line 6 %s now disconnected\n",
+		 line6->properties->name);
 
-	line6_destruct(interface);
+	/* make sure the device isn't destructed twice: */
+	usb_set_intfdata(interface, NULL);
 
-	/* decrement reference counters: */
-	usb_put_intf(interface);
-	usb_put_dev(usbdev);
+	snd_card_free_when_closed(line6->card);
 }
+EXPORT_SYMBOL_GPL(line6_disconnect);
 
 #ifdef CONFIG_PM
 
 /*
-	Suspend Line6 device.
+	Suspend Line 6 device.
 */
-static int line6_suspend(struct usb_interface *interface, pm_message_t message)
+int line6_suspend(struct usb_interface *interface, pm_message_t message)
 {
 	struct usb_line6 *line6 = usb_get_intfdata(interface);
 	struct snd_line6_pcm *line6pcm = line6->line6pcm;
@@ -1047,17 +633,17 @@
 
 	if (line6pcm != NULL) {
 		snd_pcm_suspend_all(line6pcm->pcm);
-		line6_pcm_disconnect(line6pcm);
 		line6pcm->flags = 0;
 	}
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(line6_suspend);
 
 /*
-	Resume Line6 device.
+	Resume Line 6 device.
 */
-static int line6_resume(struct usb_interface *interface)
+int line6_resume(struct usb_interface *interface)
 {
 	struct usb_line6 *line6 = usb_get_intfdata(interface);
 
@@ -1067,48 +653,10 @@
 	snd_power_change_state(line6->card, SNDRV_CTL_POWER_D0);
 	return 0;
 }
-
-/*
-	Resume Line6 device after reset.
-*/
-static int line6_reset_resume(struct usb_interface *interface)
-{
-	struct usb_line6 *line6 = usb_get_intfdata(interface);
-
-	switch (line6->type) {
-	case LINE6_PODSTUDIO_GX:
-	case LINE6_PODSTUDIO_UX1:
-	case LINE6_PODSTUDIO_UX2:
-	case LINE6_TONEPORT_GX:
-	case LINE6_TONEPORT_UX1:
-	case LINE6_TONEPORT_UX2:
-	case LINE6_GUITARPORT:
-		line6_toneport_reset_resume((struct usb_line6_toneport *)line6);
-
-	default:
-		break;
-	}
-
-	return line6_resume(interface);
-}
+EXPORT_SYMBOL_GPL(line6_resume);
 
 #endif /* CONFIG_PM */
 
-static struct usb_driver line6_driver = {
-	.name = DRIVER_NAME,
-	.probe = line6_probe,
-	.disconnect = line6_disconnect,
-#ifdef CONFIG_PM
-	.suspend = line6_suspend,
-	.resume = line6_resume,
-	.reset_resume = line6_reset_resume,
-#endif
-	.id_table = line6_id_table,
-};
-
-module_usb_driver(line6_driver);
-
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
 MODULE_LICENSE("GPL");
-MODULE_VERSION(DRIVER_VERSION);
diff --git a/sound/usb/line6/driver.h b/sound/usb/line6/driver.h
index ad203f1..efd58ac 100644
--- a/sound/usb/line6/driver.h
+++ b/sound/usb/line6/driver.h
@@ -1,5 +1,5 @@
 /*
- * Line6 Linux USB driver - 0.9.1beta
+ * Line 6 Linux USB driver
  *
  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
  *
@@ -20,35 +20,12 @@
 
 #define DRIVER_NAME "line6usb"
 
-enum line6_device_type {
-	LINE6_BASSPODXT,
-	LINE6_BASSPODXTLIVE,
-	LINE6_BASSPODXTPRO,
-	LINE6_GUITARPORT,
-	LINE6_POCKETPOD,
-	LINE6_PODHD300,
-	LINE6_PODHD400,
-	LINE6_PODHD500_0,
-	LINE6_PODHD500_1,
-	LINE6_PODSTUDIO_GX,
-	LINE6_PODSTUDIO_UX1,
-	LINE6_PODSTUDIO_UX2,
-	LINE6_PODXT,
-	LINE6_PODXTLIVE_POD,
-	LINE6_PODXTLIVE_VARIAX,
-	LINE6_PODXTPRO,
-	LINE6_TONEPORT_GX,
-	LINE6_TONEPORT_UX1,
-	LINE6_TONEPORT_UX2,
-	LINE6_VARIAX
-};
-
 #define LINE6_TIMEOUT 1
 #define LINE6_BUFSIZE_LISTEN 32
 #define LINE6_MESSAGE_MAXLEN 256
 
 /*
-	Line6 MIDI control commands
+	Line 6 MIDI control commands
 */
 #define LINE6_PARAM_CHANGE   0xb0
 #define LINE6_PROGRAM_CHANGE 0xc0
@@ -71,17 +48,6 @@
 
 #define LINE6_CHANNEL_MASK 0x0f
 
-#define MISSING_CASE	\
-	pr_err("line6usb driver bug: missing case in %s:%d\n", \
-		__FILE__, __LINE__)
-
-#define CHECK_RETURN(x)		\
-do {				\
-	err = x;		\
-	if (err < 0)		\
-		return err;	\
-} while (0)
-
 #define CHECK_STARTUP_PROGRESS(x, n)	\
 do {					\
 	if ((x) >= (n))			\
@@ -95,7 +61,7 @@
 static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4;
 
 /**
-	 Common properties of Line6 devices.
+	 Common properties of Line 6 devices.
 */
 struct line6_properties {
 	/**
@@ -125,7 +91,7 @@
 };
 
 /**
-	 Common data shared by all Line6 devices.
+	 Common data shared by all Line 6 devices.
 	 Corresponds to a pair of USB endpoints.
 */
 struct usb_line6 {
@@ -135,11 +101,6 @@
 	struct usb_device *usbdev;
 
 	/**
-		 Device type.
-	*/
-	enum line6_device_type type;
-
-	/**
 		 Properties.
 	*/
 	const struct line6_properties *properties;
@@ -160,18 +121,18 @@
 	struct device *ifcdev;
 
 	/**
-		 Line6 sound card data structure.
+		 Line 6 sound card data structure.
 		 Each device has at least MIDI or PCM.
 	*/
 	struct snd_card *card;
 
 	/**
-		 Line6 PCM device data structure.
+		 Line 6 PCM device data structure.
 	*/
 	struct snd_line6_pcm *line6pcm;
 
 	/**
-		 Line6 MIDI device data structure.
+		 Line 6 MIDI device data structure.
 	*/
 	struct snd_line6_midi *line6midi;
 
@@ -207,9 +168,6 @@
 			   size_t datalen);
 extern int line6_read_serial_number(struct usb_line6 *line6,
 				    int *serial_number);
-extern int line6_send_program(struct usb_line6 *line6, u8 value);
-extern int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
-				  int size);
 extern int line6_send_raw_message_async(struct usb_line6 *line6,
 					const char *buffer, int size);
 extern int line6_send_sysex_message(struct usb_line6 *line6,
@@ -219,10 +177,19 @@
 extern void line6_start_timer(struct timer_list *timer, unsigned int msecs,
 			      void (*function)(unsigned long),
 			      unsigned long data);
-extern int line6_transmit_parameter(struct usb_line6 *line6, int param,
-				    u8 value);
 extern int line6_version_request_async(struct usb_line6 *line6);
 extern int line6_write_data(struct usb_line6 *line6, int address, void *data,
 			    size_t datalen);
 
+int line6_probe(struct usb_interface *interface,
+		struct usb_line6 *line6,
+		const struct line6_properties *properties,
+		int (*private_init)(struct usb_interface *, struct usb_line6 *));
+void line6_disconnect(struct usb_interface *interface);
+
+#ifdef CONFIG_PM
+int line6_suspend(struct usb_interface *interface, pm_message_t message);
+int line6_resume(struct usb_interface *interface);
+#endif
+
 #endif
diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c
index c9d725a..b5a58a7 100644
--- a/sound/usb/line6/midi.c
+++ b/sound/usb/line6/midi.c
@@ -1,5 +1,5 @@
 /*
- * Line6 Linux USB driver - 0.9.1beta
+ * Line 6 Linux USB driver
  *
  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
  *
@@ -11,13 +11,12 @@
 
 #include <linux/slab.h>
 #include <linux/usb.h>
+#include <linux/export.h>
 #include <sound/core.h>
 #include <sound/rawmidi.h>
 
-#include "audio.h"
 #include "driver.h"
 #include "midi.h"
-#include "pod.h"
 #include "usbdefs.h"
 
 #define line6_rawmidi_substream_midi(substream) \
@@ -121,16 +120,13 @@
 
 	urb = usb_alloc_urb(0, GFP_ATOMIC);
 
-	if (urb == NULL) {
-		dev_err(line6->ifcdev, "Out of memory\n");
+	if (urb == NULL)
 		return -ENOMEM;
-	}
 
 	transfer_buffer = kmemdup(data, length, GFP_ATOMIC);
 
 	if (transfer_buffer == NULL) {
 		usb_free_urb(urb);
-		dev_err(line6->ifcdev, "Out of memory\n");
 		return -ENOMEM;
 	}
 
@@ -223,28 +219,20 @@
 	.trigger = line6_midi_input_trigger,
 };
 
-/*
-	Cleanup the Line6 MIDI device.
-*/
-static void line6_cleanup_midi(struct snd_rawmidi *rmidi)
-{
-}
-
 /* Create a MIDI device */
-static int snd_line6_new_midi(struct snd_line6_midi *line6midi)
+static int snd_line6_new_midi(struct usb_line6 *line6,
+			      struct snd_rawmidi **rmidi_ret)
 {
 	struct snd_rawmidi *rmidi;
 	int err;
 
-	err = snd_rawmidi_new(line6midi->line6->card, "Line6 MIDI", 0, 1, 1,
-			      &rmidi);
+	err = snd_rawmidi_new(line6->card, "Line 6 MIDI", 0, 1, 1, rmidi_ret);
 	if (err < 0)
 		return err;
 
-	rmidi->private_data = line6midi;
-	rmidi->private_free = line6_cleanup_midi;
-	strcpy(rmidi->id, line6midi->line6->properties->id);
-	strcpy(rmidi->name, line6midi->line6->properties->name);
+	rmidi = *rmidi_ret;
+	strcpy(rmidi->id, line6->properties->id);
+	strcpy(rmidi->name, line6->properties->name);
 
 	rmidi->info_flags =
 	    SNDRV_RAWMIDI_INFO_OUTPUT |
@@ -258,25 +246,22 @@
 }
 
 /* MIDI device destructor */
-static int snd_line6_midi_free(struct snd_device *device)
+static void snd_line6_midi_free(struct snd_rawmidi *rmidi)
 {
-	struct snd_line6_midi *line6midi = device->device_data;
+	struct snd_line6_midi *line6midi = rmidi->private_data;
 
 	line6_midibuf_destroy(&line6midi->midibuf_in);
 	line6_midibuf_destroy(&line6midi->midibuf_out);
-	return 0;
+	kfree(line6midi);
 }
 
 /*
-	Initialize the Line6 MIDI subsystem.
+	Initialize the Line 6 MIDI subsystem.
 */
 int line6_init_midi(struct usb_line6 *line6)
 {
-	static struct snd_device_ops midi_ops = {
-		.dev_free = snd_line6_midi_free,
-	};
-
 	int err;
+	struct snd_rawmidi *rmidi;
 	struct snd_line6_midi *line6midi;
 
 	if (!(line6->properties->capabilities & LINE6_CAP_CONTROL)) {
@@ -284,38 +269,31 @@
 		return 0;
 	}
 
-	line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL);
+	err = snd_line6_new_midi(line6, &rmidi);
+	if (err < 0)
+		return err;
 
-	if (line6midi == NULL)
+	line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL);
+	if (!line6midi)
 		return -ENOMEM;
 
-	err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0);
-	if (err < 0) {
-		kfree(line6midi);
-		return err;
-	}
-
-	err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1);
-	if (err < 0) {
-		kfree(line6midi->midibuf_in.buf);
-		kfree(line6midi);
-		return err;
-	}
-
-	line6midi->line6 = line6;
-	line6->line6midi = line6midi;
-
-	err = snd_device_new(line6->card, SNDRV_DEV_RAWMIDI, line6midi,
-			     &midi_ops);
-	if (err < 0)
-		return err;
-
-	err = snd_line6_new_midi(line6midi);
-	if (err < 0)
-		return err;
+	rmidi->private_data = line6midi;
+	rmidi->private_free = snd_line6_midi_free;
 
 	init_waitqueue_head(&line6midi->send_wait);
 	spin_lock_init(&line6midi->send_urb_lock);
 	spin_lock_init(&line6midi->midi_transmit_lock);
+	line6midi->line6 = line6;
+
+	err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0);
+	if (err < 0)
+		return err;
+
+	err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1);
+	if (err < 0)
+		return err;
+
+	line6->line6midi = line6midi;
 	return 0;
 }
+EXPORT_SYMBOL_GPL(line6_init_midi);
diff --git a/sound/usb/line6/midi.h b/sound/usb/line6/midi.h
index 78f903f..ba6bf38 100644
--- a/sound/usb/line6/midi.h
+++ b/sound/usb/line6/midi.h
@@ -1,5 +1,5 @@
 /*
- * Line6 Linux USB driver - 0.9.1beta
+ * Line 6 Linux USB driver
  *
  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
  *
@@ -20,7 +20,7 @@
 
 struct snd_line6_midi {
 	/**
-		 Pointer back to the Line6 driver data structure.
+		 Pointer back to the Line 6 driver data structure.
 	*/
 	struct usb_line6 *line6;
 
diff --git a/sound/usb/line6/midibuf.c b/sound/usb/line6/midibuf.c
index 1ff8569..b5c4d79 100644
--- a/sound/usb/line6/midibuf.c
+++ b/sound/usb/line6/midibuf.c
@@ -1,5 +1,5 @@
 /*
- * Line6 Linux USB driver - 0.9.1beta
+ * Line 6 Linux USB driver
  *
  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
  *
@@ -26,7 +26,7 @@
 	} else {
 		/*
 		   Note that according to the MIDI specification 0xf2 is
-		   the "Song Position Pointer", but this is used by Line6
+		   the "Song Position Pointer", but this is used by Line 6
 		   to send sysex messages to the host.
 		 */
 		static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1,
diff --git a/sound/usb/line6/midibuf.h b/sound/usb/line6/midibuf.h
index 707482b..05dbf11 100644
--- a/sound/usb/line6/midibuf.h
+++ b/sound/usb/line6/midibuf.h
@@ -1,5 +1,5 @@
 /*
- * Line6 Linux USB driver - 0.9.1beta
+ * Line 6 Linux USB driver
  *
  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
  *
diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c
index 6d4e5cd..8a6059a 100644
--- a/sound/usb/line6/pcm.c
+++ b/sound/usb/line6/pcm.c
@@ -1,5 +1,5 @@
 /*
- * Line6 Linux USB driver - 0.9.1beta
+ * Line 6 Linux USB driver
  *
  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
  *
@@ -10,91 +10,85 @@
  */
 
 #include <linux/slab.h>
+#include <linux/export.h>
 #include <sound/core.h>
 #include <sound/control.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 
-#include "audio.h"
 #include "capture.h"
 #include "driver.h"
 #include "playback.h"
-#include "pod.h"
 
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-
-static struct snd_line6_pcm *dev2pcm(struct device *dev)
+/* impulse response volume controls */
+static int snd_line6_impulse_volume_info(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_info *uinfo)
 {
-	struct usb_interface *interface = to_usb_interface(dev);
-	struct usb_line6 *line6 = usb_get_intfdata(interface);
-	struct snd_line6_pcm *line6pcm = line6->line6pcm;
-	return line6pcm;
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 255;
+	return 0;
 }
 
-/*
-	"read" request on "impulse_volume" special file.
-*/
-static ssize_t impulse_volume_show(struct device *dev,
-				   struct device_attribute *attr, char *buf)
+static int snd_line6_impulse_volume_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
 {
-	return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_volume);
+	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+
+	ucontrol->value.integer.value[0] = line6pcm->impulse_volume;
+	return 0;
 }
 
-/*
-	"write" request on "impulse_volume" special file.
-*/
-static ssize_t impulse_volume_store(struct device *dev,
-				    struct device_attribute *attr,
-				    const char *buf, size_t count)
+static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
 {
-	struct snd_line6_pcm *line6pcm = dev2pcm(dev);
-	int value;
-	int ret;
+	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+	int value = ucontrol->value.integer.value[0];
 
-	ret = kstrtoint(buf, 10, &value);
-	if (ret < 0)
-		return ret;
+	if (line6pcm->impulse_volume == value)
+		return 0;
 
 	line6pcm->impulse_volume = value;
-
 	if (value > 0)
 		line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE);
 	else
 		line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE);
-
-	return count;
+	return 1;
 }
-static DEVICE_ATTR_RW(impulse_volume);
 
-/*
-	"read" request on "impulse_period" special file.
-*/
-static ssize_t impulse_period_show(struct device *dev,
-				   struct device_attribute *attr, char *buf)
+/* impulse response period controls */
+static int snd_line6_impulse_period_info(struct snd_kcontrol *kcontrol,
+					 struct snd_ctl_elem_info *uinfo)
 {
-	return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_period);
+	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+	uinfo->count = 1;
+	uinfo->value.integer.min = 0;
+	uinfo->value.integer.max = 2000;
+	return 0;
 }
 
-/*
-	"write" request on "impulse_period" special file.
-*/
-static ssize_t impulse_period_store(struct device *dev,
-				    struct device_attribute *attr,
-				    const char *buf, size_t count)
+static int snd_line6_impulse_period_get(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
 {
-	int value;
-	int ret;
+	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
 
-	ret = kstrtoint(buf, 10, &value);
-	if (ret < 0)
-		return ret;
-
-	dev2pcm(dev)->impulse_period = value;
-	return count;
+	ucontrol->value.integer.value[0] = line6pcm->impulse_period;
+	return 0;
 }
-static DEVICE_ATTR_RW(impulse_period);
 
-#endif
+static int snd_line6_impulse_period_put(struct snd_kcontrol *kcontrol,
+					struct snd_ctl_elem_value *ucontrol)
+{
+	struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+	int value = ucontrol->value.integer.value[0];
+
+	if (line6pcm->impulse_period == value)
+		return 0;
+
+	line6pcm->impulse_period = value;
+	return 1;
+}
 
 static bool test_flags(unsigned long flags0, unsigned long flags1,
 		       unsigned long mask)
@@ -195,6 +189,7 @@
 	line6_pcm_release(line6pcm, flags_final & channels);
 	return err;
 }
+EXPORT_SYMBOL_GPL(line6_pcm_acquire);
 
 int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels)
 {
@@ -223,6 +218,7 @@
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(line6_pcm_release);
 
 /* trigger callback */
 int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
@@ -230,19 +226,19 @@
 	struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
 	struct snd_pcm_substream *s;
 	int err;
-	unsigned long flags;
 
-	spin_lock_irqsave(&line6pcm->lock_trigger, flags);
+	spin_lock(&line6pcm->lock_trigger);
 	clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags);
 
 	snd_pcm_group_for_each_entry(s, substream) {
+		if (s->pcm->card != substream->pcm->card)
+			continue;
 		switch (s->stream) {
 		case SNDRV_PCM_STREAM_PLAYBACK:
 			err = snd_line6_playback_trigger(line6pcm, cmd);
 
 			if (err < 0) {
-				spin_unlock_irqrestore(&line6pcm->lock_trigger,
-						       flags);
+				spin_unlock(&line6pcm->lock_trigger);
 				return err;
 			}
 
@@ -252,8 +248,7 @@
 			err = snd_line6_capture_trigger(line6pcm, cmd);
 
 			if (err < 0) {
-				spin_unlock_irqrestore(&line6pcm->lock_trigger,
-						       flags);
+				spin_unlock(&line6pcm->lock_trigger);
 				return err;
 			}
 
@@ -265,7 +260,7 @@
 		}
 	}
 
-	spin_unlock_irqrestore(&line6pcm->lock_trigger, flags);
+	spin_unlock(&line6pcm->lock_trigger);
 	return 0;
 }
 
@@ -312,14 +307,28 @@
 }
 
 /* control definition */
-static struct snd_kcontrol_new line6_control_playback = {
-	.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-	.name = "PCM Playback Volume",
-	.index = 0,
-	.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-	.info = snd_line6_control_playback_info,
-	.get = snd_line6_control_playback_get,
-	.put = snd_line6_control_playback_put
+static struct snd_kcontrol_new line6_controls[] = {
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "PCM Playback Volume",
+		.info = snd_line6_control_playback_info,
+		.get = snd_line6_control_playback_get,
+		.put = snd_line6_control_playback_put
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Impulse Response Volume",
+		.info = snd_line6_impulse_volume_info,
+		.get = snd_line6_impulse_volume_get,
+		.put = snd_line6_impulse_volume_put
+	},
+	{
+		.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+		.name = "Impulse Response Period",
+		.info = snd_line6_impulse_period_info,
+		.get = snd_line6_impulse_period_get,
+		.put = snd_line6_impulse_period_put
+	},
 };
 
 /*
@@ -330,11 +339,6 @@
 	int i;
 	struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm);
 
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-	device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_volume);
-	device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_period);
-#endif
-
 	for (i = LINE6_ISO_BUFFERS; i--;) {
 		if (line6pcm->urb_audio_out[i]) {
 			usb_kill_urb(line6pcm->urb_audio_out[i]);
@@ -345,24 +349,21 @@
 			usb_free_urb(line6pcm->urb_audio_in[i]);
 		}
 	}
+	kfree(line6pcm);
 }
 
 /* create a PCM device */
-static int snd_line6_new_pcm(struct snd_line6_pcm *line6pcm)
+static int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret)
 {
 	struct snd_pcm *pcm;
 	int err;
 
-	err = snd_pcm_new(line6pcm->line6->card,
-			  (char *)line6pcm->line6->properties->name,
-			  0, 1, 1, &pcm);
+	err = snd_pcm_new(line6->card, (char *)line6->properties->name,
+			  0, 1, 1, pcm_ret);
 	if (err < 0)
 		return err;
-
-	pcm->private_data = line6pcm;
-	pcm->private_free = line6_cleanup_pcm;
-	line6pcm->pcm = pcm;
-	strcpy(pcm->name, line6pcm->line6->properties->name);
+	pcm = *pcm_ret;
+	strcpy(pcm->name, line6->properties->name);
 
 	/* set operators */
 	snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
@@ -374,37 +375,14 @@
 					      snd_dma_continuous_data
 					      (GFP_KERNEL), 64 * 1024,
 					      128 * 1024);
-
-	return 0;
-}
-
-/* PCM device destructor */
-static int snd_line6_pcm_free(struct snd_device *device)
-{
 	return 0;
 }
 
 /*
-	Stop substream if still running.
-*/
-static void pcm_disconnect_substream(struct snd_pcm_substream *substream)
-{
-	if (substream->runtime && snd_pcm_running(substream)) {
-		snd_pcm_stream_lock_irq(substream);
-		snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
-		snd_pcm_stream_unlock_irq(substream);
-	}
-}
-
-/*
-	Stop PCM stream.
+	Sync with PCM stream stops.
 */
 void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm)
 {
-	pcm_disconnect_substream(get_substream
-				 (line6pcm, SNDRV_PCM_STREAM_CAPTURE));
-	pcm_disconnect_substream(get_substream
-				 (line6pcm, SNDRV_PCM_STREAM_PLAYBACK));
 	line6_unlink_wait_clear_audio_out_urbs(line6pcm);
 	line6_unlink_wait_clear_audio_in_urbs(line6pcm);
 }
@@ -416,23 +394,25 @@
 int line6_init_pcm(struct usb_line6 *line6,
 		   struct line6_pcm_properties *properties)
 {
-	static struct snd_device_ops pcm_ops = {
-		.dev_free = snd_line6_pcm_free,
-	};
-
-	int err;
+	int i, err;
 	unsigned ep_read = line6->properties->ep_audio_r;
 	unsigned ep_write = line6->properties->ep_audio_w;
+	struct snd_pcm *pcm;
 	struct snd_line6_pcm *line6pcm;
 
 	if (!(line6->properties->capabilities & LINE6_CAP_PCM))
 		return 0;	/* skip PCM initialization and report success */
 
-	line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL);
+	err = snd_line6_new_pcm(line6, &pcm);
+	if (err < 0)
+		return err;
 
-	if (line6pcm == NULL)
+	line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL);
+	if (!line6pcm)
 		return -ENOMEM;
 
+	line6pcm->pcm = pcm;
+	line6pcm->properties = properties;
 	line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255;
 	line6pcm->volume_monitor = 255;
 	line6pcm->line6 = line6;
@@ -444,21 +424,15 @@
 			usb_maxpacket(line6->usbdev,
 				usb_sndisocpipe(line6->usbdev, ep_write), 1));
 
-	line6pcm->properties = properties;
-	line6->line6pcm = line6pcm;
-
-	/* PCM device: */
-	err = snd_device_new(line6->card, SNDRV_DEV_PCM, line6, &pcm_ops);
-	if (err < 0)
-		return err;
-
-	err = snd_line6_new_pcm(line6pcm);
-	if (err < 0)
-		return err;
-
 	spin_lock_init(&line6pcm->lock_audio_out);
 	spin_lock_init(&line6pcm->lock_audio_in);
 	spin_lock_init(&line6pcm->lock_trigger);
+	line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
+
+	line6->line6pcm = line6pcm;
+
+	pcm->private_data = line6pcm;
+	pcm->private_free = line6_cleanup_pcm;
 
 	err = line6_create_audio_out_urbs(line6pcm);
 	if (err < 0)
@@ -469,27 +443,16 @@
 		return err;
 
 	/* mixer: */
-	err =
-	    snd_ctl_add(line6->card,
-			snd_ctl_new1(&line6_control_playback, line6pcm));
-	if (err < 0)
-		return err;
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-	/* impulse response test: */
-	err = device_create_file(line6->ifcdev, &dev_attr_impulse_volume);
-	if (err < 0)
-		return err;
-
-	err = device_create_file(line6->ifcdev, &dev_attr_impulse_period);
-	if (err < 0)
-		return err;
-
-	line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
-#endif
+	for (i = 0; i < ARRAY_SIZE(line6_controls); i++) {
+		err = snd_ctl_add(line6->card,
+				  snd_ctl_new1(&line6_controls[i], line6pcm));
+		if (err < 0)
+			return err;
+	}
 
 	return 0;
 }
+EXPORT_SYMBOL_GPL(line6_init_pcm);
 
 /* prepare pcm callback */
 int snd_line6_prepare(struct snd_pcm_substream *substream)
@@ -508,9 +471,6 @@
 			line6_unlink_wait_clear_audio_in_urbs(line6pcm);
 
 		break;
-
-	default:
-		MISSING_CASE;
 	}
 
 	if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) {
diff --git a/sound/usb/line6/pcm.h b/sound/usb/line6/pcm.h
index 7315e81..c742b33 100644
--- a/sound/usb/line6/pcm.h
+++ b/sound/usb/line6/pcm.h
@@ -1,5 +1,5 @@
 /*
- * Line6 Linux USB driver - 0.9.1beta
+ * Line 6 Linux USB driver
  *
  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
  *
@@ -26,7 +26,7 @@
 
 /*
 	number of USB frames per URB
-	The Line6 Windows driver always transmits two frames per packet, but
+	The Line 6 Windows driver always transmits two frames per packet, but
 	the Linux driver performs significantly better (i.e., lower latency)
 	with only one frame per packet.
 */
@@ -35,12 +35,10 @@
 /* in a "full speed" device (such as the PODxt Pro) this means 1ms */
 #define LINE6_ISO_INTERVAL	1
 
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
 #define LINE6_IMPULSE_DEFAULT_PERIOD 100
-#endif
 
 /*
-	Get substream from Line6 PCM data structure
+	Get substream from Line 6 PCM data structure
 */
 #define get_substream(line6pcm, stream)	\
 		(line6pcm->pcm->streams[stream].substream)
@@ -48,7 +46,7 @@
 /*
 	PCM mode bits.
 
-	There are several features of the Line6 USB driver which require PCM
+	There are several features of the Line 6 USB driver which require PCM
 	data to be exchanged with the device:
 	*) PCM playback and capture via ALSA
 	*) software monitoring (for devices without hardware monitoring)
@@ -89,12 +87,10 @@
 	LINE6_INDEX_PCM_MONITOR_PLAYBACK_STREAM,
 	LINE6_INDEX_PCM_MONITOR_CAPTURE_BUFFER,
 	LINE6_INDEX_PCM_MONITOR_CAPTURE_STREAM,
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
 	LINE6_INDEX_PCM_IMPULSE_PLAYBACK_BUFFER,
 	LINE6_INDEX_PCM_IMPULSE_PLAYBACK_STREAM,
 	LINE6_INDEX_PCM_IMPULSE_CAPTURE_BUFFER,
 	LINE6_INDEX_PCM_IMPULSE_CAPTURE_STREAM,
-#endif
 	LINE6_INDEX_PAUSE_PLAYBACK,
 	LINE6_INDEX_PREPARED,
 
@@ -109,12 +105,10 @@
 	LINE6_BIT(PCM_MONITOR_PLAYBACK_STREAM),
 	LINE6_BIT(PCM_MONITOR_CAPTURE_BUFFER),
 	LINE6_BIT(PCM_MONITOR_CAPTURE_STREAM),
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
 	LINE6_BIT(PCM_IMPULSE_PLAYBACK_BUFFER),
 	LINE6_BIT(PCM_IMPULSE_PLAYBACK_STREAM),
 	LINE6_BIT(PCM_IMPULSE_CAPTURE_BUFFER),
 	LINE6_BIT(PCM_IMPULSE_CAPTURE_STREAM),
-#endif
 	LINE6_BIT(PAUSE_PLAYBACK),
 	LINE6_BIT(PREPARED),
 
@@ -133,40 +127,30 @@
 	    LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER |
 	    LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,
 
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
 	LINE6_BITS_PCM_IMPULSE =
 	    LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
 	    LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM |
 	    LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER |
 	    LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM,
-#endif
 
 	/* combined bit masks (by direction): */
 	LINE6_BITS_PLAYBACK_BUFFER =
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
 	    LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
-#endif
 	    LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER |
 	    LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER,
 
 	LINE6_BITS_PLAYBACK_STREAM =
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
 	    LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM |
-#endif
 	    LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM |
 	    LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM,
 
 	LINE6_BITS_CAPTURE_BUFFER =
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
 	    LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER |
-#endif
 	    LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER |
 	    LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER,
 
 	LINE6_BITS_CAPTURE_STREAM =
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
 	    LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM |
-#endif
 	    LINE6_BIT_PCM_ALSA_CAPTURE_STREAM |
 	    LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,
 
@@ -183,7 +167,7 @@
 
 struct snd_line6_pcm {
 	/**
-		 Pointer back to the Line6 driver data structure.
+		 Pointer back to the Line 6 driver data structure.
 	*/
 	struct usb_line6 *line6;
 
@@ -338,7 +322,6 @@
 	*/
 	int volume_monitor;
 
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
 	/**
 		 Volume of impulse response test signal (if zero, test is disabled).
 	*/
@@ -353,7 +336,6 @@
 		 Counter for impulse response test signal.
 	*/
 	int impulse_count;
-#endif
 
 	/**
 		 Several status bits (see LINE6_BIT_*).
diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c
index da2e3b8..1c9f95a 100644
--- a/sound/usb/line6/playback.c
+++ b/sound/usb/line6/playback.c
@@ -1,5 +1,5 @@
 /*
- * Line6 Linux USB driver - 0.9.1beta
+ * Line 6 Linux USB driver
  *
  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
  *
@@ -14,11 +14,9 @@
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 
-#include "audio.h"
 #include "capture.h"
 #include "driver.h"
 #include "pcm.h"
-#include "pod.h"
 #include "playback.h"
 
 /*
@@ -61,8 +59,6 @@
 	}
 }
 
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-
 /*
 	Create signal for impulse response test.
 */
@@ -106,8 +102,6 @@
 	}
 }
 
-#endif
-
 /*
 	Add signal to buffer for software monitoring.
 */
@@ -244,7 +238,6 @@
 	change_volume(urb_out, line6pcm->volume_playback, bytes_per_frame);
 
 	if (line6pcm->prev_fbuf != NULL) {
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
 		if (line6pcm->flags & LINE6_BITS_PCM_IMPULSE) {
 			create_impulse_test_signal(line6pcm, urb_out,
 						   bytes_per_frame);
@@ -258,7 +251,6 @@
 					urb_out->transfer_buffer_length);
 			}
 		} else {
-#endif
 			if (!
 			    (line6pcm->line6->
 			     properties->capabilities & LINE6_CAP_HWMON)
@@ -267,9 +259,7 @@
 				add_monitor_signal(urb_out, line6pcm->prev_fbuf,
 						   line6pcm->volume_monitor,
 						   bytes_per_frame);
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
 		}
-#endif
 	}
 
 	ret = usb_submit_urb(urb_out, GFP_ATOMIC);
@@ -499,9 +489,7 @@
 
 	switch (cmd) {
 	case SNDRV_PCM_TRIGGER_START:
-#ifdef CONFIG_PM
 	case SNDRV_PCM_TRIGGER_RESUME:
-#endif
 		err = line6_pcm_acquire(line6pcm,
 					LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM);
 
@@ -511,9 +499,7 @@
 		break;
 
 	case SNDRV_PCM_TRIGGER_STOP:
-#ifdef CONFIG_PM
 	case SNDRV_PCM_TRIGGER_SUSPEND:
-#endif
 		err = line6_pcm_release(line6pcm,
 					LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM);
 
@@ -571,10 +557,8 @@
 		urb = line6pcm->urb_audio_out[i] =
 		    usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
 
-		if (urb == NULL) {
-			dev_err(line6->ifcdev, "Out of memory\n");
+		if (urb == NULL)
 			return -ENOMEM;
-		}
 
 		urb->dev = line6->usbdev;
 		urb->pipe =
diff --git a/sound/usb/line6/playback.h b/sound/usb/line6/playback.h
index 743bd6f..78a8851132 100644
--- a/sound/usb/line6/playback.h
+++ b/sound/usb/line6/playback.h
@@ -1,5 +1,5 @@
 /*
- * Line6 Linux USB driver - 0.9.1beta
+ * Line 6 Linux USB driver
  *
  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
  *
diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c
index 85a4363..bf027fc 100644
--- a/sound/usb/line6/pod.c
+++ b/sound/usb/line6/pod.c
@@ -1,5 +1,5 @@
 /*
- * Line6 Linux USB driver - 0.9.1beta
+ * Line 6 Linux USB driver
  *
  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
  *
@@ -11,13 +11,93 @@
 
 #include <linux/slab.h>
 #include <linux/wait.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+
+#include <sound/core.h>
 #include <sound/control.h>
 
-#include "audio.h"
 #include "capture.h"
 #include "driver.h"
 #include "playback.h"
-#include "pod.h"
+#include "usbdefs.h"
+
+/*
+	Locate name in binary program dump
+*/
+#define	POD_NAME_OFFSET 0
+#define	POD_NAME_LENGTH 16
+
+/*
+	Other constants
+*/
+#define POD_CONTROL_SIZE 0x80
+#define POD_BUFSIZE_DUMPREQ 7
+#define POD_STARTUP_DELAY 1000
+
+/*
+	Stages of POD startup procedure
+*/
+enum {
+	POD_STARTUP_INIT = 1,
+	POD_STARTUP_VERSIONREQ,
+	POD_STARTUP_WORKQUEUE,
+	POD_STARTUP_SETUP,
+	POD_STARTUP_LAST = POD_STARTUP_SETUP - 1
+};
+
+enum {
+	LINE6_BASSPODXT,
+	LINE6_BASSPODXTLIVE,
+	LINE6_BASSPODXTPRO,
+	LINE6_POCKETPOD,
+	LINE6_PODXT,
+	LINE6_PODXTLIVE_POD,
+	LINE6_PODXTPRO,
+};
+
+struct usb_line6_pod {
+	/**
+		Generic Line 6 USB data.
+	*/
+	struct usb_line6 line6;
+
+	/**
+		Instrument monitor level.
+	*/
+	int monitor_level;
+
+	/**
+		Timer for device initializaton.
+	*/
+	struct timer_list startup_timer;
+
+	/**
+		Work handler for device initializaton.
+	*/
+	struct work_struct startup_work;
+
+	/**
+		Current progress in startup procedure.
+	*/
+	int startup_progress;
+
+	/**
+		Serial number of device.
+	*/
+	int serial_number;
+
+	/**
+		Firmware version (x 100).
+	*/
+	int firmware_version;
+
+	/**
+		Device ID.
+	*/
+	int device_id;
+};
 
 #define POD_SYSEX_CODE 3
 #define POD_BYTES_PER_FRAME 6	/* 24bit audio (stereo) */
@@ -72,9 +152,6 @@
 					   SNDRV_PCM_INFO_BLOCK_TRANSFER |
 					   SNDRV_PCM_INFO_MMAP_VALID |
 					   SNDRV_PCM_INFO_PAUSE |
-#ifdef CONFIG_PM
-					   SNDRV_PCM_INFO_RESUME |
-#endif
 					   SNDRV_PCM_INFO_SYNC_START),
 				  .formats = SNDRV_PCM_FMTBIT_S24_3LE,
 				  .rates = SNDRV_PCM_RATE_KNOT,
@@ -92,9 +169,6 @@
 					  SNDRV_PCM_INFO_INTERLEAVED |
 					  SNDRV_PCM_INFO_BLOCK_TRANSFER |
 					  SNDRV_PCM_INFO_MMAP_VALID |
-#ifdef CONFIG_PM
-					  SNDRV_PCM_INFO_RESUME |
-#endif
 					  SNDRV_PCM_INFO_SYNC_START),
 				 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
 				 .rates = SNDRV_PCM_RATE_KNOT,
@@ -265,7 +339,7 @@
 	line6_read_serial_number(&pod->line6, &pod->serial_number);
 
 	/* ALSA audio interface: */
-	line6_register_audio(line6);
+	snd_card_register(line6->card);
 }
 
 /* POD special files: */
@@ -323,21 +397,6 @@
 };
 
 /*
-	POD destructor.
-*/
-static void pod_destruct(struct usb_interface *interface)
-{
-	struct usb_line6_pod *pod = usb_get_intfdata(interface);
-
-	if (pod == NULL)
-		return;
-	line6_cleanup_audio(&pod->line6);
-
-	del_timer(&pod->startup_timer);
-	cancel_work_sync(&pod->startup_work);
-}
-
-/*
 	POD device disconnected.
 */
 static void line6_pod_disconnect(struct usb_interface *interface)
@@ -349,21 +408,18 @@
 	pod = usb_get_intfdata(interface);
 
 	if (pod != NULL) {
-		struct snd_line6_pcm *line6pcm = pod->line6.line6pcm;
 		struct device *dev = &interface->dev;
 
-		if (line6pcm != NULL)
-			line6_pcm_disconnect(line6pcm);
-
 		if (dev != NULL) {
 			/* remove sysfs entries: */
 			device_remove_file(dev, &dev_attr_device_id);
 			device_remove_file(dev, &dev_attr_firmware_version);
 			device_remove_file(dev, &dev_attr_serial_number);
 		}
-	}
 
-	pod_destruct(interface);
+		del_timer_sync(&pod->startup_timer);
+		cancel_work_sync(&pod->startup_work);
+	}
 }
 
 /*
@@ -373,17 +429,23 @@
 {
 	int err;
 
-	CHECK_RETURN(device_create_file(dev, &dev_attr_device_id));
-	CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version));
-	CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number));
+	err = device_create_file(dev, &dev_attr_device_id);
+	if (err < 0)
+		return err;
+	err = device_create_file(dev, &dev_attr_firmware_version);
+	if (err < 0)
+		return err;
+	err = device_create_file(dev, &dev_attr_serial_number);
+	if (err < 0)
+		return err;
 	return 0;
 }
 
 /*
 	 Try to init POD device.
 */
-static int pod_try_init(struct usb_interface *interface,
-			struct usb_line6 *line6)
+static int pod_init(struct usb_interface *interface,
+		    struct usb_line6 *line6)
 {
 	int err;
 	struct usb_line6_pod *pod = (struct usb_line6_pod *) line6;
@@ -402,11 +464,6 @@
 	if (err < 0)
 		return err;
 
-	/* initialize audio system: */
-	err = line6_init_audio(line6);
-	if (err < 0)
-		return err;
-
 	/* initialize MIDI subsystem: */
 	err = line6_init_midi(line6);
 	if (err < 0)
@@ -439,15 +496,136 @@
 	return 0;
 }
 
+#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 pod_id_table[] = {
+	{ LINE6_DEVICE(0x4250),    .driver_info = LINE6_BASSPODXT },
+	{ LINE6_DEVICE(0x4642),    .driver_info = LINE6_BASSPODXTLIVE },
+	{ LINE6_DEVICE(0x4252),    .driver_info = LINE6_BASSPODXTPRO },
+	{ LINE6_IF_NUM(0x5051, 1), .driver_info = LINE6_POCKETPOD },
+	{ LINE6_DEVICE(0x5044),    .driver_info = LINE6_PODXT },
+	{ LINE6_IF_NUM(0x4650, 0), .driver_info = LINE6_PODXTLIVE_POD },
+	{ LINE6_DEVICE(0x5050),    .driver_info = LINE6_PODXTPRO },
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, pod_id_table);
+
+static const struct line6_properties pod_properties_table[] = {
+	[LINE6_BASSPODXT] = {
+		.id = "BassPODxt",
+		.name = "BassPODxt",
+		.capabilities	= LINE6_CAP_CONTROL
+				| LINE6_CAP_PCM
+				| LINE6_CAP_HWMON,
+		.altsetting = 5,
+		.ep_ctrl_r = 0x84,
+		.ep_ctrl_w = 0x03,
+		.ep_audio_r = 0x82,
+		.ep_audio_w = 0x01,
+	},
+	[LINE6_BASSPODXTLIVE] = {
+		.id = "BassPODxtLive",
+		.name = "BassPODxt Live",
+		.capabilities	= LINE6_CAP_CONTROL
+				| LINE6_CAP_PCM
+				| LINE6_CAP_HWMON,
+		.altsetting = 1,
+		.ep_ctrl_r = 0x84,
+		.ep_ctrl_w = 0x03,
+		.ep_audio_r = 0x82,
+		.ep_audio_w = 0x01,
+	},
+	[LINE6_BASSPODXTPRO] = {
+		.id = "BassPODxtPro",
+		.name = "BassPODxt Pro",
+		.capabilities	= LINE6_CAP_CONTROL
+				| LINE6_CAP_PCM
+				| LINE6_CAP_HWMON,
+		.altsetting = 5,
+		.ep_ctrl_r = 0x84,
+		.ep_ctrl_w = 0x03,
+		.ep_audio_r = 0x82,
+		.ep_audio_w = 0x01,
+	},
+	[LINE6_POCKETPOD] = {
+		.id = "PocketPOD",
+		.name = "Pocket POD",
+		.capabilities	= LINE6_CAP_CONTROL,
+		.altsetting = 0,
+		.ep_ctrl_r = 0x82,
+		.ep_ctrl_w = 0x02,
+		/* no audio channel */
+	},
+	[LINE6_PODXT] = {
+		.id = "PODxt",
+		.name = "PODxt",
+		.capabilities	= LINE6_CAP_CONTROL
+				| LINE6_CAP_PCM
+				| LINE6_CAP_HWMON,
+		.altsetting = 5,
+		.ep_ctrl_r = 0x84,
+		.ep_ctrl_w = 0x03,
+		.ep_audio_r = 0x82,
+		.ep_audio_w = 0x01,
+	},
+	[LINE6_PODXTLIVE_POD] = {
+		.id = "PODxtLive",
+		.name = "PODxt Live",
+		.capabilities	= LINE6_CAP_CONTROL
+				| LINE6_CAP_PCM
+				| LINE6_CAP_HWMON,
+		.altsetting = 1,
+		.ep_ctrl_r = 0x84,
+		.ep_ctrl_w = 0x03,
+		.ep_audio_r = 0x82,
+		.ep_audio_w = 0x01,
+	},
+	[LINE6_PODXTPRO] = {
+		.id = "PODxtPro",
+		.name = "PODxt Pro",
+		.capabilities	= LINE6_CAP_CONTROL
+				| LINE6_CAP_PCM
+				| LINE6_CAP_HWMON,
+		.altsetting = 5,
+		.ep_ctrl_r = 0x84,
+		.ep_ctrl_w = 0x03,
+		.ep_audio_r = 0x82,
+		.ep_audio_w = 0x01,
+	},
+};
+
 /*
-	 Init POD device (and clean up in case of failure).
+	Probe USB device.
 */
-int line6_pod_init(struct usb_interface *interface, struct usb_line6 *line6)
+static int pod_probe(struct usb_interface *interface,
+		     const struct usb_device_id *id)
 {
-	int err = pod_try_init(interface, line6);
+	struct usb_line6_pod *pod;
 
-	if (err < 0)
-		pod_destruct(interface);
-
-	return err;
+	pod = kzalloc(sizeof(*pod), GFP_KERNEL);
+	if (!pod)
+		return -ENODEV;
+	return line6_probe(interface, &pod->line6,
+			   &pod_properties_table[id->driver_info],
+			   pod_init);
 }
+
+static struct usb_driver pod_driver = {
+	.name = KBUILD_MODNAME,
+	.probe = pod_probe,
+	.disconnect = line6_disconnect,
+#ifdef CONFIG_PM
+	.suspend = line6_suspend,
+	.resume = line6_resume,
+	.reset_resume = line6_resume,
+#endif
+	.id_table = pod_id_table,
+};
+
+module_usb_driver(pod_driver);
+
+MODULE_DESCRIPTION("Line 6 POD USB driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/usb/line6/pod.h b/sound/usb/line6/pod.h
deleted file mode 100644
index 87a8f0f..0000000
--- a/sound/usb/line6/pod.h
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License as
- *	published by the Free Software Foundation, version 2.
- *
- */
-
-#ifndef POD_H
-#define POD_H
-
-#include <linux/interrupt.h>
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-
-#include <sound/core.h>
-
-#include "driver.h"
-
-/*
-	Locate name in binary program dump
-*/
-#define	POD_NAME_OFFSET 0
-#define	POD_NAME_LENGTH 16
-
-/*
-	Other constants
-*/
-#define POD_CONTROL_SIZE 0x80
-#define POD_BUFSIZE_DUMPREQ 7
-#define POD_STARTUP_DELAY 1000
-
-/*
-	Stages of POD startup procedure
-*/
-enum {
-	POD_STARTUP_INIT = 1,
-	POD_STARTUP_VERSIONREQ,
-	POD_STARTUP_WORKQUEUE,
-	POD_STARTUP_SETUP,
-	POD_STARTUP_LAST = POD_STARTUP_SETUP - 1
-};
-
-struct usb_line6_pod {
-	/**
-		Generic Line6 USB data.
-	*/
-	struct usb_line6 line6;
-
-	/**
-		Instrument monitor level.
-	*/
-	int monitor_level;
-
-	/**
-		Timer for device initializaton.
-	*/
-	struct timer_list startup_timer;
-
-	/**
-		Work handler for device initializaton.
-	*/
-	struct work_struct startup_work;
-
-	/**
-		Current progress in startup procedure.
-	*/
-	int startup_progress;
-
-	/**
-		Serial number of device.
-	*/
-	int serial_number;
-
-	/**
-		Firmware version (x 100).
-	*/
-	int firmware_version;
-
-	/**
-		Device ID.
-	*/
-	int device_id;
-};
-
-extern int line6_pod_init(struct usb_interface *interface,
-			  struct usb_line6 *line6);
-
-#endif
diff --git a/sound/usb/line6/podhd.c b/sound/usb/line6/podhd.c
index 27c5402..7217fa7 100644
--- a/sound/usb/line6/podhd.c
+++ b/sound/usb/line6/podhd.c
@@ -1,5 +1,5 @@
 /*
- * Line6 Pod HD
+ * Line 6 Pod HD
  *
  * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
  *
@@ -9,13 +9,29 @@
  *
  */
 
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/module.h>
 #include <sound/core.h>
 #include <sound/pcm.h>
 
-#include "audio.h"
 #include "driver.h"
 #include "pcm.h"
-#include "podhd.h"
+#include "usbdefs.h"
+
+enum {
+	LINE6_PODHD300,
+	LINE6_PODHD400,
+	LINE6_PODHD500_0,
+	LINE6_PODHD500_1,
+};
+
+struct usb_line6_podhd {
+	/**
+		Generic Line 6 USB data.
+	*/
+	struct usb_line6 line6;
+};
 
 #define PODHD_BYTES_PER_FRAME 6	/* 24bit audio (stereo) */
 
@@ -33,9 +49,6 @@
 					   SNDRV_PCM_INFO_BLOCK_TRANSFER |
 					   SNDRV_PCM_INFO_MMAP_VALID |
 					   SNDRV_PCM_INFO_PAUSE |
-#ifdef CONFIG_PM
-					   SNDRV_PCM_INFO_RESUME |
-#endif
 					   SNDRV_PCM_INFO_SYNC_START),
 				  .formats = SNDRV_PCM_FMTBIT_S24_3LE,
 				  .rates = SNDRV_PCM_RATE_48000,
@@ -53,9 +66,6 @@
 					  SNDRV_PCM_INFO_INTERLEAVED |
 					  SNDRV_PCM_INFO_BLOCK_TRANSFER |
 					  SNDRV_PCM_INFO_MMAP_VALID |
-#ifdef CONFIG_PM
-					  SNDRV_PCM_INFO_RESUME |
-#endif
 					  SNDRV_PCM_INFO_SYNC_START),
 				 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
 				 .rates = SNDRV_PCM_RATE_48000,
@@ -75,57 +85,17 @@
 };
 
 /*
-	POD HD destructor.
-*/
-static void podhd_destruct(struct usb_interface *interface)
-{
-	struct usb_line6_podhd *podhd = usb_get_intfdata(interface);
-
-	if (podhd == NULL)
-		return;
-	line6_cleanup_audio(&podhd->line6);
-}
-
-/*
-	POD HD device disconnected.
-*/
-static void line6_podhd_disconnect(struct usb_interface *interface)
-{
-	struct usb_line6_podhd *podhd;
-
-	if (interface == NULL)
-		return;
-	podhd = usb_get_intfdata(interface);
-
-	if (podhd != NULL) {
-		struct snd_line6_pcm *line6pcm = podhd->line6.line6pcm;
-
-		if (line6pcm != NULL)
-			line6_pcm_disconnect(line6pcm);
-	}
-
-	podhd_destruct(interface);
-}
-
-/*
 	Try to init POD HD device.
 */
-static int podhd_try_init(struct usb_interface *interface,
-			  struct usb_line6_podhd *podhd)
+static int podhd_init(struct usb_interface *interface,
+		      struct usb_line6 *line6)
 {
+	struct usb_line6_podhd *podhd = (struct usb_line6_podhd *) line6;
 	int err;
-	struct usb_line6 *line6 = &podhd->line6;
 
 	if ((interface == NULL) || (podhd == NULL))
 		return -ENODEV;
 
-	line6->disconnect = line6_podhd_disconnect;
-
-	/* initialize audio system: */
-	err = line6_init_audio(line6);
-	if (err < 0)
-		return err;
-
 	/* initialize MIDI subsystem: */
 	err = line6_init_midi(line6);
 	if (err < 0)
@@ -137,20 +107,103 @@
 		return err;
 
 	/* register USB audio system: */
-	err = line6_register_audio(line6);
-	return err;
+	return snd_card_register(line6->card);
 }
 
+#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[] = {
+	{ LINE6_DEVICE(0x5057),    .driver_info = LINE6_PODHD300 },
+	{ LINE6_DEVICE(0x5058),    .driver_info = LINE6_PODHD400 },
+	{ LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500_0 },
+	{ LINE6_IF_NUM(0x414D, 1), .driver_info = LINE6_PODHD500_1 },
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, podhd_id_table);
+
+static const struct line6_properties podhd_properties_table[] = {
+	[LINE6_PODHD300] = {
+		.id = "PODHD300",
+		.name = "POD HD300",
+		.capabilities	= LINE6_CAP_CONTROL
+				| LINE6_CAP_PCM
+				| 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",
+		.capabilities	= LINE6_CAP_CONTROL
+				| LINE6_CAP_PCM
+				| LINE6_CAP_HWMON,
+		.altsetting = 5,
+		.ep_ctrl_r = 0x84,
+		.ep_ctrl_w = 0x03,
+		.ep_audio_r = 0x82,
+		.ep_audio_w = 0x01,
+	},
+	[LINE6_PODHD500_0] = {
+		.id = "PODHD500",
+		.name = "POD HD500",
+		.capabilities	= LINE6_CAP_CONTROL
+				| LINE6_CAP_PCM
+				| LINE6_CAP_HWMON,
+		.altsetting = 1,
+		.ep_ctrl_r = 0x81,
+		.ep_ctrl_w = 0x01,
+		.ep_audio_r = 0x86,
+		.ep_audio_w = 0x02,
+	},
+	[LINE6_PODHD500_1] = {
+		.id = "PODHD500",
+		.name = "POD HD500",
+		.capabilities	= LINE6_CAP_CONTROL
+				| LINE6_CAP_PCM
+				| LINE6_CAP_HWMON,
+		.altsetting = 1,
+		.ep_ctrl_r = 0x81,
+		.ep_ctrl_w = 0x01,
+		.ep_audio_r = 0x86,
+		.ep_audio_w = 0x02,
+	},
+};
+
 /*
-	Init POD HD device (and clean up in case of failure).
+	Probe USB device.
 */
-int line6_podhd_init(struct usb_interface *interface, struct usb_line6 *line6)
+static int podhd_probe(struct usb_interface *interface,
+		       const struct usb_device_id *id)
 {
-	struct usb_line6_podhd *podhd = (struct usb_line6_podhd *) line6;
-	int err = podhd_try_init(interface, podhd);
+	struct usb_line6_podhd *podhd;
 
-	if (err < 0)
-		podhd_destruct(interface);
-
-	return err;
+	podhd = kzalloc(sizeof(*podhd), GFP_KERNEL);
+	if (!podhd)
+		return -ENODEV;
+	return line6_probe(interface, &podhd->line6,
+			   &podhd_properties_table[id->driver_info],
+			   podhd_init);
 }
+
+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);
+
+MODULE_DESCRIPTION("Line 6 PODHD USB driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/usb/line6/podhd.h b/sound/usb/line6/podhd.h
deleted file mode 100644
index a14f711..0000000
--- a/sound/usb/line6/podhd.h
+++ /dev/null
@@ -1,29 +0,0 @@
-/*
- * Line6 Pod HD
- *
- * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License as
- *	published by the Free Software Foundation, version 2.
- *
- */
-
-#ifndef PODHD_H
-#define PODHD_H
-
-#include <linux/usb.h>
-
-#include "driver.h"
-
-struct usb_line6_podhd {
-	/**
-		Generic Line6 USB data.
-	*/
-	struct usb_line6 line6;
-};
-
-extern int line6_podhd_init(struct usb_interface *interface,
-			    struct usb_line6 *line6);
-
-#endif /* PODHD_H */
diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c
index aae78d8..c1f61cd 100644
--- a/sound/usb/line6/toneport.c
+++ b/sound/usb/line6/toneport.c
@@ -1,5 +1,5 @@
 /*
- * Line6 Linux USB driver - 0.9.1beta
+ * Line 6 Linux USB driver
  *
  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
  *                         Emil Myhrman (emil.myhrman@gmail.com)
@@ -11,13 +11,58 @@
  */
 
 #include <linux/wait.h>
+#include <linux/usb.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <sound/core.h>
 #include <sound/control.h>
 
-#include "audio.h"
 #include "capture.h"
 #include "driver.h"
 #include "playback.h"
-#include "toneport.h"
+#include "usbdefs.h"
+
+enum line6_device_type {
+	LINE6_GUITARPORT,
+	LINE6_PODSTUDIO_GX,
+	LINE6_PODSTUDIO_UX1,
+	LINE6_PODSTUDIO_UX2,
+	LINE6_TONEPORT_GX,
+	LINE6_TONEPORT_UX1,
+	LINE6_TONEPORT_UX2,
+};
+
+struct usb_line6_toneport {
+	/**
+		Generic Line 6 USB data.
+	*/
+	struct usb_line6 line6;
+
+	/**
+		Source selector.
+	*/
+	int source;
+
+	/**
+		Serial number of device.
+	*/
+	int serial_number;
+
+	/**
+		Firmware version (x 100).
+	*/
+	int firmware_version;
+
+	/**
+		 Timer for delayed PCM startup.
+	*/
+	struct timer_list timer;
+
+	/**
+		 Device type.
+	*/
+	enum line6_device_type type;
+};
 
 static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2);
 
@@ -37,9 +82,6 @@
 					   SNDRV_PCM_INFO_BLOCK_TRANSFER |
 					   SNDRV_PCM_INFO_MMAP_VALID |
 					   SNDRV_PCM_INFO_PAUSE |
-#ifdef CONFIG_PM
-					   SNDRV_PCM_INFO_RESUME |
-#endif
 					   SNDRV_PCM_INFO_SYNC_START),
 				  .formats = SNDRV_PCM_FMTBIT_S16_LE,
 				  .rates = SNDRV_PCM_RATE_KNOT,
@@ -57,9 +99,6 @@
 					  SNDRV_PCM_INFO_INTERLEAVED |
 					  SNDRV_PCM_INFO_BLOCK_TRANSFER |
 					  SNDRV_PCM_INFO_MMAP_VALID |
-#ifdef CONFIG_PM
-					  SNDRV_PCM_INFO_RESUME |
-#endif
 					  SNDRV_PCM_INFO_SYNC_START),
 				 .formats = SNDRV_PCM_FMTBIT_S16_LE,
 				 .rates = SNDRV_PCM_RATE_KNOT,
@@ -291,18 +330,6 @@
 };
 
 /*
-	Toneport destructor.
-*/
-static void toneport_destruct(struct usb_interface *interface)
-{
-	struct usb_line6_toneport *toneport = usb_get_intfdata(interface);
-
-	if (toneport == NULL)
-		return;
-	line6_cleanup_audio(&toneport->line6);
-}
-
-/*
 	Setup Toneport device.
 */
 static void toneport_setup(struct usb_line6_toneport *toneport)
@@ -319,7 +346,7 @@
 	toneport_send_cmd(usbdev, 0x0301, 0x0000);
 
 	/* initialize source select: */
-	switch (line6->type) {
+	switch (toneport->type) {
 	case LINE6_TONEPORT_UX1:
 	case LINE6_TONEPORT_UX2:
 	case LINE6_PODSTUDIO_UX1:
@@ -331,7 +358,7 @@
 		break;
 	}
 
-	if (toneport_has_led(line6->type))
+	if (toneport_has_led(toneport->type))
 		toneport_update_led(&usbdev->dev);
 }
 
@@ -354,25 +381,14 @@
 		device_remove_file(&interface->dev, &dev_attr_led_red);
 		device_remove_file(&interface->dev, &dev_attr_led_green);
 	}
-
-	if (toneport != NULL) {
-		struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm;
-
-		if (line6pcm != NULL) {
-			line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
-			line6_pcm_disconnect(line6pcm);
-		}
-	}
-
-	toneport_destruct(interface);
 }
 
 
 /*
 	 Try to init Toneport device.
 */
-static int toneport_try_init(struct usb_interface *interface,
-			     struct usb_line6 *line6)
+static int toneport_init(struct usb_interface *interface,
+			 struct usb_line6 *line6)
 {
 	int err;
 	struct usb_line6_toneport *toneport =  (struct usb_line6_toneport *) line6;
@@ -382,11 +398,6 @@
 
 	line6->disconnect = line6_toneport_disconnect;
 
-	/* initialize audio system: */
-	err = line6_init_audio(line6);
-	if (err < 0)
-		return err;
-
 	/* initialize PCM subsystem: */
 	err = line6_init_pcm(line6, &toneport_pcm_properties);
 	if (err < 0)
@@ -400,7 +411,7 @@
 		return err;
 
 	/* register source select control: */
-	switch (line6->type) {
+	switch (toneport->type) {
 	case LINE6_TONEPORT_UX1:
 	case LINE6_TONEPORT_UX2:
 	case LINE6_PODSTUDIO_UX1:
@@ -416,50 +427,152 @@
 		break;
 	}
 
-	/* register audio system: */
-	err = line6_register_audio(line6);
-	if (err < 0)
-		return err;
-
 	line6_read_serial_number(line6, &toneport->serial_number);
 	line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1);
 
-	if (toneport_has_led(line6->type)) {
-		CHECK_RETURN(device_create_file
-			     (&interface->dev, &dev_attr_led_red));
-		CHECK_RETURN(device_create_file
-			     (&interface->dev, &dev_attr_led_green));
+	if (toneport_has_led(toneport->type)) {
+		err = device_create_file(&interface->dev, &dev_attr_led_red);
+		if (err < 0)
+			return err;
+		err = device_create_file(&interface->dev, &dev_attr_led_green);
+		if (err < 0)
+			return err;
 	}
 
 	toneport_setup(toneport);
 
-	init_timer(&toneport->timer);
-	toneport->timer.expires = jiffies + TONEPORT_PCM_DELAY * HZ;
-	toneport->timer.function = toneport_start_pcm;
-	toneport->timer.data = (unsigned long)toneport;
-	add_timer(&toneport->timer);
+	setup_timer(&toneport->timer, toneport_start_pcm,
+		    (unsigned long)toneport);
+	mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ);
 
-	return 0;
+	/* register audio system: */
+	return snd_card_register(line6->card);
 }
 
-/*
-	 Init Toneport device (and clean up in case of failure).
-*/
-int line6_toneport_init(struct usb_interface *interface,
-			struct usb_line6 *line6)
-{
-	int err = toneport_try_init(interface, line6);
-
-	if (err < 0)
-		toneport_destruct(interface);
-
-	return err;
-}
-
+#ifdef CONFIG_PM
 /*
 	Resume Toneport device after reset.
 */
-void line6_toneport_reset_resume(struct usb_line6_toneport *toneport)
+static int toneport_reset_resume(struct usb_interface *interface)
 {
-	toneport_setup(toneport);
+	toneport_setup(usb_get_intfdata(interface));
+	return line6_resume(interface);
 }
+#endif
+
+#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 toneport_id_table[] = {
+	{ LINE6_DEVICE(0x4750),    .driver_info = LINE6_GUITARPORT },
+	{ LINE6_DEVICE(0x4153),    .driver_info = LINE6_PODSTUDIO_GX },
+	{ LINE6_DEVICE(0x4150),    .driver_info = LINE6_PODSTUDIO_UX1 },
+	{ LINE6_IF_NUM(0x4151, 0), .driver_info = LINE6_PODSTUDIO_UX2 },
+	{ LINE6_DEVICE(0x4147),    .driver_info = LINE6_TONEPORT_GX },
+	{ LINE6_DEVICE(0x4141),    .driver_info = LINE6_TONEPORT_UX1 },
+	{ LINE6_IF_NUM(0x4142, 0), .driver_info = LINE6_TONEPORT_UX2 },
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, toneport_id_table);
+
+static const struct line6_properties toneport_properties_table[] = {
+	[LINE6_GUITARPORT] = {
+		.id = "GuitarPort",
+		.name = "GuitarPort",
+		.capabilities	= LINE6_CAP_PCM,
+		.altsetting = 2,  /* 1..4 seem to be ok */
+		/* no control channel */
+		.ep_audio_r = 0x82,
+		.ep_audio_w = 0x01,
+	},
+	[LINE6_PODSTUDIO_GX] = {
+		.id = "PODStudioGX",
+		.name = "POD Studio GX",
+		.capabilities	= LINE6_CAP_PCM,
+		.altsetting = 2,  /* 1..4 seem to be ok */
+		/* no control channel */
+		.ep_audio_r = 0x82,
+		.ep_audio_w = 0x01,
+	},
+	[LINE6_PODSTUDIO_UX1] = {
+		.id = "PODStudioUX1",
+		.name = "POD Studio UX1",
+		.capabilities	= LINE6_CAP_PCM,
+		.altsetting = 2,  /* 1..4 seem to be ok */
+		/* no control channel */
+		.ep_audio_r = 0x82,
+		.ep_audio_w = 0x01,
+	},
+	[LINE6_PODSTUDIO_UX2] = {
+		.id = "PODStudioUX2",
+		.name = "POD Studio UX2",
+		.capabilities	= LINE6_CAP_PCM,
+		.altsetting = 2,  /* defaults to 44.1kHz, 16-bit */
+		/* no control channel */
+		.ep_audio_r = 0x82,
+		.ep_audio_w = 0x01,
+	},
+	[LINE6_TONEPORT_GX] = {
+		.id = "TonePortGX",
+		.name = "TonePort GX",
+		.capabilities	= LINE6_CAP_PCM,
+		.altsetting = 2,  /* 1..4 seem to be ok */
+		/* no control channel */
+		.ep_audio_r = 0x82,
+		.ep_audio_w = 0x01,
+	},
+	[LINE6_TONEPORT_UX1] = {
+		.id = "TonePortUX1",
+		.name = "TonePort UX1",
+		.capabilities	= LINE6_CAP_PCM,
+		.altsetting = 2,  /* 1..4 seem to be ok */
+		/* no control channel */
+		.ep_audio_r = 0x82,
+		.ep_audio_w = 0x01,
+	},
+	[LINE6_TONEPORT_UX2] = {
+		.id = "TonePortUX2",
+		.name = "TonePort UX2",
+		.capabilities	= LINE6_CAP_PCM,
+		.altsetting = 2,  /* defaults to 44.1kHz, 16-bit */
+		/* no control channel */
+		.ep_audio_r = 0x82,
+		.ep_audio_w = 0x01,
+	},
+};
+
+/*
+	Probe USB device.
+*/
+static int toneport_probe(struct usb_interface *interface,
+			  const struct usb_device_id *id)
+{
+	struct usb_line6_toneport *toneport;
+
+	toneport = kzalloc(sizeof(*toneport), GFP_KERNEL);
+	if (!toneport)
+		return -ENODEV;
+	toneport->type = id->driver_info;
+	return line6_probe(interface, &toneport->line6,
+			   &toneport_properties_table[id->driver_info],
+			   toneport_init);
+}
+
+static struct usb_driver toneport_driver = {
+	.name = KBUILD_MODNAME,
+	.probe = toneport_probe,
+	.disconnect = line6_disconnect,
+#ifdef CONFIG_PM
+	.suspend = line6_suspend,
+	.resume = line6_resume,
+	.reset_resume = toneport_reset_resume,
+#endif
+	.id_table = toneport_id_table,
+};
+
+module_usb_driver(toneport_driver);
+
+MODULE_DESCRIPTION("TonePort USB driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/usb/line6/toneport.h b/sound/usb/line6/toneport.h
deleted file mode 100644
index 8cb1442..0000000
--- a/sound/usb/line6/toneport.h
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License as
- *	published by the Free Software Foundation, version 2.
- *
- */
-
-#ifndef TONEPORT_H
-#define TONEPORT_H
-
-#include <linux/usb.h>
-#include <sound/core.h>
-
-#include "driver.h"
-
-struct usb_line6_toneport {
-	/**
-		Generic Line6 USB data.
-	*/
-	struct usb_line6 line6;
-
-	/**
-		Source selector.
-	*/
-	int source;
-
-	/**
-		Serial number of device.
-	*/
-	int serial_number;
-
-	/**
-		Firmware version (x 100).
-	*/
-	int firmware_version;
-
-	/**
-		 Timer for delayed PCM startup.
-	*/
-	struct timer_list timer;
-};
-
-extern int line6_toneport_init(struct usb_interface *interface,
-			       struct usb_line6 *line6);
-extern void line6_toneport_reset_resume(struct usb_line6_toneport *toneport);
-
-#endif
diff --git a/sound/usb/line6/usbdefs.h b/sound/usb/line6/usbdefs.h
index f4d080e..5ef7bcd 100644
--- a/sound/usb/line6/usbdefs.h
+++ b/sound/usb/line6/usbdefs.h
@@ -1,5 +1,5 @@
 /*
- * Line6 Linux USB driver - 0.9.1beta
+ * Line 6 Linux USB driver
  *
  * Copyright (C) 2005-2008 Markus Grabner (grabner@icg.tugraz.at)
  *
diff --git a/sound/usb/line6/variax.c b/sound/usb/line6/variax.c
index b4a41b0..99a58cb 100644
--- a/sound/usb/line6/variax.c
+++ b/sound/usb/line6/variax.c
@@ -1,5 +1,5 @@
 /*
- * Line6 Linux USB driver - 0.9.1beta
+ * Line 6 Linux USB driver
  *
  * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
  *
@@ -10,10 +10,64 @@
  */
 
 #include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include <sound/core.h>
 
-#include "audio.h"
 #include "driver.h"
-#include "variax.h"
+#include "usbdefs.h"
+
+#define VARIAX_STARTUP_DELAY1 1000
+#define VARIAX_STARTUP_DELAY3 100
+#define VARIAX_STARTUP_DELAY4 100
+
+/*
+	Stages of Variax startup procedure
+*/
+enum {
+	VARIAX_STARTUP_INIT = 1,
+	VARIAX_STARTUP_VERSIONREQ,
+	VARIAX_STARTUP_WAIT,
+	VARIAX_STARTUP_ACTIVATE,
+	VARIAX_STARTUP_WORKQUEUE,
+	VARIAX_STARTUP_SETUP,
+	VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1
+};
+
+enum {
+	LINE6_PODXTLIVE_VARIAX,
+	LINE6_VARIAX
+};
+
+struct usb_line6_variax {
+	/**
+		Generic Line 6 USB data.
+	*/
+	struct usb_line6 line6;
+
+	/**
+		Buffer for activation code.
+	*/
+	unsigned char *buffer_activate;
+
+	/**
+		Handler for device initializaton.
+	*/
+	struct work_struct startup_work;
+
+	/**
+		Timers for device initializaton.
+	*/
+	struct timer_list startup_timer1;
+	struct timer_list startup_timer2;
+
+	/**
+		Current progress in startup procedure.
+	*/
+	int startup_progress;
+};
 
 #define VARIAX_OFFSET_ACTIVATE 7
 
@@ -124,7 +178,7 @@
 	CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
 
 	/* ALSA audio interface: */
-	line6_register_audio(&variax->line6);
+	snd_card_register(variax->line6.card);
 }
 
 /*
@@ -156,13 +210,16 @@
 /*
 	Variax destructor.
 */
-static void variax_destruct(struct usb_interface *interface)
+static void line6_variax_disconnect(struct usb_interface *interface)
 {
-	struct usb_line6_variax *variax = usb_get_intfdata(interface);
+	struct usb_line6_variax *variax;
 
-	if (variax == NULL)
+	if (!interface)
 		return;
-	line6_cleanup_audio(&variax->line6);
+
+	variax = usb_get_intfdata(interface);
+	if (!variax)
+		return;
 
 	del_timer(&variax->startup_timer1);
 	del_timer(&variax->startup_timer2);
@@ -172,21 +229,10 @@
 }
 
 /*
-	Workbench device disconnected.
-*/
-static void line6_variax_disconnect(struct usb_interface *interface)
-{
-	if (interface == NULL)
-		return;
-
-	variax_destruct(interface);
-}
-
-/*
 	 Try to init workbench device.
 */
-static int variax_try_init(struct usb_interface *interface,
-			   struct usb_line6 *line6)
+static int variax_init(struct usb_interface *interface,
+		       struct usb_line6 *line6)
 {
 	struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
 	int err;
@@ -205,15 +251,8 @@
 	variax->buffer_activate = kmemdup(variax_activate,
 					  sizeof(variax_activate), GFP_KERNEL);
 
-	if (variax->buffer_activate == NULL) {
-		dev_err(&interface->dev, "Out of memory\n");
+	if (variax->buffer_activate == NULL)
 		return -ENOMEM;
-	}
-
-	/* initialize audio system: */
-	err = line6_init_audio(&variax->line6);
-	if (err < 0)
-		return err;
 
 	/* initialize MIDI subsystem: */
 	err = line6_init_midi(&variax->line6);
@@ -225,15 +264,71 @@
 	return 0;
 }
 
+#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 variax_id_table[] = {
+	{ LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX },
+	{ LINE6_DEVICE(0x534d),    .driver_info = LINE6_VARIAX },
+	{}
+};
+
+MODULE_DEVICE_TABLE(usb, variax_id_table);
+
+static const struct line6_properties variax_properties_table[] = {
+	[LINE6_PODXTLIVE_VARIAX] = {
+		.id = "PODxtLive",
+		.name = "PODxt Live",
+		.capabilities	= LINE6_CAP_CONTROL
+				| LINE6_CAP_PCM
+				| LINE6_CAP_HWMON,
+		.altsetting = 1,
+		.ep_ctrl_r = 0x86,
+		.ep_ctrl_w = 0x05,
+		.ep_audio_r = 0x82,
+		.ep_audio_w = 0x01,
+	},
+	[LINE6_VARIAX] = {
+		.id = "Variax",
+		.name = "Variax Workbench",
+		.capabilities	= LINE6_CAP_CONTROL,
+		.altsetting = 1,
+		.ep_ctrl_r = 0x82,
+		.ep_ctrl_w = 0x01,
+		/* no audio channel */
+	}
+};
+
 /*
-	 Init workbench device (and clean up in case of failure).
+	Probe USB device.
 */
-int line6_variax_init(struct usb_interface *interface, struct usb_line6 *line6)
+static int variax_probe(struct usb_interface *interface,
+			const struct usb_device_id *id)
 {
-	int err = variax_try_init(interface, line6);
+	struct usb_line6_variax *variax;
 
-	if (err < 0)
-		variax_destruct(interface);
-
-	return err;
+	variax = kzalloc(sizeof(*variax), GFP_KERNEL);
+	if (!variax)
+		return -ENODEV;
+	return line6_probe(interface, &variax->line6,
+			   &variax_properties_table[id->driver_info],
+			   variax_init);
 }
+
+static struct usb_driver variax_driver = {
+	.name = KBUILD_MODNAME,
+	.probe = variax_probe,
+	.disconnect = line6_disconnect,
+#ifdef CONFIG_PM
+	.suspend = line6_suspend,
+	.resume = line6_resume,
+	.reset_resume = line6_resume,
+#endif
+	.id_table = variax_id_table,
+};
+
+module_usb_driver(variax_driver);
+
+MODULE_DESCRIPTION("Vairax Workbench USB driver");
+MODULE_LICENSE("GPL");
diff --git a/sound/usb/line6/variax.h b/sound/usb/line6/variax.h
deleted file mode 100644
index dfb94e5..0000000
--- a/sound/usb/line6/variax.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *
- *	This program is free software; you can redistribute it and/or
- *	modify it under the terms of the GNU General Public License as
- *	published by the Free Software Foundation, version 2.
- *
- */
-
-#ifndef VARIAX_H
-#define VARIAX_H
-
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-#include <linux/wait.h>
-#include <sound/core.h>
-
-#include "driver.h"
-
-#define VARIAX_STARTUP_DELAY1 1000
-#define VARIAX_STARTUP_DELAY3 100
-#define VARIAX_STARTUP_DELAY4 100
-
-/*
-	Stages of Variax startup procedure
-*/
-enum {
-	VARIAX_STARTUP_INIT = 1,
-	VARIAX_STARTUP_VERSIONREQ,
-	VARIAX_STARTUP_WAIT,
-	VARIAX_STARTUP_ACTIVATE,
-	VARIAX_STARTUP_WORKQUEUE,
-	VARIAX_STARTUP_SETUP,
-	VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1
-};
-
-struct usb_line6_variax {
-	/**
-		Generic Line6 USB data.
-	*/
-	struct usb_line6 line6;
-
-	/**
-		Buffer for activation code.
-	*/
-	unsigned char *buffer_activate;
-
-	/**
-		Handler for device initializaton.
-	*/
-	struct work_struct startup_work;
-
-	/**
-		Timers for device initializaton.
-	*/
-	struct timer_list startup_timer1;
-	struct timer_list startup_timer2;
-
-	/**
-		Current progress in startup procedure.
-	*/
-	int startup_progress;
-};
-
-extern int line6_variax_init(struct usb_interface *interface,
-			     struct usb_line6 *line6);
-
-#endif