]> git.karo-electronics.de Git - linux-beck.git/blobdiff - drivers/staging/line6/pod.c
Merge branches 'x86-fixes-for-linus', 'perf-fixes-for-linus' and 'sched-fixes-for...
[linux-beck.git] / drivers / staging / line6 / pod.c
index 28f514611abce4a0f55acdd716c6b907d76571bf..d9b30212585c6851c428a7c525976feb05e7b85d 100644 (file)
@@ -1,7 +1,7 @@
 /*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
  *
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * 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
@@ -9,20 +9,21 @@
  *
  */
 
-#include "driver.h"
-
 #include <linux/slab.h>
+#include <linux/wait.h>
+#include <sound/control.h>
 
 #include "audio.h"
 #include "capture.h"
 #include "control.h"
+#include "driver.h"
 #include "playback.h"
 #include "pod.h"
 
-
 #define POD_SYSEX_CODE 3
-#define POD_BYTES_PER_FRAME 6  /* 24bit audio (stereo) */
+#define POD_BYTES_PER_FRAME 6  /* 24bit audio (stereo) */
 
+/* *INDENT-OFF* */
 
 enum {
        POD_SYSEX_CLIP      = 0x0f,
@@ -45,9 +46,11 @@ enum {
        POD_tuner_freq     = 0x15,
        POD_tuner_note     = 0x16,
        POD_tuner_pitch    = 0x17,
-       POD_system_invalid = 0x7fff
+       POD_system_invalid = 0x10000
 };
 
+/* *INDENT-ON* */
+
 enum {
        POD_DUMP_MEMORY = 2
 };
@@ -60,7 +63,6 @@ enum {
        POD_BUSY_MIDISEND
 };
 
-
 static struct snd_ratden pod_ratden = {
        .num_min = 78125,
        .num_max = 78125,
@@ -69,54 +71,65 @@ static struct snd_ratden pod_ratden = {
 };
 
 static struct line6_pcm_properties pod_pcm_properties = {
-  .snd_line6_playback_hw = {
-               .info = (SNDRV_PCM_INFO_MMAP |
-                                                SNDRV_PCM_INFO_INTERLEAVED |
-                                                SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                                                SNDRV_PCM_INFO_MMAP_VALID |
-                                                SNDRV_PCM_INFO_PAUSE |
-                                                SNDRV_PCM_INFO_SYNC_START),
-               .formats =          SNDRV_PCM_FMTBIT_S24_3LE,
-               .rates =            SNDRV_PCM_RATE_KNOT,
-               .rate_min =         39062,
-               .rate_max =         39063,
-               .channels_min =     2,
-               .channels_max =     2,
-               .buffer_bytes_max = 60000,
-               .period_bytes_min = LINE6_ISO_PACKET_SIZE_MAX * POD_BYTES_PER_FRAME,  /* at least one URB must fit into one period */
-               .period_bytes_max = 8192,
-               .periods_min =      1,
-               .periods_max =      1024
-       },
-  .snd_line6_capture_hw = {
-               .info = (SNDRV_PCM_INFO_MMAP |
-                                                SNDRV_PCM_INFO_INTERLEAVED |
-                                                SNDRV_PCM_INFO_BLOCK_TRANSFER |
-                                                SNDRV_PCM_INFO_MMAP_VALID |
-                                                SNDRV_PCM_INFO_SYNC_START),
-               .formats =          SNDRV_PCM_FMTBIT_S24_3LE,
-               .rates =            SNDRV_PCM_RATE_KNOT,
-               .rate_min =         39062,
-               .rate_max =         39063,
-               .channels_min =     2,
-               .channels_max =     2,
-               .buffer_bytes_max = 60000,
-               .period_bytes_min = LINE6_ISO_PACKET_SIZE_MAX * POD_BYTES_PER_FRAME,  /* at least one URB must fit into one period */
-               .period_bytes_max = 8192,
-               .periods_min =      1,
-               .periods_max =      1024
-       },
+       .snd_line6_playback_hw = {
+                                 .info = (SNDRV_PCM_INFO_MMAP |
+                                          SNDRV_PCM_INFO_INTERLEAVED |
+                                          SNDRV_PCM_INFO_BLOCK_TRANSFER |
+                                          SNDRV_PCM_INFO_MMAP_VALID |
+                                          SNDRV_PCM_INFO_PAUSE |
+#ifdef CONFIG_PM
+                                          SNDRV_PCM_INFO_RESUME |
+#endif
+                                          SNDRV_PCM_INFO_SYNC_START),
+                                 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                 .rates = SNDRV_PCM_RATE_KNOT,
+                                 .rate_min = 39062,
+                                 .rate_max = 39063,
+                                 .channels_min = 2,
+                                 .channels_max = 2,
+                                 .buffer_bytes_max = 60000,
+                                 .period_bytes_min = 64,
+                                 .period_bytes_max = 8192,
+                                 .periods_min = 1,
+                                 .periods_max = 1024},
+       .snd_line6_capture_hw = {
+                                .info = (SNDRV_PCM_INFO_MMAP |
+                                         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,
+                                .rate_min = 39062,
+                                .rate_max = 39063,
+                                .channels_min = 2,
+                                .channels_max = 2,
+                                .buffer_bytes_max = 60000,
+                                .period_bytes_min = 64,
+                                .period_bytes_max = 8192,
+                                .periods_min = 1,
+                                .periods_max = 1024},
        .snd_line6_rates = {
-               .nrats = 1,
-               .rats = &pod_ratden
-       },
+                           .nrats = 1,
+                           .rats = &pod_ratden},
        .bytes_per_frame = POD_BYTES_PER_FRAME
 };
 
-static const char pod_request_version[] = { 0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7 };
-static const char pod_request_channel[] = { 0xf0, 0x00, 0x01, 0x0c, 0x03, 0x75, 0xf7 };
-static const char pod_version_header[]  = { 0xf2, 0x7e, 0x7f, 0x06, 0x02 };
+static const char pod_request_channel[] = {
+       0xf0, 0x00, 0x01, 0x0c, 0x03, 0x75, 0xf7
+};
+
+static const char pod_version_header[] = {
+       0xf2, 0x7e, 0x7f, 0x06, 0x02
+};
 
+/* forward declarations: */
+static void pod_startup2(unsigned long data);
+static void pod_startup3(struct usb_line6_pod *pod);
+static void pod_startup4(struct usb_line6_pod *pod);
 
 /*
        Mark all parameters as dirty and notify waiting processes.
@@ -129,63 +142,11 @@ static void pod_mark_batch_all_dirty(struct usb_line6_pod *pod)
                set_bit(i, pod->param_dirty);
 }
 
-/*
-       Send an asynchronous request for the POD firmware version and device ID.
-*/
-static int pod_version_request_async(struct usb_line6_pod *pod)
-{
-       return line6_send_raw_message_async(&pod->line6, pod->buffer_versionreq, sizeof(pod_request_version));
-}
-
-static void pod_create_files_work(struct work_struct *work)
-{
-       struct usb_line6_pod *pod = container_of(work, struct usb_line6_pod, create_files_work);
-
-       pod_create_files(pod->firmware_version, pod->line6.properties->device_bit, pod->line6.ifcdev);
-}
-
-static void pod_startup_timeout(unsigned long arg)
-{
-       enum {
-               REQUEST_NONE,
-               REQUEST_DUMP,
-               REQUEST_VERSION
-       };
-
-       int request = REQUEST_NONE;
-       struct usb_line6_pod *pod = (struct usb_line6_pod *)arg;
-
-       if (pod->dumpreq.ok) {
-               if (!pod->versionreq_ok)
-                       request = REQUEST_VERSION;
-       } else {
-               if (pod->versionreq_ok)
-                       request = REQUEST_DUMP;
-               else if (pod->startup_count++ & 1)
-                       request = REQUEST_DUMP;
-               else
-                       request = REQUEST_VERSION;
-       }
-
-       switch (request) {
-       case REQUEST_DUMP:
-               line6_dump_request_async(&pod->dumpreq, &pod->line6, 0);
-               break;
-
-       case REQUEST_VERSION:
-               pod_version_request_async(pod);
-               break;
-
-       default:
-               return;
-       }
-
-       line6_startup_delayed(&pod->dumpreq, 1, pod_startup_timeout, pod);
-}
-
-static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code, int size)
+static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code,
+                                   int size)
 {
-       return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code, size);
+       return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code,
+                                       size);
 }
 
 /*
@@ -218,9 +179,10 @@ static void pod_store_parameter(struct usb_line6_pod *pod, int param, int value)
 }
 
 /*
-       Handle SAVE button
+       Handle SAVE button.
 */
-static void pod_save_button_pressed(struct usb_line6_pod *pod, int type, int index)
+static void pod_save_button_pressed(struct usb_line6_pod *pod, int type,
+                                   int index)
 {
        pod->dirty = 0;
        set_bit(POD_SAVE_PRESSED, &pod->atomic_flags);
@@ -229,7 +191,7 @@ static void pod_save_button_pressed(struct usb_line6_pod *pod, int type, int ind
 /*
        Process a completely received message.
 */
-void pod_process_message(struct usb_line6_pod *pod)
+void line6_pod_process_message(struct usb_line6_pod *pod)
 {
        const unsigned char *buf = pod->line6.buffer_message;
 
@@ -238,10 +200,10 @@ void pod_process_message(struct usb_line6_pod *pod)
        case LINE6_PARAM_CHANGE:
        case LINE6_PROGRAM_CHANGE:
        case LINE6_SYSEX_BEGIN:
-               break;  /* handle these further down */
+               break;          /* handle these further down */
 
        default:
-               return;  /* ignore all others */
+               return;         /* ignore all others */
        }
 
        /* process all remaining messages */
@@ -254,7 +216,8 @@ void pod_process_message(struct usb_line6_pod *pod)
                if ((buf[1] == POD_amp_model_setup) ||
                    (buf[1] == POD_effect_setup))
                        /* these also affect other settings */
-                       line6_dump_request_async(&pod->dumpreq, &pod->line6, 0);
+                       line6_dump_request_async(&pod->dumpreq, &pod->line6, 0,
+                                                LINE6_DUMP_CURRENT);
 
                break;
 
@@ -263,7 +226,8 @@ void pod_process_message(struct usb_line6_pod *pod)
                pod->channel_num = buf[1];
                pod->dirty = 0;
                set_bit(POD_CHANNEL_DIRTY, &pod->atomic_flags);
-               line6_dump_request_async(&pod->dumpreq, &pod->line6, 0);
+               line6_dump_request_async(&pod->dumpreq, &pod->line6, 0,
+                                        LINE6_DUMP_CURRENT);
                break;
 
        case LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE:
@@ -271,54 +235,82 @@ void pod_process_message(struct usb_line6_pod *pod)
                if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) == 0) {
                        switch (buf[5]) {
                        case POD_SYSEX_DUMP:
-                               if (pod->line6.message_length == sizeof(pod->prog_data) + 7) {
+                               if (pod->line6.message_length ==
+                                   sizeof(pod->prog_data) + 7) {
                                        switch (pod->dumpreq.in_progress) {
                                        case LINE6_DUMP_CURRENT:
-                                               memcpy(&pod->prog_data, buf + 7, sizeof(pod->prog_data));
+                                               memcpy(&pod->prog_data, buf + 7,
+                                                      sizeof(pod->prog_data));
                                                pod_mark_batch_all_dirty(pod);
-                                               pod->dumpreq.ok = 1;
                                                break;
 
                                        case POD_DUMP_MEMORY:
-                                               memcpy(&pod->prog_data_buf, buf + 7, sizeof(pod->prog_data_buf));
+                                               memcpy(&pod->prog_data_buf,
+                                                      buf + 7,
+                                                      sizeof
+                                                      (pod->prog_data_buf));
                                                break;
 
                                        default:
-                                               DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "unknown dump code %02X\n", pod->dumpreq.in_progress));
+                                               DEBUG_MESSAGES(dev_err
+                                                              (pod->
+                                                               line6.ifcdev,
+                                                               "unknown dump code %02X\n",
+                                                               pod->
+                                                               dumpreq.in_progress));
                                        }
 
                                        line6_dump_finished(&pod->dumpreq);
+                                       pod_startup3(pod);
                                } else
-                                       DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "wrong size of channel dump message (%d instead of %d)\n",
-                                                                                                                                pod->line6.message_length, (int)sizeof(pod->prog_data) + 7));
+                                       DEBUG_MESSAGES(dev_err
+                                                      (pod->line6.ifcdev,
+                                                       "wrong size of channel dump message (%d instead of %d)\n",
+                                                       pod->
+                                                       line6.message_length,
+                                                       (int)
+                                                       sizeof(pod->prog_data) +
+                                                       7));
 
                                break;
 
-                       case POD_SYSEX_SYSTEM: {
-                               short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) | ((int)buf[9] << 4) | (int)buf[10];
+                       case POD_SYSEX_SYSTEM:{
+                                       short value =
+                                           ((int)buf[7] << 12) | ((int)buf[8]
+                                                                  << 8) |
+                                           ((int)buf[9] << 4) | (int)buf[10];
 
 #define PROCESS_SYSTEM_PARAM(x) \
                                        case POD_ ## x: \
                                                pod->x.value = value; \
-                                               wake_up_interruptible(&pod->x.wait); \
+                                               wake_up(&pod->x.wait); \
                                                break;
 
-                               switch (buf[6]) {
-                                       PROCESS_SYSTEM_PARAM(monitor_level);
-                                       PROCESS_SYSTEM_PARAM(routing);
-                                       PROCESS_SYSTEM_PARAM(tuner_mute);
-                                       PROCESS_SYSTEM_PARAM(tuner_freq);
-                                       PROCESS_SYSTEM_PARAM(tuner_note);
-                                       PROCESS_SYSTEM_PARAM(tuner_pitch);
+                                       switch (buf[6]) {
+                                               PROCESS_SYSTEM_PARAM
+                                                   (monitor_level);
+                                               PROCESS_SYSTEM_PARAM(routing);
+                                               PROCESS_SYSTEM_PARAM
+                                                   (tuner_mute);
+                                               PROCESS_SYSTEM_PARAM
+                                                   (tuner_freq);
+                                               PROCESS_SYSTEM_PARAM
+                                                   (tuner_note);
+                                               PROCESS_SYSTEM_PARAM
+                                                   (tuner_pitch);
 
 #undef PROCESS_SYSTEM_PARAM
 
-                               default:
-                                       DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "unknown tuner/system response %02X\n", buf[6]));
-                               }
+                                       default:
+                                               DEBUG_MESSAGES(dev_err
+                                                              (pod->
+                                                               line6.ifcdev,
+                                                               "unknown tuner/system response %02X\n",
+                                                               buf[6]));
+                                       }
 
-                               break;
-                       }
+                                       break;
+                               }
 
                        case POD_SYSEX_FINISH:
                                /* do we need to respond to this? */
@@ -329,32 +321,40 @@ void pod_process_message(struct usb_line6_pod *pod)
                                break;
 
                        case POD_SYSEX_CLIP:
-                               DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "audio clipped\n"));
+                               DEBUG_MESSAGES(dev_err
+                                              (pod->line6.ifcdev,
+                                               "audio clipped\n"));
                                pod->clipping.value = 1;
-                               wake_up_interruptible(&pod->clipping.wait);
+                               wake_up(&pod->clipping.wait);
                                break;
 
                        case POD_SYSEX_STORE:
-                               DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "message %02X not yet implemented\n", buf[5]));
+                               DEBUG_MESSAGES(dev_err
+                                              (pod->line6.ifcdev,
+                                               "message %02X not yet implemented\n",
+                                               buf[5]));
                                break;
 
                        default:
-                               DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "unknown sysex message %02X\n", buf[5]));
+                               DEBUG_MESSAGES(dev_err
+                                              (pod->line6.ifcdev,
+                                               "unknown sysex message %02X\n",
+                                               buf[5]));
                        }
-               } else if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) {
-                       if (pod->versionreq_ok == 0) {
-                               pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15];
-                               pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) | (int)buf[10];
-                               pod->versionreq_ok = 1;
-
-                               /* Now we know the firmware version, so we schedule a bottom half
-                                        handler to create the special files: */
-                               INIT_WORK(&pod->create_files_work, pod_create_files_work);
-                               queue_work(line6_workqueue, &pod->create_files_work);
-                       } else
-                               DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "multiple firmware version message\n"));
                } else
-                       DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "unknown sysex header\n"));
+                   if (memcmp
+                       (buf, pod_version_header,
+                        sizeof(pod_version_header)) == 0) {
+                       pod->firmware_version =
+                           buf[13] * 100 + buf[14] * 10 + buf[15];
+                       pod->device_id =
+                           ((int)buf[8] << 16) | ((int)buf[9] << 8) | (int)
+                           buf[10];
+                       pod_startup4(pod);
+               } else
+                       DEBUG_MESSAGES(dev_err
+                                      (pod->line6.ifcdev,
+                                       "unknown sysex header\n"));
 
                break;
 
@@ -362,7 +362,9 @@ void pod_process_message(struct usb_line6_pod *pod)
                break;
 
        default:
-               DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "POD: unknown message %02X\n", buf[0]));
+               DEBUG_MESSAGES(dev_err
+                              (pod->line6.ifcdev,
+                               "POD: unknown message %02X\n", buf[0]));
        }
 }
 
@@ -377,7 +379,8 @@ void pod_process_message(struct usb_line6_pod *pod)
        *) This method fails if a param change message is "chopped" after the first
        byte.
 */
-void pod_midi_postprocess(struct usb_line6_pod *pod, unsigned char *data, int length)
+void line6_pod_midi_postprocess(struct usb_line6_pod *pod, unsigned char *data,
+                               int length)
 {
        int i;
 
@@ -388,8 +391,11 @@ void pod_midi_postprocess(struct usb_line6_pod *pod, unsigned char *data, int le
                if (data[i] == (LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST)) {
                        line6_invalidate_current(&pod->dumpreq);
                        break;
-               } else if ((data[i] == (LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST)) && (i < length - 1))
-                       if ((data[i + 1] == POD_amp_model_setup) || (data[i + 1] == POD_effect_setup)) {
+               } else
+                   if ((data[i] == (LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST))
+                       && (i < length - 1))
+                       if ((data[i + 1] == POD_amp_model_setup)
+                           || (data[i + 1] == POD_effect_setup)) {
                                line6_invalidate_current(&pod->dumpreq);
                                break;
                        }
@@ -412,19 +418,21 @@ static void pod_send_channel(struct usb_line6_pod *pod, int value)
 /*
        Transmit PODxt Pro control parameter.
 */
-void pod_transmit_parameter(struct usb_line6_pod *pod, int param, int value)
+void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param,
+                                 int value)
 {
        if (line6_transmit_parameter(&pod->line6, param, value) == 0)
                pod_store_parameter(pod, param, value);
 
-       if ((param == POD_amp_model_setup) || (param == POD_effect_setup))  /* these also affect other settings */
+       if ((param == POD_amp_model_setup) || (param == POD_effect_setup))      /* these also affect other settings */
                line6_invalidate_current(&pod->dumpreq);
 }
 
 /*
        Resolve value to memory location.
 */
-static int pod_resolve(const char *buf, short block0, short block1, unsigned char *location)
+static int pod_resolve(const char *buf, short block0, short block1,
+                      unsigned char *location)
 {
        unsigned long value;
        short block;
@@ -444,7 +452,8 @@ static int pod_resolve(const char *buf, short block0, short block1, unsigned cha
 /*
        Send command to store channel/effects setup/amp setup to PODxt Pro.
 */
-static ssize_t pod_send_store_command(struct device *dev, const char *buf, size_t count, short block0, short block1)
+static ssize_t pod_send_store_command(struct device *dev, const char *buf,
+                                     size_t count, short block0, short block1)
 {
        struct usb_interface *interface = to_usb_interface(dev);
        struct usb_line6_pod *pod = usb_get_intfdata(interface);
@@ -455,14 +464,15 @@ static ssize_t pod_send_store_command(struct device *dev, const char *buf, size_
        if (!sysex)
                return 0;
 
-       sysex[SYSEX_DATA_OFS] = 5;  /* see pod_dump() */
+       sysex[SYSEX_DATA_OFS] = 5;      /* see pod_dump() */
        ret = pod_resolve(buf, block0, block1, sysex + SYSEX_DATA_OFS + 1);
        if (ret) {
                kfree(sysex);
                return ret;
        }
 
-       memcpy(sysex + SYSEX_DATA_OFS + 3, &pod->prog_data_buf, sizeof(pod->prog_data_buf));
+       memcpy(sysex + SYSEX_DATA_OFS + 3, &pod->prog_data_buf,
+              sizeof(pod->prog_data_buf));
 
        line6_send_sysex_message(&pod->line6, sysex, size);
        kfree(sysex);
@@ -473,7 +483,9 @@ static ssize_t pod_send_store_command(struct device *dev, const char *buf, size_
 /*
        Send command to retrieve channel/effects setup/amp setup to PODxt Pro.
 */
-static ssize_t pod_send_retrieve_command(struct device *dev, const char *buf, size_t count, short block0, short block1)
+static ssize_t pod_send_retrieve_command(struct device *dev, const char *buf,
+                                        size_t count, short block0,
+                                        short block1)
 {
        struct usb_interface *interface = to_usb_interface(dev);
        struct usb_line6_pod *pod = usb_get_intfdata(interface);
@@ -504,14 +516,15 @@ static ssize_t pod_send_retrieve_command(struct device *dev, const char *buf, si
 /*
        Generic get name function.
 */
-static ssize_t get_name_generic(struct usb_line6_pod *pod, const char *str, char *buf)
+static ssize_t get_name_generic(struct usb_line6_pod *pod, const char *str,
+                               char *buf)
 {
        int length = 0;
        const char *p1;
        char *p2;
        char *last_non_space = buf;
 
-       int retval = line6_wait_dump(&pod->dumpreq, 0);
+       int retval = line6_dump_wait_interruptible(&pod->dumpreq);
        if (retval < 0)
                return retval;
 
@@ -566,7 +579,8 @@ static ssize_t pod_get_name(struct device *dev, struct device_attribute *attr,
 {
        struct usb_interface *interface = to_usb_interface(dev);
        struct usb_line6_pod *pod = usb_get_intfdata(interface);
-       return get_name_generic(pod, pod->prog_data.header + POD_NAME_OFFSET, buf);
+       return get_name_generic(pod, pod->prog_data.header + POD_NAME_OFFSET,
+                               buf);
 }
 
 /*
@@ -577,7 +591,9 @@ static ssize_t pod_get_name_buf(struct device *dev,
 {
        struct usb_interface *interface = to_usb_interface(dev);
        struct usb_line6_pod *pod = usb_get_intfdata(interface);
-       return get_name_generic(pod, pod->prog_data_buf.header + POD_NAME_OFFSET, buf);
+       return get_name_generic(pod,
+                               pod->prog_data_buf.header + POD_NAME_OFFSET,
+                               buf);
 }
 
 /*
@@ -588,7 +604,7 @@ static ssize_t pod_get_dump(struct device *dev, struct device_attribute *attr,
 {
        struct usb_interface *interface = to_usb_interface(dev);
        struct usb_line6_pod *pod = usb_get_intfdata(interface);
-       int retval = line6_wait_dump(&pod->dumpreq, 0);
+       int retval = line6_dump_wait_interruptible(&pod->dumpreq);
        if (retval < 0)
                return retval;
        memcpy(buf, &pod->prog_data, sizeof(pod->prog_data));
@@ -606,8 +622,8 @@ static ssize_t pod_set_dump(struct device *dev, struct device_attribute *attr,
 
        if (count != sizeof(pod->prog_data)) {
                dev_err(pod->line6.ifcdev,
-                       "data block must be exactly %zu bytes\n",
-                       sizeof(pod->prog_data));
+                       "data block must be exactly %d bytes\n",
+                       (int)sizeof(pod->prog_data));
                return -EINVAL;
        }
 
@@ -616,86 +632,116 @@ static ssize_t pod_set_dump(struct device *dev, struct device_attribute *attr,
 }
 
 /*
-       Request system parameter.
+       Identify system parameters related to the tuner.
+*/
+static bool pod_is_tuner(int code)
+{
+       return
+           (code == POD_tuner_mute) ||
+           (code == POD_tuner_freq) ||
+           (code == POD_tuner_note) || (code == POD_tuner_pitch);
+}
+
+/*
+       Get system parameter (as integer).
        @param tuner non-zero, if code refers to a tuner parameter
 */
-static ssize_t pod_get_system_param(struct usb_line6_pod *pod, char *buf, int code, struct ValueWait *param, int tuner, int sign)
+static int pod_get_system_param_int(struct usb_line6_pod *pod, int *value,
+                                   int code, struct ValueWait *param, int sign)
 {
        char *sysex;
-       int value;
        static const int size = 1;
        int retval = 0;
-       DECLARE_WAITQUEUE(wait, current);
 
-       if (((pod->prog_data.control[POD_tuner] & 0x40) == 0) && tuner)
+       if (((pod->prog_data.control[POD_tuner] & 0x40) == 0)
+           && pod_is_tuner(code))
                return -ENODEV;
 
-       /* send value request to tuner: */
+       /* send value request to device: */
        param->value = POD_system_invalid;
        sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEMREQ, size);
+
        if (!sysex)
-               return 0;
+               return -ENOMEM;
+
        sysex[SYSEX_DATA_OFS] = code;
        line6_send_sysex_message(&pod->line6, sysex, size);
        kfree(sysex);
 
-       /* wait for tuner to respond: */
-       add_wait_queue(&param->wait, &wait);
-       current->state = TASK_INTERRUPTIBLE;
+       /* wait for device to respond: */
+       retval =
+           wait_event_interruptible(param->wait,
+                                    param->value != POD_system_invalid);
 
-       while (param->value == POD_system_invalid) {
-               if (signal_pending(current)) {
-                       retval = -ERESTARTSYS;
-                       break;
-               } else
-                       schedule();
-       }
+       if (retval < 0)
+               return retval;
+
+       *value = sign ? (int)(signed short)param->value : (int)(unsigned short)
+           param->value;
 
-       current->state = TASK_RUNNING;
-       remove_wait_queue(&param->wait, &wait);
+       if (*value == POD_system_invalid)
+               *value = 0;     /* don't report uninitialized values */
+
+       return 0;
+}
+
+/*
+       Get system parameter (as string).
+       @param tuner non-zero, if code refers to a tuner parameter
+*/
+static ssize_t pod_get_system_param_string(struct usb_line6_pod *pod, char *buf,
+                                          int code, struct ValueWait *param,
+                                          int sign)
+{
+       int retval, value = 0;
+       retval = pod_get_system_param_int(pod, &value, code, param, sign);
 
        if (retval < 0)
                return retval;
 
-       value = sign ? (int)(signed short)param->value : (int)(unsigned short)param->value;
        return sprintf(buf, "%d\n", value);
 }
 
 /*
-       Send system parameter.
+       Send system parameter (from integer).
        @param tuner non-zero, if code refers to a tuner parameter
 */
-static ssize_t pod_set_system_param(struct usb_line6_pod *pod, const char *buf,
-                                   int count, int code, unsigned short mask,
-                                   int tuner)
+static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
+                                   int code)
 {
        char *sysex;
        static const int size = 5;
-       unsigned short value;
-       unsigned long result;
-       int ret;
 
-       if (((pod->prog_data.control[POD_tuner] & 0x40) == 0) && tuner)
+       if (((pod->prog_data.control[POD_tuner] & 0x40) == 0)
+           && pod_is_tuner(code))
                return -EINVAL;
 
        /* send value to tuner: */
        sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
        if (!sysex)
-               return 0;
-
-       ret = strict_strtoul(buf, 10, &result);
-       if (ret)
-               return ret;
-
-       value = result & mask;
+               return -ENOMEM;
        sysex[SYSEX_DATA_OFS] = code;
        sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f;
-       sysex[SYSEX_DATA_OFS + 2] = (value >>  8) & 0x0f;
-       sysex[SYSEX_DATA_OFS + 3] = (value >>  4) & 0x0f;
-       sysex[SYSEX_DATA_OFS + 4] = (value      ) & 0x0f;
+       sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f;
+       sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f;
+       sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f;
        line6_send_sysex_message(&pod->line6, sysex, size);
        kfree(sysex);
-       return count;
+       return 0;
+}
+
+/*
+       Send system parameter (from string).
+       @param tuner non-zero, if code refers to a tuner parameter
+*/
+static ssize_t pod_set_system_param_string(struct usb_line6_pod *pod,
+                                          const char *buf, int count, int code,
+                                          unsigned short mask)
+{
+       int retval;
+       unsigned short value = simple_strtoul(buf, NULL, 10) & mask;
+       retval = pod_set_system_param_int(pod, value, code);
+       return (retval < 0) ? retval : count;
 }
 
 /*
@@ -706,7 +752,7 @@ static ssize_t pod_get_dump_buf(struct device *dev,
 {
        struct usb_interface *interface = to_usb_interface(dev);
        struct usb_line6_pod *pod = usb_get_intfdata(interface);
-       int retval = line6_wait_dump(&pod->dumpreq, 0);
+       int retval = line6_dump_wait_interruptible(&pod->dumpreq);
        if (retval < 0)
                return retval;
        memcpy(buf, &pod->prog_data_buf, sizeof(pod->prog_data_buf));
@@ -725,8 +771,8 @@ static ssize_t pod_set_dump_buf(struct device *dev,
 
        if (count != sizeof(pod->prog_data)) {
                dev_err(pod->line6.ifcdev,
-                                               "data block must be exactly %zu bytes\n",
-                                               sizeof(pod->prog_data));
+                       "data block must be exactly %d bytes\n",
+                       (int)sizeof(pod->prog_data));
                return -EINVAL;
        }
 
@@ -900,87 +946,203 @@ static ssize_t pod_wait_for_clip(struct device *dev,
 {
        struct usb_interface *interface = to_usb_interface(dev);
        struct usb_line6_pod *pod = usb_get_intfdata(interface);
-       int err = 0;
-       DECLARE_WAITQUEUE(wait, current);
-       pod->clipping.value = 0;
-       add_wait_queue(&pod->clipping.wait, &wait);
-       current->state = TASK_INTERRUPTIBLE;
-
-       while (pod->clipping.value == 0) {
-               if (signal_pending(current)) {
-                       err = -ERESTARTSYS;
-                       break;
-               } else
-                       schedule();
-       }
+       return wait_event_interruptible(pod->clipping.wait,
+                                       pod->clipping.value != 0);
+}
 
-       current->state = TASK_RUNNING;
-       remove_wait_queue(&pod->clipping.wait, &wait);
-       return err;
+/*
+       POD startup procedure.
+       This is a sequence of functions with special requirements (e.g., must
+       not run immediately after initialization, must not run in interrupt
+       context). After the last one has finished, the device is ready to use.
+*/
+
+static void pod_startup1(struct usb_line6_pod *pod)
+{
+       CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT);
+
+       /* delay startup procedure: */
+       line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
+                         (unsigned long)pod);
+}
+
+static void pod_startup2(unsigned long data)
+{
+       struct usb_line6_pod *pod = (struct usb_line6_pod *)data;
+
+       /* schedule another startup procedure until startup is complete: */
+       if (pod->startup_progress >= POD_STARTUP_LAST)
+               return;
+
+       pod->startup_progress = POD_STARTUP_DUMPREQ;
+       line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
+                         (unsigned long)pod);
+
+       /* current channel dump: */
+       line6_dump_request_async(&pod->dumpreq, &pod->line6, 0,
+                                LINE6_DUMP_CURRENT);
+}
+
+static void pod_startup3(struct usb_line6_pod *pod)
+{
+       struct usb_line6 *line6 = &pod->line6;
+       CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ);
+
+       /* request firmware version: */
+       line6_version_request_async(line6);
+}
+
+static void pod_startup4(struct usb_line6_pod *pod)
+{
+       CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE);
+
+       /* schedule work for global work queue: */
+       schedule_work(&pod->startup_work);
 }
 
-#define POD_GET_SYSTEM_PARAM(code, tuner, sign) \
+static void pod_startup5(struct work_struct *work)
+{
+       struct usb_line6_pod *pod =
+           container_of(work, struct usb_line6_pod, startup_work);
+       struct usb_line6 *line6 = &pod->line6;
+
+       CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP);
+
+       /* serial number: */
+       line6_read_serial_number(&pod->line6, &pod->serial_number);
+
+       /* ALSA audio interface: */
+       line6_register_audio(line6);
+
+       /* device files: */
+       line6_pod_create_files(pod->firmware_version,
+                              line6->properties->device_bit, line6->ifcdev);
+}
+
+#define POD_GET_SYSTEM_PARAM(code, sign) \
 static ssize_t pod_get_ ## code(struct device *dev, \
                                struct device_attribute *attr, char *buf) \
 { \
        struct usb_interface *interface = to_usb_interface(dev); \
        struct usb_line6_pod *pod = usb_get_intfdata(interface); \
-       return pod_get_system_param(pod, buf, POD_ ## code, &pod->code, \
-                                   tuner, sign); \
+       return pod_get_system_param_string(pod, buf, POD_ ## code,      \
+                                          &pod->code, sign);           \
 }
 
-#define POD_GET_SET_SYSTEM_PARAM(code, mask, tuner, sign) \
-POD_GET_SYSTEM_PARAM(code, tuner, sign) \
+#define POD_GET_SET_SYSTEM_PARAM(code, mask, sign) \
+POD_GET_SYSTEM_PARAM(code, sign) \
 static ssize_t pod_set_ ## code(struct device *dev, \
                                struct device_attribute *attr, \
                                const char *buf, size_t count) \
 { \
        struct usb_interface *interface = to_usb_interface(dev); \
        struct usb_line6_pod *pod = usb_get_intfdata(interface); \
-       return pod_set_system_param(pod, buf, count, POD_ ## code, mask, \
-                                   tuner); \
+       return pod_set_system_param_string(pod, buf, count, POD_ ## code, mask); \
 }
 
-POD_GET_SET_SYSTEM_PARAM(monitor_level, 0xffff, 0, 0);
-POD_GET_SET_SYSTEM_PARAM(routing, 0x0003, 0, 0);
-POD_GET_SET_SYSTEM_PARAM(tuner_mute, 0x0001, 1, 0);
-POD_GET_SET_SYSTEM_PARAM(tuner_freq, 0xffff, 1, 0);
-POD_GET_SYSTEM_PARAM(tuner_note, 1, 1);
-POD_GET_SYSTEM_PARAM(tuner_pitch, 1, 1);
+POD_GET_SET_SYSTEM_PARAM(monitor_level, 0xffff, 0);
+POD_GET_SET_SYSTEM_PARAM(routing, 0x0003, 0);
+POD_GET_SET_SYSTEM_PARAM(tuner_mute, 0x0001, 0);
+POD_GET_SET_SYSTEM_PARAM(tuner_freq, 0xffff, 0);
+POD_GET_SYSTEM_PARAM(tuner_note, 1);
+POD_GET_SYSTEM_PARAM(tuner_pitch, 1);
 
 #undef GET_SET_SYSTEM_PARAM
 #undef GET_SYSTEM_PARAM
 
 /* POD special files: */
-static DEVICE_ATTR(channel, S_IWUGO | S_IRUGO, pod_get_channel, pod_set_channel);
+static DEVICE_ATTR(channel, S_IWUSR | S_IRUGO, pod_get_channel,
+                  pod_set_channel);
 static DEVICE_ATTR(clip, S_IRUGO, pod_wait_for_clip, line6_nop_write);
 static DEVICE_ATTR(device_id, S_IRUGO, pod_get_device_id, line6_nop_write);
 static DEVICE_ATTR(dirty, S_IRUGO, pod_get_dirty, line6_nop_write);
-static DEVICE_ATTR(dump, S_IWUGO | S_IRUGO, pod_get_dump, pod_set_dump);
-static DEVICE_ATTR(dump_buf, S_IWUGO | S_IRUGO, pod_get_dump_buf, pod_set_dump_buf);
-static DEVICE_ATTR(finish, S_IWUGO, line6_nop_read, pod_set_finish);
-static DEVICE_ATTR(firmware_version, S_IRUGO, pod_get_firmware_version, line6_nop_write);
-static DEVICE_ATTR(midi_postprocess, S_IWUGO | S_IRUGO, pod_get_midi_postprocess, pod_set_midi_postprocess);
-static DEVICE_ATTR(monitor_level, S_IWUGO | S_IRUGO, pod_get_monitor_level, pod_set_monitor_level);
+static DEVICE_ATTR(dump, S_IWUSR | S_IRUGO, pod_get_dump, pod_set_dump);
+static DEVICE_ATTR(dump_buf, S_IWUSR | S_IRUGO, pod_get_dump_buf,
+                  pod_set_dump_buf);
+static DEVICE_ATTR(finish, S_IWUSR, line6_nop_read, pod_set_finish);
+static DEVICE_ATTR(firmware_version, S_IRUGO, pod_get_firmware_version,
+                  line6_nop_write);
+static DEVICE_ATTR(midi_postprocess, S_IWUSR | S_IRUGO,
+                  pod_get_midi_postprocess, pod_set_midi_postprocess);
+static DEVICE_ATTR(monitor_level, S_IWUSR | S_IRUGO, pod_get_monitor_level,
+                  pod_set_monitor_level);
 static DEVICE_ATTR(name, S_IRUGO, pod_get_name, line6_nop_write);
 static DEVICE_ATTR(name_buf, S_IRUGO, pod_get_name_buf, line6_nop_write);
-static DEVICE_ATTR(retrieve_amp_setup, S_IWUGO, line6_nop_read, pod_set_retrieve_amp_setup);
-static DEVICE_ATTR(retrieve_channel, S_IWUGO, line6_nop_read, pod_set_retrieve_channel);
-static DEVICE_ATTR(retrieve_effects_setup, S_IWUGO, line6_nop_read, pod_set_retrieve_effects_setup);
-static DEVICE_ATTR(routing, S_IWUGO | S_IRUGO, pod_get_routing, pod_set_routing);
-static DEVICE_ATTR(serial_number, S_IRUGO, pod_get_serial_number, line6_nop_write);
-static DEVICE_ATTR(store_amp_setup, S_IWUGO, line6_nop_read, pod_set_store_amp_setup);
-static DEVICE_ATTR(store_channel, S_IWUGO, line6_nop_read, pod_set_store_channel);
-static DEVICE_ATTR(store_effects_setup, S_IWUGO, line6_nop_read, pod_set_store_effects_setup);
-static DEVICE_ATTR(tuner_freq, S_IWUGO | S_IRUGO, pod_get_tuner_freq, pod_set_tuner_freq);
-static DEVICE_ATTR(tuner_mute, S_IWUGO | S_IRUGO, pod_get_tuner_mute, pod_set_tuner_mute);
+static DEVICE_ATTR(retrieve_amp_setup, S_IWUSR, line6_nop_read,
+                  pod_set_retrieve_amp_setup);
+static DEVICE_ATTR(retrieve_channel, S_IWUSR, line6_nop_read,
+                  pod_set_retrieve_channel);
+static DEVICE_ATTR(retrieve_effects_setup, S_IWUSR, line6_nop_read,
+                  pod_set_retrieve_effects_setup);
+static DEVICE_ATTR(routing, S_IWUSR | S_IRUGO, pod_get_routing,
+                  pod_set_routing);
+static DEVICE_ATTR(serial_number, S_IRUGO, pod_get_serial_number,
+                  line6_nop_write);
+static DEVICE_ATTR(store_amp_setup, S_IWUSR, line6_nop_read,
+                  pod_set_store_amp_setup);
+static DEVICE_ATTR(store_channel, S_IWUSR, line6_nop_read,
+                  pod_set_store_channel);
+static DEVICE_ATTR(store_effects_setup, S_IWUSR, line6_nop_read,
+                  pod_set_store_effects_setup);
+static DEVICE_ATTR(tuner_freq, S_IWUSR | S_IRUGO, pod_get_tuner_freq,
+                  pod_set_tuner_freq);
+static DEVICE_ATTR(tuner_mute, S_IWUSR | S_IRUGO, pod_get_tuner_mute,
+                  pod_set_tuner_mute);
 static DEVICE_ATTR(tuner_note, S_IRUGO, pod_get_tuner_note, line6_nop_write);
 static DEVICE_ATTR(tuner_pitch, S_IRUGO, pod_get_tuner_pitch, line6_nop_write);
 
-#if CREATE_RAW_FILE
-static DEVICE_ATTR(raw, S_IWUGO, line6_nop_read, line6_set_raw);
+#ifdef CONFIG_LINE6_USB_RAW
+static DEVICE_ATTR(raw, S_IWUSR, line6_nop_read, line6_set_raw);
 #endif
 
+/* control info callback */
+static int snd_pod_control_monitor_info(struct snd_kcontrol *kcontrol,
+                                       struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 65535;
+       return 0;
+}
+
+/* control get callback */
+static int snd_pod_control_monitor_get(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+       struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
+       ucontrol->value.integer.value[0] = pod->monitor_level.value;
+       return 0;
+}
+
+/* control put callback */
+static int snd_pod_control_monitor_put(struct snd_kcontrol *kcontrol,
+                                      struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+       struct usb_line6_pod *pod = (struct usb_line6_pod *)line6pcm->line6;
+
+       if (ucontrol->value.integer.value[0] == pod->monitor_level.value)
+               return 0;
+
+       pod->monitor_level.value = ucontrol->value.integer.value[0];
+       pod_set_system_param_int(pod, ucontrol->value.integer.value[0],
+                                POD_monitor_level);
+       return 1;
+}
+
+/* control definition */
+static struct snd_kcontrol_new pod_control_monitor = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Monitor Playback Volume",
+       .index = 0,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info = snd_pod_control_monitor_info,
+       .get = snd_pod_control_monitor_get,
+       .put = snd_pod_control_monitor_put
+};
+
 /*
        POD destructor.
 */
@@ -996,10 +1158,11 @@ static void pod_destruct(struct usb_interface *interface)
                return;
        line6_cleanup_audio(line6);
 
+       del_timer(&pod->startup_timer);
+       cancel_work_sync(&pod->startup_work);
+
        /* free dump request data: */
        line6_dumpreq_destruct(&pod->dumpreq);
-
-       kfree(pod->buffer_versionreq);
 }
 
 /*
@@ -1034,7 +1197,7 @@ static int pod_create_files2(struct device *dev)
        CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_note));
        CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_pitch));
 
-#if CREATE_RAW_FILE
+#ifdef CONFIG_LINE6_USB_RAW
        CHECK_RETURN(device_create_file(dev, &dev_attr_raw));
 #endif
 
@@ -1042,13 +1205,17 @@ static int pod_create_files2(struct device *dev)
 }
 
 /*
-        Init POD device.
+        Try to init POD device.
 */
-int pod_init(struct usb_interface *interface, struct usb_line6_pod *pod)
+static int pod_try_init(struct usb_interface *interface,
+                       struct usb_line6_pod *pod)
 {
        int err;
        struct usb_line6 *line6 = &pod->line6;
 
+       init_timer(&pod->startup_timer);
+       INIT_WORK(&pod->startup_work, pod_startup5);
+
        if ((interface == NULL) || (pod == NULL))
                return -ENODEV;
 
@@ -1070,69 +1237,68 @@ int pod_init(struct usb_interface *interface, struct usb_line6_pod *pod)
                                 sizeof(pod_request_channel));
        if (err < 0) {
                dev_err(&interface->dev, "Out of memory\n");
-               pod_destruct(interface);
-               return -ENOMEM;
-       }
-
-       pod->buffer_versionreq = kmemdup(pod_request_version,
-                                        sizeof(pod_request_version),
-                                        GFP_KERNEL);
-
-       if (pod->buffer_versionreq == NULL) {
-               dev_err(&interface->dev, "Out of memory\n");
-               pod_destruct(interface);
                return -ENOMEM;
        }
 
        /* create sysfs entries: */
        err = pod_create_files2(&interface->dev);
-       if (err < 0) {
-               pod_destruct(interface);
+       if (err < 0)
                return err;
-       }
 
        /* initialize audio system: */
        err = line6_init_audio(line6);
-       if (err < 0) {
-               pod_destruct(interface);
+       if (err < 0)
                return err;
-       }
 
        /* initialize MIDI subsystem: */
        err = line6_init_midi(line6);
-       if (err < 0) {
-               pod_destruct(interface);
+       if (err < 0)
                return err;
-       }
 
        /* initialize PCM subsystem: */
        err = line6_init_pcm(line6, &pod_pcm_properties);
-       if (err < 0) {
-               pod_destruct(interface);
+       if (err < 0)
                return err;
-       }
 
-       /* register audio system: */
-       err = line6_register_audio(line6);
-       if (err < 0) {
-               pod_destruct(interface);
+       /* register monitor control: */
+       err = snd_ctl_add(line6->card,
+                         snd_ctl_new1(&pod_control_monitor, line6->line6pcm));
+       if (err < 0)
                return err;
-       }
+
+       /*
+          When the sound card is registered at this point, the PODxt Live
+          displays "Invalid Code Error 07", so we do it later in the event
+          handler.
+        */
 
        if (pod->line6.properties->capabilities & LINE6_BIT_CONTROL) {
-               /* query some data: */
-               line6_startup_delayed(&pod->dumpreq, POD_STARTUP_DELAY,
-                                     pod_startup_timeout, pod);
-               line6_read_serial_number(&pod->line6, &pod->serial_number);
+               pod->monitor_level.value = POD_system_invalid;
+
+               /* initiate startup procedure: */
+               pod_startup1(pod);
        }
 
        return 0;
 }
 
+/*
+        Init POD device (and clean up in case of failure).
+*/
+int line6_pod_init(struct usb_interface *interface, struct usb_line6_pod *pod)
+{
+       int err = pod_try_init(interface, pod);
+
+       if (err < 0)
+               pod_destruct(interface);
+
+       return err;
+}
+
 /*
        POD device disconnected.
 */
-void pod_disconnect(struct usb_interface *interface)
+void line6_pod_disconnect(struct usb_interface *interface)
 {
        struct usb_line6_pod *pod;
 
@@ -1144,15 +1310,14 @@ void pod_disconnect(struct usb_interface *interface)
                struct snd_line6_pcm *line6pcm = pod->line6.line6pcm;
                struct device *dev = &interface->dev;
 
-               if (line6pcm != NULL) {
-                       unlink_wait_clear_audio_out_urbs(line6pcm);
-                       unlink_wait_clear_audio_in_urbs(line6pcm);
-               }
+               if (line6pcm != NULL)
+                       line6_pcm_disconnect(line6pcm);
 
                if (dev != NULL) {
                        /* remove sysfs entries: */
-                       if (pod->versionreq_ok)
-                               pod_remove_files(pod->firmware_version, pod->line6.properties->device_bit, dev);
+                       line6_pod_remove_files(pod->firmware_version,
+                                              pod->line6.
+                                              properties->device_bit, dev);
 
                        device_remove_file(dev, &dev_attr_channel);
                        device_remove_file(dev, &dev_attr_clip);
@@ -1168,7 +1333,8 @@ void pod_disconnect(struct usb_interface *interface)
                        device_remove_file(dev, &dev_attr_name_buf);
                        device_remove_file(dev, &dev_attr_retrieve_amp_setup);
                        device_remove_file(dev, &dev_attr_retrieve_channel);
-                       device_remove_file(dev, &dev_attr_retrieve_effects_setup);
+                       device_remove_file(dev,
+                                          &dev_attr_retrieve_effects_setup);
                        device_remove_file(dev, &dev_attr_routing);
                        device_remove_file(dev, &dev_attr_serial_number);
                        device_remove_file(dev, &dev_attr_store_amp_setup);
@@ -1179,7 +1345,7 @@ void pod_disconnect(struct usb_interface *interface)
                        device_remove_file(dev, &dev_attr_tuner_note);
                        device_remove_file(dev, &dev_attr_tuner_pitch);
 
-#if CREATE_RAW_FILE
+#ifdef CONFIG_LINE6_USB_RAW
                        device_remove_file(dev, &dev_attr_raw);
 #endif
                }