ALSA: move line6 usb driver into sound/usb
authorTakashi Iwai <tiwai@suse.de>
Mon, 12 Jan 2015 21:29:57 +0000 (22:29 +0100)
committerTakashi Iwai <tiwai@suse.de>
Mon, 12 Jan 2015 21:29:57 +0000 (22:29 +0100)
Promote line6 driver from staging to sound/usb/line6 directory, and
maintain through sound subsystem tree.

This commit just moves the code and adapts Makefile / Kconfig.
The further renames and misc cleanups will follow.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
56 files changed:
drivers/staging/Kconfig
drivers/staging/Makefile
drivers/staging/line6/Kconfig [deleted file]
drivers/staging/line6/Makefile [deleted file]
drivers/staging/line6/audio.c [deleted file]
drivers/staging/line6/audio.h [deleted file]
drivers/staging/line6/capture.c [deleted file]
drivers/staging/line6/capture.h [deleted file]
drivers/staging/line6/driver.c [deleted file]
drivers/staging/line6/driver.h [deleted file]
drivers/staging/line6/midi.c [deleted file]
drivers/staging/line6/midi.h [deleted file]
drivers/staging/line6/midibuf.c [deleted file]
drivers/staging/line6/midibuf.h [deleted file]
drivers/staging/line6/pcm.c [deleted file]
drivers/staging/line6/pcm.h [deleted file]
drivers/staging/line6/playback.c [deleted file]
drivers/staging/line6/playback.h [deleted file]
drivers/staging/line6/pod.c [deleted file]
drivers/staging/line6/pod.h [deleted file]
drivers/staging/line6/podhd.c [deleted file]
drivers/staging/line6/podhd.h [deleted file]
drivers/staging/line6/revision.h [deleted file]
drivers/staging/line6/toneport.c [deleted file]
drivers/staging/line6/toneport.h [deleted file]
drivers/staging/line6/usbdefs.h [deleted file]
drivers/staging/line6/variax.c [deleted file]
drivers/staging/line6/variax.h [deleted file]
sound/usb/Kconfig
sound/usb/Makefile
sound/usb/line6/Kconfig [new file with mode: 0644]
sound/usb/line6/Makefile [new file with mode: 0644]
sound/usb/line6/audio.c [new file with mode: 0644]
sound/usb/line6/audio.h [new file with mode: 0644]
sound/usb/line6/capture.c [new file with mode: 0644]
sound/usb/line6/capture.h [new file with mode: 0644]
sound/usb/line6/driver.c [new file with mode: 0644]
sound/usb/line6/driver.h [new file with mode: 0644]
sound/usb/line6/midi.c [new file with mode: 0644]
sound/usb/line6/midi.h [new file with mode: 0644]
sound/usb/line6/midibuf.c [new file with mode: 0644]
sound/usb/line6/midibuf.h [new file with mode: 0644]
sound/usb/line6/pcm.c [new file with mode: 0644]
sound/usb/line6/pcm.h [new file with mode: 0644]
sound/usb/line6/playback.c [new file with mode: 0644]
sound/usb/line6/playback.h [new file with mode: 0644]
sound/usb/line6/pod.c [new file with mode: 0644]
sound/usb/line6/pod.h [new file with mode: 0644]
sound/usb/line6/podhd.c [new file with mode: 0644]
sound/usb/line6/podhd.h [new file with mode: 0644]
sound/usb/line6/revision.h [new file with mode: 0644]
sound/usb/line6/toneport.c [new file with mode: 0644]
sound/usb/line6/toneport.h [new file with mode: 0644]
sound/usb/line6/usbdefs.h [new file with mode: 0644]
sound/usb/line6/variax.c [new file with mode: 0644]
sound/usb/line6/variax.h [new file with mode: 0644]

index 815de379a1309c9acc49366ccd9a2a6ef3cf44b3..9049dd91b5694658345999ce20a422c1e99fedd5 100644 (file)
@@ -46,8 +46,6 @@ source "drivers/staging/rtl8723au/Kconfig"
 
 source "drivers/staging/rts5208/Kconfig"
 
-source "drivers/staging/line6/Kconfig"
-
 source "drivers/staging/octeon/Kconfig"
 
 source "drivers/staging/octeon-usb/Kconfig"
index 33c640b4956649cea2ecd50e6dc5439669004842..fe26ff162b428c7a7e634f94639b13ca6abd47be 100644 (file)
@@ -15,7 +15,6 @@ obj-$(CONFIG_R8712U)          += rtl8712/
 obj-$(CONFIG_R8188EU)          += rtl8188eu/
 obj-$(CONFIG_R8723AU)          += rtl8723au/
 obj-$(CONFIG_RTS5208)          += rts5208/
-obj-$(CONFIG_LINE6_USB)                += line6/
 obj-$(CONFIG_NETLOGIC_XLR_NET) += netlogic/
 obj-$(CONFIG_OCTEON_ETHERNET)  += octeon/
 obj-$(CONFIG_OCTEON_USB)       += octeon-usb/
diff --git a/drivers/staging/line6/Kconfig b/drivers/staging/line6/Kconfig
deleted file mode 100644 (file)
index 4f1219b..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-menuconfig LINE6_USB
-       tristate "Line6 USB support"
-       depends on USB && SND
-       select SND_RAWMIDI
-       select SND_PCM
-       help
-         This is a driver for the guitar amp, cab, and effects modeller
-         PODxt Pro by Line6 (and similar devices), supporting the
-         following features:
-           * Reading/writing individual parameters
-           * Reading/writing complete channel, effects setup, and amp
-             setup data
-           * Channel switching
-           * Virtual MIDI interface
-           * Tuner access
-           * Playback/capture/mixer device for any ALSA-compatible PCM
-             audio application
-           * 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
-       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.
-
-         If unsure, say N.
-
-endif # LINE6_USB
diff --git a/drivers/staging/line6/Makefile b/drivers/staging/line6/Makefile
deleted file mode 100644 (file)
index ae5c374..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-obj-$(CONFIG_LINE6_USB)                += line6usb.o
-
-line6usb-y :=          \
-               audio.o         \
-               capture.o       \
-               driver.o        \
-               midi.o          \
-               midibuf.o       \
-               pcm.o           \
-               playback.o      \
-               pod.o           \
-               toneport.o      \
-               variax.o        \
-               podhd.o
diff --git a/drivers/staging/line6/audio.c b/drivers/staging/line6/audio.c
deleted file mode 100644 (file)
index 171d80c..0000000
+++ /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/drivers/staging/line6/audio.h b/drivers/staging/line6/audio.h
deleted file mode 100644 (file)
index 5f8a09a..0000000
+++ /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/drivers/staging/line6/capture.c b/drivers/staging/line6/capture.c
deleted file mode 100644 (file)
index f24c7c5..0000000
+++ /dev/null
@@ -1,433 +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 <linux/slab.h>
-#include <sound/core.h>
-#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.
-*/
-static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)
-{
-       int index;
-       unsigned long flags;
-       int i, urb_size;
-       int ret;
-       struct urb *urb_in;
-
-       spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
-       index =
-           find_first_zero_bit(&line6pcm->active_urb_in, LINE6_ISO_BUFFERS);
-
-       if (index < 0 || index >= LINE6_ISO_BUFFERS) {
-               spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
-               dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
-               return -EINVAL;
-       }
-
-       urb_in = line6pcm->urb_audio_in[index];
-       urb_size = 0;
-
-       for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
-               struct usb_iso_packet_descriptor *fin =
-                   &urb_in->iso_frame_desc[i];
-               fin->offset = urb_size;
-               fin->length = line6pcm->max_packet_size;
-               urb_size += line6pcm->max_packet_size;
-       }
-
-       urb_in->transfer_buffer =
-           line6pcm->buffer_in +
-           index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
-       urb_in->transfer_buffer_length = urb_size;
-       urb_in->context = line6pcm;
-
-       ret = usb_submit_urb(urb_in, GFP_ATOMIC);
-
-       if (ret == 0)
-               set_bit(index, &line6pcm->active_urb_in);
-       else
-               dev_err(line6pcm->line6->ifcdev,
-                       "URB in #%d submission failed (%d)\n", index, ret);
-
-       spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
-       return 0;
-}
-
-/*
-       Submit all currently available capture URBs.
-*/
-int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm)
-{
-       int ret, i;
-
-       for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
-               ret = submit_audio_in_urb(line6pcm);
-               if (ret < 0)
-                       return ret;
-       }
-
-       return 0;
-}
-
-/*
-       Unlink all currently active capture URBs.
-*/
-void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm)
-{
-       unsigned int i;
-
-       for (i = LINE6_ISO_BUFFERS; i--;) {
-               if (test_bit(i, &line6pcm->active_urb_in)) {
-                       if (!test_and_set_bit(i, &line6pcm->unlink_urb_in)) {
-                               struct urb *u = line6pcm->urb_audio_in[i];
-
-                               usb_unlink_urb(u);
-                       }
-               }
-       }
-}
-
-/*
-       Wait until unlinking of all currently active capture URBs has been
-       finished.
-*/
-void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
-{
-       int timeout = HZ;
-       unsigned int i;
-       int alive;
-
-       do {
-               alive = 0;
-               for (i = LINE6_ISO_BUFFERS; i--;) {
-                       if (test_bit(i, &line6pcm->active_urb_in))
-                               alive++;
-               }
-               if (!alive)
-                       break;
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(1);
-       } while (--timeout > 0);
-       if (alive)
-               snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
-}
-
-/*
-       Unlink all currently active capture URBs, and wait for finishing.
-*/
-void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
-{
-       line6_unlink_audio_in_urbs(line6pcm);
-       line6_wait_clear_audio_in_urbs(line6pcm);
-}
-
-/*
-       Copy data into ALSA capture buffer.
-*/
-void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize)
-{
-       struct snd_pcm_substream *substream =
-           get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
-       int frames = fsize / bytes_per_frame;
-
-       if (runtime == NULL)
-               return;
-
-       if (line6pcm->pos_in_done + frames > runtime->buffer_size) {
-               /*
-                  The transferred area goes over buffer boundary,
-                  copy two separate chunks.
-                */
-               int len;
-
-               len = runtime->buffer_size - line6pcm->pos_in_done;
-
-               if (len > 0) {
-                       memcpy(runtime->dma_area +
-                              line6pcm->pos_in_done * bytes_per_frame, fbuf,
-                              len * bytes_per_frame);
-                       memcpy(runtime->dma_area, fbuf + len * bytes_per_frame,
-                              (frames - len) * bytes_per_frame);
-               } else {
-                       /* this is somewhat paranoid */
-                       dev_err(line6pcm->line6->ifcdev,
-                               "driver bug: len = %d\n", len);
-               }
-       } else {
-               /* copy single chunk */
-               memcpy(runtime->dma_area +
-                      line6pcm->pos_in_done * bytes_per_frame, fbuf, fsize);
-       }
-
-       line6pcm->pos_in_done += frames;
-       if (line6pcm->pos_in_done >= runtime->buffer_size)
-               line6pcm->pos_in_done -= runtime->buffer_size;
-}
-
-void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length)
-{
-       struct snd_pcm_substream *substream =
-           get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
-
-       line6pcm->bytes_in += length;
-       if (line6pcm->bytes_in >= line6pcm->period_in) {
-               line6pcm->bytes_in %= line6pcm->period_in;
-               snd_pcm_period_elapsed(substream);
-       }
-}
-
-void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm)
-{
-       kfree(line6pcm->buffer_in);
-       line6pcm->buffer_in = NULL;
-}
-
-/*
- * Callback for completed capture URB.
- */
-static void audio_in_callback(struct urb *urb)
-{
-       int i, index, length = 0, shutdown = 0;
-       unsigned long flags;
-
-       struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;
-
-       line6pcm->last_frame_in = urb->start_frame;
-
-       /* find index of URB */
-       for (index = 0; index < LINE6_ISO_BUFFERS; ++index)
-               if (urb == line6pcm->urb_audio_in[index])
-                       break;
-
-       spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
-
-       for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
-               char *fbuf;
-               int fsize;
-               struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i];
-
-               if (fin->status == -EXDEV) {
-                       shutdown = 1;
-                       break;
-               }
-
-               fbuf = urb->transfer_buffer + fin->offset;
-               fsize = fin->actual_length;
-
-               if (fsize > line6pcm->max_packet_size) {
-                       dev_err(line6pcm->line6->ifcdev,
-                               "driver and/or device bug: packet too large (%d > %d)\n",
-                               fsize, line6pcm->max_packet_size);
-               }
-
-               length += fsize;
-
-               /* the following assumes LINE6_ISO_PACKETS == 1: */
-               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);
-       }
-
-       clear_bit(index, &line6pcm->active_urb_in);
-
-       if (test_and_clear_bit(index, &line6pcm->unlink_urb_in))
-               shutdown = 1;
-
-       spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
-
-       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);
-       }
-}
-
-/* open capture callback */
-static int snd_line6_capture_open(struct snd_pcm_substream *substream)
-{
-       int err;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
-       err = snd_pcm_hw_constraint_ratdens(runtime, 0,
-                                           SNDRV_PCM_HW_PARAM_RATE,
-                                           (&line6pcm->
-                                            properties->snd_line6_rates));
-       if (err < 0)
-               return err;
-
-       runtime->hw = line6pcm->properties->snd_line6_capture_hw;
-       return 0;
-}
-
-/* close capture callback */
-static int snd_line6_capture_close(struct snd_pcm_substream *substream)
-{
-       return 0;
-}
-
-/* hw_params capture callback */
-static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream,
-                                      struct snd_pcm_hw_params *hw_params)
-{
-       int ret;
-       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
-       /* -- Florian Demski [FD] */
-       /* don't ask me why, but this fixes the bug on my machine */
-       if (line6pcm == NULL) {
-               if (substream->pcm == NULL)
-                       return -ENOMEM;
-               if (substream->pcm->private_data == NULL)
-                       return -ENOMEM;
-               substream->private_data = substream->pcm->private_data;
-               line6pcm = snd_pcm_substream_chip(substream);
-       }
-       /* -- [FD] end */
-
-       ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
-
-       if (ret < 0)
-               return ret;
-
-       ret = snd_pcm_lib_malloc_pages(substream,
-                                      params_buffer_bytes(hw_params));
-       if (ret < 0) {
-               line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
-               return ret;
-       }
-
-       line6pcm->period_in = params_period_bytes(hw_params);
-       return 0;
-}
-
-/* hw_free capture callback */
-static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
-       line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
-       return snd_pcm_lib_free_pages(substream);
-}
-
-/* trigger callback */
-int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd)
-{
-       int err;
-
-       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);
-
-               if (err < 0)
-                       return err;
-
-               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);
-
-               if (err < 0)
-                       return err;
-
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/* capture pointer callback */
-static snd_pcm_uframes_t
-snd_line6_capture_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
-       return line6pcm->pos_in_done;
-}
-
-/* capture operators */
-struct snd_pcm_ops snd_line6_capture_ops = {
-       .open = snd_line6_capture_open,
-       .close = snd_line6_capture_close,
-       .ioctl = snd_pcm_lib_ioctl,
-       .hw_params = snd_line6_capture_hw_params,
-       .hw_free = snd_line6_capture_hw_free,
-       .prepare = snd_line6_prepare,
-       .trigger = snd_line6_trigger,
-       .pointer = snd_line6_capture_pointer,
-};
-
-int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
-{
-       struct usb_line6 *line6 = line6pcm->line6;
-       int i;
-
-       /* create audio URBs and fill in constant values: */
-       for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
-               struct urb *urb;
-
-               /* URB for audio in: */
-               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");
-                       return -ENOMEM;
-               }
-
-               urb->dev = line6->usbdev;
-               urb->pipe =
-                   usb_rcvisocpipe(line6->usbdev,
-                                   line6->properties->ep_audio_r &
-                                   USB_ENDPOINT_NUMBER_MASK);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->start_frame = -1;
-               urb->number_of_packets = LINE6_ISO_PACKETS;
-               urb->interval = LINE6_ISO_INTERVAL;
-               urb->error_count = 0;
-               urb->complete = audio_in_callback;
-       }
-
-       return 0;
-}
diff --git a/drivers/staging/line6/capture.h b/drivers/staging/line6/capture.h
deleted file mode 100644 (file)
index 4157bcb..0000000
+++ /dev/null
@@ -1,35 +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 CAPTURE_H
-#define CAPTURE_H
-
-#include <sound/pcm.h>
-
-#include "driver.h"
-#include "pcm.h"
-
-extern struct snd_pcm_ops snd_line6_capture_ops;
-
-extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf,
-                              int fsize);
-extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm,
-                                      int length);
-extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm);
-extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm
-                                                 *line6pcm);
-extern void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm);
-extern int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd);
-
-#endif
diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c
deleted file mode 100644 (file)
index fc852f6..0000000
+++ /dev/null
@@ -1,1114 +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 <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/usb.h>
-
-#include "audio.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 */
-       }
-};
-
-/*
-       This is Line6's MIDI manufacturer ID.
-*/
-const unsigned char line6_midi_id[] = {
-       0x00, 0x01, 0x0c
-};
-
-/*
-       Code to request version of POD, Variax interface
-       (and maybe other devices).
-*/
-static const char line6_request_version[] = {
-       0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7
-};
-
-/**
-        Class for asynchronous messages.
-*/
-struct message {
-       struct usb_line6 *line6;
-       const char *buffer;
-       int size;
-       int done;
-};
-
-/*
-       Forward declarations.
-*/
-static void line6_data_received(struct urb *urb);
-static int line6_send_raw_message_async_part(struct message *msg,
-                                            struct urb *urb);
-
-/*
-       Start to listen on endpoint.
-*/
-static int line6_start_listen(struct usb_line6 *line6)
-{
-       int err;
-
-       usb_fill_int_urb(line6->urb_listen, line6->usbdev,
-               usb_rcvintpipe(line6->usbdev, line6->properties->ep_ctrl_r),
-               line6->buffer_listen, LINE6_BUFSIZE_LISTEN,
-               line6_data_received, line6, line6->interval);
-       line6->urb_listen->actual_length = 0;
-       err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC);
-       return err;
-}
-
-/*
-       Stop listening on endpoint.
-*/
-static void line6_stop_listen(struct usb_line6 *line6)
-{
-       usb_kill_urb(line6->urb_listen);
-}
-
-/*
-       Send raw message in pieces of wMaxPacketSize bytes.
-*/
-int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
-                          int size)
-{
-       int i, done = 0;
-
-       for (i = 0; i < size; i += line6->max_packet_size) {
-               int partial;
-               const char *frag_buf = buffer + i;
-               int frag_size = min(line6->max_packet_size, size - i);
-               int retval;
-
-               retval = usb_interrupt_msg(line6->usbdev,
-                                       usb_sndintpipe(line6->usbdev,
-                                               line6->properties->ep_ctrl_w),
-                                       (char *)frag_buf, frag_size,
-                                       &partial, LINE6_TIMEOUT * HZ);
-
-               if (retval) {
-                       dev_err(line6->ifcdev,
-                               "usb_interrupt_msg failed (%d)\n", retval);
-                       break;
-               }
-
-               done += frag_size;
-       }
-
-       return done;
-}
-
-/*
-       Notification of completion of asynchronous request transmission.
-*/
-static void line6_async_request_sent(struct urb *urb)
-{
-       struct message *msg = (struct message *)urb->context;
-
-       if (msg->done >= msg->size) {
-               usb_free_urb(urb);
-               kfree(msg);
-       } else
-               line6_send_raw_message_async_part(msg, urb);
-}
-
-/*
-       Asynchronously send part of a raw message.
-*/
-static int line6_send_raw_message_async_part(struct message *msg,
-                                            struct urb *urb)
-{
-       int retval;
-       struct usb_line6 *line6 = msg->line6;
-       int done = msg->done;
-       int bytes = min(msg->size - done, line6->max_packet_size);
-
-       usb_fill_int_urb(urb, line6->usbdev,
-               usb_sndintpipe(line6->usbdev, line6->properties->ep_ctrl_w),
-               (char *)msg->buffer + done, bytes,
-               line6_async_request_sent, msg, line6->interval);
-
-       msg->done += bytes;
-       retval = usb_submit_urb(urb, GFP_ATOMIC);
-
-       if (retval < 0) {
-               dev_err(line6->ifcdev, "%s: usb_submit_urb failed (%d)\n",
-                       __func__, retval);
-               usb_free_urb(urb);
-               kfree(msg);
-               return retval;
-       }
-
-       return 0;
-}
-
-/*
-       Setup and start timer.
-*/
-void line6_start_timer(struct timer_list *timer, unsigned int msecs,
-                      void (*function)(unsigned long), unsigned long data)
-{
-       setup_timer(timer, function, data);
-       timer->expires = jiffies + msecs * HZ / 1000;
-       add_timer(timer);
-}
-
-/*
-       Asynchronously send raw message.
-*/
-int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer,
-                                int size)
-{
-       struct message *msg;
-       struct urb *urb;
-
-       /* create message: */
-       msg = kmalloc(sizeof(struct message), GFP_ATOMIC);
-       if (msg == NULL)
-               return -ENOMEM;
-
-       /* create URB: */
-       urb = usb_alloc_urb(0, GFP_ATOMIC);
-
-       if (urb == NULL) {
-               kfree(msg);
-               dev_err(line6->ifcdev, "Out of memory\n");
-               return -ENOMEM;
-       }
-
-       /* set message data: */
-       msg->line6 = line6;
-       msg->buffer = buffer;
-       msg->size = size;
-       msg->done = 0;
-
-       /* start sending: */
-       return line6_send_raw_message_async_part(msg, urb);
-}
-
-/*
-       Send asynchronous device version request.
-*/
-int line6_version_request_async(struct usb_line6 *line6)
-{
-       char *buffer;
-       int retval;
-
-       buffer = kmemdup(line6_request_version,
-                       sizeof(line6_request_version), GFP_ATOMIC);
-       if (buffer == NULL) {
-               dev_err(line6->ifcdev, "Out of memory");
-               return -ENOMEM;
-       }
-
-       retval = line6_send_raw_message_async(line6, buffer,
-                                             sizeof(line6_request_version));
-       kfree(buffer);
-       return retval;
-}
-
-/*
-       Send sysex message in pieces of wMaxPacketSize bytes.
-*/
-int line6_send_sysex_message(struct usb_line6 *line6, const char *buffer,
-                            int size)
-{
-       return line6_send_raw_message(line6, buffer,
-                                     size + SYSEX_EXTRA_SIZE) -
-           SYSEX_EXTRA_SIZE;
-}
-
-/*
-       Allocate buffer for sysex message and prepare header.
-       @param code sysex message code
-       @param size number of bytes between code and sysex end
-*/
-char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2,
-                              int size)
-{
-       char *buffer = kmalloc(size + SYSEX_EXTRA_SIZE, GFP_ATOMIC);
-
-       if (!buffer)
-               return NULL;
-
-       buffer[0] = LINE6_SYSEX_BEGIN;
-       memcpy(buffer + 1, line6_midi_id, sizeof(line6_midi_id));
-       buffer[sizeof(line6_midi_id) + 1] = code1;
-       buffer[sizeof(line6_midi_id) + 2] = code2;
-       buffer[sizeof(line6_midi_id) + 3 + size] = LINE6_SYSEX_END;
-       return buffer;
-}
-
-/*
-       Notification of data received from the Line6 device.
-*/
-static void line6_data_received(struct urb *urb)
-{
-       struct usb_line6 *line6 = (struct usb_line6 *)urb->context;
-       struct midi_buffer *mb = &line6->line6midi->midibuf_in;
-       int done;
-
-       if (urb->status == -ESHUTDOWN)
-               return;
-
-       done =
-           line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length);
-
-       if (done < urb->actual_length) {
-               line6_midibuf_ignore(mb, done);
-               dev_dbg(line6->ifcdev, "%d %d buffer overflow - message skipped\n",
-                       done, urb->actual_length);
-       }
-
-       for (;;) {
-               done =
-                   line6_midibuf_read(mb, line6->buffer_message,
-                                      LINE6_MESSAGE_MAXLEN);
-
-               if (done == 0)
-                       break;
-
-               line6->message_length = done;
-               line6_midi_receive(line6, line6->buffer_message, done);
-
-               if (line6->process_message)
-                       line6->process_message(line6);
-       }
-
-       line6_start_listen(line6);
-}
-
-/*
-       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,
-                   size_t datalen)
-{
-       struct usb_device *usbdev = line6->usbdev;
-       int ret;
-       unsigned char len;
-
-       /* query the serial number: */
-       ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
-                             USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
-                             (datalen << 8) | 0x21, address,
-                             NULL, 0, LINE6_TIMEOUT * HZ);
-
-       if (ret < 0) {
-               dev_err(line6->ifcdev, "read request failed (error %d)\n", ret);
-               return ret;
-       }
-
-       /* Wait for data length. We'll get 0xff until length arrives. */
-       do {
-               ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67,
-                                     USB_TYPE_VENDOR | USB_RECIP_DEVICE |
-                                     USB_DIR_IN,
-                                     0x0012, 0x0000, &len, 1,
-                                     LINE6_TIMEOUT * HZ);
-               if (ret < 0) {
-                       dev_err(line6->ifcdev,
-                               "receive length failed (error %d)\n", ret);
-                       return ret;
-               }
-       } while (len == 0xff);
-
-       if (len != datalen) {
-               /* should be equal or something went wrong */
-               dev_err(line6->ifcdev,
-                       "length mismatch (expected %d, got %d)\n",
-                       (int)datalen, (int)len);
-               return -EINVAL;
-       }
-
-       /* receive the result: */
-       ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67,
-                             USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
-                             0x0013, 0x0000, data, datalen,
-                             LINE6_TIMEOUT * HZ);
-
-       if (ret < 0) {
-               dev_err(line6->ifcdev, "read failed (error %d)\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-/*
-       Write data to device.
-*/
-int line6_write_data(struct usb_line6 *line6, int address, void *data,
-                    size_t datalen)
-{
-       struct usb_device *usbdev = line6->usbdev;
-       int ret;
-       unsigned char status;
-
-       ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
-                             USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
-                             0x0022, address, data, datalen,
-                             LINE6_TIMEOUT * HZ);
-
-       if (ret < 0) {
-               dev_err(line6->ifcdev,
-                       "write request failed (error %d)\n", ret);
-               return ret;
-       }
-
-       do {
-               ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
-                                     0x67,
-                                     USB_TYPE_VENDOR | USB_RECIP_DEVICE |
-                                     USB_DIR_IN,
-                                     0x0012, 0x0000,
-                                     &status, 1, LINE6_TIMEOUT * HZ);
-
-               if (ret < 0) {
-                       dev_err(line6->ifcdev,
-                               "receiving status failed (error %d)\n", ret);
-                       return ret;
-               }
-       } while (status == 0xff);
-
-       if (status != 0) {
-               dev_err(line6->ifcdev, "write failed (error %d)\n", ret);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/*
-       Read Line6 device serial number.
-       (POD, TonePort, GuitarPort)
-*/
-int line6_read_serial_number(struct usb_line6 *line6, int *serial_number)
-{
-       return line6_read_data(line6, 0x80d0, serial_number,
-                              sizeof(*serial_number));
-}
-
-/*
-       No operation (i.e., unsupported).
-*/
-ssize_t line6_nop_read(struct device *dev, struct device_attribute *attr,
-                      char *buf)
-{
-       return 0;
-}
-
-/*
-       Generic destructor.
-*/
-static void line6_destruct(struct usb_interface *interface)
-{
-       struct usb_line6 *line6;
-
-       if (interface == NULL)
-               return;
-       line6 = usb_get_intfdata(interface);
-       if (line6 == NULL)
-               return;
-
-       /* free buffer memory first: */
-       kfree(line6->buffer_message);
-       kfree(line6->buffer_listen);
-
-       /* 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);
-}
-
-/*
-       Probe USB device.
-*/
-static int line6_probe(struct usb_interface *interface,
-                      const struct usb_device_id *id)
-{
-       enum line6_device_type devtype;
-       struct usb_device *usbdev;
-       struct usb_line6 *line6;
-       const struct line6_properties *properties;
-       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);
-
-       /* query interface number */
-       interface_number = interface->cur_altsetting->desc.bInterfaceNumber;
-
-       ret = usb_set_interface(usbdev, interface_number,
-                       properties->altsetting);
-       if (ret < 0) {
-               dev_err(&interface->dev, "set_interface failed\n");
-               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): */
-       {
-               struct usb_host_endpoint *ep;
-               unsigned pipe = usb_rcvintpipe(usbdev, properties->ep_ctrl_r);
-               unsigned epnum = usb_pipeendpoint(pipe);
-               ep = usbdev->ep_in[epnum];
-
-               if (ep != NULL) {
-                       line6->interval = ep->desc.bInterval;
-                       line6->max_packet_size =
-                           le16_to_cpu(ep->desc.wMaxPacketSize);
-               } else {
-                       line6->interval = LINE6_FALLBACK_INTERVAL;
-                       line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE;
-                       dev_err(line6->ifcdev,
-                               "endpoint not available, using fallback values");
-               }
-       }
-
-       usb_set_intfdata(interface, line6);
-
-       if (properties->capabilities & LINE6_CAP_CONTROL) {
-               /* initialize USB buffers: */
-               line6->buffer_listen =
-                   kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL);
-               if (line6->buffer_listen == NULL) {
-                       ret = -ENOMEM;
-                       goto err_destruct;
-               }
-
-               line6->buffer_message =
-                   kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL);
-               if (line6->buffer_message == NULL) {
-                       ret = -ENOMEM;
-                       goto err_destruct;
-               }
-
-               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;
-               }
-
-               ret = line6_start_listen(line6);
-               if (ret < 0) {
-                       dev_err(&interface->dev, "%s: usb_submit_urb failed\n",
-                               __func__);
-                       goto err_destruct;
-               }
-       }
-
-       /* 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");
-       if (ret < 0)
-               goto err_destruct;
-
-       /* creation of additional special files should go here */
-
-       dev_info(&interface->dev, "Line6 %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:
-       return ret;
-}
-
-/*
-       Line6 device disconnected.
-*/
-static void line6_disconnect(struct usb_interface *interface)
-{
-       struct usb_line6 *line6;
-       struct usb_device *usbdev;
-       int interface_number;
-
-       if (interface == NULL)
-               return;
-       usbdev = interface_to_usbdev(interface);
-       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 != NULL) {
-               if (line6->urb_listen != NULL)
-                       line6_stop_listen(line6);
-
-               if (usbdev != line6->usbdev)
-                       dev_err(line6->ifcdev,
-                               "driver bug: inconsistent usb device\n");
-
-               line6->disconnect(interface);
-
-               dev_info(&interface->dev, "Line6 %s now disconnected\n",
-                        line6->properties->name);
-       }
-
-       line6_destruct(interface);
-
-       /* decrement reference counters: */
-       usb_put_intf(interface);
-       usb_put_dev(usbdev);
-}
-
-#ifdef CONFIG_PM
-
-/*
-       Suspend Line6 device.
-*/
-static 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;
-
-       snd_power_change_state(line6->card, SNDRV_CTL_POWER_D3hot);
-
-       if (line6->properties->capabilities & LINE6_CAP_CONTROL)
-               line6_stop_listen(line6);
-
-       if (line6pcm != NULL) {
-               snd_pcm_suspend_all(line6pcm->pcm);
-               line6_pcm_disconnect(line6pcm);
-               line6pcm->flags = 0;
-       }
-
-       return 0;
-}
-
-/*
-       Resume Line6 device.
-*/
-static int line6_resume(struct usb_interface *interface)
-{
-       struct usb_line6 *line6 = usb_get_intfdata(interface);
-
-       if (line6->properties->capabilities & LINE6_CAP_CONTROL)
-               line6_start_listen(line6);
-
-       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);
-}
-
-#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/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h
deleted file mode 100644 (file)
index ad203f1..0000000
+++ /dev/null
@@ -1,228 +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 DRIVER_H
-#define DRIVER_H
-
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-#include <sound/core.h>
-
-#include "midi.h"
-
-#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
-*/
-#define LINE6_PARAM_CHANGE   0xb0
-#define LINE6_PROGRAM_CHANGE 0xc0
-#define LINE6_SYSEX_BEGIN    0xf0
-#define LINE6_SYSEX_END      0xf7
-#define LINE6_RESET          0xff
-
-/*
-       MIDI channel for messages initiated by the host
-       (and eventually echoed back by the device)
-*/
-#define LINE6_CHANNEL_HOST   0x00
-
-/*
-       MIDI channel for messages initiated by the device
-*/
-#define LINE6_CHANNEL_DEVICE 0x02
-
-#define LINE6_CHANNEL_UNKNOWN 5        /* don't know yet what this is good for */
-
-#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))                 \
-               return;                 \
-       x = (n);                        \
-} while (0)
-
-extern const unsigned char line6_midi_id[3];
-
-static const int SYSEX_DATA_OFS = sizeof(line6_midi_id) + 3;
-static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4;
-
-/**
-        Common properties of Line6 devices.
-*/
-struct line6_properties {
-       /**
-                Card id string (maximum 16 characters).
-                This can be used to address the device in ALSA programs as
-                "default:CARD=<id>"
-       */
-       const char *id;
-
-       /**
-                Card short name (maximum 32 characters).
-       */
-       const char *name;
-
-       /**
-                Bit vector defining this device's capabilities in the
-                line6usb driver.
-       */
-       int capabilities;
-
-       int altsetting;
-
-       unsigned ep_ctrl_r;
-       unsigned ep_ctrl_w;
-       unsigned ep_audio_r;
-       unsigned ep_audio_w;
-};
-
-/**
-        Common data shared by all Line6 devices.
-        Corresponds to a pair of USB endpoints.
-*/
-struct usb_line6 {
-       /**
-                USB device.
-       */
-       struct usb_device *usbdev;
-
-       /**
-                Device type.
-       */
-       enum line6_device_type type;
-
-       /**
-                Properties.
-       */
-       const struct line6_properties *properties;
-
-       /**
-                Interval (ms).
-       */
-       int interval;
-
-       /**
-                Maximum size of USB packet.
-       */
-       int max_packet_size;
-
-       /**
-                Device representing the USB interface.
-       */
-       struct device *ifcdev;
-
-       /**
-                Line6 sound card data structure.
-                Each device has at least MIDI or PCM.
-       */
-       struct snd_card *card;
-
-       /**
-                Line6 PCM device data structure.
-       */
-       struct snd_line6_pcm *line6pcm;
-
-       /**
-                Line6 MIDI device data structure.
-       */
-       struct snd_line6_midi *line6midi;
-
-       /**
-                URB for listening to PODxt Pro control endpoint.
-       */
-       struct urb *urb_listen;
-
-       /**
-                Buffer for listening to PODxt Pro control endpoint.
-       */
-       unsigned char *buffer_listen;
-
-       /**
-                Buffer for message to be processed.
-       */
-       unsigned char *buffer_message;
-
-       /**
-                Length of message to be processed.
-       */
-       int message_length;
-
-       void (*process_message)(struct usb_line6 *);
-       void (*disconnect)(struct usb_interface *);
-};
-
-extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1,
-                                     int code2, int size);
-extern ssize_t line6_nop_read(struct device *dev,
-                             struct device_attribute *attr, char *buf);
-extern int line6_read_data(struct usb_line6 *line6, int address, void *data,
-                          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,
-                                   const char *buffer, int size);
-extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr,
-                            const char *buf, size_t count);
-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);
-
-#endif
diff --git a/drivers/staging/line6/midi.c b/drivers/staging/line6/midi.c
deleted file mode 100644 (file)
index c9d725a..0000000
+++ /dev/null
@@ -1,321 +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 <linux/slab.h>
-#include <linux/usb.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) \
-       ((struct snd_line6_midi *)((substream)->rmidi->private_data))
-
-static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
-                          int length);
-
-/*
-       Pass data received via USB to MIDI.
-*/
-void line6_midi_receive(struct usb_line6 *line6, unsigned char *data,
-                       int length)
-{
-       if (line6->line6midi->substream_receive)
-               snd_rawmidi_receive(line6->line6midi->substream_receive,
-                                   data, length);
-}
-
-/*
-       Read data from MIDI buffer and transmit them via USB.
-*/
-static void line6_midi_transmit(struct snd_rawmidi_substream *substream)
-{
-       struct usb_line6 *line6 =
-           line6_rawmidi_substream_midi(substream)->line6;
-       struct snd_line6_midi *line6midi = line6->line6midi;
-       struct midi_buffer *mb = &line6midi->midibuf_out;
-       unsigned long flags;
-       unsigned char chunk[LINE6_FALLBACK_MAXPACKETSIZE];
-       int req, done;
-
-       spin_lock_irqsave(&line6->line6midi->midi_transmit_lock, flags);
-
-       for (;;) {
-               req = min(line6_midibuf_bytes_free(mb), line6->max_packet_size);
-               done = snd_rawmidi_transmit_peek(substream, chunk, req);
-
-               if (done == 0)
-                       break;
-
-               line6_midibuf_write(mb, chunk, done);
-               snd_rawmidi_transmit_ack(substream, done);
-       }
-
-       for (;;) {
-               done = line6_midibuf_read(mb, chunk,
-                                         LINE6_FALLBACK_MAXPACKETSIZE);
-
-               if (done == 0)
-                       break;
-
-               send_midi_async(line6, chunk, done);
-       }
-
-       spin_unlock_irqrestore(&line6->line6midi->midi_transmit_lock, flags);
-}
-
-/*
-       Notification of completion of MIDI transmission.
-*/
-static void midi_sent(struct urb *urb)
-{
-       unsigned long flags;
-       int status;
-       int num;
-       struct usb_line6 *line6 = (struct usb_line6 *)urb->context;
-
-       status = urb->status;
-       kfree(urb->transfer_buffer);
-       usb_free_urb(urb);
-
-       if (status == -ESHUTDOWN)
-               return;
-
-       spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags);
-       num = --line6->line6midi->num_active_send_urbs;
-
-       if (num == 0) {
-               line6_midi_transmit(line6->line6midi->substream_transmit);
-               num = line6->line6midi->num_active_send_urbs;
-       }
-
-       if (num == 0)
-               wake_up(&line6->line6midi->send_wait);
-
-       spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags);
-}
-
-/*
-       Send an asynchronous MIDI message.
-       Assumes that line6->line6midi->send_urb_lock is held
-       (i.e., this function is serialized).
-*/
-static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
-                          int length)
-{
-       struct urb *urb;
-       int retval;
-       unsigned char *transfer_buffer;
-
-       urb = usb_alloc_urb(0, GFP_ATOMIC);
-
-       if (urb == NULL) {
-               dev_err(line6->ifcdev, "Out of memory\n");
-               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;
-       }
-
-       usb_fill_int_urb(urb, line6->usbdev,
-                        usb_sndbulkpipe(line6->usbdev,
-                                        line6->properties->ep_ctrl_w),
-                        transfer_buffer, length, midi_sent, line6,
-                        line6->interval);
-       urb->actual_length = 0;
-       retval = usb_submit_urb(urb, GFP_ATOMIC);
-
-       if (retval < 0) {
-               dev_err(line6->ifcdev, "usb_submit_urb failed\n");
-               usb_free_urb(urb);
-               return retval;
-       }
-
-       ++line6->line6midi->num_active_send_urbs;
-       return 0;
-}
-
-static int line6_midi_output_open(struct snd_rawmidi_substream *substream)
-{
-       return 0;
-}
-
-static int line6_midi_output_close(struct snd_rawmidi_substream *substream)
-{
-       return 0;
-}
-
-static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream,
-                                     int up)
-{
-       unsigned long flags;
-       struct usb_line6 *line6 =
-           line6_rawmidi_substream_midi(substream)->line6;
-
-       line6->line6midi->substream_transmit = substream;
-       spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags);
-
-       if (line6->line6midi->num_active_send_urbs == 0)
-               line6_midi_transmit(substream);
-
-       spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags);
-}
-
-static void line6_midi_output_drain(struct snd_rawmidi_substream *substream)
-{
-       struct usb_line6 *line6 =
-           line6_rawmidi_substream_midi(substream)->line6;
-       struct snd_line6_midi *midi = line6->line6midi;
-
-       wait_event_interruptible(midi->send_wait,
-                                midi->num_active_send_urbs == 0);
-}
-
-static int line6_midi_input_open(struct snd_rawmidi_substream *substream)
-{
-       return 0;
-}
-
-static int line6_midi_input_close(struct snd_rawmidi_substream *substream)
-{
-       return 0;
-}
-
-static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream,
-                                    int up)
-{
-       struct usb_line6 *line6 =
-           line6_rawmidi_substream_midi(substream)->line6;
-
-       if (up)
-               line6->line6midi->substream_receive = substream;
-       else
-               line6->line6midi->substream_receive = NULL;
-}
-
-static struct snd_rawmidi_ops line6_midi_output_ops = {
-       .open = line6_midi_output_open,
-       .close = line6_midi_output_close,
-       .trigger = line6_midi_output_trigger,
-       .drain = line6_midi_output_drain,
-};
-
-static struct snd_rawmidi_ops line6_midi_input_ops = {
-       .open = line6_midi_input_open,
-       .close = line6_midi_input_close,
-       .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)
-{
-       struct snd_rawmidi *rmidi;
-       int err;
-
-       err = snd_rawmidi_new(line6midi->line6->card, "Line6 MIDI", 0, 1, 1,
-                             &rmidi);
-       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->info_flags =
-           SNDRV_RAWMIDI_INFO_OUTPUT |
-           SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
-
-       snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
-                           &line6_midi_output_ops);
-       snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
-                           &line6_midi_input_ops);
-       return 0;
-}
-
-/* MIDI device destructor */
-static int snd_line6_midi_free(struct snd_device *device)
-{
-       struct snd_line6_midi *line6midi = device->device_data;
-
-       line6_midibuf_destroy(&line6midi->midibuf_in);
-       line6_midibuf_destroy(&line6midi->midibuf_out);
-       return 0;
-}
-
-/*
-       Initialize the Line6 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_line6_midi *line6midi;
-
-       if (!(line6->properties->capabilities & LINE6_CAP_CONTROL)) {
-               /* skip MIDI initialization and report success */
-               return 0;
-       }
-
-       line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL);
-
-       if (line6midi == NULL)
-               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;
-
-       init_waitqueue_head(&line6midi->send_wait);
-       spin_lock_init(&line6midi->send_urb_lock);
-       spin_lock_init(&line6midi->midi_transmit_lock);
-       return 0;
-}
diff --git a/drivers/staging/line6/midi.h b/drivers/staging/line6/midi.h
deleted file mode 100644 (file)
index 78f903f..0000000
+++ /dev/null
@@ -1,72 +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 MIDI_H
-#define MIDI_H
-
-#include <sound/rawmidi.h>
-
-#include "midibuf.h"
-
-#define MIDI_BUFFER_SIZE 1024
-
-struct snd_line6_midi {
-       /**
-                Pointer back to the Line6 driver data structure.
-       */
-       struct usb_line6 *line6;
-
-       /**
-                MIDI substream for receiving (or NULL if not active).
-       */
-       struct snd_rawmidi_substream *substream_receive;
-
-       /**
-                MIDI substream for transmitting (or NULL if not active).
-       */
-       struct snd_rawmidi_substream *substream_transmit;
-
-       /**
-                Number of currently active MIDI send URBs.
-       */
-       int num_active_send_urbs;
-
-       /**
-                Spin lock to protect updates of send_urb.
-       */
-       spinlock_t send_urb_lock;
-
-       /**
-                Spin lock to protect MIDI buffer handling.
-       */
-       spinlock_t midi_transmit_lock;
-
-       /**
-                Wait queue for MIDI transmission.
-       */
-       wait_queue_head_t send_wait;
-
-       /**
-                Buffer for incoming MIDI stream.
-       */
-       struct midi_buffer midibuf_in;
-
-       /**
-                Buffer for outgoing MIDI stream.
-       */
-       struct midi_buffer midibuf_out;
-};
-
-extern int line6_init_midi(struct usb_line6 *line6);
-extern void line6_midi_receive(struct usb_line6 *line6, unsigned char *data,
-                              int length);
-
-#endif
diff --git a/drivers/staging/line6/midibuf.c b/drivers/staging/line6/midibuf.c
deleted file mode 100644 (file)
index 1ff8569..0000000
+++ /dev/null
@@ -1,270 +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 <linux/slab.h>
-
-#include "midibuf.h"
-
-static int midibuf_message_length(unsigned char code)
-{
-       int message_length;
-
-       if (code < 0x80)
-               message_length = -1;
-       else if (code < 0xf0) {
-               static const int length[] = { 3, 3, 3, 3, 2, 2, 3 };
-
-               message_length = length[(code >> 4) - 8];
-       } else {
-               /*
-                  Note that according to the MIDI specification 0xf2 is
-                  the "Song Position Pointer", but this is used by Line6
-                  to send sysex messages to the host.
-                */
-               static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1,
-                       1, 1, 1, -1, 1, 1
-               };
-               message_length = length[code & 0x0f];
-       }
-
-       return message_length;
-}
-
-static int midibuf_is_empty(struct midi_buffer *this)
-{
-       return (this->pos_read == this->pos_write) && !this->full;
-}
-
-static int midibuf_is_full(struct midi_buffer *this)
-{
-       return this->full;
-}
-
-void line6_midibuf_reset(struct midi_buffer *this)
-{
-       this->pos_read = this->pos_write = this->full = 0;
-       this->command_prev = -1;
-}
-
-int line6_midibuf_init(struct midi_buffer *this, int size, int split)
-{
-       this->buf = kmalloc(size, GFP_KERNEL);
-
-       if (this->buf == NULL)
-               return -ENOMEM;
-
-       this->size = size;
-       this->split = split;
-       line6_midibuf_reset(this);
-       return 0;
-}
-
-void line6_midibuf_status(struct midi_buffer *this)
-{
-       pr_debug("midibuf size=%d split=%d pos_read=%d pos_write=%d full=%d command_prev=%02x\n",
-                this->size, this->split, this->pos_read, this->pos_write,
-                this->full, this->command_prev);
-}
-
-int line6_midibuf_bytes_free(struct midi_buffer *this)
-{
-       return
-           midibuf_is_full(this) ?
-           0 :
-           (this->pos_read - this->pos_write + this->size - 1) % this->size +
-           1;
-}
-
-int line6_midibuf_bytes_used(struct midi_buffer *this)
-{
-       return
-           midibuf_is_empty(this) ?
-           0 :
-           (this->pos_write - this->pos_read + this->size - 1) % this->size +
-           1;
-}
-
-int line6_midibuf_write(struct midi_buffer *this, unsigned char *data,
-                       int length)
-{
-       int bytes_free;
-       int length1, length2;
-       int skip_active_sense = 0;
-
-       if (midibuf_is_full(this) || (length <= 0))
-               return 0;
-
-       /* skip trailing active sense */
-       if (data[length - 1] == 0xfe) {
-               --length;
-               skip_active_sense = 1;
-       }
-
-       bytes_free = line6_midibuf_bytes_free(this);
-
-       if (length > bytes_free)
-               length = bytes_free;
-
-       if (length > 0) {
-               length1 = this->size - this->pos_write;
-
-               if (length < length1) {
-                       /* no buffer wraparound */
-                       memcpy(this->buf + this->pos_write, data, length);
-                       this->pos_write += length;
-               } else {
-                       /* buffer wraparound */
-                       length2 = length - length1;
-                       memcpy(this->buf + this->pos_write, data, length1);
-                       memcpy(this->buf, data + length1, length2);
-                       this->pos_write = length2;
-               }
-
-               if (this->pos_write == this->pos_read)
-                       this->full = 1;
-       }
-
-       return length + skip_active_sense;
-}
-
-int line6_midibuf_read(struct midi_buffer *this, unsigned char *data,
-                      int length)
-{
-       int bytes_used;
-       int length1, length2;
-       int command;
-       int midi_length;
-       int repeat = 0;
-       int i;
-
-       /* we need to be able to store at least a 3 byte MIDI message */
-       if (length < 3)
-               return -EINVAL;
-
-       if (midibuf_is_empty(this))
-               return 0;
-
-       bytes_used = line6_midibuf_bytes_used(this);
-
-       if (length > bytes_used)
-               length = bytes_used;
-
-       length1 = this->size - this->pos_read;
-
-       /* check MIDI command length */
-       command = this->buf[this->pos_read];
-
-       if (command & 0x80) {
-               midi_length = midibuf_message_length(command);
-               this->command_prev = command;
-       } else {
-               if (this->command_prev > 0) {
-                       int midi_length_prev =
-                           midibuf_message_length(this->command_prev);
-
-                       if (midi_length_prev > 0) {
-                               midi_length = midi_length_prev - 1;
-                               repeat = 1;
-                       } else
-                               midi_length = -1;
-               } else
-                       midi_length = -1;
-       }
-
-       if (midi_length < 0) {
-               /* search for end of message */
-               if (length < length1) {
-                       /* no buffer wraparound */
-                       for (i = 1; i < length; ++i)
-                               if (this->buf[this->pos_read + i] & 0x80)
-                                       break;
-
-                       midi_length = i;
-               } else {
-                       /* buffer wraparound */
-                       length2 = length - length1;
-
-                       for (i = 1; i < length1; ++i)
-                               if (this->buf[this->pos_read + i] & 0x80)
-                                       break;
-
-                       if (i < length1)
-                               midi_length = i;
-                       else {
-                               for (i = 0; i < length2; ++i)
-                                       if (this->buf[i] & 0x80)
-                                               break;
-
-                               midi_length = length1 + i;
-                       }
-               }
-
-               if (midi_length == length)
-                       midi_length = -1;       /* end of message not found */
-       }
-
-       if (midi_length < 0) {
-               if (!this->split)
-                       return 0;       /* command is not yet complete */
-       } else {
-               if (length < midi_length)
-                       return 0;       /* command is not yet complete */
-
-               length = midi_length;
-       }
-
-       if (length < length1) {
-               /* no buffer wraparound */
-               memcpy(data + repeat, this->buf + this->pos_read, length);
-               this->pos_read += length;
-       } else {
-               /* buffer wraparound */
-               length2 = length - length1;
-               memcpy(data + repeat, this->buf + this->pos_read, length1);
-               memcpy(data + repeat + length1, this->buf, length2);
-               this->pos_read = length2;
-       }
-
-       if (repeat)
-               data[0] = this->command_prev;
-
-       this->full = 0;
-       return length + repeat;
-}
-
-int line6_midibuf_ignore(struct midi_buffer *this, int length)
-{
-       int bytes_used = line6_midibuf_bytes_used(this);
-
-       if (length > bytes_used)
-               length = bytes_used;
-
-       this->pos_read = (this->pos_read + length) % this->size;
-       this->full = 0;
-       return length;
-}
-
-int line6_midibuf_skip_message(struct midi_buffer *this, unsigned short mask)
-{
-       int cmd = this->command_prev;
-
-       if ((cmd >= 0x80) && (cmd < 0xf0))
-               if ((mask & (1 << (cmd & 0x0f))) == 0)
-                       return 1;
-
-       return 0;
-}
-
-void line6_midibuf_destroy(struct midi_buffer *this)
-{
-       kfree(this->buf);
-       this->buf = NULL;
-}
diff --git a/drivers/staging/line6/midibuf.h b/drivers/staging/line6/midibuf.h
deleted file mode 100644 (file)
index 707482b..0000000
+++ /dev/null
@@ -1,38 +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 MIDIBUF_H
-#define MIDIBUF_H
-
-struct midi_buffer {
-       unsigned char *buf;
-       int size;
-       int split;
-       int pos_read, pos_write;
-       int full;
-       int command_prev;
-};
-
-extern int line6_midibuf_bytes_used(struct midi_buffer *mb);
-extern int line6_midibuf_bytes_free(struct midi_buffer *mb);
-extern void line6_midibuf_destroy(struct midi_buffer *mb);
-extern int line6_midibuf_ignore(struct midi_buffer *mb, int length);
-extern int line6_midibuf_init(struct midi_buffer *mb, int size, int split);
-extern int line6_midibuf_read(struct midi_buffer *mb, unsigned char *data,
-                             int length);
-extern void line6_midibuf_reset(struct midi_buffer *mb);
-extern int line6_midibuf_skip_message(struct midi_buffer *mb,
-                                     unsigned short mask);
-extern void line6_midibuf_status(struct midi_buffer *mb);
-extern int line6_midibuf_write(struct midi_buffer *mb, unsigned char *data,
-                              int length);
-
-#endif
diff --git a/drivers/staging/line6/pcm.c b/drivers/staging/line6/pcm.c
deleted file mode 100644 (file)
index 6d4e5cd..0000000
+++ /dev/null
@@ -1,527 +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 <linux/slab.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)
-{
-       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;
-}
-
-/*
-       "read" request on "impulse_volume" special file.
-*/
-static ssize_t impulse_volume_show(struct device *dev,
-                                  struct device_attribute *attr, char *buf)
-{
-       return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_volume);
-}
-
-/*
-       "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)
-{
-       struct snd_line6_pcm *line6pcm = dev2pcm(dev);
-       int value;
-       int ret;
-
-       ret = kstrtoint(buf, 10, &value);
-       if (ret < 0)
-               return ret;
-
-       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;
-}
-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)
-{
-       return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_period);
-}
-
-/*
-       "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)
-{
-       int value;
-       int ret;
-
-       ret = kstrtoint(buf, 10, &value);
-       if (ret < 0)
-               return ret;
-
-       dev2pcm(dev)->impulse_period = value;
-       return count;
-}
-static DEVICE_ATTR_RW(impulse_period);
-
-#endif
-
-static bool test_flags(unsigned long flags0, unsigned long flags1,
-                      unsigned long mask)
-{
-       return ((flags0 & mask) == 0) && ((flags1 & mask) != 0);
-}
-
-int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels)
-{
-       unsigned long flags_old, flags_new, flags_final;
-       int err;
-
-       do {
-               flags_old = ACCESS_ONCE(line6pcm->flags);
-               flags_new = flags_old | channels;
-       } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old);
-
-       flags_final = flags_old;
-
-       line6pcm->prev_fbuf = NULL;
-
-       if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) {
-               /* Invoked multiple times in a row so allocate once only */
-               if (!line6pcm->buffer_in) {
-                       line6pcm->buffer_in =
-                               kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
-                                       line6pcm->max_packet_size, GFP_KERNEL);
-                       if (!line6pcm->buffer_in) {
-                               err = -ENOMEM;
-                               goto pcm_acquire_error;
-                       }
-
-                       flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER;
-               }
-       }
-
-       if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) {
-               /*
-                  Waiting for completion of active URBs in the stop handler is
-                  a bug, we therefore report an error if capturing is restarted
-                  too soon.
-                */
-               if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) {
-                       dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
-                       return -EBUSY;
-               }
-
-               line6pcm->count_in = 0;
-               line6pcm->prev_fsize = 0;
-               err = line6_submit_audio_in_all_urbs(line6pcm);
-
-               if (err < 0)
-                       goto pcm_acquire_error;
-
-               flags_final |= channels & LINE6_BITS_CAPTURE_STREAM;
-       }
-
-       if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) {
-               /* Invoked multiple times in a row so allocate once only */
-               if (!line6pcm->buffer_out) {
-                       line6pcm->buffer_out =
-                               kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
-                                       line6pcm->max_packet_size, GFP_KERNEL);
-                       if (!line6pcm->buffer_out) {
-                               err = -ENOMEM;
-                               goto pcm_acquire_error;
-                       }
-
-                       flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER;
-               }
-       }
-
-       if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) {
-               /*
-                 See comment above regarding PCM restart.
-               */
-               if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) {
-                       dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
-                       return -EBUSY;
-               }
-
-               line6pcm->count_out = 0;
-               err = line6_submit_audio_out_all_urbs(line6pcm);
-
-               if (err < 0)
-                       goto pcm_acquire_error;
-
-               flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM;
-       }
-
-       return 0;
-
-pcm_acquire_error:
-       /*
-          If not all requested resources/streams could be obtained, release
-          those which were successfully obtained (if any).
-       */
-       line6_pcm_release(line6pcm, flags_final & channels);
-       return err;
-}
-
-int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels)
-{
-       unsigned long flags_old, flags_new;
-
-       do {
-               flags_old = ACCESS_ONCE(line6pcm->flags);
-               flags_new = flags_old & ~channels;
-       } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old);
-
-       if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM))
-               line6_unlink_audio_in_urbs(line6pcm);
-
-       if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) {
-               line6_wait_clear_audio_in_urbs(line6pcm);
-               line6_free_capture_buffer(line6pcm);
-       }
-
-       if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM))
-               line6_unlink_audio_out_urbs(line6pcm);
-
-       if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) {
-               line6_wait_clear_audio_out_urbs(line6pcm);
-               line6_free_playback_buffer(line6pcm);
-       }
-
-       return 0;
-}
-
-/* trigger callback */
-int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
-{
-       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);
-       clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags);
-
-       snd_pcm_group_for_each_entry(s, substream) {
-               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);
-                               return err;
-                       }
-
-                       break;
-
-               case SNDRV_PCM_STREAM_CAPTURE:
-                       err = snd_line6_capture_trigger(line6pcm, cmd);
-
-                       if (err < 0) {
-                               spin_unlock_irqrestore(&line6pcm->lock_trigger,
-                                                      flags);
-                               return err;
-                       }
-
-                       break;
-
-               default:
-                       dev_err(line6pcm->line6->ifcdev,
-                               "Unknown stream direction %d\n", s->stream);
-               }
-       }
-
-       spin_unlock_irqrestore(&line6pcm->lock_trigger, flags);
-       return 0;
-}
-
-/* control info callback */
-static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol,
-                                          struct snd_ctl_elem_info *uinfo)
-{
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 2;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = 256;
-       return 0;
-}
-
-/* control get callback */
-static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol,
-                                         struct snd_ctl_elem_value *ucontrol)
-{
-       int i;
-       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-
-       for (i = 2; i--;)
-               ucontrol->value.integer.value[i] = line6pcm->volume_playback[i];
-
-       return 0;
-}
-
-/* control put callback */
-static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol,
-                                         struct snd_ctl_elem_value *ucontrol)
-{
-       int i, changed = 0;
-       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-
-       for (i = 2; i--;)
-               if (line6pcm->volume_playback[i] !=
-                   ucontrol->value.integer.value[i]) {
-                       line6pcm->volume_playback[i] =
-                           ucontrol->value.integer.value[i];
-                       changed = 1;
-               }
-
-       return changed;
-}
-
-/* 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
-};
-
-/*
-       Cleanup the PCM device.
-*/
-static void line6_cleanup_pcm(struct snd_pcm *pcm)
-{
-       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]);
-                       usb_free_urb(line6pcm->urb_audio_out[i]);
-               }
-               if (line6pcm->urb_audio_in[i]) {
-                       usb_kill_urb(line6pcm->urb_audio_in[i]);
-                       usb_free_urb(line6pcm->urb_audio_in[i]);
-               }
-       }
-}
-
-/* create a PCM device */
-static int snd_line6_new_pcm(struct snd_line6_pcm *line6pcm)
-{
-       struct snd_pcm *pcm;
-       int err;
-
-       err = snd_pcm_new(line6pcm->line6->card,
-                         (char *)line6pcm->line6->properties->name,
-                         0, 1, 1, &pcm);
-       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);
-
-       /* set operators */
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
-                       &snd_line6_playback_ops);
-       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops);
-
-       /* pre-allocation of buffers */
-       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
-                                             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.
-*/
-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);
-}
-
-/*
-       Create and register the PCM device and mixer entries.
-       Create URBs for playback and capture.
-*/
-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;
-       unsigned ep_read = line6->properties->ep_audio_r;
-       unsigned ep_write = line6->properties->ep_audio_w;
-       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);
-
-       if (line6pcm == NULL)
-               return -ENOMEM;
-
-       line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255;
-       line6pcm->volume_monitor = 255;
-       line6pcm->line6 = line6;
-
-       /* Read and write buffers are sized identically, so choose minimum */
-       line6pcm->max_packet_size = min(
-                       usb_maxpacket(line6->usbdev,
-                               usb_rcvisocpipe(line6->usbdev, ep_read), 0),
-                       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);
-
-       err = line6_create_audio_out_urbs(line6pcm);
-       if (err < 0)
-               return err;
-
-       err = line6_create_audio_in_urbs(line6pcm);
-       if (err < 0)
-               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
-
-       return 0;
-}
-
-/* prepare pcm callback */
-int snd_line6_prepare(struct snd_pcm_substream *substream)
-{
-       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
-       switch (substream->stream) {
-       case SNDRV_PCM_STREAM_PLAYBACK:
-               if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0)
-                       line6_unlink_wait_clear_audio_out_urbs(line6pcm);
-
-               break;
-
-       case SNDRV_PCM_STREAM_CAPTURE:
-               if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0)
-                       line6_unlink_wait_clear_audio_in_urbs(line6pcm);
-
-               break;
-
-       default:
-               MISSING_CASE;
-       }
-
-       if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) {
-               line6pcm->count_out = 0;
-               line6pcm->pos_out = 0;
-               line6pcm->pos_out_done = 0;
-               line6pcm->bytes_out = 0;
-               line6pcm->count_in = 0;
-               line6pcm->pos_in_done = 0;
-               line6pcm->bytes_in = 0;
-       }
-
-       return 0;
-}
diff --git a/drivers/staging/line6/pcm.h b/drivers/staging/line6/pcm.h
deleted file mode 100644 (file)
index 7315e81..0000000
+++ /dev/null
@@ -1,374 +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.
- *
- */
-
-/*
-       PCM interface to POD series devices.
-*/
-
-#ifndef PCM_H
-#define PCM_H
-
-#include <sound/pcm.h>
-
-#include "driver.h"
-#include "usbdefs.h"
-
-/* number of URBs */
-#define LINE6_ISO_BUFFERS      2
-
-/*
-       number of USB frames per URB
-       The Line6 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.
-*/
-#define LINE6_ISO_PACKETS      1
-
-/* 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
-*/
-#define get_substream(line6pcm, stream)        \
-               (line6pcm->pcm->streams[stream].substream)
-
-/*
-       PCM mode bits.
-
-       There are several features of the Line6 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)
-       *) optional impulse response measurement
-       However, from the device's point of view, there is just a single
-       capture and playback stream, which must be shared between these
-       subsystems. It is therefore necessary to maintain the state of the
-       subsystems with respect to PCM usage. We define several constants of
-       the form LINE6_BIT_PCM_<subsystem>_<direction>_<resource> with the
-       following meanings:
-       *) <subsystem> is one of
-       -) ALSA: PCM playback and capture via ALSA
-       -) MONITOR: software monitoring
-       -) IMPULSE: optional impulse response measurement
-       *) <direction> is one of
-       -) PLAYBACK: audio output (from host to device)
-       -) CAPTURE: audio input (from device to host)
-       *) <resource> is one of
-       -) BUFFER: buffer required by PCM data stream
-       -) STREAM: actual PCM data stream
-
-       The subsystems call line6_pcm_acquire() to acquire the (shared)
-       resources needed for a particular operation (e.g., allocate the buffer
-       for ALSA playback or start the capture stream for software monitoring).
-       When a resource is no longer needed, it is released by calling
-       line6_pcm_release(). Buffer allocation and stream startup are handled
-       separately to allow the ALSA kernel driver to perform them at
-       appropriate places (since the callback which starts a PCM stream is not
-       allowed to sleep).
-*/
-enum {
-       /* individual bit indices: */
-       LINE6_INDEX_PCM_ALSA_PLAYBACK_BUFFER,
-       LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM,
-       LINE6_INDEX_PCM_ALSA_CAPTURE_BUFFER,
-       LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
-       LINE6_INDEX_PCM_MONITOR_PLAYBACK_BUFFER,
-       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,
-
-#define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_INDEX_ ## x
-
-       /* individual bit masks: */
-       LINE6_BIT(PCM_ALSA_PLAYBACK_BUFFER),
-       LINE6_BIT(PCM_ALSA_PLAYBACK_STREAM),
-       LINE6_BIT(PCM_ALSA_CAPTURE_BUFFER),
-       LINE6_BIT(PCM_ALSA_CAPTURE_STREAM),
-       LINE6_BIT(PCM_MONITOR_PLAYBACK_BUFFER),
-       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),
-
-       /* combined bit masks (by operation): */
-       LINE6_BITS_PCM_ALSA_BUFFER =
-           LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER |
-           LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER,
-
-       LINE6_BITS_PCM_ALSA_STREAM =
-           LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM |
-           LINE6_BIT_PCM_ALSA_CAPTURE_STREAM,
-
-       LINE6_BITS_PCM_MONITOR =
-           LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER |
-           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_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,
-
-       LINE6_BITS_STREAM =
-           LINE6_BITS_PLAYBACK_STREAM |
-           LINE6_BITS_CAPTURE_STREAM
-};
-
-struct line6_pcm_properties {
-       struct snd_pcm_hardware snd_line6_playback_hw, snd_line6_capture_hw;
-       struct snd_pcm_hw_constraint_ratdens snd_line6_rates;
-       int bytes_per_frame;
-};
-
-struct snd_line6_pcm {
-       /**
-                Pointer back to the Line6 driver data structure.
-       */
-       struct usb_line6 *line6;
-
-       /**
-                Properties.
-       */
-       struct line6_pcm_properties *properties;
-
-       /**
-                ALSA pcm stream
-       */
-       struct snd_pcm *pcm;
-
-       /**
-                URBs for audio playback.
-       */
-       struct urb *urb_audio_out[LINE6_ISO_BUFFERS];
-
-       /**
-                URBs for audio capture.
-       */
-       struct urb *urb_audio_in[LINE6_ISO_BUFFERS];
-
-       /**
-                Temporary buffer for playback.
-                Since the packet size is not known in advance, this buffer is
-                large enough to store maximum size packets.
-       */
-       unsigned char *buffer_out;
-
-       /**
-                Temporary buffer for capture.
-                Since the packet size is not known in advance, this buffer is
-                large enough to store maximum size packets.
-       */
-       unsigned char *buffer_in;
-
-       /**
-                Previously captured frame (for software monitoring).
-       */
-       unsigned char *prev_fbuf;
-
-       /**
-                Size of previously captured frame (for software monitoring).
-       */
-       int prev_fsize;
-
-       /**
-                Free frame position in the playback buffer.
-       */
-       snd_pcm_uframes_t pos_out;
-
-       /**
-                Count processed bytes for playback.
-                This is modulo period size (to determine when a period is
-                finished).
-       */
-       unsigned bytes_out;
-
-       /**
-                Counter to create desired playback sample rate.
-       */
-       unsigned count_out;
-
-       /**
-                Playback period size in bytes
-       */
-       unsigned period_out;
-
-       /**
-                Processed frame position in the playback buffer.
-                The contents of the output ring buffer have been consumed by
-                the USB subsystem (i.e., sent to the USB device) up to this
-                position.
-       */
-       snd_pcm_uframes_t pos_out_done;
-
-       /**
-                Count processed bytes for capture.
-                This is modulo period size (to determine when a period is
-                finished).
-       */
-       unsigned bytes_in;
-
-       /**
-                Counter to create desired capture sample rate.
-       */
-       unsigned count_in;
-
-       /**
-                Capture period size in bytes
-       */
-       unsigned period_in;
-
-       /**
-                Processed frame position in the capture buffer.
-                The contents of the output ring buffer have been consumed by
-                the USB subsystem (i.e., sent to the USB device) up to this
-                position.
-       */
-       snd_pcm_uframes_t pos_in_done;
-
-       /**
-                Bit mask of active playback URBs.
-       */
-       unsigned long active_urb_out;
-
-       /**
-                Maximum size of USB packet.
-       */
-       int max_packet_size;
-
-       /**
-                Bit mask of active capture URBs.
-       */
-       unsigned long active_urb_in;
-
-       /**
-                Bit mask of playback URBs currently being unlinked.
-       */
-       unsigned long unlink_urb_out;
-
-       /**
-                Bit mask of capture URBs currently being unlinked.
-       */
-       unsigned long unlink_urb_in;
-
-       /**
-                Spin lock to protect updates of the playback buffer positions (not
-                contents!)
-       */
-       spinlock_t lock_audio_out;
-
-       /**
-                Spin lock to protect updates of the capture buffer positions (not
-                contents!)
-       */
-       spinlock_t lock_audio_in;
-
-       /**
-                Spin lock to protect trigger.
-       */
-       spinlock_t lock_trigger;
-
-       /**
-                PCM playback volume (left and right).
-       */
-       int volume_playback[2];
-
-       /**
-                PCM monitor volume.
-       */
-       int volume_monitor;
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-       /**
-                Volume of impulse response test signal (if zero, test is disabled).
-       */
-       int impulse_volume;
-
-       /**
-                Period of impulse response test signal.
-       */
-       int impulse_period;
-
-       /**
-                Counter for impulse response test signal.
-       */
-       int impulse_count;
-#endif
-
-       /**
-                Several status bits (see LINE6_BIT_*).
-       */
-       unsigned long flags;
-
-       int last_frame_in, last_frame_out;
-};
-
-extern int line6_init_pcm(struct usb_line6 *line6,
-                         struct line6_pcm_properties *properties);
-extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd);
-extern int snd_line6_prepare(struct snd_pcm_substream *substream);
-extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm);
-extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels);
-extern int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels);
-
-#endif
diff --git a/drivers/staging/line6/playback.c b/drivers/staging/line6/playback.c
deleted file mode 100644 (file)
index da2e3b8..0000000
+++ /dev/null
@@ -1,593 +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 <linux/slab.h>
-#include <sound/core.h>
-#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"
-
-/*
-       Software stereo volume control.
-*/
-static void change_volume(struct urb *urb_out, int volume[],
-                         int bytes_per_frame)
-{
-       int chn = 0;
-
-       if (volume[0] == 256 && volume[1] == 256)
-               return;         /* maximum volume - no change */
-
-       if (bytes_per_frame == 4) {
-               short *p, *buf_end;
-
-               p = (short *)urb_out->transfer_buffer;
-               buf_end = p + urb_out->transfer_buffer_length / sizeof(*p);
-
-               for (; p < buf_end; ++p) {
-                       *p = (*p * volume[chn & 1]) >> 8;
-                       ++chn;
-               }
-       } else if (bytes_per_frame == 6) {
-               unsigned char *p, *buf_end;
-
-               p = (unsigned char *)urb_out->transfer_buffer;
-               buf_end = p + urb_out->transfer_buffer_length;
-
-               for (; p < buf_end; p += 3) {
-                       int val;
-
-                       val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16);
-                       val = (val * volume[chn & 1]) >> 8;
-                       p[0] = val;
-                       p[1] = val >> 8;
-                       p[2] = val >> 16;
-                       ++chn;
-               }
-       }
-}
-
-#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
-
-/*
-       Create signal for impulse response test.
-*/
-static void create_impulse_test_signal(struct snd_line6_pcm *line6pcm,
-                                      struct urb *urb_out, int bytes_per_frame)
-{
-       int frames = urb_out->transfer_buffer_length / bytes_per_frame;
-
-       if (bytes_per_frame == 4) {
-               int i;
-               short *pi = (short *)line6pcm->prev_fbuf;
-               short *po = (short *)urb_out->transfer_buffer;
-
-               for (i = 0; i < frames; ++i) {
-                       po[0] = pi[0];
-                       po[1] = 0;
-                       pi += 2;
-                       po += 2;
-               }
-       } else if (bytes_per_frame == 6) {
-               int i, j;
-               unsigned char *pi = line6pcm->prev_fbuf;
-               unsigned char *po = urb_out->transfer_buffer;
-
-               for (i = 0; i < frames; ++i) {
-                       for (j = 0; j < bytes_per_frame / 2; ++j)
-                               po[j] = pi[j];
-
-                       for (; j < bytes_per_frame; ++j)
-                               po[j] = 0;
-
-                       pi += bytes_per_frame;
-                       po += bytes_per_frame;
-               }
-       }
-       if (--line6pcm->impulse_count <= 0) {
-               ((unsigned char *)(urb_out->transfer_buffer))[bytes_per_frame -
-                                                             1] =
-                   line6pcm->impulse_volume;
-               line6pcm->impulse_count = line6pcm->impulse_period;
-       }
-}
-
-#endif
-
-/*
-       Add signal to buffer for software monitoring.
-*/
-static void add_monitor_signal(struct urb *urb_out, unsigned char *signal,
-                              int volume, int bytes_per_frame)
-{
-       if (volume == 0)
-               return;         /* zero volume - no change */
-
-       if (bytes_per_frame == 4) {
-               short *pi, *po, *buf_end;
-
-               pi = (short *)signal;
-               po = (short *)urb_out->transfer_buffer;
-               buf_end = po + urb_out->transfer_buffer_length / sizeof(*po);
-
-               for (; po < buf_end; ++pi, ++po)
-                       *po += (*pi * volume) >> 8;
-       }
-
-       /*
-          We don't need to handle devices with 6 bytes per frame here
-          since they all support hardware monitoring.
-        */
-}
-
-/*
-       Find a free URB, prepare audio data, and submit URB.
-*/
-static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
-{
-       int index;
-       unsigned long flags;
-       int i, urb_size, urb_frames;
-       int ret;
-       const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
-       const int frame_increment =
-           line6pcm->properties->snd_line6_rates.rats[0].num_min;
-       const int frame_factor =
-           line6pcm->properties->snd_line6_rates.rats[0].den *
-           (USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL);
-       struct urb *urb_out;
-
-       spin_lock_irqsave(&line6pcm->lock_audio_out, flags);
-       index =
-           find_first_zero_bit(&line6pcm->active_urb_out, LINE6_ISO_BUFFERS);
-
-       if (index < 0 || index >= LINE6_ISO_BUFFERS) {
-               spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
-               dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
-               return -EINVAL;
-       }
-
-       urb_out = line6pcm->urb_audio_out[index];
-       urb_size = 0;
-
-       for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
-               /* compute frame size for given sampling rate */
-               int fsize = 0;
-               struct usb_iso_packet_descriptor *fout =
-                   &urb_out->iso_frame_desc[i];
-
-               if (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM)
-                       fsize = line6pcm->prev_fsize;
-
-               if (fsize == 0) {
-                       int n;
-
-                       line6pcm->count_out += frame_increment;
-                       n = line6pcm->count_out / frame_factor;
-                       line6pcm->count_out -= n * frame_factor;
-                       fsize = n * bytes_per_frame;
-               }
-
-               fout->offset = urb_size;
-               fout->length = fsize;
-               urb_size += fsize;
-       }
-
-       if (urb_size == 0) {
-               /* can't determine URB size */
-               spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
-               dev_err(line6pcm->line6->ifcdev, "driver bug: urb_size = 0\n");
-               return -EINVAL;
-       }
-
-       urb_frames = urb_size / bytes_per_frame;
-       urb_out->transfer_buffer =
-           line6pcm->buffer_out +
-           index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
-       urb_out->transfer_buffer_length = urb_size;
-       urb_out->context = line6pcm;
-
-       if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags) &&
-           !test_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags)) {
-               struct snd_pcm_runtime *runtime =
-                   get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime;
-
-               if (line6pcm->pos_out + urb_frames > runtime->buffer_size) {
-                       /*
-                          The transferred area goes over buffer boundary,
-                          copy the data to the temp buffer.
-                        */
-                       int len;
-
-                       len = runtime->buffer_size - line6pcm->pos_out;
-
-                       if (len > 0) {
-                               memcpy(urb_out->transfer_buffer,
-                                      runtime->dma_area +
-                                      line6pcm->pos_out * bytes_per_frame,
-                                      len * bytes_per_frame);
-                               memcpy(urb_out->transfer_buffer +
-                                      len * bytes_per_frame, runtime->dma_area,
-                                      (urb_frames - len) * bytes_per_frame);
-                       } else
-                               dev_err(line6pcm->line6->ifcdev, "driver bug: len = %d\n",
-                                       len);
-               } else {
-                       memcpy(urb_out->transfer_buffer,
-                              runtime->dma_area +
-                              line6pcm->pos_out * bytes_per_frame,
-                              urb_out->transfer_buffer_length);
-               }
-
-               line6pcm->pos_out += urb_frames;
-               if (line6pcm->pos_out >= runtime->buffer_size)
-                       line6pcm->pos_out -= runtime->buffer_size;
-       } else {
-               memset(urb_out->transfer_buffer, 0,
-                      urb_out->transfer_buffer_length);
-       }
-
-       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);
-                       if (line6pcm->flags &
-                           LINE6_BIT_PCM_ALSA_CAPTURE_STREAM) {
-                               line6_capture_copy(line6pcm,
-                                                  urb_out->transfer_buffer,
-                                                  urb_out->
-                                                  transfer_buffer_length);
-                               line6_capture_check_period(line6pcm,
-                                       urb_out->transfer_buffer_length);
-                       }
-               } else {
-#endif
-                       if (!
-                           (line6pcm->line6->
-                            properties->capabilities & LINE6_CAP_HWMON)
-                           && (line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM)
-                           && (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM))
-                               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);
-
-       if (ret == 0)
-               set_bit(index, &line6pcm->active_urb_out);
-       else
-               dev_err(line6pcm->line6->ifcdev,
-                       "URB out #%d submission failed (%d)\n", index, ret);
-
-       spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
-       return 0;
-}
-
-/*
-       Submit all currently available playback URBs.
-*/
-int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm)
-{
-       int ret, i;
-
-       for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
-               ret = submit_audio_out_urb(line6pcm);
-               if (ret < 0)
-                       return ret;
-       }
-
-       return 0;
-}
-
-/*
-       Unlink all currently active playback URBs.
-*/
-void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm)
-{
-       unsigned int i;
-
-       for (i = LINE6_ISO_BUFFERS; i--;) {
-               if (test_bit(i, &line6pcm->active_urb_out)) {
-                       if (!test_and_set_bit(i, &line6pcm->unlink_urb_out)) {
-                               struct urb *u = line6pcm->urb_audio_out[i];
-
-                               usb_unlink_urb(u);
-                       }
-               }
-       }
-}
-
-/*
-       Wait until unlinking of all currently active playback URBs has been
-       finished.
-*/
-void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
-{
-       int timeout = HZ;
-       unsigned int i;
-       int alive;
-
-       do {
-               alive = 0;
-               for (i = LINE6_ISO_BUFFERS; i--;) {
-                       if (test_bit(i, &line6pcm->active_urb_out))
-                               alive++;
-               }
-               if (!alive)
-                       break;
-               set_current_state(TASK_UNINTERRUPTIBLE);
-               schedule_timeout(1);
-       } while (--timeout > 0);
-       if (alive)
-               snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
-}
-
-/*
-       Unlink all currently active playback URBs, and wait for finishing.
-*/
-void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
-{
-       line6_unlink_audio_out_urbs(line6pcm);
-       line6_wait_clear_audio_out_urbs(line6pcm);
-}
-
-void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm)
-{
-       kfree(line6pcm->buffer_out);
-       line6pcm->buffer_out = NULL;
-}
-
-/*
-       Callback for completed playback URB.
-*/
-static void audio_out_callback(struct urb *urb)
-{
-       int i, index, length = 0, shutdown = 0;
-       unsigned long flags;
-       struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;
-       struct snd_pcm_substream *substream =
-           get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK);
-
-#if USE_CLEAR_BUFFER_WORKAROUND
-       memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
-#endif
-
-       line6pcm->last_frame_out = urb->start_frame;
-
-       /* find index of URB */
-       for (index = LINE6_ISO_BUFFERS; index--;)
-               if (urb == line6pcm->urb_audio_out[index])
-                       break;
-
-       if (index < 0)
-               return;         /* URB has been unlinked asynchronously */
-
-       for (i = LINE6_ISO_PACKETS; i--;)
-               length += urb->iso_frame_desc[i].length;
-
-       spin_lock_irqsave(&line6pcm->lock_audio_out, flags);
-
-       if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags)) {
-               struct snd_pcm_runtime *runtime = substream->runtime;
-
-               line6pcm->pos_out_done +=
-                   length / line6pcm->properties->bytes_per_frame;
-
-               if (line6pcm->pos_out_done >= runtime->buffer_size)
-                       line6pcm->pos_out_done -= runtime->buffer_size;
-       }
-
-       clear_bit(index, &line6pcm->active_urb_out);
-
-       for (i = LINE6_ISO_PACKETS; i--;)
-               if (urb->iso_frame_desc[i].status == -EXDEV) {
-                       shutdown = 1;
-                       break;
-               }
-
-       if (test_and_clear_bit(index, &line6pcm->unlink_urb_out))
-               shutdown = 1;
-
-       spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
-
-       if (!shutdown) {
-               submit_audio_out_urb(line6pcm);
-
-               if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM,
-                            &line6pcm->flags)) {
-                       line6pcm->bytes_out += length;
-                       if (line6pcm->bytes_out >= line6pcm->period_out) {
-                               line6pcm->bytes_out %= line6pcm->period_out;
-                               snd_pcm_period_elapsed(substream);
-                       }
-               }
-       }
-}
-
-/* open playback callback */
-static int snd_line6_playback_open(struct snd_pcm_substream *substream)
-{
-       int err;
-       struct snd_pcm_runtime *runtime = substream->runtime;
-       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
-       err = snd_pcm_hw_constraint_ratdens(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
-                                           (&line6pcm->
-                                            properties->snd_line6_rates));
-       if (err < 0)
-               return err;
-
-       runtime->hw = line6pcm->properties->snd_line6_playback_hw;
-       return 0;
-}
-
-/* close playback callback */
-static int snd_line6_playback_close(struct snd_pcm_substream *substream)
-{
-       return 0;
-}
-
-/* hw_params playback callback */
-static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream,
-                                       struct snd_pcm_hw_params *hw_params)
-{
-       int ret;
-       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
-       /* -- Florian Demski [FD] */
-       /* don't ask me why, but this fixes the bug on my machine */
-       if (line6pcm == NULL) {
-               if (substream->pcm == NULL)
-                       return -ENOMEM;
-               if (substream->pcm->private_data == NULL)
-                       return -ENOMEM;
-               substream->private_data = substream->pcm->private_data;
-               line6pcm = snd_pcm_substream_chip(substream);
-       }
-       /* -- [FD] end */
-
-       ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
-
-       if (ret < 0)
-               return ret;
-
-       ret = snd_pcm_lib_malloc_pages(substream,
-                                      params_buffer_bytes(hw_params));
-       if (ret < 0) {
-               line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
-               return ret;
-       }
-
-       line6pcm->period_out = params_period_bytes(hw_params);
-       return 0;
-}
-
-/* hw_free playback callback */
-static int snd_line6_playback_hw_free(struct snd_pcm_substream *substream)
-{
-       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
-       line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
-       return snd_pcm_lib_free_pages(substream);
-}
-
-/* trigger playback callback */
-int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd)
-{
-       int err;
-
-       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);
-
-               if (err < 0)
-                       return err;
-
-               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);
-
-               if (err < 0)
-                       return err;
-
-               break;
-
-       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-               set_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags);
-               break;
-
-       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-               clear_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags);
-               break;
-
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-/* playback pointer callback */
-static snd_pcm_uframes_t
-snd_line6_playback_pointer(struct snd_pcm_substream *substream)
-{
-       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
-
-       return line6pcm->pos_out_done;
-}
-
-/* playback operators */
-struct snd_pcm_ops snd_line6_playback_ops = {
-       .open = snd_line6_playback_open,
-       .close = snd_line6_playback_close,
-       .ioctl = snd_pcm_lib_ioctl,
-       .hw_params = snd_line6_playback_hw_params,
-       .hw_free = snd_line6_playback_hw_free,
-       .prepare = snd_line6_prepare,
-       .trigger = snd_line6_trigger,
-       .pointer = snd_line6_playback_pointer,
-};
-
-int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm)
-{
-       struct usb_line6 *line6 = line6pcm->line6;
-       int i;
-
-       /* create audio URBs and fill in constant values: */
-       for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
-               struct urb *urb;
-
-               /* URB for audio out: */
-               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");
-                       return -ENOMEM;
-               }
-
-               urb->dev = line6->usbdev;
-               urb->pipe =
-                   usb_sndisocpipe(line6->usbdev,
-                                   line6->properties->ep_audio_w &
-                                   USB_ENDPOINT_NUMBER_MASK);
-               urb->transfer_flags = URB_ISO_ASAP;
-               urb->start_frame = -1;
-               urb->number_of_packets = LINE6_ISO_PACKETS;
-               urb->interval = LINE6_ISO_INTERVAL;
-               urb->error_count = 0;
-               urb->complete = audio_out_callback;
-       }
-
-       return 0;
-}
diff --git a/drivers/staging/line6/playback.h b/drivers/staging/line6/playback.h
deleted file mode 100644 (file)
index 743bd6f..0000000
+++ /dev/null
@@ -1,41 +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 PLAYBACK_H
-#define PLAYBACK_H
-
-#include <sound/pcm.h>
-
-#include "driver.h"
-
-/*
- * When the TonePort is used with jack in full duplex mode and the outputs are
- * not connected, the software monitor produces an ugly noise since everything
- * written to the output buffer (i.e., the input signal) will be repeated in
- * the next period (sounds like a delay effect). As a workaround, the output
- * buffer is cleared after the data have been read, but there must be a better
- * solution. Until one is found, this workaround can be used to fix the
- * problem.
- */
-#define USE_CLEAR_BUFFER_WORKAROUND 1
-
-extern struct snd_pcm_ops snd_line6_playback_ops;
-
-extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm);
-extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm);
-extern void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm
-                                                  *line6pcm);
-extern void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm);
-extern int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd);
-
-#endif
diff --git a/drivers/staging/line6/pod.c b/drivers/staging/line6/pod.c
deleted file mode 100644 (file)
index 85a4363..0000000
+++ /dev/null
@@ -1,453 +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 <linux/slab.h>
-#include <linux/wait.h>
-#include <sound/control.h>
-
-#include "audio.h"
-#include "capture.h"
-#include "driver.h"
-#include "playback.h"
-#include "pod.h"
-
-#define POD_SYSEX_CODE 3
-#define POD_BYTES_PER_FRAME 6  /* 24bit audio (stereo) */
-
-/* *INDENT-OFF* */
-
-enum {
-       POD_SYSEX_SAVE      = 0x24,
-       POD_SYSEX_SYSTEM    = 0x56,
-       POD_SYSEX_SYSTEMREQ = 0x57,
-       /* POD_SYSEX_UPDATE    = 0x6c, */  /* software update! */
-       POD_SYSEX_STORE     = 0x71,
-       POD_SYSEX_FINISH    = 0x72,
-       POD_SYSEX_DUMPMEM   = 0x73,
-       POD_SYSEX_DUMP      = 0x74,
-       POD_SYSEX_DUMPREQ   = 0x75
-
-       /* dumps entire internal memory of PODxt Pro */
-       /* POD_SYSEX_DUMPMEM2  = 0x76 */
-};
-
-enum {
-       POD_MONITOR_LEVEL  = 0x04,
-       POD_SYSTEM_INVALID = 0x10000
-};
-
-/* *INDENT-ON* */
-
-enum {
-       POD_DUMP_MEMORY = 2
-};
-
-enum {
-       POD_BUSY_READ,
-       POD_BUSY_WRITE,
-       POD_CHANNEL_DIRTY,
-       POD_SAVE_PRESSED,
-       POD_BUSY_MIDISEND
-};
-
-static struct snd_ratden pod_ratden = {
-       .num_min = 78125,
-       .num_max = 78125,
-       .num_step = 1,
-       .den = 2
-};
-
-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 |
-#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},
-       .bytes_per_frame = POD_BYTES_PER_FRAME
-};
-
-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 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);
-}
-
-/*
-       Process a completely received message.
-*/
-static void line6_pod_process_message(struct usb_line6 *line6)
-{
-       struct usb_line6_pod *pod = (struct usb_line6_pod *) line6;
-       const unsigned char *buf = pod->line6.buffer_message;
-
-       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_startup3(pod);
-               return;
-       }
-
-       /* Only look for sysex messages from this device */
-       if (buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE) &&
-           buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN)) {
-               return;
-       }
-       if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) != 0)
-               return;
-
-       if (buf[5] == POD_SYSEX_SYSTEM && buf[6] == POD_MONITOR_LEVEL) {
-               short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) |
-                             ((int)buf[9] << 4) | (int)buf[10];
-               pod->monitor_level = value;
-       }
-}
-
-/*
-       Send system parameter (from integer).
-*/
-static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
-                                   int code)
-{
-       char *sysex;
-       static const int size = 5;
-
-       sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
-       if (!sysex)
-               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;
-       line6_send_sysex_message(&pod->line6, sysex, size);
-       kfree(sysex);
-       return 0;
-}
-
-/*
-       "read" request on "serial_number" special file.
-*/
-static ssize_t serial_number_show(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 sprintf(buf, "%d\n", pod->serial_number);
-}
-
-/*
-       "read" request on "firmware_version" special file.
-*/
-static ssize_t firmware_version_show(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 sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
-                      pod->firmware_version % 100);
-}
-
-/*
-       "read" request on "device_id" special file.
-*/
-static ssize_t device_id_show(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 sprintf(buf, "%d\n", pod->device_id);
-}
-
-/*
-       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;
-       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_startup3(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);
-}
-
-static void pod_startup4(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);
-}
-
-/* POD special files: */
-static DEVICE_ATTR_RO(device_id);
-static DEVICE_ATTR_RO(firmware_version);
-static DEVICE_ATTR_RO(serial_number);
-
-/* 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;
-       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)
-               return 0;
-
-       pod->monitor_level = 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.
-*/
-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)
-{
-       struct usb_line6_pod *pod;
-
-       if (interface == NULL)
-               return;
-       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);
-}
-
-/*
-       Create sysfs entries.
-*/
-static int pod_create_files2(struct device *dev)
-{
-       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));
-       return 0;
-}
-
-/*
-        Try to init POD device.
-*/
-static int pod_try_init(struct usb_interface *interface,
-                       struct usb_line6 *line6)
-{
-       int err;
-       struct usb_line6_pod *pod = (struct usb_line6_pod *) line6;
-
-       line6->process_message = line6_pod_process_message;
-       line6->disconnect = line6_pod_disconnect;
-
-       init_timer(&pod->startup_timer);
-       INIT_WORK(&pod->startup_work, pod_startup4);
-
-       if ((interface == NULL) || (pod == NULL))
-               return -ENODEV;
-
-       /* create sysfs entries: */
-       err = pod_create_files2(&interface->dev);
-       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)
-               return err;
-
-       /* initialize PCM subsystem: */
-       err = line6_init_pcm(line6, &pod_pcm_properties);
-       if (err < 0)
-               return err;
-
-       /* 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_CAP_CONTROL) {
-               pod->monitor_level = 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 *line6)
-{
-       int err = pod_try_init(interface, line6);
-
-       if (err < 0)
-               pod_destruct(interface);
-
-       return err;
-}
diff --git a/drivers/staging/line6/pod.h b/drivers/staging/line6/pod.h
deleted file mode 100644 (file)
index 87a8f0f..0000000
+++ /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/drivers/staging/line6/podhd.c b/drivers/staging/line6/podhd.c
deleted file mode 100644 (file)
index 27c5402..0000000
+++ /dev/null
@@ -1,156 +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.
- *
- */
-
-#include <sound/core.h>
-#include <sound/pcm.h>
-
-#include "audio.h"
-#include "driver.h"
-#include "pcm.h"
-#include "podhd.h"
-
-#define PODHD_BYTES_PER_FRAME 6        /* 24bit audio (stereo) */
-
-static struct snd_ratden podhd_ratden = {
-       .num_min = 48000,
-       .num_max = 48000,
-       .num_step = 1,
-       .den = 1,
-};
-
-static struct line6_pcm_properties podhd_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 |
-#ifdef CONFIG_PM
-                                          SNDRV_PCM_INFO_RESUME |
-#endif
-                                          SNDRV_PCM_INFO_SYNC_START),
-                                 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
-                                 .rates = SNDRV_PCM_RATE_48000,
-                                 .rate_min = 48000,
-                                 .rate_max = 48000,
-                                 .channels_min = 2,
-                                 .channels_max = 2,
-                                 .buffer_bytes_max = 60000,
-                                 .period_bytes_min = 64,
-                                 .period_bytes_max = 8192,
-                                 .periods_min = 1,
-                                 .periods_max = 1024},
-       .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_48000,
-                                .rate_min = 48000,
-                                .rate_max = 48000,
-                                .channels_min = 2,
-                                .channels_max = 2,
-                                .buffer_bytes_max = 60000,
-                                .period_bytes_min = 64,
-                                .period_bytes_max = 8192,
-                                .periods_min = 1,
-                                .periods_max = 1024},
-       .snd_line6_rates = {
-                           .nrats = 1,
-                           .rats = &podhd_ratden},
-       .bytes_per_frame = PODHD_BYTES_PER_FRAME
-};
-
-/*
-       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)
-{
-       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)
-               return err;
-
-       /* initialize PCM subsystem: */
-       err = line6_init_pcm(line6, &podhd_pcm_properties);
-       if (err < 0)
-               return err;
-
-       /* register USB audio system: */
-       err = line6_register_audio(line6);
-       return err;
-}
-
-/*
-       Init POD HD device (and clean up in case of failure).
-*/
-int line6_podhd_init(struct usb_interface *interface, struct usb_line6 *line6)
-{
-       struct usb_line6_podhd *podhd = (struct usb_line6_podhd *) line6;
-       int err = podhd_try_init(interface, podhd);
-
-       if (err < 0)
-               podhd_destruct(interface);
-
-       return err;
-}
diff --git a/drivers/staging/line6/podhd.h b/drivers/staging/line6/podhd.h
deleted file mode 100644 (file)
index a14f711..0000000
+++ /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/drivers/staging/line6/revision.h b/drivers/staging/line6/revision.h
deleted file mode 100644 (file)
index b4eee2b..0000000
+++ /dev/null
@@ -1,4 +0,0 @@
-#ifndef DRIVER_REVISION
-/* current subversion revision */
-#define DRIVER_REVISION " (904)"
-#endif
diff --git a/drivers/staging/line6/toneport.c b/drivers/staging/line6/toneport.c
deleted file mode 100644 (file)
index aae78d8..0000000
+++ /dev/null
@@ -1,465 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
- *                         Emil Myhrman (emil.myhrman@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.
- *
- */
-
-#include <linux/wait.h>
-#include <sound/control.h>
-
-#include "audio.h"
-#include "capture.h"
-#include "driver.h"
-#include "playback.h"
-#include "toneport.h"
-
-static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2);
-
-#define TONEPORT_PCM_DELAY 1
-
-static struct snd_ratden toneport_ratden = {
-       .num_min = 44100,
-       .num_max = 44100,
-       .num_step = 1,
-       .den = 1
-};
-
-static struct line6_pcm_properties toneport_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 |
-#ifdef CONFIG_PM
-                                          SNDRV_PCM_INFO_RESUME |
-#endif
-                                          SNDRV_PCM_INFO_SYNC_START),
-                                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
-                                 .rates = SNDRV_PCM_RATE_KNOT,
-                                 .rate_min = 44100,
-                                 .rate_max = 44100,
-                                 .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_S16_LE,
-                                .rates = SNDRV_PCM_RATE_KNOT,
-                                .rate_min = 44100,
-                                .rate_max = 44100,
-                                .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 = &toneport_ratden},
-       .bytes_per_frame = 4
-};
-
-/*
-       For the led on Guitarport.
-       Brightness goes from 0x00 to 0x26. Set a value above this to have led
-       blink.
-       (void cmd_0x02(byte red, byte green)
-*/
-static int led_red = 0x00;
-static int led_green = 0x26;
-
-static const struct {
-       const char *name;
-       int code;
-} toneport_source_info[] = {
-       {"Microphone", 0x0a01},
-       {"Line", 0x0801},
-       {"Instrument", 0x0b01},
-       {"Inst & Mic", 0x0901}
-};
-
-static bool toneport_has_led(enum line6_device_type type)
-{
-       return
-           (type == LINE6_GUITARPORT) ||
-           (type == LINE6_TONEPORT_GX);
-       /* add your device here if you are missing support for the LEDs */
-}
-
-static void toneport_update_led(struct device *dev)
-{
-       struct usb_interface *interface = to_usb_interface(dev);
-       struct usb_line6_toneport *tp = usb_get_intfdata(interface);
-       struct usb_line6 *line6;
-
-       if (!tp)
-               return;
-
-       line6 = &tp->line6;
-       if (line6)
-               toneport_send_cmd(line6->usbdev, (led_red << 8) | 0x0002,
-                                 led_green);
-}
-
-static ssize_t toneport_set_led_red(struct device *dev,
-                                   struct device_attribute *attr,
-                                   const char *buf, size_t count)
-{
-       int retval;
-
-       retval = kstrtoint(buf, 10, &led_red);
-       if (retval)
-               return retval;
-
-       toneport_update_led(dev);
-       return count;
-}
-
-static ssize_t toneport_set_led_green(struct device *dev,
-                                     struct device_attribute *attr,
-                                     const char *buf, size_t count)
-{
-       int retval;
-
-       retval = kstrtoint(buf, 10, &led_green);
-       if (retval)
-               return retval;
-
-       toneport_update_led(dev);
-       return count;
-}
-
-static DEVICE_ATTR(led_red, S_IWUSR | S_IRUGO, line6_nop_read,
-                  toneport_set_led_red);
-static DEVICE_ATTR(led_green, S_IWUSR | S_IRUGO, line6_nop_read,
-                  toneport_set_led_green);
-
-static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)
-{
-       int ret;
-
-       ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
-                             USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
-                             cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ);
-
-       if (ret < 0) {
-               dev_err(&usbdev->dev, "send failed (error %d)\n", ret);
-               return ret;
-       }
-
-       return 0;
-}
-
-/* monitor info callback */
-static int snd_toneport_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 = 256;
-       return 0;
-}
-
-/* monitor get callback */
-static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-
-       ucontrol->value.integer.value[0] = line6pcm->volume_monitor;
-       return 0;
-}
-
-/* monitor put callback */
-static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-
-       if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor)
-               return 0;
-
-       line6pcm->volume_monitor = ucontrol->value.integer.value[0];
-
-       if (line6pcm->volume_monitor > 0)
-               line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_MONITOR);
-       else
-               line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
-
-       return 1;
-}
-
-/* source info callback */
-static int snd_toneport_source_info(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_info *uinfo)
-{
-       const int size = ARRAY_SIZE(toneport_source_info);
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
-       uinfo->count = 1;
-       uinfo->value.enumerated.items = size;
-
-       if (uinfo->value.enumerated.item >= size)
-               uinfo->value.enumerated.item = size - 1;
-
-       strcpy(uinfo->value.enumerated.name,
-              toneport_source_info[uinfo->value.enumerated.item].name);
-
-       return 0;
-}
-
-/* source get callback */
-static int snd_toneport_source_get(struct snd_kcontrol *kcontrol,
-                                  struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-       struct usb_line6_toneport *toneport =
-           (struct usb_line6_toneport *)line6pcm->line6;
-       ucontrol->value.enumerated.item[0] = toneport->source;
-       return 0;
-}
-
-/* source put callback */
-static int snd_toneport_source_put(struct snd_kcontrol *kcontrol,
-                                  struct snd_ctl_elem_value *ucontrol)
-{
-       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
-       struct usb_line6_toneport *toneport =
-           (struct usb_line6_toneport *)line6pcm->line6;
-       unsigned int source;
-
-       source = ucontrol->value.enumerated.item[0];
-       if (source >= ARRAY_SIZE(toneport_source_info))
-               return -EINVAL;
-       if (source == toneport->source)
-               return 0;
-
-       toneport->source = source;
-       toneport_send_cmd(toneport->line6.usbdev,
-                         toneport_source_info[source].code, 0x0000);
-       return 1;
-}
-
-static void toneport_start_pcm(unsigned long arg)
-{
-       struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg;
-       struct usb_line6 *line6 = &toneport->line6;
-
-       line6_pcm_acquire(line6->line6pcm, LINE6_BITS_PCM_MONITOR);
-}
-
-/* control definition */
-static struct snd_kcontrol_new toneport_control_monitor = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "Monitor Playback Volume",
-       .index = 0,
-       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-       .info = snd_toneport_monitor_info,
-       .get = snd_toneport_monitor_get,
-       .put = snd_toneport_monitor_put
-};
-
-/* source selector definition */
-static struct snd_kcontrol_new toneport_control_source = {
-       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
-       .name = "PCM Capture Source",
-       .index = 0,
-       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
-       .info = snd_toneport_source_info,
-       .get = snd_toneport_source_get,
-       .put = snd_toneport_source_put
-};
-
-/*
-       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)
-{
-       int ticks;
-       struct usb_line6 *line6 = &toneport->line6;
-       struct usb_device *usbdev = line6->usbdev;
-
-       /* sync time on device with host: */
-       ticks = (int)get_seconds();
-       line6_write_data(line6, 0x80c6, &ticks, 4);
-
-       /* enable device: */
-       toneport_send_cmd(usbdev, 0x0301, 0x0000);
-
-       /* initialize source select: */
-       switch (line6->type) {
-       case LINE6_TONEPORT_UX1:
-       case LINE6_TONEPORT_UX2:
-       case LINE6_PODSTUDIO_UX1:
-       case LINE6_PODSTUDIO_UX2:
-               toneport_send_cmd(usbdev,
-                                 toneport_source_info[toneport->source].code,
-                                 0x0000);
-       default:
-               break;
-       }
-
-       if (toneport_has_led(line6->type))
-               toneport_update_led(&usbdev->dev);
-}
-
-/*
-       Toneport device disconnected.
-*/
-static void line6_toneport_disconnect(struct usb_interface *interface)
-{
-       struct usb_line6_toneport *toneport;
-       u16 idProduct;
-
-       if (interface == NULL)
-               return;
-
-       toneport = usb_get_intfdata(interface);
-       del_timer_sync(&toneport->timer);
-       idProduct = le16_to_cpu(toneport->line6.usbdev->descriptor.idProduct);
-
-       if (toneport_has_led(idProduct)) {
-               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)
-{
-       int err;
-       struct usb_line6_toneport *toneport =  (struct usb_line6_toneport *) line6;
-
-       if ((interface == NULL) || (toneport == NULL))
-               return -ENODEV;
-
-       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)
-               return err;
-
-       /* register monitor control: */
-       err = snd_ctl_add(line6->card,
-                         snd_ctl_new1(&toneport_control_monitor,
-                                      line6->line6pcm));
-       if (err < 0)
-               return err;
-
-       /* register source select control: */
-       switch (line6->type) {
-       case LINE6_TONEPORT_UX1:
-       case LINE6_TONEPORT_UX2:
-       case LINE6_PODSTUDIO_UX1:
-       case LINE6_PODSTUDIO_UX2:
-               err =
-                   snd_ctl_add(line6->card,
-                               snd_ctl_new1(&toneport_control_source,
-                                            line6->line6pcm));
-               if (err < 0)
-                       return err;
-
-       default:
-               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));
-       }
-
-       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);
-
-       return 0;
-}
-
-/*
-        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;
-}
-
-/*
-       Resume Toneport device after reset.
-*/
-void line6_toneport_reset_resume(struct usb_line6_toneport *toneport)
-{
-       toneport_setup(toneport);
-}
diff --git a/drivers/staging/line6/toneport.h b/drivers/staging/line6/toneport.h
deleted file mode 100644 (file)
index 8cb1442..0000000
+++ /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/drivers/staging/line6/usbdefs.h b/drivers/staging/line6/usbdefs.h
deleted file mode 100644 (file)
index f4d080e..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.9.1beta
- *
- * Copyright (C) 2005-2008 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 USBDEFS_H
-#define USBDEFS_H
-
-#define USB_INTERVALS_PER_SECOND 1000
-
-/* device supports settings parameter via USB */
-#define LINE6_CAP_CONTROL (1 << 0)
-/* device supports PCM input/output via USB */
-#define LINE6_CAP_PCM (1 << 1)
-/* device support hardware monitoring */
-#define LINE6_CAP_HWMON (1 << 2)
-
-#define LINE6_FALLBACK_INTERVAL 10
-#define LINE6_FALLBACK_MAXPACKETSIZE 16
-
-#endif
diff --git a/drivers/staging/line6/variax.c b/drivers/staging/line6/variax.c
deleted file mode 100644 (file)
index b4a41b0..0000000
+++ /dev/null
@@ -1,239 +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 <linux/slab.h>
-
-#include "audio.h"
-#include "driver.h"
-#include "variax.h"
-
-#define VARIAX_OFFSET_ACTIVATE 7
-
-/*
-       This message is sent by the device during initialization and identifies
-       the connected guitar version.
-*/
-static const char variax_init_version[] = {
-       0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
-       0x07, 0x00, 0x00, 0x00
-};
-
-/*
-       This message is the last one sent by the device during initialization.
-*/
-static const char variax_init_done[] = {
-       0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
-};
-
-static const char variax_activate[] = {
-       0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
-       0xf7
-};
-
-/* forward declarations: */
-static void variax_startup2(unsigned long data);
-static void variax_startup4(unsigned long data);
-static void variax_startup5(unsigned long data);
-
-static void variax_activate_async(struct usb_line6_variax *variax, int a)
-{
-       variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
-       line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
-                                    sizeof(variax_activate));
-}
-
-/*
-       Variax 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 variax_startup1(struct usb_line6_variax *variax)
-{
-       CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);
-
-       /* delay startup procedure: */
-       line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
-                         variax_startup2, (unsigned long)variax);
-}
-
-static void variax_startup2(unsigned long data)
-{
-       struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
-       struct usb_line6 *line6 = &variax->line6;
-
-       /* schedule another startup procedure until startup is complete: */
-       if (variax->startup_progress >= VARIAX_STARTUP_LAST)
-               return;
-
-       variax->startup_progress = VARIAX_STARTUP_VERSIONREQ;
-       line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
-                         variax_startup2, (unsigned long)variax);
-
-       /* request firmware version: */
-       line6_version_request_async(line6);
-}
-
-static void variax_startup3(struct usb_line6_variax *variax)
-{
-       CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);
-
-       /* delay startup procedure: */
-       line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
-                         variax_startup4, (unsigned long)variax);
-}
-
-static void variax_startup4(unsigned long data)
-{
-       struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
-
-       CHECK_STARTUP_PROGRESS(variax->startup_progress,
-                              VARIAX_STARTUP_ACTIVATE);
-
-       /* activate device: */
-       variax_activate_async(variax, 1);
-       line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
-                         variax_startup5, (unsigned long)variax);
-}
-
-static void variax_startup5(unsigned long data)
-{
-       struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
-
-       CHECK_STARTUP_PROGRESS(variax->startup_progress,
-                              VARIAX_STARTUP_WORKQUEUE);
-
-       /* schedule work for global work queue: */
-       schedule_work(&variax->startup_work);
-}
-
-static void variax_startup6(struct work_struct *work)
-{
-       struct usb_line6_variax *variax =
-           container_of(work, struct usb_line6_variax, startup_work);
-
-       CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
-
-       /* ALSA audio interface: */
-       line6_register_audio(&variax->line6);
-}
-
-/*
-       Process a completely received message.
-*/
-static void line6_variax_process_message(struct usb_line6 *line6)
-{
-       struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
-       const unsigned char *buf = variax->line6.buffer_message;
-
-       switch (buf[0]) {
-       case LINE6_RESET:
-               dev_info(variax->line6.ifcdev, "VARIAX reset\n");
-               break;
-
-       case LINE6_SYSEX_BEGIN:
-               if (memcmp(buf + 1, variax_init_version + 1,
-                          sizeof(variax_init_version) - 1) == 0) {
-                       variax_startup3(variax);
-               } else if (memcmp(buf + 1, variax_init_done + 1,
-                                 sizeof(variax_init_done) - 1) == 0) {
-                       /* notify of complete initialization: */
-                       variax_startup4((unsigned long)variax);
-               }
-               break;
-       }
-}
-
-/*
-       Variax destructor.
-*/
-static void variax_destruct(struct usb_interface *interface)
-{
-       struct usb_line6_variax *variax = usb_get_intfdata(interface);
-
-       if (variax == NULL)
-               return;
-       line6_cleanup_audio(&variax->line6);
-
-       del_timer(&variax->startup_timer1);
-       del_timer(&variax->startup_timer2);
-       cancel_work_sync(&variax->startup_work);
-
-       kfree(variax->buffer_activate);
-}
-
-/*
-       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)
-{
-       struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
-       int err;
-
-       line6->process_message = line6_variax_process_message;
-       line6->disconnect = line6_variax_disconnect;
-
-       init_timer(&variax->startup_timer1);
-       init_timer(&variax->startup_timer2);
-       INIT_WORK(&variax->startup_work, variax_startup6);
-
-       if ((interface == NULL) || (variax == NULL))
-               return -ENODEV;
-
-       /* initialize USB buffers: */
-       variax->buffer_activate = kmemdup(variax_activate,
-                                         sizeof(variax_activate), GFP_KERNEL);
-
-       if (variax->buffer_activate == NULL) {
-               dev_err(&interface->dev, "Out of memory\n");
-               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);
-       if (err < 0)
-               return err;
-
-       /* initiate startup procedure: */
-       variax_startup1(variax);
-       return 0;
-}
-
-/*
-        Init workbench device (and clean up in case of failure).
-*/
-int line6_variax_init(struct usb_interface *interface, struct usb_line6 *line6)
-{
-       int err = variax_try_init(interface, line6);
-
-       if (err < 0)
-               variax_destruct(interface);
-
-       return err;
-}
diff --git a/drivers/staging/line6/variax.h b/drivers/staging/line6/variax.h
deleted file mode 100644 (file)
index dfb94e5..0000000
+++ /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
index d393153c474f2d763be5cdad6e39f4a1798d2463..a452ad7cec4016f603142e722b5d2535959c4581 100644 (file)
@@ -160,5 +160,7 @@ config SND_BCD2000
          To compile this driver as a module, choose M here: the module
          will be called snd-bcd2000.
 
+source "sound/usb/line6/Kconfig"
+
 endif  # SND_USB
 
index bcee4060fd1815f2c7cdb526807be3ba2d21178e..54045b745d11eec4d021a74303ca935e7446a90d 100644 (file)
@@ -25,3 +25,4 @@ obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o
 obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o
 
 obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/
+obj-$(CONFIG_LINE6_USB)                += line6/
diff --git a/sound/usb/line6/Kconfig b/sound/usb/line6/Kconfig
new file mode 100644 (file)
index 0000000..4f1219b
--- /dev/null
@@ -0,0 +1,38 @@
+menuconfig LINE6_USB
+       tristate "Line6 USB support"
+       depends on USB && SND
+       select SND_RAWMIDI
+       select SND_PCM
+       help
+         This is a driver for the guitar amp, cab, and effects modeller
+         PODxt Pro by Line6 (and similar devices), supporting the
+         following features:
+           * Reading/writing individual parameters
+           * Reading/writing complete channel, effects setup, and amp
+             setup data
+           * Channel switching
+           * Virtual MIDI interface
+           * Tuner access
+           * Playback/capture/mixer device for any ALSA-compatible PCM
+             audio application
+           * 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
+       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.
+
+         If unsure, say N.
+
+endif # LINE6_USB
diff --git a/sound/usb/line6/Makefile b/sound/usb/line6/Makefile
new file mode 100644 (file)
index 0000000..ae5c374
--- /dev/null
@@ -0,0 +1,14 @@
+obj-$(CONFIG_LINE6_USB)                += line6usb.o
+
+line6usb-y :=          \
+               audio.o         \
+               capture.o       \
+               driver.o        \
+               midi.o          \
+               midibuf.o       \
+               pcm.o           \
+               playback.o      \
+               pod.o           \
+               toneport.o      \
+               variax.o        \
+               podhd.o
diff --git a/sound/usb/line6/audio.c b/sound/usb/line6/audio.c
new file mode 100644 (file)
index 0000000..171d80c
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..5f8a09a
--- /dev/null
@@ -0,0 +1,21 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..f24c7c5
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+ * 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 <linux/slab.h>
+#include <sound/core.h>
+#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.
+*/
+static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)
+{
+       int index;
+       unsigned long flags;
+       int i, urb_size;
+       int ret;
+       struct urb *urb_in;
+
+       spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
+       index =
+           find_first_zero_bit(&line6pcm->active_urb_in, LINE6_ISO_BUFFERS);
+
+       if (index < 0 || index >= LINE6_ISO_BUFFERS) {
+               spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
+               dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
+               return -EINVAL;
+       }
+
+       urb_in = line6pcm->urb_audio_in[index];
+       urb_size = 0;
+
+       for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
+               struct usb_iso_packet_descriptor *fin =
+                   &urb_in->iso_frame_desc[i];
+               fin->offset = urb_size;
+               fin->length = line6pcm->max_packet_size;
+               urb_size += line6pcm->max_packet_size;
+       }
+
+       urb_in->transfer_buffer =
+           line6pcm->buffer_in +
+           index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
+       urb_in->transfer_buffer_length = urb_size;
+       urb_in->context = line6pcm;
+
+       ret = usb_submit_urb(urb_in, GFP_ATOMIC);
+
+       if (ret == 0)
+               set_bit(index, &line6pcm->active_urb_in);
+       else
+               dev_err(line6pcm->line6->ifcdev,
+                       "URB in #%d submission failed (%d)\n", index, ret);
+
+       spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
+       return 0;
+}
+
+/*
+       Submit all currently available capture URBs.
+*/
+int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm)
+{
+       int ret, i;
+
+       for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
+               ret = submit_audio_in_urb(line6pcm);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/*
+       Unlink all currently active capture URBs.
+*/
+void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm)
+{
+       unsigned int i;
+
+       for (i = LINE6_ISO_BUFFERS; i--;) {
+               if (test_bit(i, &line6pcm->active_urb_in)) {
+                       if (!test_and_set_bit(i, &line6pcm->unlink_urb_in)) {
+                               struct urb *u = line6pcm->urb_audio_in[i];
+
+                               usb_unlink_urb(u);
+                       }
+               }
+       }
+}
+
+/*
+       Wait until unlinking of all currently active capture URBs has been
+       finished.
+*/
+void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
+{
+       int timeout = HZ;
+       unsigned int i;
+       int alive;
+
+       do {
+               alive = 0;
+               for (i = LINE6_ISO_BUFFERS; i--;) {
+                       if (test_bit(i, &line6pcm->active_urb_in))
+                               alive++;
+               }
+               if (!alive)
+                       break;
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(1);
+       } while (--timeout > 0);
+       if (alive)
+               snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
+}
+
+/*
+       Unlink all currently active capture URBs, and wait for finishing.
+*/
+void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
+{
+       line6_unlink_audio_in_urbs(line6pcm);
+       line6_wait_clear_audio_in_urbs(line6pcm);
+}
+
+/*
+       Copy data into ALSA capture buffer.
+*/
+void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf, int fsize)
+{
+       struct snd_pcm_substream *substream =
+           get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
+       int frames = fsize / bytes_per_frame;
+
+       if (runtime == NULL)
+               return;
+
+       if (line6pcm->pos_in_done + frames > runtime->buffer_size) {
+               /*
+                  The transferred area goes over buffer boundary,
+                  copy two separate chunks.
+                */
+               int len;
+
+               len = runtime->buffer_size - line6pcm->pos_in_done;
+
+               if (len > 0) {
+                       memcpy(runtime->dma_area +
+                              line6pcm->pos_in_done * bytes_per_frame, fbuf,
+                              len * bytes_per_frame);
+                       memcpy(runtime->dma_area, fbuf + len * bytes_per_frame,
+                              (frames - len) * bytes_per_frame);
+               } else {
+                       /* this is somewhat paranoid */
+                       dev_err(line6pcm->line6->ifcdev,
+                               "driver bug: len = %d\n", len);
+               }
+       } else {
+               /* copy single chunk */
+               memcpy(runtime->dma_area +
+                      line6pcm->pos_in_done * bytes_per_frame, fbuf, fsize);
+       }
+
+       line6pcm->pos_in_done += frames;
+       if (line6pcm->pos_in_done >= runtime->buffer_size)
+               line6pcm->pos_in_done -= runtime->buffer_size;
+}
+
+void line6_capture_check_period(struct snd_line6_pcm *line6pcm, int length)
+{
+       struct snd_pcm_substream *substream =
+           get_substream(line6pcm, SNDRV_PCM_STREAM_CAPTURE);
+
+       line6pcm->bytes_in += length;
+       if (line6pcm->bytes_in >= line6pcm->period_in) {
+               line6pcm->bytes_in %= line6pcm->period_in;
+               snd_pcm_period_elapsed(substream);
+       }
+}
+
+void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm)
+{
+       kfree(line6pcm->buffer_in);
+       line6pcm->buffer_in = NULL;
+}
+
+/*
+ * Callback for completed capture URB.
+ */
+static void audio_in_callback(struct urb *urb)
+{
+       int i, index, length = 0, shutdown = 0;
+       unsigned long flags;
+
+       struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;
+
+       line6pcm->last_frame_in = urb->start_frame;
+
+       /* find index of URB */
+       for (index = 0; index < LINE6_ISO_BUFFERS; ++index)
+               if (urb == line6pcm->urb_audio_in[index])
+                       break;
+
+       spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
+
+       for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
+               char *fbuf;
+               int fsize;
+               struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i];
+
+               if (fin->status == -EXDEV) {
+                       shutdown = 1;
+                       break;
+               }
+
+               fbuf = urb->transfer_buffer + fin->offset;
+               fsize = fin->actual_length;
+
+               if (fsize > line6pcm->max_packet_size) {
+                       dev_err(line6pcm->line6->ifcdev,
+                               "driver and/or device bug: packet too large (%d > %d)\n",
+                               fsize, line6pcm->max_packet_size);
+               }
+
+               length += fsize;
+
+               /* the following assumes LINE6_ISO_PACKETS == 1: */
+               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);
+       }
+
+       clear_bit(index, &line6pcm->active_urb_in);
+
+       if (test_and_clear_bit(index, &line6pcm->unlink_urb_in))
+               shutdown = 1;
+
+       spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
+
+       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);
+       }
+}
+
+/* open capture callback */
+static int snd_line6_capture_open(struct snd_pcm_substream *substream)
+{
+       int err;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+
+       err = snd_pcm_hw_constraint_ratdens(runtime, 0,
+                                           SNDRV_PCM_HW_PARAM_RATE,
+                                           (&line6pcm->
+                                            properties->snd_line6_rates));
+       if (err < 0)
+               return err;
+
+       runtime->hw = line6pcm->properties->snd_line6_capture_hw;
+       return 0;
+}
+
+/* close capture callback */
+static int snd_line6_capture_close(struct snd_pcm_substream *substream)
+{
+       return 0;
+}
+
+/* hw_params capture callback */
+static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream,
+                                      struct snd_pcm_hw_params *hw_params)
+{
+       int ret;
+       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+
+       /* -- Florian Demski [FD] */
+       /* don't ask me why, but this fixes the bug on my machine */
+       if (line6pcm == NULL) {
+               if (substream->pcm == NULL)
+                       return -ENOMEM;
+               if (substream->pcm->private_data == NULL)
+                       return -ENOMEM;
+               substream->private_data = substream->pcm->private_data;
+               line6pcm = snd_pcm_substream_chip(substream);
+       }
+       /* -- [FD] end */
+
+       ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
+
+       if (ret < 0)
+               return ret;
+
+       ret = snd_pcm_lib_malloc_pages(substream,
+                                      params_buffer_bytes(hw_params));
+       if (ret < 0) {
+               line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
+               return ret;
+       }
+
+       line6pcm->period_in = params_period_bytes(hw_params);
+       return 0;
+}
+
+/* hw_free capture callback */
+static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+
+       line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
+       return snd_pcm_lib_free_pages(substream);
+}
+
+/* trigger callback */
+int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd)
+{
+       int err;
+
+       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);
+
+               if (err < 0)
+                       return err;
+
+               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);
+
+               if (err < 0)
+                       return err;
+
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* capture pointer callback */
+static snd_pcm_uframes_t
+snd_line6_capture_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+
+       return line6pcm->pos_in_done;
+}
+
+/* capture operators */
+struct snd_pcm_ops snd_line6_capture_ops = {
+       .open = snd_line6_capture_open,
+       .close = snd_line6_capture_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = snd_line6_capture_hw_params,
+       .hw_free = snd_line6_capture_hw_free,
+       .prepare = snd_line6_prepare,
+       .trigger = snd_line6_trigger,
+       .pointer = snd_line6_capture_pointer,
+};
+
+int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
+{
+       struct usb_line6 *line6 = line6pcm->line6;
+       int i;
+
+       /* create audio URBs and fill in constant values: */
+       for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
+               struct urb *urb;
+
+               /* URB for audio in: */
+               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");
+                       return -ENOMEM;
+               }
+
+               urb->dev = line6->usbdev;
+               urb->pipe =
+                   usb_rcvisocpipe(line6->usbdev,
+                                   line6->properties->ep_audio_r &
+                                   USB_ENDPOINT_NUMBER_MASK);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->start_frame = -1;
+               urb->number_of_packets = LINE6_ISO_PACKETS;
+               urb->interval = LINE6_ISO_INTERVAL;
+               urb->error_count = 0;
+               urb->complete = audio_in_callback;
+       }
+
+       return 0;
+}
diff --git a/sound/usb/line6/capture.h b/sound/usb/line6/capture.h
new file mode 100644 (file)
index 0000000..4157bcb
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ * 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 CAPTURE_H
+#define CAPTURE_H
+
+#include <sound/pcm.h>
+
+#include "driver.h"
+#include "pcm.h"
+
+extern struct snd_pcm_ops snd_line6_capture_ops;
+
+extern void line6_capture_copy(struct snd_line6_pcm *line6pcm, char *fbuf,
+                              int fsize);
+extern void line6_capture_check_period(struct snd_line6_pcm *line6pcm,
+                                      int length);
+extern int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm);
+extern void line6_free_capture_buffer(struct snd_line6_pcm *line6pcm);
+extern int line6_submit_audio_in_all_urbs(struct snd_line6_pcm *line6pcm);
+extern void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm);
+extern void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm
+                                                 *line6pcm);
+extern void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm);
+extern int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd);
+
+#endif
diff --git a/sound/usb/line6/driver.c b/sound/usb/line6/driver.c
new file mode 100644 (file)
index 0000000..fc852f6
--- /dev/null
@@ -0,0 +1,1114 @@
+/*
+ * 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 <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+
+#include "audio.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 */
+       }
+};
+
+/*
+       This is Line6's MIDI manufacturer ID.
+*/
+const unsigned char line6_midi_id[] = {
+       0x00, 0x01, 0x0c
+};
+
+/*
+       Code to request version of POD, Variax interface
+       (and maybe other devices).
+*/
+static const char line6_request_version[] = {
+       0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7
+};
+
+/**
+        Class for asynchronous messages.
+*/
+struct message {
+       struct usb_line6 *line6;
+       const char *buffer;
+       int size;
+       int done;
+};
+
+/*
+       Forward declarations.
+*/
+static void line6_data_received(struct urb *urb);
+static int line6_send_raw_message_async_part(struct message *msg,
+                                            struct urb *urb);
+
+/*
+       Start to listen on endpoint.
+*/
+static int line6_start_listen(struct usb_line6 *line6)
+{
+       int err;
+
+       usb_fill_int_urb(line6->urb_listen, line6->usbdev,
+               usb_rcvintpipe(line6->usbdev, line6->properties->ep_ctrl_r),
+               line6->buffer_listen, LINE6_BUFSIZE_LISTEN,
+               line6_data_received, line6, line6->interval);
+       line6->urb_listen->actual_length = 0;
+       err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC);
+       return err;
+}
+
+/*
+       Stop listening on endpoint.
+*/
+static void line6_stop_listen(struct usb_line6 *line6)
+{
+       usb_kill_urb(line6->urb_listen);
+}
+
+/*
+       Send raw message in pieces of wMaxPacketSize bytes.
+*/
+int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
+                          int size)
+{
+       int i, done = 0;
+
+       for (i = 0; i < size; i += line6->max_packet_size) {
+               int partial;
+               const char *frag_buf = buffer + i;
+               int frag_size = min(line6->max_packet_size, size - i);
+               int retval;
+
+               retval = usb_interrupt_msg(line6->usbdev,
+                                       usb_sndintpipe(line6->usbdev,
+                                               line6->properties->ep_ctrl_w),
+                                       (char *)frag_buf, frag_size,
+                                       &partial, LINE6_TIMEOUT * HZ);
+
+               if (retval) {
+                       dev_err(line6->ifcdev,
+                               "usb_interrupt_msg failed (%d)\n", retval);
+                       break;
+               }
+
+               done += frag_size;
+       }
+
+       return done;
+}
+
+/*
+       Notification of completion of asynchronous request transmission.
+*/
+static void line6_async_request_sent(struct urb *urb)
+{
+       struct message *msg = (struct message *)urb->context;
+
+       if (msg->done >= msg->size) {
+               usb_free_urb(urb);
+               kfree(msg);
+       } else
+               line6_send_raw_message_async_part(msg, urb);
+}
+
+/*
+       Asynchronously send part of a raw message.
+*/
+static int line6_send_raw_message_async_part(struct message *msg,
+                                            struct urb *urb)
+{
+       int retval;
+       struct usb_line6 *line6 = msg->line6;
+       int done = msg->done;
+       int bytes = min(msg->size - done, line6->max_packet_size);
+
+       usb_fill_int_urb(urb, line6->usbdev,
+               usb_sndintpipe(line6->usbdev, line6->properties->ep_ctrl_w),
+               (char *)msg->buffer + done, bytes,
+               line6_async_request_sent, msg, line6->interval);
+
+       msg->done += bytes;
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+
+       if (retval < 0) {
+               dev_err(line6->ifcdev, "%s: usb_submit_urb failed (%d)\n",
+                       __func__, retval);
+               usb_free_urb(urb);
+               kfree(msg);
+               return retval;
+       }
+
+       return 0;
+}
+
+/*
+       Setup and start timer.
+*/
+void line6_start_timer(struct timer_list *timer, unsigned int msecs,
+                      void (*function)(unsigned long), unsigned long data)
+{
+       setup_timer(timer, function, data);
+       timer->expires = jiffies + msecs * HZ / 1000;
+       add_timer(timer);
+}
+
+/*
+       Asynchronously send raw message.
+*/
+int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer,
+                                int size)
+{
+       struct message *msg;
+       struct urb *urb;
+
+       /* create message: */
+       msg = kmalloc(sizeof(struct message), GFP_ATOMIC);
+       if (msg == NULL)
+               return -ENOMEM;
+
+       /* create URB: */
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
+
+       if (urb == NULL) {
+               kfree(msg);
+               dev_err(line6->ifcdev, "Out of memory\n");
+               return -ENOMEM;
+       }
+
+       /* set message data: */
+       msg->line6 = line6;
+       msg->buffer = buffer;
+       msg->size = size;
+       msg->done = 0;
+
+       /* start sending: */
+       return line6_send_raw_message_async_part(msg, urb);
+}
+
+/*
+       Send asynchronous device version request.
+*/
+int line6_version_request_async(struct usb_line6 *line6)
+{
+       char *buffer;
+       int retval;
+
+       buffer = kmemdup(line6_request_version,
+                       sizeof(line6_request_version), GFP_ATOMIC);
+       if (buffer == NULL) {
+               dev_err(line6->ifcdev, "Out of memory");
+               return -ENOMEM;
+       }
+
+       retval = line6_send_raw_message_async(line6, buffer,
+                                             sizeof(line6_request_version));
+       kfree(buffer);
+       return retval;
+}
+
+/*
+       Send sysex message in pieces of wMaxPacketSize bytes.
+*/
+int line6_send_sysex_message(struct usb_line6 *line6, const char *buffer,
+                            int size)
+{
+       return line6_send_raw_message(line6, buffer,
+                                     size + SYSEX_EXTRA_SIZE) -
+           SYSEX_EXTRA_SIZE;
+}
+
+/*
+       Allocate buffer for sysex message and prepare header.
+       @param code sysex message code
+       @param size number of bytes between code and sysex end
+*/
+char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2,
+                              int size)
+{
+       char *buffer = kmalloc(size + SYSEX_EXTRA_SIZE, GFP_ATOMIC);
+
+       if (!buffer)
+               return NULL;
+
+       buffer[0] = LINE6_SYSEX_BEGIN;
+       memcpy(buffer + 1, line6_midi_id, sizeof(line6_midi_id));
+       buffer[sizeof(line6_midi_id) + 1] = code1;
+       buffer[sizeof(line6_midi_id) + 2] = code2;
+       buffer[sizeof(line6_midi_id) + 3 + size] = LINE6_SYSEX_END;
+       return buffer;
+}
+
+/*
+       Notification of data received from the Line6 device.
+*/
+static void line6_data_received(struct urb *urb)
+{
+       struct usb_line6 *line6 = (struct usb_line6 *)urb->context;
+       struct midi_buffer *mb = &line6->line6midi->midibuf_in;
+       int done;
+
+       if (urb->status == -ESHUTDOWN)
+               return;
+
+       done =
+           line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length);
+
+       if (done < urb->actual_length) {
+               line6_midibuf_ignore(mb, done);
+               dev_dbg(line6->ifcdev, "%d %d buffer overflow - message skipped\n",
+                       done, urb->actual_length);
+       }
+
+       for (;;) {
+               done =
+                   line6_midibuf_read(mb, line6->buffer_message,
+                                      LINE6_MESSAGE_MAXLEN);
+
+               if (done == 0)
+                       break;
+
+               line6->message_length = done;
+               line6_midi_receive(line6, line6->buffer_message, done);
+
+               if (line6->process_message)
+                       line6->process_message(line6);
+       }
+
+       line6_start_listen(line6);
+}
+
+/*
+       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,
+                   size_t datalen)
+{
+       struct usb_device *usbdev = line6->usbdev;
+       int ret;
+       unsigned char len;
+
+       /* query the serial number: */
+       ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
+                             USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+                             (datalen << 8) | 0x21, address,
+                             NULL, 0, LINE6_TIMEOUT * HZ);
+
+       if (ret < 0) {
+               dev_err(line6->ifcdev, "read request failed (error %d)\n", ret);
+               return ret;
+       }
+
+       /* Wait for data length. We'll get 0xff until length arrives. */
+       do {
+               ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67,
+                                     USB_TYPE_VENDOR | USB_RECIP_DEVICE |
+                                     USB_DIR_IN,
+                                     0x0012, 0x0000, &len, 1,
+                                     LINE6_TIMEOUT * HZ);
+               if (ret < 0) {
+                       dev_err(line6->ifcdev,
+                               "receive length failed (error %d)\n", ret);
+                       return ret;
+               }
+       } while (len == 0xff);
+
+       if (len != datalen) {
+               /* should be equal or something went wrong */
+               dev_err(line6->ifcdev,
+                       "length mismatch (expected %d, got %d)\n",
+                       (int)datalen, (int)len);
+               return -EINVAL;
+       }
+
+       /* receive the result: */
+       ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0), 0x67,
+                             USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+                             0x0013, 0x0000, data, datalen,
+                             LINE6_TIMEOUT * HZ);
+
+       if (ret < 0) {
+               dev_err(line6->ifcdev, "read failed (error %d)\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+/*
+       Write data to device.
+*/
+int line6_write_data(struct usb_line6 *line6, int address, void *data,
+                    size_t datalen)
+{
+       struct usb_device *usbdev = line6->usbdev;
+       int ret;
+       unsigned char status;
+
+       ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
+                             USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+                             0x0022, address, data, datalen,
+                             LINE6_TIMEOUT * HZ);
+
+       if (ret < 0) {
+               dev_err(line6->ifcdev,
+                       "write request failed (error %d)\n", ret);
+               return ret;
+       }
+
+       do {
+               ret = usb_control_msg(usbdev, usb_rcvctrlpipe(usbdev, 0),
+                                     0x67,
+                                     USB_TYPE_VENDOR | USB_RECIP_DEVICE |
+                                     USB_DIR_IN,
+                                     0x0012, 0x0000,
+                                     &status, 1, LINE6_TIMEOUT * HZ);
+
+               if (ret < 0) {
+                       dev_err(line6->ifcdev,
+                               "receiving status failed (error %d)\n", ret);
+                       return ret;
+               }
+       } while (status == 0xff);
+
+       if (status != 0) {
+               dev_err(line6->ifcdev, "write failed (error %d)\n", ret);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/*
+       Read Line6 device serial number.
+       (POD, TonePort, GuitarPort)
+*/
+int line6_read_serial_number(struct usb_line6 *line6, int *serial_number)
+{
+       return line6_read_data(line6, 0x80d0, serial_number,
+                              sizeof(*serial_number));
+}
+
+/*
+       No operation (i.e., unsupported).
+*/
+ssize_t line6_nop_read(struct device *dev, struct device_attribute *attr,
+                      char *buf)
+{
+       return 0;
+}
+
+/*
+       Generic destructor.
+*/
+static void line6_destruct(struct usb_interface *interface)
+{
+       struct usb_line6 *line6;
+
+       if (interface == NULL)
+               return;
+       line6 = usb_get_intfdata(interface);
+       if (line6 == NULL)
+               return;
+
+       /* free buffer memory first: */
+       kfree(line6->buffer_message);
+       kfree(line6->buffer_listen);
+
+       /* 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);
+}
+
+/*
+       Probe USB device.
+*/
+static int line6_probe(struct usb_interface *interface,
+                      const struct usb_device_id *id)
+{
+       enum line6_device_type devtype;
+       struct usb_device *usbdev;
+       struct usb_line6 *line6;
+       const struct line6_properties *properties;
+       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);
+
+       /* query interface number */
+       interface_number = interface->cur_altsetting->desc.bInterfaceNumber;
+
+       ret = usb_set_interface(usbdev, interface_number,
+                       properties->altsetting);
+       if (ret < 0) {
+               dev_err(&interface->dev, "set_interface failed\n");
+               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): */
+       {
+               struct usb_host_endpoint *ep;
+               unsigned pipe = usb_rcvintpipe(usbdev, properties->ep_ctrl_r);
+               unsigned epnum = usb_pipeendpoint(pipe);
+               ep = usbdev->ep_in[epnum];
+
+               if (ep != NULL) {
+                       line6->interval = ep->desc.bInterval;
+                       line6->max_packet_size =
+                           le16_to_cpu(ep->desc.wMaxPacketSize);
+               } else {
+                       line6->interval = LINE6_FALLBACK_INTERVAL;
+                       line6->max_packet_size = LINE6_FALLBACK_MAXPACKETSIZE;
+                       dev_err(line6->ifcdev,
+                               "endpoint not available, using fallback values");
+               }
+       }
+
+       usb_set_intfdata(interface, line6);
+
+       if (properties->capabilities & LINE6_CAP_CONTROL) {
+               /* initialize USB buffers: */
+               line6->buffer_listen =
+                   kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL);
+               if (line6->buffer_listen == NULL) {
+                       ret = -ENOMEM;
+                       goto err_destruct;
+               }
+
+               line6->buffer_message =
+                   kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL);
+               if (line6->buffer_message == NULL) {
+                       ret = -ENOMEM;
+                       goto err_destruct;
+               }
+
+               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;
+               }
+
+               ret = line6_start_listen(line6);
+               if (ret < 0) {
+                       dev_err(&interface->dev, "%s: usb_submit_urb failed\n",
+                               __func__);
+                       goto err_destruct;
+               }
+       }
+
+       /* 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");
+       if (ret < 0)
+               goto err_destruct;
+
+       /* creation of additional special files should go here */
+
+       dev_info(&interface->dev, "Line6 %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:
+       return ret;
+}
+
+/*
+       Line6 device disconnected.
+*/
+static void line6_disconnect(struct usb_interface *interface)
+{
+       struct usb_line6 *line6;
+       struct usb_device *usbdev;
+       int interface_number;
+
+       if (interface == NULL)
+               return;
+       usbdev = interface_to_usbdev(interface);
+       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 != NULL) {
+               if (line6->urb_listen != NULL)
+                       line6_stop_listen(line6);
+
+               if (usbdev != line6->usbdev)
+                       dev_err(line6->ifcdev,
+                               "driver bug: inconsistent usb device\n");
+
+               line6->disconnect(interface);
+
+               dev_info(&interface->dev, "Line6 %s now disconnected\n",
+                        line6->properties->name);
+       }
+
+       line6_destruct(interface);
+
+       /* decrement reference counters: */
+       usb_put_intf(interface);
+       usb_put_dev(usbdev);
+}
+
+#ifdef CONFIG_PM
+
+/*
+       Suspend Line6 device.
+*/
+static 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;
+
+       snd_power_change_state(line6->card, SNDRV_CTL_POWER_D3hot);
+
+       if (line6->properties->capabilities & LINE6_CAP_CONTROL)
+               line6_stop_listen(line6);
+
+       if (line6pcm != NULL) {
+               snd_pcm_suspend_all(line6pcm->pcm);
+               line6_pcm_disconnect(line6pcm);
+               line6pcm->flags = 0;
+       }
+
+       return 0;
+}
+
+/*
+       Resume Line6 device.
+*/
+static int line6_resume(struct usb_interface *interface)
+{
+       struct usb_line6 *line6 = usb_get_intfdata(interface);
+
+       if (line6->properties->capabilities & LINE6_CAP_CONTROL)
+               line6_start_listen(line6);
+
+       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);
+}
+
+#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
new file mode 100644 (file)
index 0000000..ad203f1
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * 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 DRIVER_H
+#define DRIVER_H
+
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+#include <sound/core.h>
+
+#include "midi.h"
+
+#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
+*/
+#define LINE6_PARAM_CHANGE   0xb0
+#define LINE6_PROGRAM_CHANGE 0xc0
+#define LINE6_SYSEX_BEGIN    0xf0
+#define LINE6_SYSEX_END      0xf7
+#define LINE6_RESET          0xff
+
+/*
+       MIDI channel for messages initiated by the host
+       (and eventually echoed back by the device)
+*/
+#define LINE6_CHANNEL_HOST   0x00
+
+/*
+       MIDI channel for messages initiated by the device
+*/
+#define LINE6_CHANNEL_DEVICE 0x02
+
+#define LINE6_CHANNEL_UNKNOWN 5        /* don't know yet what this is good for */
+
+#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))                 \
+               return;                 \
+       x = (n);                        \
+} while (0)
+
+extern const unsigned char line6_midi_id[3];
+
+static const int SYSEX_DATA_OFS = sizeof(line6_midi_id) + 3;
+static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4;
+
+/**
+        Common properties of Line6 devices.
+*/
+struct line6_properties {
+       /**
+                Card id string (maximum 16 characters).
+                This can be used to address the device in ALSA programs as
+                "default:CARD=<id>"
+       */
+       const char *id;
+
+       /**
+                Card short name (maximum 32 characters).
+       */
+       const char *name;
+
+       /**
+                Bit vector defining this device's capabilities in the
+                line6usb driver.
+       */
+       int capabilities;
+
+       int altsetting;
+
+       unsigned ep_ctrl_r;
+       unsigned ep_ctrl_w;
+       unsigned ep_audio_r;
+       unsigned ep_audio_w;
+};
+
+/**
+        Common data shared by all Line6 devices.
+        Corresponds to a pair of USB endpoints.
+*/
+struct usb_line6 {
+       /**
+                USB device.
+       */
+       struct usb_device *usbdev;
+
+       /**
+                Device type.
+       */
+       enum line6_device_type type;
+
+       /**
+                Properties.
+       */
+       const struct line6_properties *properties;
+
+       /**
+                Interval (ms).
+       */
+       int interval;
+
+       /**
+                Maximum size of USB packet.
+       */
+       int max_packet_size;
+
+       /**
+                Device representing the USB interface.
+       */
+       struct device *ifcdev;
+
+       /**
+                Line6 sound card data structure.
+                Each device has at least MIDI or PCM.
+       */
+       struct snd_card *card;
+
+       /**
+                Line6 PCM device data structure.
+       */
+       struct snd_line6_pcm *line6pcm;
+
+       /**
+                Line6 MIDI device data structure.
+       */
+       struct snd_line6_midi *line6midi;
+
+       /**
+                URB for listening to PODxt Pro control endpoint.
+       */
+       struct urb *urb_listen;
+
+       /**
+                Buffer for listening to PODxt Pro control endpoint.
+       */
+       unsigned char *buffer_listen;
+
+       /**
+                Buffer for message to be processed.
+       */
+       unsigned char *buffer_message;
+
+       /**
+                Length of message to be processed.
+       */
+       int message_length;
+
+       void (*process_message)(struct usb_line6 *);
+       void (*disconnect)(struct usb_interface *);
+};
+
+extern char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1,
+                                     int code2, int size);
+extern ssize_t line6_nop_read(struct device *dev,
+                             struct device_attribute *attr, char *buf);
+extern int line6_read_data(struct usb_line6 *line6, int address, void *data,
+                          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,
+                                   const char *buffer, int size);
+extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr,
+                            const char *buf, size_t count);
+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);
+
+#endif
diff --git a/sound/usb/line6/midi.c b/sound/usb/line6/midi.c
new file mode 100644 (file)
index 0000000..c9d725a
--- /dev/null
@@ -0,0 +1,321 @@
+/*
+ * 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 <linux/slab.h>
+#include <linux/usb.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) \
+       ((struct snd_line6_midi *)((substream)->rmidi->private_data))
+
+static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
+                          int length);
+
+/*
+       Pass data received via USB to MIDI.
+*/
+void line6_midi_receive(struct usb_line6 *line6, unsigned char *data,
+                       int length)
+{
+       if (line6->line6midi->substream_receive)
+               snd_rawmidi_receive(line6->line6midi->substream_receive,
+                                   data, length);
+}
+
+/*
+       Read data from MIDI buffer and transmit them via USB.
+*/
+static void line6_midi_transmit(struct snd_rawmidi_substream *substream)
+{
+       struct usb_line6 *line6 =
+           line6_rawmidi_substream_midi(substream)->line6;
+       struct snd_line6_midi *line6midi = line6->line6midi;
+       struct midi_buffer *mb = &line6midi->midibuf_out;
+       unsigned long flags;
+       unsigned char chunk[LINE6_FALLBACK_MAXPACKETSIZE];
+       int req, done;
+
+       spin_lock_irqsave(&line6->line6midi->midi_transmit_lock, flags);
+
+       for (;;) {
+               req = min(line6_midibuf_bytes_free(mb), line6->max_packet_size);
+               done = snd_rawmidi_transmit_peek(substream, chunk, req);
+
+               if (done == 0)
+                       break;
+
+               line6_midibuf_write(mb, chunk, done);
+               snd_rawmidi_transmit_ack(substream, done);
+       }
+
+       for (;;) {
+               done = line6_midibuf_read(mb, chunk,
+                                         LINE6_FALLBACK_MAXPACKETSIZE);
+
+               if (done == 0)
+                       break;
+
+               send_midi_async(line6, chunk, done);
+       }
+
+       spin_unlock_irqrestore(&line6->line6midi->midi_transmit_lock, flags);
+}
+
+/*
+       Notification of completion of MIDI transmission.
+*/
+static void midi_sent(struct urb *urb)
+{
+       unsigned long flags;
+       int status;
+       int num;
+       struct usb_line6 *line6 = (struct usb_line6 *)urb->context;
+
+       status = urb->status;
+       kfree(urb->transfer_buffer);
+       usb_free_urb(urb);
+
+       if (status == -ESHUTDOWN)
+               return;
+
+       spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags);
+       num = --line6->line6midi->num_active_send_urbs;
+
+       if (num == 0) {
+               line6_midi_transmit(line6->line6midi->substream_transmit);
+               num = line6->line6midi->num_active_send_urbs;
+       }
+
+       if (num == 0)
+               wake_up(&line6->line6midi->send_wait);
+
+       spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags);
+}
+
+/*
+       Send an asynchronous MIDI message.
+       Assumes that line6->line6midi->send_urb_lock is held
+       (i.e., this function is serialized).
+*/
+static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
+                          int length)
+{
+       struct urb *urb;
+       int retval;
+       unsigned char *transfer_buffer;
+
+       urb = usb_alloc_urb(0, GFP_ATOMIC);
+
+       if (urb == NULL) {
+               dev_err(line6->ifcdev, "Out of memory\n");
+               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;
+       }
+
+       usb_fill_int_urb(urb, line6->usbdev,
+                        usb_sndbulkpipe(line6->usbdev,
+                                        line6->properties->ep_ctrl_w),
+                        transfer_buffer, length, midi_sent, line6,
+                        line6->interval);
+       urb->actual_length = 0;
+       retval = usb_submit_urb(urb, GFP_ATOMIC);
+
+       if (retval < 0) {
+               dev_err(line6->ifcdev, "usb_submit_urb failed\n");
+               usb_free_urb(urb);
+               return retval;
+       }
+
+       ++line6->line6midi->num_active_send_urbs;
+       return 0;
+}
+
+static int line6_midi_output_open(struct snd_rawmidi_substream *substream)
+{
+       return 0;
+}
+
+static int line6_midi_output_close(struct snd_rawmidi_substream *substream)
+{
+       return 0;
+}
+
+static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream,
+                                     int up)
+{
+       unsigned long flags;
+       struct usb_line6 *line6 =
+           line6_rawmidi_substream_midi(substream)->line6;
+
+       line6->line6midi->substream_transmit = substream;
+       spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags);
+
+       if (line6->line6midi->num_active_send_urbs == 0)
+               line6_midi_transmit(substream);
+
+       spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags);
+}
+
+static void line6_midi_output_drain(struct snd_rawmidi_substream *substream)
+{
+       struct usb_line6 *line6 =
+           line6_rawmidi_substream_midi(substream)->line6;
+       struct snd_line6_midi *midi = line6->line6midi;
+
+       wait_event_interruptible(midi->send_wait,
+                                midi->num_active_send_urbs == 0);
+}
+
+static int line6_midi_input_open(struct snd_rawmidi_substream *substream)
+{
+       return 0;
+}
+
+static int line6_midi_input_close(struct snd_rawmidi_substream *substream)
+{
+       return 0;
+}
+
+static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream,
+                                    int up)
+{
+       struct usb_line6 *line6 =
+           line6_rawmidi_substream_midi(substream)->line6;
+
+       if (up)
+               line6->line6midi->substream_receive = substream;
+       else
+               line6->line6midi->substream_receive = NULL;
+}
+
+static struct snd_rawmidi_ops line6_midi_output_ops = {
+       .open = line6_midi_output_open,
+       .close = line6_midi_output_close,
+       .trigger = line6_midi_output_trigger,
+       .drain = line6_midi_output_drain,
+};
+
+static struct snd_rawmidi_ops line6_midi_input_ops = {
+       .open = line6_midi_input_open,
+       .close = line6_midi_input_close,
+       .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)
+{
+       struct snd_rawmidi *rmidi;
+       int err;
+
+       err = snd_rawmidi_new(line6midi->line6->card, "Line6 MIDI", 0, 1, 1,
+                             &rmidi);
+       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->info_flags =
+           SNDRV_RAWMIDI_INFO_OUTPUT |
+           SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
+
+       snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+                           &line6_midi_output_ops);
+       snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+                           &line6_midi_input_ops);
+       return 0;
+}
+
+/* MIDI device destructor */
+static int snd_line6_midi_free(struct snd_device *device)
+{
+       struct snd_line6_midi *line6midi = device->device_data;
+
+       line6_midibuf_destroy(&line6midi->midibuf_in);
+       line6_midibuf_destroy(&line6midi->midibuf_out);
+       return 0;
+}
+
+/*
+       Initialize the Line6 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_line6_midi *line6midi;
+
+       if (!(line6->properties->capabilities & LINE6_CAP_CONTROL)) {
+               /* skip MIDI initialization and report success */
+               return 0;
+       }
+
+       line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL);
+
+       if (line6midi == NULL)
+               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;
+
+       init_waitqueue_head(&line6midi->send_wait);
+       spin_lock_init(&line6midi->send_urb_lock);
+       spin_lock_init(&line6midi->midi_transmit_lock);
+       return 0;
+}
diff --git a/sound/usb/line6/midi.h b/sound/usb/line6/midi.h
new file mode 100644 (file)
index 0000000..78f903f
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * 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 MIDI_H
+#define MIDI_H
+
+#include <sound/rawmidi.h>
+
+#include "midibuf.h"
+
+#define MIDI_BUFFER_SIZE 1024
+
+struct snd_line6_midi {
+       /**
+                Pointer back to the Line6 driver data structure.
+       */
+       struct usb_line6 *line6;
+
+       /**
+                MIDI substream for receiving (or NULL if not active).
+       */
+       struct snd_rawmidi_substream *substream_receive;
+
+       /**
+                MIDI substream for transmitting (or NULL if not active).
+       */
+       struct snd_rawmidi_substream *substream_transmit;
+
+       /**
+                Number of currently active MIDI send URBs.
+       */
+       int num_active_send_urbs;
+
+       /**
+                Spin lock to protect updates of send_urb.
+       */
+       spinlock_t send_urb_lock;
+
+       /**
+                Spin lock to protect MIDI buffer handling.
+       */
+       spinlock_t midi_transmit_lock;
+
+       /**
+                Wait queue for MIDI transmission.
+       */
+       wait_queue_head_t send_wait;
+
+       /**
+                Buffer for incoming MIDI stream.
+       */
+       struct midi_buffer midibuf_in;
+
+       /**
+                Buffer for outgoing MIDI stream.
+       */
+       struct midi_buffer midibuf_out;
+};
+
+extern int line6_init_midi(struct usb_line6 *line6);
+extern void line6_midi_receive(struct usb_line6 *line6, unsigned char *data,
+                              int length);
+
+#endif
diff --git a/sound/usb/line6/midibuf.c b/sound/usb/line6/midibuf.c
new file mode 100644 (file)
index 0000000..1ff8569
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * 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 <linux/slab.h>
+
+#include "midibuf.h"
+
+static int midibuf_message_length(unsigned char code)
+{
+       int message_length;
+
+       if (code < 0x80)
+               message_length = -1;
+       else if (code < 0xf0) {
+               static const int length[] = { 3, 3, 3, 3, 2, 2, 3 };
+
+               message_length = length[(code >> 4) - 8];
+       } else {
+               /*
+                  Note that according to the MIDI specification 0xf2 is
+                  the "Song Position Pointer", but this is used by Line6
+                  to send sysex messages to the host.
+                */
+               static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1,
+                       1, 1, 1, -1, 1, 1
+               };
+               message_length = length[code & 0x0f];
+       }
+
+       return message_length;
+}
+
+static int midibuf_is_empty(struct midi_buffer *this)
+{
+       return (this->pos_read == this->pos_write) && !this->full;
+}
+
+static int midibuf_is_full(struct midi_buffer *this)
+{
+       return this->full;
+}
+
+void line6_midibuf_reset(struct midi_buffer *this)
+{
+       this->pos_read = this->pos_write = this->full = 0;
+       this->command_prev = -1;
+}
+
+int line6_midibuf_init(struct midi_buffer *this, int size, int split)
+{
+       this->buf = kmalloc(size, GFP_KERNEL);
+
+       if (this->buf == NULL)
+               return -ENOMEM;
+
+       this->size = size;
+       this->split = split;
+       line6_midibuf_reset(this);
+       return 0;
+}
+
+void line6_midibuf_status(struct midi_buffer *this)
+{
+       pr_debug("midibuf size=%d split=%d pos_read=%d pos_write=%d full=%d command_prev=%02x\n",
+                this->size, this->split, this->pos_read, this->pos_write,
+                this->full, this->command_prev);
+}
+
+int line6_midibuf_bytes_free(struct midi_buffer *this)
+{
+       return
+           midibuf_is_full(this) ?
+           0 :
+           (this->pos_read - this->pos_write + this->size - 1) % this->size +
+           1;
+}
+
+int line6_midibuf_bytes_used(struct midi_buffer *this)
+{
+       return
+           midibuf_is_empty(this) ?
+           0 :
+           (this->pos_write - this->pos_read + this->size - 1) % this->size +
+           1;
+}
+
+int line6_midibuf_write(struct midi_buffer *this, unsigned char *data,
+                       int length)
+{
+       int bytes_free;
+       int length1, length2;
+       int skip_active_sense = 0;
+
+       if (midibuf_is_full(this) || (length <= 0))
+               return 0;
+
+       /* skip trailing active sense */
+       if (data[length - 1] == 0xfe) {
+               --length;
+               skip_active_sense = 1;
+       }
+
+       bytes_free = line6_midibuf_bytes_free(this);
+
+       if (length > bytes_free)
+               length = bytes_free;
+
+       if (length > 0) {
+               length1 = this->size - this->pos_write;
+
+               if (length < length1) {
+                       /* no buffer wraparound */
+                       memcpy(this->buf + this->pos_write, data, length);
+                       this->pos_write += length;
+               } else {
+                       /* buffer wraparound */
+                       length2 = length - length1;
+                       memcpy(this->buf + this->pos_write, data, length1);
+                       memcpy(this->buf, data + length1, length2);
+                       this->pos_write = length2;
+               }
+
+               if (this->pos_write == this->pos_read)
+                       this->full = 1;
+       }
+
+       return length + skip_active_sense;
+}
+
+int line6_midibuf_read(struct midi_buffer *this, unsigned char *data,
+                      int length)
+{
+       int bytes_used;
+       int length1, length2;
+       int command;
+       int midi_length;
+       int repeat = 0;
+       int i;
+
+       /* we need to be able to store at least a 3 byte MIDI message */
+       if (length < 3)
+               return -EINVAL;
+
+       if (midibuf_is_empty(this))
+               return 0;
+
+       bytes_used = line6_midibuf_bytes_used(this);
+
+       if (length > bytes_used)
+               length = bytes_used;
+
+       length1 = this->size - this->pos_read;
+
+       /* check MIDI command length */
+       command = this->buf[this->pos_read];
+
+       if (command & 0x80) {
+               midi_length = midibuf_message_length(command);
+               this->command_prev = command;
+       } else {
+               if (this->command_prev > 0) {
+                       int midi_length_prev =
+                           midibuf_message_length(this->command_prev);
+
+                       if (midi_length_prev > 0) {
+                               midi_length = midi_length_prev - 1;
+                               repeat = 1;
+                       } else
+                               midi_length = -1;
+               } else
+                       midi_length = -1;
+       }
+
+       if (midi_length < 0) {
+               /* search for end of message */
+               if (length < length1) {
+                       /* no buffer wraparound */
+                       for (i = 1; i < length; ++i)
+                               if (this->buf[this->pos_read + i] & 0x80)
+                                       break;
+
+                       midi_length = i;
+               } else {
+                       /* buffer wraparound */
+                       length2 = length - length1;
+
+                       for (i = 1; i < length1; ++i)
+                               if (this->buf[this->pos_read + i] & 0x80)
+                                       break;
+
+                       if (i < length1)
+                               midi_length = i;
+                       else {
+                               for (i = 0; i < length2; ++i)
+                                       if (this->buf[i] & 0x80)
+                                               break;
+
+                               midi_length = length1 + i;
+                       }
+               }
+
+               if (midi_length == length)
+                       midi_length = -1;       /* end of message not found */
+       }
+
+       if (midi_length < 0) {
+               if (!this->split)
+                       return 0;       /* command is not yet complete */
+       } else {
+               if (length < midi_length)
+                       return 0;       /* command is not yet complete */
+
+               length = midi_length;
+       }
+
+       if (length < length1) {
+               /* no buffer wraparound */
+               memcpy(data + repeat, this->buf + this->pos_read, length);
+               this->pos_read += length;
+       } else {
+               /* buffer wraparound */
+               length2 = length - length1;
+               memcpy(data + repeat, this->buf + this->pos_read, length1);
+               memcpy(data + repeat + length1, this->buf, length2);
+               this->pos_read = length2;
+       }
+
+       if (repeat)
+               data[0] = this->command_prev;
+
+       this->full = 0;
+       return length + repeat;
+}
+
+int line6_midibuf_ignore(struct midi_buffer *this, int length)
+{
+       int bytes_used = line6_midibuf_bytes_used(this);
+
+       if (length > bytes_used)
+               length = bytes_used;
+
+       this->pos_read = (this->pos_read + length) % this->size;
+       this->full = 0;
+       return length;
+}
+
+int line6_midibuf_skip_message(struct midi_buffer *this, unsigned short mask)
+{
+       int cmd = this->command_prev;
+
+       if ((cmd >= 0x80) && (cmd < 0xf0))
+               if ((mask & (1 << (cmd & 0x0f))) == 0)
+                       return 1;
+
+       return 0;
+}
+
+void line6_midibuf_destroy(struct midi_buffer *this)
+{
+       kfree(this->buf);
+       this->buf = NULL;
+}
diff --git a/sound/usb/line6/midibuf.h b/sound/usb/line6/midibuf.h
new file mode 100644 (file)
index 0000000..707482b
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * 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 MIDIBUF_H
+#define MIDIBUF_H
+
+struct midi_buffer {
+       unsigned char *buf;
+       int size;
+       int split;
+       int pos_read, pos_write;
+       int full;
+       int command_prev;
+};
+
+extern int line6_midibuf_bytes_used(struct midi_buffer *mb);
+extern int line6_midibuf_bytes_free(struct midi_buffer *mb);
+extern void line6_midibuf_destroy(struct midi_buffer *mb);
+extern int line6_midibuf_ignore(struct midi_buffer *mb, int length);
+extern int line6_midibuf_init(struct midi_buffer *mb, int size, int split);
+extern int line6_midibuf_read(struct midi_buffer *mb, unsigned char *data,
+                             int length);
+extern void line6_midibuf_reset(struct midi_buffer *mb);
+extern int line6_midibuf_skip_message(struct midi_buffer *mb,
+                                     unsigned short mask);
+extern void line6_midibuf_status(struct midi_buffer *mb);
+extern int line6_midibuf_write(struct midi_buffer *mb, unsigned char *data,
+                              int length);
+
+#endif
diff --git a/sound/usb/line6/pcm.c b/sound/usb/line6/pcm.c
new file mode 100644 (file)
index 0000000..6d4e5cd
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+ * 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 <linux/slab.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)
+{
+       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;
+}
+
+/*
+       "read" request on "impulse_volume" special file.
+*/
+static ssize_t impulse_volume_show(struct device *dev,
+                                  struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_volume);
+}
+
+/*
+       "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)
+{
+       struct snd_line6_pcm *line6pcm = dev2pcm(dev);
+       int value;
+       int ret;
+
+       ret = kstrtoint(buf, 10, &value);
+       if (ret < 0)
+               return ret;
+
+       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;
+}
+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)
+{
+       return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_period);
+}
+
+/*
+       "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)
+{
+       int value;
+       int ret;
+
+       ret = kstrtoint(buf, 10, &value);
+       if (ret < 0)
+               return ret;
+
+       dev2pcm(dev)->impulse_period = value;
+       return count;
+}
+static DEVICE_ATTR_RW(impulse_period);
+
+#endif
+
+static bool test_flags(unsigned long flags0, unsigned long flags1,
+                      unsigned long mask)
+{
+       return ((flags0 & mask) == 0) && ((flags1 & mask) != 0);
+}
+
+int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels)
+{
+       unsigned long flags_old, flags_new, flags_final;
+       int err;
+
+       do {
+               flags_old = ACCESS_ONCE(line6pcm->flags);
+               flags_new = flags_old | channels;
+       } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old);
+
+       flags_final = flags_old;
+
+       line6pcm->prev_fbuf = NULL;
+
+       if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_BUFFER)) {
+               /* Invoked multiple times in a row so allocate once only */
+               if (!line6pcm->buffer_in) {
+                       line6pcm->buffer_in =
+                               kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
+                                       line6pcm->max_packet_size, GFP_KERNEL);
+                       if (!line6pcm->buffer_in) {
+                               err = -ENOMEM;
+                               goto pcm_acquire_error;
+                       }
+
+                       flags_final |= channels & LINE6_BITS_CAPTURE_BUFFER;
+               }
+       }
+
+       if (test_flags(flags_old, flags_new, LINE6_BITS_CAPTURE_STREAM)) {
+               /*
+                  Waiting for completion of active URBs in the stop handler is
+                  a bug, we therefore report an error if capturing is restarted
+                  too soon.
+                */
+               if (line6pcm->active_urb_in | line6pcm->unlink_urb_in) {
+                       dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
+                       return -EBUSY;
+               }
+
+               line6pcm->count_in = 0;
+               line6pcm->prev_fsize = 0;
+               err = line6_submit_audio_in_all_urbs(line6pcm);
+
+               if (err < 0)
+                       goto pcm_acquire_error;
+
+               flags_final |= channels & LINE6_BITS_CAPTURE_STREAM;
+       }
+
+       if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_BUFFER)) {
+               /* Invoked multiple times in a row so allocate once only */
+               if (!line6pcm->buffer_out) {
+                       line6pcm->buffer_out =
+                               kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS *
+                                       line6pcm->max_packet_size, GFP_KERNEL);
+                       if (!line6pcm->buffer_out) {
+                               err = -ENOMEM;
+                               goto pcm_acquire_error;
+                       }
+
+                       flags_final |= channels & LINE6_BITS_PLAYBACK_BUFFER;
+               }
+       }
+
+       if (test_flags(flags_old, flags_new, LINE6_BITS_PLAYBACK_STREAM)) {
+               /*
+                 See comment above regarding PCM restart.
+               */
+               if (line6pcm->active_urb_out | line6pcm->unlink_urb_out) {
+                       dev_err(line6pcm->line6->ifcdev, "Device not yet ready\n");
+                       return -EBUSY;
+               }
+
+               line6pcm->count_out = 0;
+               err = line6_submit_audio_out_all_urbs(line6pcm);
+
+               if (err < 0)
+                       goto pcm_acquire_error;
+
+               flags_final |= channels & LINE6_BITS_PLAYBACK_STREAM;
+       }
+
+       return 0;
+
+pcm_acquire_error:
+       /*
+          If not all requested resources/streams could be obtained, release
+          those which were successfully obtained (if any).
+       */
+       line6_pcm_release(line6pcm, flags_final & channels);
+       return err;
+}
+
+int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels)
+{
+       unsigned long flags_old, flags_new;
+
+       do {
+               flags_old = ACCESS_ONCE(line6pcm->flags);
+               flags_new = flags_old & ~channels;
+       } while (cmpxchg(&line6pcm->flags, flags_old, flags_new) != flags_old);
+
+       if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_STREAM))
+               line6_unlink_audio_in_urbs(line6pcm);
+
+       if (test_flags(flags_new, flags_old, LINE6_BITS_CAPTURE_BUFFER)) {
+               line6_wait_clear_audio_in_urbs(line6pcm);
+               line6_free_capture_buffer(line6pcm);
+       }
+
+       if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_STREAM))
+               line6_unlink_audio_out_urbs(line6pcm);
+
+       if (test_flags(flags_new, flags_old, LINE6_BITS_PLAYBACK_BUFFER)) {
+               line6_wait_clear_audio_out_urbs(line6pcm);
+               line6_free_playback_buffer(line6pcm);
+       }
+
+       return 0;
+}
+
+/* trigger callback */
+int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+       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);
+       clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags);
+
+       snd_pcm_group_for_each_entry(s, substream) {
+               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);
+                               return err;
+                       }
+
+                       break;
+
+               case SNDRV_PCM_STREAM_CAPTURE:
+                       err = snd_line6_capture_trigger(line6pcm, cmd);
+
+                       if (err < 0) {
+                               spin_unlock_irqrestore(&line6pcm->lock_trigger,
+                                                      flags);
+                               return err;
+                       }
+
+                       break;
+
+               default:
+                       dev_err(line6pcm->line6->ifcdev,
+                               "Unknown stream direction %d\n", s->stream);
+               }
+       }
+
+       spin_unlock_irqrestore(&line6pcm->lock_trigger, flags);
+       return 0;
+}
+
+/* control info callback */
+static int snd_line6_control_playback_info(struct snd_kcontrol *kcontrol,
+                                          struct snd_ctl_elem_info *uinfo)
+{
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 2;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = 256;
+       return 0;
+}
+
+/* control get callback */
+static int snd_line6_control_playback_get(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_value *ucontrol)
+{
+       int i;
+       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+
+       for (i = 2; i--;)
+               ucontrol->value.integer.value[i] = line6pcm->volume_playback[i];
+
+       return 0;
+}
+
+/* control put callback */
+static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol,
+                                         struct snd_ctl_elem_value *ucontrol)
+{
+       int i, changed = 0;
+       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+
+       for (i = 2; i--;)
+               if (line6pcm->volume_playback[i] !=
+                   ucontrol->value.integer.value[i]) {
+                       line6pcm->volume_playback[i] =
+                           ucontrol->value.integer.value[i];
+                       changed = 1;
+               }
+
+       return changed;
+}
+
+/* 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
+};
+
+/*
+       Cleanup the PCM device.
+*/
+static void line6_cleanup_pcm(struct snd_pcm *pcm)
+{
+       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]);
+                       usb_free_urb(line6pcm->urb_audio_out[i]);
+               }
+               if (line6pcm->urb_audio_in[i]) {
+                       usb_kill_urb(line6pcm->urb_audio_in[i]);
+                       usb_free_urb(line6pcm->urb_audio_in[i]);
+               }
+       }
+}
+
+/* create a PCM device */
+static int snd_line6_new_pcm(struct snd_line6_pcm *line6pcm)
+{
+       struct snd_pcm *pcm;
+       int err;
+
+       err = snd_pcm_new(line6pcm->line6->card,
+                         (char *)line6pcm->line6->properties->name,
+                         0, 1, 1, &pcm);
+       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);
+
+       /* set operators */
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
+                       &snd_line6_playback_ops);
+       snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_line6_capture_ops);
+
+       /* pre-allocation of buffers */
+       snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_CONTINUOUS,
+                                             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.
+*/
+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);
+}
+
+/*
+       Create and register the PCM device and mixer entries.
+       Create URBs for playback and capture.
+*/
+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;
+       unsigned ep_read = line6->properties->ep_audio_r;
+       unsigned ep_write = line6->properties->ep_audio_w;
+       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);
+
+       if (line6pcm == NULL)
+               return -ENOMEM;
+
+       line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255;
+       line6pcm->volume_monitor = 255;
+       line6pcm->line6 = line6;
+
+       /* Read and write buffers are sized identically, so choose minimum */
+       line6pcm->max_packet_size = min(
+                       usb_maxpacket(line6->usbdev,
+                               usb_rcvisocpipe(line6->usbdev, ep_read), 0),
+                       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);
+
+       err = line6_create_audio_out_urbs(line6pcm);
+       if (err < 0)
+               return err;
+
+       err = line6_create_audio_in_urbs(line6pcm);
+       if (err < 0)
+               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
+
+       return 0;
+}
+
+/* prepare pcm callback */
+int snd_line6_prepare(struct snd_pcm_substream *substream)
+{
+       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+
+       switch (substream->stream) {
+       case SNDRV_PCM_STREAM_PLAYBACK:
+               if ((line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM) == 0)
+                       line6_unlink_wait_clear_audio_out_urbs(line6pcm);
+
+               break;
+
+       case SNDRV_PCM_STREAM_CAPTURE:
+               if ((line6pcm->flags & LINE6_BITS_CAPTURE_STREAM) == 0)
+                       line6_unlink_wait_clear_audio_in_urbs(line6pcm);
+
+               break;
+
+       default:
+               MISSING_CASE;
+       }
+
+       if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) {
+               line6pcm->count_out = 0;
+               line6pcm->pos_out = 0;
+               line6pcm->pos_out_done = 0;
+               line6pcm->bytes_out = 0;
+               line6pcm->count_in = 0;
+               line6pcm->pos_in_done = 0;
+               line6pcm->bytes_in = 0;
+       }
+
+       return 0;
+}
diff --git a/sound/usb/line6/pcm.h b/sound/usb/line6/pcm.h
new file mode 100644 (file)
index 0000000..7315e81
--- /dev/null
@@ -0,0 +1,374 @@
+/*
+ * 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.
+ *
+ */
+
+/*
+       PCM interface to POD series devices.
+*/
+
+#ifndef PCM_H
+#define PCM_H
+
+#include <sound/pcm.h>
+
+#include "driver.h"
+#include "usbdefs.h"
+
+/* number of URBs */
+#define LINE6_ISO_BUFFERS      2
+
+/*
+       number of USB frames per URB
+       The Line6 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.
+*/
+#define LINE6_ISO_PACKETS      1
+
+/* 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
+*/
+#define get_substream(line6pcm, stream)        \
+               (line6pcm->pcm->streams[stream].substream)
+
+/*
+       PCM mode bits.
+
+       There are several features of the Line6 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)
+       *) optional impulse response measurement
+       However, from the device's point of view, there is just a single
+       capture and playback stream, which must be shared between these
+       subsystems. It is therefore necessary to maintain the state of the
+       subsystems with respect to PCM usage. We define several constants of
+       the form LINE6_BIT_PCM_<subsystem>_<direction>_<resource> with the
+       following meanings:
+       *) <subsystem> is one of
+       -) ALSA: PCM playback and capture via ALSA
+       -) MONITOR: software monitoring
+       -) IMPULSE: optional impulse response measurement
+       *) <direction> is one of
+       -) PLAYBACK: audio output (from host to device)
+       -) CAPTURE: audio input (from device to host)
+       *) <resource> is one of
+       -) BUFFER: buffer required by PCM data stream
+       -) STREAM: actual PCM data stream
+
+       The subsystems call line6_pcm_acquire() to acquire the (shared)
+       resources needed for a particular operation (e.g., allocate the buffer
+       for ALSA playback or start the capture stream for software monitoring).
+       When a resource is no longer needed, it is released by calling
+       line6_pcm_release(). Buffer allocation and stream startup are handled
+       separately to allow the ALSA kernel driver to perform them at
+       appropriate places (since the callback which starts a PCM stream is not
+       allowed to sleep).
+*/
+enum {
+       /* individual bit indices: */
+       LINE6_INDEX_PCM_ALSA_PLAYBACK_BUFFER,
+       LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM,
+       LINE6_INDEX_PCM_ALSA_CAPTURE_BUFFER,
+       LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
+       LINE6_INDEX_PCM_MONITOR_PLAYBACK_BUFFER,
+       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,
+
+#define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_INDEX_ ## x
+
+       /* individual bit masks: */
+       LINE6_BIT(PCM_ALSA_PLAYBACK_BUFFER),
+       LINE6_BIT(PCM_ALSA_PLAYBACK_STREAM),
+       LINE6_BIT(PCM_ALSA_CAPTURE_BUFFER),
+       LINE6_BIT(PCM_ALSA_CAPTURE_STREAM),
+       LINE6_BIT(PCM_MONITOR_PLAYBACK_BUFFER),
+       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),
+
+       /* combined bit masks (by operation): */
+       LINE6_BITS_PCM_ALSA_BUFFER =
+           LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER |
+           LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER,
+
+       LINE6_BITS_PCM_ALSA_STREAM =
+           LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM |
+           LINE6_BIT_PCM_ALSA_CAPTURE_STREAM,
+
+       LINE6_BITS_PCM_MONITOR =
+           LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER |
+           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_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,
+
+       LINE6_BITS_STREAM =
+           LINE6_BITS_PLAYBACK_STREAM |
+           LINE6_BITS_CAPTURE_STREAM
+};
+
+struct line6_pcm_properties {
+       struct snd_pcm_hardware snd_line6_playback_hw, snd_line6_capture_hw;
+       struct snd_pcm_hw_constraint_ratdens snd_line6_rates;
+       int bytes_per_frame;
+};
+
+struct snd_line6_pcm {
+       /**
+                Pointer back to the Line6 driver data structure.
+       */
+       struct usb_line6 *line6;
+
+       /**
+                Properties.
+       */
+       struct line6_pcm_properties *properties;
+
+       /**
+                ALSA pcm stream
+       */
+       struct snd_pcm *pcm;
+
+       /**
+                URBs for audio playback.
+       */
+       struct urb *urb_audio_out[LINE6_ISO_BUFFERS];
+
+       /**
+                URBs for audio capture.
+       */
+       struct urb *urb_audio_in[LINE6_ISO_BUFFERS];
+
+       /**
+                Temporary buffer for playback.
+                Since the packet size is not known in advance, this buffer is
+                large enough to store maximum size packets.
+       */
+       unsigned char *buffer_out;
+
+       /**
+                Temporary buffer for capture.
+                Since the packet size is not known in advance, this buffer is
+                large enough to store maximum size packets.
+       */
+       unsigned char *buffer_in;
+
+       /**
+                Previously captured frame (for software monitoring).
+       */
+       unsigned char *prev_fbuf;
+
+       /**
+                Size of previously captured frame (for software monitoring).
+       */
+       int prev_fsize;
+
+       /**
+                Free frame position in the playback buffer.
+       */
+       snd_pcm_uframes_t pos_out;
+
+       /**
+                Count processed bytes for playback.
+                This is modulo period size (to determine when a period is
+                finished).
+       */
+       unsigned bytes_out;
+
+       /**
+                Counter to create desired playback sample rate.
+       */
+       unsigned count_out;
+
+       /**
+                Playback period size in bytes
+       */
+       unsigned period_out;
+
+       /**
+                Processed frame position in the playback buffer.
+                The contents of the output ring buffer have been consumed by
+                the USB subsystem (i.e., sent to the USB device) up to this
+                position.
+       */
+       snd_pcm_uframes_t pos_out_done;
+
+       /**
+                Count processed bytes for capture.
+                This is modulo period size (to determine when a period is
+                finished).
+       */
+       unsigned bytes_in;
+
+       /**
+                Counter to create desired capture sample rate.
+       */
+       unsigned count_in;
+
+       /**
+                Capture period size in bytes
+       */
+       unsigned period_in;
+
+       /**
+                Processed frame position in the capture buffer.
+                The contents of the output ring buffer have been consumed by
+                the USB subsystem (i.e., sent to the USB device) up to this
+                position.
+       */
+       snd_pcm_uframes_t pos_in_done;
+
+       /**
+                Bit mask of active playback URBs.
+       */
+       unsigned long active_urb_out;
+
+       /**
+                Maximum size of USB packet.
+       */
+       int max_packet_size;
+
+       /**
+                Bit mask of active capture URBs.
+       */
+       unsigned long active_urb_in;
+
+       /**
+                Bit mask of playback URBs currently being unlinked.
+       */
+       unsigned long unlink_urb_out;
+
+       /**
+                Bit mask of capture URBs currently being unlinked.
+       */
+       unsigned long unlink_urb_in;
+
+       /**
+                Spin lock to protect updates of the playback buffer positions (not
+                contents!)
+       */
+       spinlock_t lock_audio_out;
+
+       /**
+                Spin lock to protect updates of the capture buffer positions (not
+                contents!)
+       */
+       spinlock_t lock_audio_in;
+
+       /**
+                Spin lock to protect trigger.
+       */
+       spinlock_t lock_trigger;
+
+       /**
+                PCM playback volume (left and right).
+       */
+       int volume_playback[2];
+
+       /**
+                PCM monitor volume.
+       */
+       int volume_monitor;
+
+#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
+       /**
+                Volume of impulse response test signal (if zero, test is disabled).
+       */
+       int impulse_volume;
+
+       /**
+                Period of impulse response test signal.
+       */
+       int impulse_period;
+
+       /**
+                Counter for impulse response test signal.
+       */
+       int impulse_count;
+#endif
+
+       /**
+                Several status bits (see LINE6_BIT_*).
+       */
+       unsigned long flags;
+
+       int last_frame_in, last_frame_out;
+};
+
+extern int line6_init_pcm(struct usb_line6 *line6,
+                         struct line6_pcm_properties *properties);
+extern int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd);
+extern int snd_line6_prepare(struct snd_pcm_substream *substream);
+extern void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm);
+extern int line6_pcm_acquire(struct snd_line6_pcm *line6pcm, int channels);
+extern int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels);
+
+#endif
diff --git a/sound/usb/line6/playback.c b/sound/usb/line6/playback.c
new file mode 100644 (file)
index 0000000..da2e3b8
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ * 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 <linux/slab.h>
+#include <sound/core.h>
+#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"
+
+/*
+       Software stereo volume control.
+*/
+static void change_volume(struct urb *urb_out, int volume[],
+                         int bytes_per_frame)
+{
+       int chn = 0;
+
+       if (volume[0] == 256 && volume[1] == 256)
+               return;         /* maximum volume - no change */
+
+       if (bytes_per_frame == 4) {
+               short *p, *buf_end;
+
+               p = (short *)urb_out->transfer_buffer;
+               buf_end = p + urb_out->transfer_buffer_length / sizeof(*p);
+
+               for (; p < buf_end; ++p) {
+                       *p = (*p * volume[chn & 1]) >> 8;
+                       ++chn;
+               }
+       } else if (bytes_per_frame == 6) {
+               unsigned char *p, *buf_end;
+
+               p = (unsigned char *)urb_out->transfer_buffer;
+               buf_end = p + urb_out->transfer_buffer_length;
+
+               for (; p < buf_end; p += 3) {
+                       int val;
+
+                       val = p[0] + (p[1] << 8) + ((signed char)p[2] << 16);
+                       val = (val * volume[chn & 1]) >> 8;
+                       p[0] = val;
+                       p[1] = val >> 8;
+                       p[2] = val >> 16;
+                       ++chn;
+               }
+       }
+}
+
+#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
+
+/*
+       Create signal for impulse response test.
+*/
+static void create_impulse_test_signal(struct snd_line6_pcm *line6pcm,
+                                      struct urb *urb_out, int bytes_per_frame)
+{
+       int frames = urb_out->transfer_buffer_length / bytes_per_frame;
+
+       if (bytes_per_frame == 4) {
+               int i;
+               short *pi = (short *)line6pcm->prev_fbuf;
+               short *po = (short *)urb_out->transfer_buffer;
+
+               for (i = 0; i < frames; ++i) {
+                       po[0] = pi[0];
+                       po[1] = 0;
+                       pi += 2;
+                       po += 2;
+               }
+       } else if (bytes_per_frame == 6) {
+               int i, j;
+               unsigned char *pi = line6pcm->prev_fbuf;
+               unsigned char *po = urb_out->transfer_buffer;
+
+               for (i = 0; i < frames; ++i) {
+                       for (j = 0; j < bytes_per_frame / 2; ++j)
+                               po[j] = pi[j];
+
+                       for (; j < bytes_per_frame; ++j)
+                               po[j] = 0;
+
+                       pi += bytes_per_frame;
+                       po += bytes_per_frame;
+               }
+       }
+       if (--line6pcm->impulse_count <= 0) {
+               ((unsigned char *)(urb_out->transfer_buffer))[bytes_per_frame -
+                                                             1] =
+                   line6pcm->impulse_volume;
+               line6pcm->impulse_count = line6pcm->impulse_period;
+       }
+}
+
+#endif
+
+/*
+       Add signal to buffer for software monitoring.
+*/
+static void add_monitor_signal(struct urb *urb_out, unsigned char *signal,
+                              int volume, int bytes_per_frame)
+{
+       if (volume == 0)
+               return;         /* zero volume - no change */
+
+       if (bytes_per_frame == 4) {
+               short *pi, *po, *buf_end;
+
+               pi = (short *)signal;
+               po = (short *)urb_out->transfer_buffer;
+               buf_end = po + urb_out->transfer_buffer_length / sizeof(*po);
+
+               for (; po < buf_end; ++pi, ++po)
+                       *po += (*pi * volume) >> 8;
+       }
+
+       /*
+          We don't need to handle devices with 6 bytes per frame here
+          since they all support hardware monitoring.
+        */
+}
+
+/*
+       Find a free URB, prepare audio data, and submit URB.
+*/
+static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
+{
+       int index;
+       unsigned long flags;
+       int i, urb_size, urb_frames;
+       int ret;
+       const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
+       const int frame_increment =
+           line6pcm->properties->snd_line6_rates.rats[0].num_min;
+       const int frame_factor =
+           line6pcm->properties->snd_line6_rates.rats[0].den *
+           (USB_INTERVALS_PER_SECOND / LINE6_ISO_INTERVAL);
+       struct urb *urb_out;
+
+       spin_lock_irqsave(&line6pcm->lock_audio_out, flags);
+       index =
+           find_first_zero_bit(&line6pcm->active_urb_out, LINE6_ISO_BUFFERS);
+
+       if (index < 0 || index >= LINE6_ISO_BUFFERS) {
+               spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
+               dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
+               return -EINVAL;
+       }
+
+       urb_out = line6pcm->urb_audio_out[index];
+       urb_size = 0;
+
+       for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
+               /* compute frame size for given sampling rate */
+               int fsize = 0;
+               struct usb_iso_packet_descriptor *fout =
+                   &urb_out->iso_frame_desc[i];
+
+               if (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM)
+                       fsize = line6pcm->prev_fsize;
+
+               if (fsize == 0) {
+                       int n;
+
+                       line6pcm->count_out += frame_increment;
+                       n = line6pcm->count_out / frame_factor;
+                       line6pcm->count_out -= n * frame_factor;
+                       fsize = n * bytes_per_frame;
+               }
+
+               fout->offset = urb_size;
+               fout->length = fsize;
+               urb_size += fsize;
+       }
+
+       if (urb_size == 0) {
+               /* can't determine URB size */
+               spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
+               dev_err(line6pcm->line6->ifcdev, "driver bug: urb_size = 0\n");
+               return -EINVAL;
+       }
+
+       urb_frames = urb_size / bytes_per_frame;
+       urb_out->transfer_buffer =
+           line6pcm->buffer_out +
+           index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
+       urb_out->transfer_buffer_length = urb_size;
+       urb_out->context = line6pcm;
+
+       if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags) &&
+           !test_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags)) {
+               struct snd_pcm_runtime *runtime =
+                   get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK)->runtime;
+
+               if (line6pcm->pos_out + urb_frames > runtime->buffer_size) {
+                       /*
+                          The transferred area goes over buffer boundary,
+                          copy the data to the temp buffer.
+                        */
+                       int len;
+
+                       len = runtime->buffer_size - line6pcm->pos_out;
+
+                       if (len > 0) {
+                               memcpy(urb_out->transfer_buffer,
+                                      runtime->dma_area +
+                                      line6pcm->pos_out * bytes_per_frame,
+                                      len * bytes_per_frame);
+                               memcpy(urb_out->transfer_buffer +
+                                      len * bytes_per_frame, runtime->dma_area,
+                                      (urb_frames - len) * bytes_per_frame);
+                       } else
+                               dev_err(line6pcm->line6->ifcdev, "driver bug: len = %d\n",
+                                       len);
+               } else {
+                       memcpy(urb_out->transfer_buffer,
+                              runtime->dma_area +
+                              line6pcm->pos_out * bytes_per_frame,
+                              urb_out->transfer_buffer_length);
+               }
+
+               line6pcm->pos_out += urb_frames;
+               if (line6pcm->pos_out >= runtime->buffer_size)
+                       line6pcm->pos_out -= runtime->buffer_size;
+       } else {
+               memset(urb_out->transfer_buffer, 0,
+                      urb_out->transfer_buffer_length);
+       }
+
+       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);
+                       if (line6pcm->flags &
+                           LINE6_BIT_PCM_ALSA_CAPTURE_STREAM) {
+                               line6_capture_copy(line6pcm,
+                                                  urb_out->transfer_buffer,
+                                                  urb_out->
+                                                  transfer_buffer_length);
+                               line6_capture_check_period(line6pcm,
+                                       urb_out->transfer_buffer_length);
+                       }
+               } else {
+#endif
+                       if (!
+                           (line6pcm->line6->
+                            properties->capabilities & LINE6_CAP_HWMON)
+                           && (line6pcm->flags & LINE6_BITS_PLAYBACK_STREAM)
+                           && (line6pcm->flags & LINE6_BITS_CAPTURE_STREAM))
+                               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);
+
+       if (ret == 0)
+               set_bit(index, &line6pcm->active_urb_out);
+       else
+               dev_err(line6pcm->line6->ifcdev,
+                       "URB out #%d submission failed (%d)\n", index, ret);
+
+       spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
+       return 0;
+}
+
+/*
+       Submit all currently available playback URBs.
+*/
+int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm)
+{
+       int ret, i;
+
+       for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
+               ret = submit_audio_out_urb(line6pcm);
+               if (ret < 0)
+                       return ret;
+       }
+
+       return 0;
+}
+
+/*
+       Unlink all currently active playback URBs.
+*/
+void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm)
+{
+       unsigned int i;
+
+       for (i = LINE6_ISO_BUFFERS; i--;) {
+               if (test_bit(i, &line6pcm->active_urb_out)) {
+                       if (!test_and_set_bit(i, &line6pcm->unlink_urb_out)) {
+                               struct urb *u = line6pcm->urb_audio_out[i];
+
+                               usb_unlink_urb(u);
+                       }
+               }
+       }
+}
+
+/*
+       Wait until unlinking of all currently active playback URBs has been
+       finished.
+*/
+void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
+{
+       int timeout = HZ;
+       unsigned int i;
+       int alive;
+
+       do {
+               alive = 0;
+               for (i = LINE6_ISO_BUFFERS; i--;) {
+                       if (test_bit(i, &line6pcm->active_urb_out))
+                               alive++;
+               }
+               if (!alive)
+                       break;
+               set_current_state(TASK_UNINTERRUPTIBLE);
+               schedule_timeout(1);
+       } while (--timeout > 0);
+       if (alive)
+               snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
+}
+
+/*
+       Unlink all currently active playback URBs, and wait for finishing.
+*/
+void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
+{
+       line6_unlink_audio_out_urbs(line6pcm);
+       line6_wait_clear_audio_out_urbs(line6pcm);
+}
+
+void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm)
+{
+       kfree(line6pcm->buffer_out);
+       line6pcm->buffer_out = NULL;
+}
+
+/*
+       Callback for completed playback URB.
+*/
+static void audio_out_callback(struct urb *urb)
+{
+       int i, index, length = 0, shutdown = 0;
+       unsigned long flags;
+       struct snd_line6_pcm *line6pcm = (struct snd_line6_pcm *)urb->context;
+       struct snd_pcm_substream *substream =
+           get_substream(line6pcm, SNDRV_PCM_STREAM_PLAYBACK);
+
+#if USE_CLEAR_BUFFER_WORKAROUND
+       memset(urb->transfer_buffer, 0, urb->transfer_buffer_length);
+#endif
+
+       line6pcm->last_frame_out = urb->start_frame;
+
+       /* find index of URB */
+       for (index = LINE6_ISO_BUFFERS; index--;)
+               if (urb == line6pcm->urb_audio_out[index])
+                       break;
+
+       if (index < 0)
+               return;         /* URB has been unlinked asynchronously */
+
+       for (i = LINE6_ISO_PACKETS; i--;)
+               length += urb->iso_frame_desc[i].length;
+
+       spin_lock_irqsave(&line6pcm->lock_audio_out, flags);
+
+       if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM, &line6pcm->flags)) {
+               struct snd_pcm_runtime *runtime = substream->runtime;
+
+               line6pcm->pos_out_done +=
+                   length / line6pcm->properties->bytes_per_frame;
+
+               if (line6pcm->pos_out_done >= runtime->buffer_size)
+                       line6pcm->pos_out_done -= runtime->buffer_size;
+       }
+
+       clear_bit(index, &line6pcm->active_urb_out);
+
+       for (i = LINE6_ISO_PACKETS; i--;)
+               if (urb->iso_frame_desc[i].status == -EXDEV) {
+                       shutdown = 1;
+                       break;
+               }
+
+       if (test_and_clear_bit(index, &line6pcm->unlink_urb_out))
+               shutdown = 1;
+
+       spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
+
+       if (!shutdown) {
+               submit_audio_out_urb(line6pcm);
+
+               if (test_bit(LINE6_INDEX_PCM_ALSA_PLAYBACK_STREAM,
+                            &line6pcm->flags)) {
+                       line6pcm->bytes_out += length;
+                       if (line6pcm->bytes_out >= line6pcm->period_out) {
+                               line6pcm->bytes_out %= line6pcm->period_out;
+                               snd_pcm_period_elapsed(substream);
+                       }
+               }
+       }
+}
+
+/* open playback callback */
+static int snd_line6_playback_open(struct snd_pcm_substream *substream)
+{
+       int err;
+       struct snd_pcm_runtime *runtime = substream->runtime;
+       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+
+       err = snd_pcm_hw_constraint_ratdens(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+                                           (&line6pcm->
+                                            properties->snd_line6_rates));
+       if (err < 0)
+               return err;
+
+       runtime->hw = line6pcm->properties->snd_line6_playback_hw;
+       return 0;
+}
+
+/* close playback callback */
+static int snd_line6_playback_close(struct snd_pcm_substream *substream)
+{
+       return 0;
+}
+
+/* hw_params playback callback */
+static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream,
+                                       struct snd_pcm_hw_params *hw_params)
+{
+       int ret;
+       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+
+       /* -- Florian Demski [FD] */
+       /* don't ask me why, but this fixes the bug on my machine */
+       if (line6pcm == NULL) {
+               if (substream->pcm == NULL)
+                       return -ENOMEM;
+               if (substream->pcm->private_data == NULL)
+                       return -ENOMEM;
+               substream->private_data = substream->pcm->private_data;
+               line6pcm = snd_pcm_substream_chip(substream);
+       }
+       /* -- [FD] end */
+
+       ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
+
+       if (ret < 0)
+               return ret;
+
+       ret = snd_pcm_lib_malloc_pages(substream,
+                                      params_buffer_bytes(hw_params));
+       if (ret < 0) {
+               line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
+               return ret;
+       }
+
+       line6pcm->period_out = params_period_bytes(hw_params);
+       return 0;
+}
+
+/* hw_free playback callback */
+static int snd_line6_playback_hw_free(struct snd_pcm_substream *substream)
+{
+       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+
+       line6_pcm_release(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
+       return snd_pcm_lib_free_pages(substream);
+}
+
+/* trigger playback callback */
+int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd)
+{
+       int err;
+
+       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);
+
+               if (err < 0)
+                       return err;
+
+               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);
+
+               if (err < 0)
+                       return err;
+
+               break;
+
+       case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+               set_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags);
+               break;
+
+       case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+               clear_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/* playback pointer callback */
+static snd_pcm_uframes_t
+snd_line6_playback_pointer(struct snd_pcm_substream *substream)
+{
+       struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+
+       return line6pcm->pos_out_done;
+}
+
+/* playback operators */
+struct snd_pcm_ops snd_line6_playback_ops = {
+       .open = snd_line6_playback_open,
+       .close = snd_line6_playback_close,
+       .ioctl = snd_pcm_lib_ioctl,
+       .hw_params = snd_line6_playback_hw_params,
+       .hw_free = snd_line6_playback_hw_free,
+       .prepare = snd_line6_prepare,
+       .trigger = snd_line6_trigger,
+       .pointer = snd_line6_playback_pointer,
+};
+
+int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm)
+{
+       struct usb_line6 *line6 = line6pcm->line6;
+       int i;
+
+       /* create audio URBs and fill in constant values: */
+       for (i = 0; i < LINE6_ISO_BUFFERS; ++i) {
+               struct urb *urb;
+
+               /* URB for audio out: */
+               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");
+                       return -ENOMEM;
+               }
+
+               urb->dev = line6->usbdev;
+               urb->pipe =
+                   usb_sndisocpipe(line6->usbdev,
+                                   line6->properties->ep_audio_w &
+                                   USB_ENDPOINT_NUMBER_MASK);
+               urb->transfer_flags = URB_ISO_ASAP;
+               urb->start_frame = -1;
+               urb->number_of_packets = LINE6_ISO_PACKETS;
+               urb->interval = LINE6_ISO_INTERVAL;
+               urb->error_count = 0;
+               urb->complete = audio_out_callback;
+       }
+
+       return 0;
+}
diff --git a/sound/usb/line6/playback.h b/sound/usb/line6/playback.h
new file mode 100644 (file)
index 0000000..743bd6f
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * 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 PLAYBACK_H
+#define PLAYBACK_H
+
+#include <sound/pcm.h>
+
+#include "driver.h"
+
+/*
+ * When the TonePort is used with jack in full duplex mode and the outputs are
+ * not connected, the software monitor produces an ugly noise since everything
+ * written to the output buffer (i.e., the input signal) will be repeated in
+ * the next period (sounds like a delay effect). As a workaround, the output
+ * buffer is cleared after the data have been read, but there must be a better
+ * solution. Until one is found, this workaround can be used to fix the
+ * problem.
+ */
+#define USE_CLEAR_BUFFER_WORKAROUND 1
+
+extern struct snd_pcm_ops snd_line6_playback_ops;
+
+extern int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm);
+extern void line6_free_playback_buffer(struct snd_line6_pcm *line6pcm);
+extern int line6_submit_audio_out_all_urbs(struct snd_line6_pcm *line6pcm);
+extern void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm);
+extern void line6_unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm
+                                                  *line6pcm);
+extern void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm);
+extern int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd);
+
+#endif
diff --git a/sound/usb/line6/pod.c b/sound/usb/line6/pod.c
new file mode 100644 (file)
index 0000000..85a4363
--- /dev/null
@@ -0,0 +1,453 @@
+/*
+ * 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 <linux/slab.h>
+#include <linux/wait.h>
+#include <sound/control.h>
+
+#include "audio.h"
+#include "capture.h"
+#include "driver.h"
+#include "playback.h"
+#include "pod.h"
+
+#define POD_SYSEX_CODE 3
+#define POD_BYTES_PER_FRAME 6  /* 24bit audio (stereo) */
+
+/* *INDENT-OFF* */
+
+enum {
+       POD_SYSEX_SAVE      = 0x24,
+       POD_SYSEX_SYSTEM    = 0x56,
+       POD_SYSEX_SYSTEMREQ = 0x57,
+       /* POD_SYSEX_UPDATE    = 0x6c, */  /* software update! */
+       POD_SYSEX_STORE     = 0x71,
+       POD_SYSEX_FINISH    = 0x72,
+       POD_SYSEX_DUMPMEM   = 0x73,
+       POD_SYSEX_DUMP      = 0x74,
+       POD_SYSEX_DUMPREQ   = 0x75
+
+       /* dumps entire internal memory of PODxt Pro */
+       /* POD_SYSEX_DUMPMEM2  = 0x76 */
+};
+
+enum {
+       POD_MONITOR_LEVEL  = 0x04,
+       POD_SYSTEM_INVALID = 0x10000
+};
+
+/* *INDENT-ON* */
+
+enum {
+       POD_DUMP_MEMORY = 2
+};
+
+enum {
+       POD_BUSY_READ,
+       POD_BUSY_WRITE,
+       POD_CHANNEL_DIRTY,
+       POD_SAVE_PRESSED,
+       POD_BUSY_MIDISEND
+};
+
+static struct snd_ratden pod_ratden = {
+       .num_min = 78125,
+       .num_max = 78125,
+       .num_step = 1,
+       .den = 2
+};
+
+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 |
+#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},
+       .bytes_per_frame = POD_BYTES_PER_FRAME
+};
+
+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 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);
+}
+
+/*
+       Process a completely received message.
+*/
+static void line6_pod_process_message(struct usb_line6 *line6)
+{
+       struct usb_line6_pod *pod = (struct usb_line6_pod *) line6;
+       const unsigned char *buf = pod->line6.buffer_message;
+
+       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_startup3(pod);
+               return;
+       }
+
+       /* Only look for sysex messages from this device */
+       if (buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE) &&
+           buf[0] != (LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN)) {
+               return;
+       }
+       if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) != 0)
+               return;
+
+       if (buf[5] == POD_SYSEX_SYSTEM && buf[6] == POD_MONITOR_LEVEL) {
+               short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) |
+                             ((int)buf[9] << 4) | (int)buf[10];
+               pod->monitor_level = value;
+       }
+}
+
+/*
+       Send system parameter (from integer).
+*/
+static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
+                                   int code)
+{
+       char *sysex;
+       static const int size = 5;
+
+       sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
+       if (!sysex)
+               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;
+       line6_send_sysex_message(&pod->line6, sysex, size);
+       kfree(sysex);
+       return 0;
+}
+
+/*
+       "read" request on "serial_number" special file.
+*/
+static ssize_t serial_number_show(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 sprintf(buf, "%d\n", pod->serial_number);
+}
+
+/*
+       "read" request on "firmware_version" special file.
+*/
+static ssize_t firmware_version_show(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 sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
+                      pod->firmware_version % 100);
+}
+
+/*
+       "read" request on "device_id" special file.
+*/
+static ssize_t device_id_show(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 sprintf(buf, "%d\n", pod->device_id);
+}
+
+/*
+       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;
+       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_startup3(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);
+}
+
+static void pod_startup4(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);
+}
+
+/* POD special files: */
+static DEVICE_ATTR_RO(device_id);
+static DEVICE_ATTR_RO(firmware_version);
+static DEVICE_ATTR_RO(serial_number);
+
+/* 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;
+       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)
+               return 0;
+
+       pod->monitor_level = 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.
+*/
+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)
+{
+       struct usb_line6_pod *pod;
+
+       if (interface == NULL)
+               return;
+       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);
+}
+
+/*
+       Create sysfs entries.
+*/
+static int pod_create_files2(struct device *dev)
+{
+       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));
+       return 0;
+}
+
+/*
+        Try to init POD device.
+*/
+static int pod_try_init(struct usb_interface *interface,
+                       struct usb_line6 *line6)
+{
+       int err;
+       struct usb_line6_pod *pod = (struct usb_line6_pod *) line6;
+
+       line6->process_message = line6_pod_process_message;
+       line6->disconnect = line6_pod_disconnect;
+
+       init_timer(&pod->startup_timer);
+       INIT_WORK(&pod->startup_work, pod_startup4);
+
+       if ((interface == NULL) || (pod == NULL))
+               return -ENODEV;
+
+       /* create sysfs entries: */
+       err = pod_create_files2(&interface->dev);
+       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)
+               return err;
+
+       /* initialize PCM subsystem: */
+       err = line6_init_pcm(line6, &pod_pcm_properties);
+       if (err < 0)
+               return err;
+
+       /* 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_CAP_CONTROL) {
+               pod->monitor_level = 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 *line6)
+{
+       int err = pod_try_init(interface, line6);
+
+       if (err < 0)
+               pod_destruct(interface);
+
+       return err;
+}
diff --git a/sound/usb/line6/pod.h b/sound/usb/line6/pod.h
new file mode 100644 (file)
index 0000000..87a8f0f
--- /dev/null
@@ -0,0 +1,92 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..27c5402
--- /dev/null
@@ -0,0 +1,156 @@
+/*
+ * 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.
+ *
+ */
+
+#include <sound/core.h>
+#include <sound/pcm.h>
+
+#include "audio.h"
+#include "driver.h"
+#include "pcm.h"
+#include "podhd.h"
+
+#define PODHD_BYTES_PER_FRAME 6        /* 24bit audio (stereo) */
+
+static struct snd_ratden podhd_ratden = {
+       .num_min = 48000,
+       .num_max = 48000,
+       .num_step = 1,
+       .den = 1,
+};
+
+static struct line6_pcm_properties podhd_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 |
+#ifdef CONFIG_PM
+                                          SNDRV_PCM_INFO_RESUME |
+#endif
+                                          SNDRV_PCM_INFO_SYNC_START),
+                                 .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+                                 .rates = SNDRV_PCM_RATE_48000,
+                                 .rate_min = 48000,
+                                 .rate_max = 48000,
+                                 .channels_min = 2,
+                                 .channels_max = 2,
+                                 .buffer_bytes_max = 60000,
+                                 .period_bytes_min = 64,
+                                 .period_bytes_max = 8192,
+                                 .periods_min = 1,
+                                 .periods_max = 1024},
+       .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_48000,
+                                .rate_min = 48000,
+                                .rate_max = 48000,
+                                .channels_min = 2,
+                                .channels_max = 2,
+                                .buffer_bytes_max = 60000,
+                                .period_bytes_min = 64,
+                                .period_bytes_max = 8192,
+                                .periods_min = 1,
+                                .periods_max = 1024},
+       .snd_line6_rates = {
+                           .nrats = 1,
+                           .rats = &podhd_ratden},
+       .bytes_per_frame = PODHD_BYTES_PER_FRAME
+};
+
+/*
+       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)
+{
+       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)
+               return err;
+
+       /* initialize PCM subsystem: */
+       err = line6_init_pcm(line6, &podhd_pcm_properties);
+       if (err < 0)
+               return err;
+
+       /* register USB audio system: */
+       err = line6_register_audio(line6);
+       return err;
+}
+
+/*
+       Init POD HD device (and clean up in case of failure).
+*/
+int line6_podhd_init(struct usb_interface *interface, struct usb_line6 *line6)
+{
+       struct usb_line6_podhd *podhd = (struct usb_line6_podhd *) line6;
+       int err = podhd_try_init(interface, podhd);
+
+       if (err < 0)
+               podhd_destruct(interface);
+
+       return err;
+}
diff --git a/sound/usb/line6/podhd.h b/sound/usb/line6/podhd.h
new file mode 100644 (file)
index 0000000..a14f711
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * 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/revision.h b/sound/usb/line6/revision.h
new file mode 100644 (file)
index 0000000..b4eee2b
--- /dev/null
@@ -0,0 +1,4 @@
+#ifndef DRIVER_REVISION
+/* current subversion revision */
+#define DRIVER_REVISION " (904)"
+#endif
diff --git a/sound/usb/line6/toneport.c b/sound/usb/line6/toneport.c
new file mode 100644 (file)
index 0000000..aae78d8
--- /dev/null
@@ -0,0 +1,465 @@
+/*
+ * Line6 Linux USB driver - 0.9.1beta
+ *
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
+ *                         Emil Myhrman (emil.myhrman@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.
+ *
+ */
+
+#include <linux/wait.h>
+#include <sound/control.h>
+
+#include "audio.h"
+#include "capture.h"
+#include "driver.h"
+#include "playback.h"
+#include "toneport.h"
+
+static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2);
+
+#define TONEPORT_PCM_DELAY 1
+
+static struct snd_ratden toneport_ratden = {
+       .num_min = 44100,
+       .num_max = 44100,
+       .num_step = 1,
+       .den = 1
+};
+
+static struct line6_pcm_properties toneport_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 |
+#ifdef CONFIG_PM
+                                          SNDRV_PCM_INFO_RESUME |
+#endif
+                                          SNDRV_PCM_INFO_SYNC_START),
+                                 .formats = SNDRV_PCM_FMTBIT_S16_LE,
+                                 .rates = SNDRV_PCM_RATE_KNOT,
+                                 .rate_min = 44100,
+                                 .rate_max = 44100,
+                                 .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_S16_LE,
+                                .rates = SNDRV_PCM_RATE_KNOT,
+                                .rate_min = 44100,
+                                .rate_max = 44100,
+                                .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 = &toneport_ratden},
+       .bytes_per_frame = 4
+};
+
+/*
+       For the led on Guitarport.
+       Brightness goes from 0x00 to 0x26. Set a value above this to have led
+       blink.
+       (void cmd_0x02(byte red, byte green)
+*/
+static int led_red = 0x00;
+static int led_green = 0x26;
+
+static const struct {
+       const char *name;
+       int code;
+} toneport_source_info[] = {
+       {"Microphone", 0x0a01},
+       {"Line", 0x0801},
+       {"Instrument", 0x0b01},
+       {"Inst & Mic", 0x0901}
+};
+
+static bool toneport_has_led(enum line6_device_type type)
+{
+       return
+           (type == LINE6_GUITARPORT) ||
+           (type == LINE6_TONEPORT_GX);
+       /* add your device here if you are missing support for the LEDs */
+}
+
+static void toneport_update_led(struct device *dev)
+{
+       struct usb_interface *interface = to_usb_interface(dev);
+       struct usb_line6_toneport *tp = usb_get_intfdata(interface);
+       struct usb_line6 *line6;
+
+       if (!tp)
+               return;
+
+       line6 = &tp->line6;
+       if (line6)
+               toneport_send_cmd(line6->usbdev, (led_red << 8) | 0x0002,
+                                 led_green);
+}
+
+static ssize_t toneport_set_led_red(struct device *dev,
+                                   struct device_attribute *attr,
+                                   const char *buf, size_t count)
+{
+       int retval;
+
+       retval = kstrtoint(buf, 10, &led_red);
+       if (retval)
+               return retval;
+
+       toneport_update_led(dev);
+       return count;
+}
+
+static ssize_t toneport_set_led_green(struct device *dev,
+                                     struct device_attribute *attr,
+                                     const char *buf, size_t count)
+{
+       int retval;
+
+       retval = kstrtoint(buf, 10, &led_green);
+       if (retval)
+               return retval;
+
+       toneport_update_led(dev);
+       return count;
+}
+
+static DEVICE_ATTR(led_red, S_IWUSR | S_IRUGO, line6_nop_read,
+                  toneport_set_led_red);
+static DEVICE_ATTR(led_green, S_IWUSR | S_IRUGO, line6_nop_read,
+                  toneport_set_led_green);
+
+static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)
+{
+       int ret;
+
+       ret = usb_control_msg(usbdev, usb_sndctrlpipe(usbdev, 0), 0x67,
+                             USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+                             cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ);
+
+       if (ret < 0) {
+               dev_err(&usbdev->dev, "send failed (error %d)\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
+/* monitor info callback */
+static int snd_toneport_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 = 256;
+       return 0;
+}
+
+/* monitor get callback */
+static int snd_toneport_monitor_get(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = line6pcm->volume_monitor;
+       return 0;
+}
+
+/* monitor put callback */
+static int snd_toneport_monitor_put(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+
+       if (ucontrol->value.integer.value[0] == line6pcm->volume_monitor)
+               return 0;
+
+       line6pcm->volume_monitor = ucontrol->value.integer.value[0];
+
+       if (line6pcm->volume_monitor > 0)
+               line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_MONITOR);
+       else
+               line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
+
+       return 1;
+}
+
+/* source info callback */
+static int snd_toneport_source_info(struct snd_kcontrol *kcontrol,
+                                   struct snd_ctl_elem_info *uinfo)
+{
+       const int size = ARRAY_SIZE(toneport_source_info);
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+       uinfo->count = 1;
+       uinfo->value.enumerated.items = size;
+
+       if (uinfo->value.enumerated.item >= size)
+               uinfo->value.enumerated.item = size - 1;
+
+       strcpy(uinfo->value.enumerated.name,
+              toneport_source_info[uinfo->value.enumerated.item].name);
+
+       return 0;
+}
+
+/* source get callback */
+static int snd_toneport_source_get(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+       struct usb_line6_toneport *toneport =
+           (struct usb_line6_toneport *)line6pcm->line6;
+       ucontrol->value.enumerated.item[0] = toneport->source;
+       return 0;
+}
+
+/* source put callback */
+static int snd_toneport_source_put(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_value *ucontrol)
+{
+       struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
+       struct usb_line6_toneport *toneport =
+           (struct usb_line6_toneport *)line6pcm->line6;
+       unsigned int source;
+
+       source = ucontrol->value.enumerated.item[0];
+       if (source >= ARRAY_SIZE(toneport_source_info))
+               return -EINVAL;
+       if (source == toneport->source)
+               return 0;
+
+       toneport->source = source;
+       toneport_send_cmd(toneport->line6.usbdev,
+                         toneport_source_info[source].code, 0x0000);
+       return 1;
+}
+
+static void toneport_start_pcm(unsigned long arg)
+{
+       struct usb_line6_toneport *toneport = (struct usb_line6_toneport *)arg;
+       struct usb_line6 *line6 = &toneport->line6;
+
+       line6_pcm_acquire(line6->line6pcm, LINE6_BITS_PCM_MONITOR);
+}
+
+/* control definition */
+static struct snd_kcontrol_new toneport_control_monitor = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "Monitor Playback Volume",
+       .index = 0,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info = snd_toneport_monitor_info,
+       .get = snd_toneport_monitor_get,
+       .put = snd_toneport_monitor_put
+};
+
+/* source selector definition */
+static struct snd_kcontrol_new toneport_control_source = {
+       .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+       .name = "PCM Capture Source",
+       .index = 0,
+       .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+       .info = snd_toneport_source_info,
+       .get = snd_toneport_source_get,
+       .put = snd_toneport_source_put
+};
+
+/*
+       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)
+{
+       int ticks;
+       struct usb_line6 *line6 = &toneport->line6;
+       struct usb_device *usbdev = line6->usbdev;
+
+       /* sync time on device with host: */
+       ticks = (int)get_seconds();
+       line6_write_data(line6, 0x80c6, &ticks, 4);
+
+       /* enable device: */
+       toneport_send_cmd(usbdev, 0x0301, 0x0000);
+
+       /* initialize source select: */
+       switch (line6->type) {
+       case LINE6_TONEPORT_UX1:
+       case LINE6_TONEPORT_UX2:
+       case LINE6_PODSTUDIO_UX1:
+       case LINE6_PODSTUDIO_UX2:
+               toneport_send_cmd(usbdev,
+                                 toneport_source_info[toneport->source].code,
+                                 0x0000);
+       default:
+               break;
+       }
+
+       if (toneport_has_led(line6->type))
+               toneport_update_led(&usbdev->dev);
+}
+
+/*
+       Toneport device disconnected.
+*/
+static void line6_toneport_disconnect(struct usb_interface *interface)
+{
+       struct usb_line6_toneport *toneport;
+       u16 idProduct;
+
+       if (interface == NULL)
+               return;
+
+       toneport = usb_get_intfdata(interface);
+       del_timer_sync(&toneport->timer);
+       idProduct = le16_to_cpu(toneport->line6.usbdev->descriptor.idProduct);
+
+       if (toneport_has_led(idProduct)) {
+               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)
+{
+       int err;
+       struct usb_line6_toneport *toneport =  (struct usb_line6_toneport *) line6;
+
+       if ((interface == NULL) || (toneport == NULL))
+               return -ENODEV;
+
+       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)
+               return err;
+
+       /* register monitor control: */
+       err = snd_ctl_add(line6->card,
+                         snd_ctl_new1(&toneport_control_monitor,
+                                      line6->line6pcm));
+       if (err < 0)
+               return err;
+
+       /* register source select control: */
+       switch (line6->type) {
+       case LINE6_TONEPORT_UX1:
+       case LINE6_TONEPORT_UX2:
+       case LINE6_PODSTUDIO_UX1:
+       case LINE6_PODSTUDIO_UX2:
+               err =
+                   snd_ctl_add(line6->card,
+                               snd_ctl_new1(&toneport_control_source,
+                                            line6->line6pcm));
+               if (err < 0)
+                       return err;
+
+       default:
+               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));
+       }
+
+       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);
+
+       return 0;
+}
+
+/*
+        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;
+}
+
+/*
+       Resume Toneport device after reset.
+*/
+void line6_toneport_reset_resume(struct usb_line6_toneport *toneport)
+{
+       toneport_setup(toneport);
+}
diff --git a/sound/usb/line6/toneport.h b/sound/usb/line6/toneport.h
new file mode 100644 (file)
index 0000000..8cb1442
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * 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
new file mode 100644 (file)
index 0000000..f4d080e
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ * Line6 Linux USB driver - 0.9.1beta
+ *
+ * Copyright (C) 2005-2008 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 USBDEFS_H
+#define USBDEFS_H
+
+#define USB_INTERVALS_PER_SECOND 1000
+
+/* device supports settings parameter via USB */
+#define LINE6_CAP_CONTROL (1 << 0)
+/* device supports PCM input/output via USB */
+#define LINE6_CAP_PCM (1 << 1)
+/* device support hardware monitoring */
+#define LINE6_CAP_HWMON (1 << 2)
+
+#define LINE6_FALLBACK_INTERVAL 10
+#define LINE6_FALLBACK_MAXPACKETSIZE 16
+
+#endif
diff --git a/sound/usb/line6/variax.c b/sound/usb/line6/variax.c
new file mode 100644 (file)
index 0000000..b4a41b0
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ * 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 <linux/slab.h>
+
+#include "audio.h"
+#include "driver.h"
+#include "variax.h"
+
+#define VARIAX_OFFSET_ACTIVATE 7
+
+/*
+       This message is sent by the device during initialization and identifies
+       the connected guitar version.
+*/
+static const char variax_init_version[] = {
+       0xf0, 0x7e, 0x7f, 0x06, 0x02, 0x00, 0x01, 0x0c,
+       0x07, 0x00, 0x00, 0x00
+};
+
+/*
+       This message is the last one sent by the device during initialization.
+*/
+static const char variax_init_done[] = {
+       0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6b
+};
+
+static const char variax_activate[] = {
+       0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x2a, 0x01,
+       0xf7
+};
+
+/* forward declarations: */
+static void variax_startup2(unsigned long data);
+static void variax_startup4(unsigned long data);
+static void variax_startup5(unsigned long data);
+
+static void variax_activate_async(struct usb_line6_variax *variax, int a)
+{
+       variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
+       line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
+                                    sizeof(variax_activate));
+}
+
+/*
+       Variax 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 variax_startup1(struct usb_line6_variax *variax)
+{
+       CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);
+
+       /* delay startup procedure: */
+       line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
+                         variax_startup2, (unsigned long)variax);
+}
+
+static void variax_startup2(unsigned long data)
+{
+       struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
+       struct usb_line6 *line6 = &variax->line6;
+
+       /* schedule another startup procedure until startup is complete: */
+       if (variax->startup_progress >= VARIAX_STARTUP_LAST)
+               return;
+
+       variax->startup_progress = VARIAX_STARTUP_VERSIONREQ;
+       line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
+                         variax_startup2, (unsigned long)variax);
+
+       /* request firmware version: */
+       line6_version_request_async(line6);
+}
+
+static void variax_startup3(struct usb_line6_variax *variax)
+{
+       CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);
+
+       /* delay startup procedure: */
+       line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
+                         variax_startup4, (unsigned long)variax);
+}
+
+static void variax_startup4(unsigned long data)
+{
+       struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
+
+       CHECK_STARTUP_PROGRESS(variax->startup_progress,
+                              VARIAX_STARTUP_ACTIVATE);
+
+       /* activate device: */
+       variax_activate_async(variax, 1);
+       line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
+                         variax_startup5, (unsigned long)variax);
+}
+
+static void variax_startup5(unsigned long data)
+{
+       struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
+
+       CHECK_STARTUP_PROGRESS(variax->startup_progress,
+                              VARIAX_STARTUP_WORKQUEUE);
+
+       /* schedule work for global work queue: */
+       schedule_work(&variax->startup_work);
+}
+
+static void variax_startup6(struct work_struct *work)
+{
+       struct usb_line6_variax *variax =
+           container_of(work, struct usb_line6_variax, startup_work);
+
+       CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
+
+       /* ALSA audio interface: */
+       line6_register_audio(&variax->line6);
+}
+
+/*
+       Process a completely received message.
+*/
+static void line6_variax_process_message(struct usb_line6 *line6)
+{
+       struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
+       const unsigned char *buf = variax->line6.buffer_message;
+
+       switch (buf[0]) {
+       case LINE6_RESET:
+               dev_info(variax->line6.ifcdev, "VARIAX reset\n");
+               break;
+
+       case LINE6_SYSEX_BEGIN:
+               if (memcmp(buf + 1, variax_init_version + 1,
+                          sizeof(variax_init_version) - 1) == 0) {
+                       variax_startup3(variax);
+               } else if (memcmp(buf + 1, variax_init_done + 1,
+                                 sizeof(variax_init_done) - 1) == 0) {
+                       /* notify of complete initialization: */
+                       variax_startup4((unsigned long)variax);
+               }
+               break;
+       }
+}
+
+/*
+       Variax destructor.
+*/
+static void variax_destruct(struct usb_interface *interface)
+{
+       struct usb_line6_variax *variax = usb_get_intfdata(interface);
+
+       if (variax == NULL)
+               return;
+       line6_cleanup_audio(&variax->line6);
+
+       del_timer(&variax->startup_timer1);
+       del_timer(&variax->startup_timer2);
+       cancel_work_sync(&variax->startup_work);
+
+       kfree(variax->buffer_activate);
+}
+
+/*
+       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)
+{
+       struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
+       int err;
+
+       line6->process_message = line6_variax_process_message;
+       line6->disconnect = line6_variax_disconnect;
+
+       init_timer(&variax->startup_timer1);
+       init_timer(&variax->startup_timer2);
+       INIT_WORK(&variax->startup_work, variax_startup6);
+
+       if ((interface == NULL) || (variax == NULL))
+               return -ENODEV;
+
+       /* initialize USB buffers: */
+       variax->buffer_activate = kmemdup(variax_activate,
+                                         sizeof(variax_activate), GFP_KERNEL);
+
+       if (variax->buffer_activate == NULL) {
+               dev_err(&interface->dev, "Out of memory\n");
+               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);
+       if (err < 0)
+               return err;
+
+       /* initiate startup procedure: */
+       variax_startup1(variax);
+       return 0;
+}
+
+/*
+        Init workbench device (and clean up in case of failure).
+*/
+int line6_variax_init(struct usb_interface *interface, struct usb_line6 *line6)
+{
+       int err = variax_try_init(interface, line6);
+
+       if (err < 0)
+               variax_destruct(interface);
+
+       return err;
+}
diff --git a/sound/usb/line6/variax.h b/sound/usb/line6/variax.h
new file mode 100644 (file)
index 0000000..dfb94e5
--- /dev/null
@@ -0,0 +1,70 @@
+/*
+ * 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