aboutsummaryrefslogtreecommitdiff
path: root/drivers/staging/line6
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/staging/line6')
-rw-r--r--drivers/staging/line6/Kconfig21
-rw-r--r--drivers/staging/line6/Makefile7
-rw-r--r--drivers/staging/line6/audio.c26
-rw-r--r--drivers/staging/line6/audio.h7
-rw-r--r--drivers/staging/line6/capture.c272
-rw-r--r--drivers/staging/line6/capture.h27
-rw-r--r--drivers/staging/line6/config.h48
-rw-r--r--drivers/staging/line6/control.c840
-rw-r--r--drivers/staging/line6/control.h187
-rw-r--r--drivers/staging/line6/driver.c722
-rw-r--r--drivers/staging/line6/driver.h61
-rw-r--r--drivers/staging/line6/dumprequest.c151
-rw-r--r--drivers/staging/line6/dumprequest.h90
-rw-r--r--drivers/staging/line6/midi.c193
-rw-r--r--drivers/staging/line6/midi.h23
-rw-r--r--drivers/staging/line6/midibuf.c97
-rw-r--r--drivers/staging/line6/midibuf.h33
-rw-r--r--drivers/staging/line6/pcm.c381
-rw-r--r--drivers/staging/line6/pcm.h206
-rw-r--r--drivers/staging/line6/playback.c389
-rw-r--r--drivers/staging/line6/playback.h31
-rw-r--r--drivers/staging/line6/pod.c1147
-rw-r--r--drivers/staging/line6/pod.h164
-rw-r--r--drivers/staging/line6/podhd.c154
-rw-r--r--drivers/staging/line6/podhd.h30
-rw-r--r--drivers/staging/line6/revision.h2
-rw-r--r--drivers/staging/line6/toneport.c399
-rw-r--r--drivers/staging/line6/toneport.h33
-rw-r--r--drivers/staging/line6/usbdefs.h106
-rw-r--r--drivers/staging/line6/variax.c545
-rw-r--r--drivers/staging/line6/variax.h94
31 files changed, 2561 insertions, 3925 deletions
diff --git a/drivers/staging/line6/Kconfig b/drivers/staging/line6/Kconfig
index 7852d4a960c..4f1219b4c69 100644
--- a/drivers/staging/line6/Kconfig
+++ b/drivers/staging/line6/Kconfig
@@ -1,7 +1,8 @@
-config LINE6_USB
+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
@@ -17,5 +18,21 @@ config LINE6_USB
* Signal routing (record clean/processed guitar signal,
re-amping)
- Preliminary support for the Variax Workbench is included.
+ 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
index a1c93edc6b1..ae5c374b0f8 100644
--- a/drivers/staging/line6/Makefile
+++ b/drivers/staging/line6/Makefile
@@ -1,15 +1,14 @@
obj-$(CONFIG_LINE6_USB) += line6usb.o
-line6usb-objs := \
+line6usb-y := \
audio.o \
capture.o \
- control.o \
driver.o \
- dumprequest.o \
midi.o \
midibuf.o \
pcm.o \
playback.o \
pod.o \
toneport.o \
- variax.o
+ variax.o \
+ podhd.o
diff --git a/drivers/staging/line6/audio.c b/drivers/staging/line6/audio.c
index e2ac8d60f8c..171d80c1b02 100644
--- a/drivers/staging/line6/audio.c
+++ b/drivers/staging/line6/audio.c
@@ -1,7 +1,7 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -9,37 +9,35 @@
*
*/
-#include "driver.h"
-#include "audio.h"
-
#include <sound/core.h>
#include <sound/initval.h>
+#include <linux/export.h>
-
-static int line6_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
-static char *line6_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
-
+#include "driver.h"
+#include "audio.h"
/*
Initialize the Line6 USB audio system.
*/
int line6_init_audio(struct usb_line6 *line6)
{
- static int dev;
struct snd_card *card;
int err;
- err = snd_card_create(line6_index[dev], line6_id[dev], THIS_MODULE, 0,
- &card);
+ 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-USB");
+ 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)); /* 80 chars - see asound.h */
+ dev_name(line6->ifcdev));
return 0;
}
diff --git a/drivers/staging/line6/audio.h b/drivers/staging/line6/audio.h
index cc0245adbcd..5f8a09a0fa9 100644
--- a/drivers/staging/line6/audio.h
+++ b/drivers/staging/line6/audio.h
@@ -1,7 +1,7 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -12,13 +12,10 @@
#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
index ea2060b4919..e6ca631e3f7 100644
--- a/drivers/staging/line6/capture.c
+++ b/drivers/staging/line6/capture.c
@@ -1,7 +1,7 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -9,35 +9,35 @@
*
*/
-#include "driver.h"
-
+#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 "capture.h"
-
/*
Find a free URB and submit it.
*/
-static int submit_audio_in_urb(struct snd_pcm_substream *substream)
+static int submit_audio_in_urb(struct snd_line6_pcm *line6pcm)
{
- unsigned int index;
+ int index;
unsigned long flags;
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
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);
+ index =
+ find_first_zero_bit(&line6pcm->active_urb_in, LINE6_ISO_BUFFERS);
- if (index >= LINE6_ISO_BUFFERS) {
+ if (index < 0 || index >= LINE6_ISO_BUFFERS) {
spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
- dev_err(s2m(substream), "no free URB found\n");
+ dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
return -EINVAL;
}
@@ -45,20 +45,26 @@ static int submit_audio_in_urb(struct snd_pcm_substream *substream)
urb_size = 0;
for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
- struct usb_iso_packet_descriptor *fin = &urb_in->iso_frame_desc[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 =
+ line6pcm->buffer_in +
+ index * LINE6_ISO_PACKETS * line6pcm->max_packet_size;
urb_in->transfer_buffer_length = urb_size;
- urb_in->context = substream;
+ urb_in->context = line6pcm;
+
+ ret = usb_submit_urb(urb_in, GFP_ATOMIC);
- if (usb_submit_urb(urb_in, GFP_ATOMIC) == 0)
+ if (ret == 0)
set_bit(index, &line6pcm->active_urb_in);
else
- dev_err(s2m(substream), "URB in #%d submission failed\n", index);
+ dev_err(line6pcm->line6->ifcdev,
+ "URB in #%d submission failed (%d)\n", index, ret);
spin_unlock_irqrestore(&line6pcm->lock_audio_in, flags);
return 0;
@@ -67,12 +73,12 @@ static int submit_audio_in_urb(struct snd_pcm_substream *substream)
/*
Submit all currently available capture URBs.
*/
-static int submit_audio_in_all_urbs(struct snd_pcm_substream *substream)
+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(substream);
+ ret = submit_audio_in_urb(line6pcm);
if (ret < 0)
return ret;
}
@@ -83,7 +89,7 @@ static int submit_audio_in_all_urbs(struct snd_pcm_substream *substream)
/*
Unlink all currently active capture URBs.
*/
-static void unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm)
+void line6_unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm)
{
unsigned int i;
@@ -91,6 +97,7 @@ static void unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm)
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);
}
}
@@ -101,7 +108,7 @@ static void unlink_audio_in_urbs(struct snd_line6_pcm *line6pcm)
Wait until unlinking of all currently active capture URBs has been
finished.
*/
-static void wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
+void line6_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
{
int timeout = HZ;
unsigned int i;
@@ -120,46 +127,97 @@ static void wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
} while (--timeout > 0);
if (alive)
snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
-
- line6pcm->active_urb_in = 0;
- line6pcm->unlink_urb_in = 0;
}
/*
Unlink all currently active capture URBs, and wait for finishing.
*/
-void unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
+void line6_unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm)
{
- unlink_audio_in_urbs(line6pcm);
- wait_clear_audio_in_urbs(line6pcm);
+ line6_unlink_audio_in_urbs(line6pcm);
+ line6_wait_clear_audio_in_urbs(line6pcm);
}
/*
- Callback for completed capture URB.
+ 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;
- int frames;
unsigned long flags;
- struct snd_pcm_substream *substream = (struct snd_pcm_substream *)urb->context;
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
- const int bytes_per_frame = line6pcm->properties->bytes_per_frame;
- struct snd_pcm_runtime *runtime = substream->runtime;
+ 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;
-#if DO_DUMP_PCM_RECEIVE
- for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
- struct usb_iso_packet_descriptor *fout = &urb->iso_frame_desc[i];
- line6_write_hexdump(line6pcm->line6, 'C', urb->transfer_buffer + fout->offset, fout->length);
- }
-#endif
-
spin_lock_irqsave(&line6pcm->lock_audio_in, flags);
for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
@@ -167,55 +225,50 @@ static void audio_in_callback(struct urb *urb)
int fsize;
struct usb_iso_packet_descriptor *fin = &urb->iso_frame_desc[i];
- if (fin->status == -18) {
+ 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;
- if (fsize > 0) {
- frames = fsize / bytes_per_frame;
-
- 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
- dev_err(s2m(substream), "driver bug: len = %d\n", len); /* this is somewhat paranoid */
- } else {
- /* copy single chunk */
- memcpy(runtime->dma_area + line6pcm->pos_in_done * bytes_per_frame, fbuf, fsize * bytes_per_frame);
- }
+ /* the following assumes LINE6_ISO_PACKETS == 1: */
+ line6pcm->prev_fbuf = fbuf;
+ line6pcm->prev_fsize = fsize;
- if ((line6pcm->pos_in_done += frames) >= runtime->buffer_size)
- line6pcm->pos_in_done -= runtime->buffer_size;
- }
+#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_bit(index, &line6pcm->unlink_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(substream);
+ submit_audio_in_urb(line6pcm);
- if ((line6pcm->bytes_in += length) >= line6pcm->period_in) {
- line6pcm->bytes_in -= line6pcm->period_in;
- snd_pcm_period_elapsed(substream);
- }
+#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);
}
}
@@ -228,7 +281,8 @@ static int snd_line6_capture_open(struct snd_pcm_substream *substream)
err = snd_pcm_hw_constraint_ratdens(runtime, 0,
SNDRV_PCM_HW_PARAM_RATE,
- (&line6pcm->properties->snd_line6_rates));
+ (&line6pcm->
+ properties->snd_line6_rates));
if (err < 0)
return err;
@@ -261,19 +315,19 @@ static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream,
}
/* -- [FD] end */
- ret = snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(hw_params));
+ ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER);
+
if (ret < 0)
return ret;
- line6pcm->period_in = params_period_bytes(hw_params);
- line6pcm->buffer_in = kmalloc(LINE6_ISO_BUFFERS * LINE6_ISO_PACKETS * LINE6_ISO_PACKET_SIZE_MAX, GFP_KERNEL);
-
- if (!line6pcm->buffer_in) {
- dev_err(s2m(substream), "cannot malloc buffer_in\n");
- return -ENOMEM;
+ 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;
}
@@ -281,37 +335,38 @@ static int snd_line6_capture_hw_params(struct snd_pcm_substream *substream,
static int snd_line6_capture_hw_free(struct snd_pcm_substream *substream)
{
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
- unlink_wait_clear_audio_in_urbs(line6pcm);
-
- kfree(line6pcm->buffer_in);
- line6pcm->buffer_in = NULL;
+ 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_pcm_substream *substream, int cmd)
+int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd)
{
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
int err;
- line6pcm->count_in = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- if (!test_and_set_bit(BIT_RUNNING_CAPTURE, &line6pcm->flags)) {
- err = submit_audio_in_all_urbs(substream);
+#ifdef CONFIG_PM
+ case SNDRV_PCM_TRIGGER_RESUME:
+#endif
+ err = line6_pcm_acquire(line6pcm,
+ LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
- if (err < 0) {
- clear_bit(BIT_RUNNING_CAPTURE, &line6pcm->flags);
- return err;
- }
- }
+ if (err < 0)
+ return err;
break;
case SNDRV_PCM_TRIGGER_STOP:
- if (test_and_clear_bit(BIT_RUNNING_CAPTURE, &line6pcm->flags))
- unlink_audio_in_urbs(line6pcm);
+#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;
@@ -327,22 +382,23 @@ 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,
+ .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 create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
+int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
{
int i;
@@ -351,7 +407,8 @@ int create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
struct urb *urb;
/* URB for audio in: */
- urb = line6pcm->urb_audio_in[i] = usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
+ urb = line6pcm->urb_audio_in[i] =
+ usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
if (urb == NULL) {
dev_err(line6pcm->line6->ifcdev, "Out of memory\n");
@@ -359,7 +416,10 @@ int create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
}
urb->dev = line6pcm->line6->usbdev;
- urb->pipe = usb_rcvisocpipe(line6pcm->line6->usbdev, line6pcm->ep_audio_read & USB_ENDPOINT_NUMBER_MASK);
+ urb->pipe =
+ usb_rcvisocpipe(line6pcm->line6->usbdev,
+ line6pcm->ep_audio_read &
+ USB_ENDPOINT_NUMBER_MASK);
urb->transfer_flags = URB_ISO_ASAP;
urb->start_frame = -1;
urb->number_of_packets = LINE6_ISO_PACKETS;
diff --git a/drivers/staging/line6/capture.h b/drivers/staging/line6/capture.h
index 5c44464d29d..4157bcb598a 100644
--- a/drivers/staging/line6/capture.h
+++ b/drivers/staging/line6/capture.h
@@ -1,7 +1,7 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -12,21 +12,24 @@
#ifndef CAPTURE_H
#define CAPTURE_H
-
-#include "driver.h"
-
#include <sound/pcm.h>
+#include "driver.h"
#include "pcm.h"
-
extern struct snd_pcm_ops snd_line6_capture_ops;
-
-extern int create_audio_in_urbs(struct snd_line6_pcm *line6pcm);
-extern int snd_line6_capture_trigger(struct snd_pcm_substream *substream,
- int cmd);
-extern void unlink_wait_clear_audio_in_urbs(struct snd_line6_pcm *line6pcm);
-
+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/config.h b/drivers/staging/line6/config.h
deleted file mode 100644
index adad130c5dc..00000000000
--- a/drivers/staging/line6/config.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.8.0
- *
- * Copyright (C) 2004-2009 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 CONFIG_H
-#define CONFIG_H
-
-
-#ifdef CONFIG_USB_DEBUG
-#define DEBUG 1
-#endif
-
-
-/**
- Development tools.
-*/
-#define DO_DEBUG_MESSAGES 0
-#define DO_DUMP_URB_SEND DO_DEBUG_MESSAGES
-#define DO_DUMP_URB_RECEIVE DO_DEBUG_MESSAGES
-#define DO_DUMP_PCM_SEND 0
-#define DO_DUMP_PCM_RECEIVE 0
-#define DO_DUMP_MIDI_SEND DO_DEBUG_MESSAGES
-#define DO_DUMP_MIDI_RECEIVE DO_DEBUG_MESSAGES
-#define DO_DUMP_ANY (DO_DUMP_URB_SEND || DO_DUMP_URB_RECEIVE || \
- DO_DUMP_PCM_SEND || DO_DUMP_PCM_RECEIVE || \
- DO_DUMP_MIDI_SEND || DO_DUMP_MIDI_RECEIVE)
-#define CREATE_RAW_FILE 0
-
-#if DO_DEBUG_MESSAGES
-#define CHECKPOINT printk(KERN_INFO "line6usb: %s (%s:%d)\n", \
- __func__, __FILE__, __LINE__)
-#endif
-
-#if DO_DEBUG_MESSAGES
-#define DEBUG_MESSAGES(x) (x)
-#else
-#define DEBUG_MESSAGES(x)
-#endif
-
-
-#endif
diff --git a/drivers/staging/line6/control.c b/drivers/staging/line6/control.c
deleted file mode 100644
index 23ad08e17f8..00000000000
--- a/drivers/staging/line6/control.c
+++ /dev/null
@@ -1,840 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.8.0
- *
- * Copyright (C) 2004-2009 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 "driver.h"
-
-#include <linux/usb.h>
-
-#include "control.h"
-#include "pod.h"
-#include "usbdefs.h"
-#include "variax.h"
-
-#define DEVICE_ATTR2(_name1, _name2, _mode, _show, _store) \
-struct device_attribute dev_attr_##_name1 = __ATTR(_name2, _mode, _show, _store)
-
-#define LINE6_PARAM_R(PREFIX, prefix, type, param) \
-static ssize_t prefix ## _get_ ## param(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- return prefix ## _get_param_ ## type(dev, buf, PREFIX ## _ ## param); \
-}
-
-#define LINE6_PARAM_RW(PREFIX, prefix, type, param) \
-LINE6_PARAM_R(PREFIX, prefix, type, param); \
-static ssize_t prefix ## _set_ ## param(struct device *dev, \
- struct device_attribute *attr, const char *buf, size_t count) \
-{ \
- return prefix ## _set_param_ ## type(dev, buf, count, PREFIX ## _ ## param); \
-}
-
-#define POD_PARAM_R(type, param) LINE6_PARAM_R(POD, pod, type, param)
-#define POD_PARAM_RW(type, param) LINE6_PARAM_RW(POD, pod, type, param)
-#define VARIAX_PARAM_R(type, param) LINE6_PARAM_R(VARIAX, variax, type, param)
-#define VARIAX_PARAM_RW(type, param) LINE6_PARAM_RW(VARIAX, variax, type, param)
-
-
-static ssize_t pod_get_param_int(struct device *dev, char *buf, int param)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6_pod *pod = usb_get_intfdata(interface);
- int retval = line6_wait_dump(&pod->dumpreq, 0);
- if (retval < 0)
- return retval;
- return sprintf(buf, "%d\n", pod->prog_data.control[param]);
-}
-
-static ssize_t pod_set_param_int(struct device *dev, const char *buf, size_t count, int param)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6_pod *pod = usb_get_intfdata(interface);
- int value = simple_strtoul(buf, NULL, 10);
- pod_transmit_parameter(pod, param, value);
- return count;
-}
-
-static ssize_t variax_get_param_int(struct device *dev, char *buf, int param)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6_variax *variax = usb_get_intfdata(interface);
- int retval = line6_wait_dump(&variax->dumpreq, 0);
- if (retval < 0)
- return retval;
- return sprintf(buf, "%d\n", variax->model_data.control[param]);
-}
-
-static ssize_t variax_get_param_float(struct device *dev, char *buf, int param)
-{
- /*
- We do our own floating point handling here since floats in the
- kernel are problematic for at least two reasons: - many distros
- are still shipped with binary kernels optimized for the ancient
- 80386 without FPU
- - there isn't a printf("%f")
- (see http://www.kernelthread.com/publications/faq/335.html)
- */
-
- static const int BIAS = 0x7f;
- static const int OFFSET = 0xf;
- static const int PRECISION = 1000;
-
- int len = 0;
- unsigned part_int, part_frac;
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6_variax *variax = usb_get_intfdata(interface);
- const unsigned char *p = variax->model_data.control + param;
- int retval = line6_wait_dump(&variax->dumpreq, 0);
- if (retval < 0)
- return retval;
-
- if ((p[0] == 0) && (p[1] == 0) && (p[2] == 0))
- part_int = part_frac = 0;
- else {
- int exponent = (((p[0] & 0x7f) << 1) | (p[1] >> 7)) - BIAS;
- unsigned mantissa = (p[1] << 8) | p[2] | 0x8000;
- exponent -= OFFSET;
-
- if (exponent >= 0) {
- part_int = mantissa << exponent;
- part_frac = 0;
- } else {
- part_int = mantissa >> -exponent;
- part_frac = (mantissa << (32 + exponent)) & 0xffffffff;
- }
-
- part_frac = (part_frac / ((1UL << 31) / (PRECISION / 2 * 10)) + 5) / 10;
- }
-
- len += sprintf(buf + len, "%s%d.%03d\n", ((p[0] & 0x80) ? "-" : ""), part_int, part_frac);
- return len;
-}
-
-POD_PARAM_RW(int, tweak);
-POD_PARAM_RW(int, wah_position);
-POD_PARAM_RW(int, compression_gain);
-POD_PARAM_RW(int, vol_pedal_position);
-POD_PARAM_RW(int, compression_threshold);
-POD_PARAM_RW(int, pan);
-POD_PARAM_RW(int, amp_model_setup);
-POD_PARAM_RW(int, amp_model);
-POD_PARAM_RW(int, drive);
-POD_PARAM_RW(int, bass);
-POD_PARAM_RW(int, mid);
-POD_PARAM_RW(int, lowmid);
-POD_PARAM_RW(int, treble);
-POD_PARAM_RW(int, highmid);
-POD_PARAM_RW(int, chan_vol);
-POD_PARAM_RW(int, reverb_mix);
-POD_PARAM_RW(int, effect_setup);
-POD_PARAM_RW(int, band_1_frequency);
-POD_PARAM_RW(int, presence);
-POD_PARAM_RW(int, treble__bass);
-POD_PARAM_RW(int, noise_gate_enable);
-POD_PARAM_RW(int, gate_threshold);
-POD_PARAM_RW(int, gate_decay_time);
-POD_PARAM_RW(int, stomp_enable);
-POD_PARAM_RW(int, comp_enable);
-POD_PARAM_RW(int, stomp_time);
-POD_PARAM_RW(int, delay_enable);
-POD_PARAM_RW(int, mod_param_1);
-POD_PARAM_RW(int, delay_param_1);
-POD_PARAM_RW(int, delay_param_1_note_value);
-POD_PARAM_RW(int, band_2_frequency__bass);
-POD_PARAM_RW(int, delay_param_2);
-POD_PARAM_RW(int, delay_volume_mix);
-POD_PARAM_RW(int, delay_param_3);
-POD_PARAM_RW(int, reverb_enable);
-POD_PARAM_RW(int, reverb_type);
-POD_PARAM_RW(int, reverb_decay);
-POD_PARAM_RW(int, reverb_tone);
-POD_PARAM_RW(int, reverb_pre_delay);
-POD_PARAM_RW(int, reverb_pre_post);
-POD_PARAM_RW(int, band_2_frequency);
-POD_PARAM_RW(int, band_3_frequency__bass);
-POD_PARAM_RW(int, wah_enable);
-POD_PARAM_RW(int, modulation_lo_cut);
-POD_PARAM_RW(int, delay_reverb_lo_cut);
-POD_PARAM_RW(int, volume_pedal_minimum);
-POD_PARAM_RW(int, eq_pre_post);
-POD_PARAM_RW(int, volume_pre_post);
-POD_PARAM_RW(int, di_model);
-POD_PARAM_RW(int, di_delay);
-POD_PARAM_RW(int, mod_enable);
-POD_PARAM_RW(int, mod_param_1_note_value);
-POD_PARAM_RW(int, mod_param_2);
-POD_PARAM_RW(int, mod_param_3);
-POD_PARAM_RW(int, mod_param_4);
-POD_PARAM_RW(int, mod_param_5);
-POD_PARAM_RW(int, mod_volume_mix);
-POD_PARAM_RW(int, mod_pre_post);
-POD_PARAM_RW(int, modulation_model);
-POD_PARAM_RW(int, band_3_frequency);
-POD_PARAM_RW(int, band_4_frequency__bass);
-POD_PARAM_RW(int, mod_param_1_double_precision);
-POD_PARAM_RW(int, delay_param_1_double_precision);
-POD_PARAM_RW(int, eq_enable);
-POD_PARAM_RW(int, tap);
-POD_PARAM_RW(int, volume_tweak_pedal_assign);
-POD_PARAM_RW(int, band_5_frequency);
-POD_PARAM_RW(int, tuner);
-POD_PARAM_RW(int, mic_selection);
-POD_PARAM_RW(int, cabinet_model);
-POD_PARAM_RW(int, stomp_model);
-POD_PARAM_RW(int, roomlevel);
-POD_PARAM_RW(int, band_4_frequency);
-POD_PARAM_RW(int, band_6_frequency);
-POD_PARAM_RW(int, stomp_param_1_note_value);
-POD_PARAM_RW(int, stomp_param_2);
-POD_PARAM_RW(int, stomp_param_3);
-POD_PARAM_RW(int, stomp_param_4);
-POD_PARAM_RW(int, stomp_param_5);
-POD_PARAM_RW(int, stomp_param_6);
-POD_PARAM_RW(int, amp_switch_select);
-POD_PARAM_RW(int, delay_param_4);
-POD_PARAM_RW(int, delay_param_5);
-POD_PARAM_RW(int, delay_pre_post);
-POD_PARAM_RW(int, delay_model);
-POD_PARAM_RW(int, delay_verb_model);
-POD_PARAM_RW(int, tempo_msb);
-POD_PARAM_RW(int, tempo_lsb);
-POD_PARAM_RW(int, wah_model);
-POD_PARAM_RW(int, bypass_volume);
-POD_PARAM_RW(int, fx_loop_on_off);
-POD_PARAM_RW(int, tweak_param_select);
-POD_PARAM_RW(int, amp1_engage);
-POD_PARAM_RW(int, band_1_gain);
-POD_PARAM_RW(int, band_2_gain__bass);
-POD_PARAM_RW(int, band_2_gain);
-POD_PARAM_RW(int, band_3_gain__bass);
-POD_PARAM_RW(int, band_3_gain);
-POD_PARAM_RW(int, band_4_gain__bass);
-POD_PARAM_RW(int, band_5_gain__bass);
-POD_PARAM_RW(int, band_4_gain);
-POD_PARAM_RW(int, band_6_gain__bass);
-VARIAX_PARAM_R(int, body);
-VARIAX_PARAM_R(int, pickup1_enable);
-VARIAX_PARAM_R(int, pickup1_type);
-VARIAX_PARAM_R(float, pickup1_position);
-VARIAX_PARAM_R(float, pickup1_angle);
-VARIAX_PARAM_R(float, pickup1_level);
-VARIAX_PARAM_R(int, pickup2_enable);
-VARIAX_PARAM_R(int, pickup2_type);
-VARIAX_PARAM_R(float, pickup2_position);
-VARIAX_PARAM_R(float, pickup2_angle);
-VARIAX_PARAM_R(float, pickup2_level);
-VARIAX_PARAM_R(int, pickup_phase);
-VARIAX_PARAM_R(float, capacitance);
-VARIAX_PARAM_R(float, tone_resistance);
-VARIAX_PARAM_R(float, volume_resistance);
-VARIAX_PARAM_R(int, taper);
-VARIAX_PARAM_R(float, tone_dump);
-VARIAX_PARAM_R(int, save_tone);
-VARIAX_PARAM_R(float, volume_dump);
-VARIAX_PARAM_R(int, tuning_enable);
-VARIAX_PARAM_R(int, tuning6);
-VARIAX_PARAM_R(int, tuning5);
-VARIAX_PARAM_R(int, tuning4);
-VARIAX_PARAM_R(int, tuning3);
-VARIAX_PARAM_R(int, tuning2);
-VARIAX_PARAM_R(int, tuning1);
-VARIAX_PARAM_R(float, detune6);
-VARIAX_PARAM_R(float, detune5);
-VARIAX_PARAM_R(float, detune4);
-VARIAX_PARAM_R(float, detune3);
-VARIAX_PARAM_R(float, detune2);
-VARIAX_PARAM_R(float, detune1);
-VARIAX_PARAM_R(float, mix6);
-VARIAX_PARAM_R(float, mix5);
-VARIAX_PARAM_R(float, mix4);
-VARIAX_PARAM_R(float, mix3);
-VARIAX_PARAM_R(float, mix2);
-VARIAX_PARAM_R(float, mix1);
-VARIAX_PARAM_R(int, pickup_wiring);
-
-static DEVICE_ATTR(tweak, S_IWUGO | S_IRUGO, pod_get_tweak, pod_set_tweak);
-static DEVICE_ATTR(wah_position, S_IWUGO | S_IRUGO, pod_get_wah_position, pod_set_wah_position);
-static DEVICE_ATTR(compression_gain, S_IWUGO | S_IRUGO, pod_get_compression_gain, pod_set_compression_gain);
-static DEVICE_ATTR(vol_pedal_position, S_IWUGO | S_IRUGO, pod_get_vol_pedal_position, pod_set_vol_pedal_position);
-static DEVICE_ATTR(compression_threshold, S_IWUGO | S_IRUGO, pod_get_compression_threshold, pod_set_compression_threshold);
-static DEVICE_ATTR(pan, S_IWUGO | S_IRUGO, pod_get_pan, pod_set_pan);
-static DEVICE_ATTR(amp_model_setup, S_IWUGO | S_IRUGO, pod_get_amp_model_setup, pod_set_amp_model_setup);
-static DEVICE_ATTR(amp_model, S_IWUGO | S_IRUGO, pod_get_amp_model, pod_set_amp_model);
-static DEVICE_ATTR(drive, S_IWUGO | S_IRUGO, pod_get_drive, pod_set_drive);
-static DEVICE_ATTR(bass, S_IWUGO | S_IRUGO, pod_get_bass, pod_set_bass);
-static DEVICE_ATTR(mid, S_IWUGO | S_IRUGO, pod_get_mid, pod_set_mid);
-static DEVICE_ATTR(lowmid, S_IWUGO | S_IRUGO, pod_get_lowmid, pod_set_lowmid);
-static DEVICE_ATTR(treble, S_IWUGO | S_IRUGO, pod_get_treble, pod_set_treble);
-static DEVICE_ATTR(highmid, S_IWUGO | S_IRUGO, pod_get_highmid, pod_set_highmid);
-static DEVICE_ATTR(chan_vol, S_IWUGO | S_IRUGO, pod_get_chan_vol, pod_set_chan_vol);
-static DEVICE_ATTR(reverb_mix, S_IWUGO | S_IRUGO, pod_get_reverb_mix, pod_set_reverb_mix);
-static DEVICE_ATTR(effect_setup, S_IWUGO | S_IRUGO, pod_get_effect_setup, pod_set_effect_setup);
-static DEVICE_ATTR(band_1_frequency, S_IWUGO | S_IRUGO, pod_get_band_1_frequency, pod_set_band_1_frequency);
-static DEVICE_ATTR(presence, S_IWUGO | S_IRUGO, pod_get_presence, pod_set_presence);
-static DEVICE_ATTR2(treble__bass, treble, S_IWUGO | S_IRUGO, pod_get_treble__bass, pod_set_treble__bass);
-static DEVICE_ATTR(noise_gate_enable, S_IWUGO | S_IRUGO, pod_get_noise_gate_enable, pod_set_noise_gate_enable);
-static DEVICE_ATTR(gate_threshold, S_IWUGO | S_IRUGO, pod_get_gate_threshold, pod_set_gate_threshold);
-static DEVICE_ATTR(gate_decay_time, S_IWUGO | S_IRUGO, pod_get_gate_decay_time, pod_set_gate_decay_time);
-static DEVICE_ATTR(stomp_enable, S_IWUGO | S_IRUGO, pod_get_stomp_enable, pod_set_stomp_enable);
-static DEVICE_ATTR(comp_enable, S_IWUGO | S_IRUGO, pod_get_comp_enable, pod_set_comp_enable);
-static DEVICE_ATTR(stomp_time, S_IWUGO | S_IRUGO, pod_get_stomp_time, pod_set_stomp_time);
-static DEVICE_ATTR(delay_enable, S_IWUGO | S_IRUGO, pod_get_delay_enable, pod_set_delay_enable);
-static DEVICE_ATTR(mod_param_1, S_IWUGO | S_IRUGO, pod_get_mod_param_1, pod_set_mod_param_1);
-static DEVICE_ATTR(delay_param_1, S_IWUGO | S_IRUGO, pod_get_delay_param_1, pod_set_delay_param_1);
-static DEVICE_ATTR(delay_param_1_note_value, S_IWUGO | S_IRUGO, pod_get_delay_param_1_note_value, pod_set_delay_param_1_note_value);
-static DEVICE_ATTR2(band_2_frequency__bass, band_2_frequency, S_IWUGO | S_IRUGO, pod_get_band_2_frequency__bass, pod_set_band_2_frequency__bass);
-static DEVICE_ATTR(delay_param_2, S_IWUGO | S_IRUGO, pod_get_delay_param_2, pod_set_delay_param_2);
-static DEVICE_ATTR(delay_volume_mix, S_IWUGO | S_IRUGO, pod_get_delay_volume_mix, pod_set_delay_volume_mix);
-static DEVICE_ATTR(delay_param_3, S_IWUGO | S_IRUGO, pod_get_delay_param_3, pod_set_delay_param_3);
-static DEVICE_ATTR(reverb_enable, S_IWUGO | S_IRUGO, pod_get_reverb_enable, pod_set_reverb_enable);
-static DEVICE_ATTR(reverb_type, S_IWUGO | S_IRUGO, pod_get_reverb_type, pod_set_reverb_type);
-static DEVICE_ATTR(reverb_decay, S_IWUGO | S_IRUGO, pod_get_reverb_decay, pod_set_reverb_decay);
-static DEVICE_ATTR(reverb_tone, S_IWUGO | S_IRUGO, pod_get_reverb_tone, pod_set_reverb_tone);
-static DEVICE_ATTR(reverb_pre_delay, S_IWUGO | S_IRUGO, pod_get_reverb_pre_delay, pod_set_reverb_pre_delay);
-static DEVICE_ATTR(reverb_pre_post, S_IWUGO | S_IRUGO, pod_get_reverb_pre_post, pod_set_reverb_pre_post);
-static DEVICE_ATTR(band_2_frequency, S_IWUGO | S_IRUGO, pod_get_band_2_frequency, pod_set_band_2_frequency);
-static DEVICE_ATTR2(band_3_frequency__bass, band_3_frequency, S_IWUGO | S_IRUGO, pod_get_band_3_frequency__bass, pod_set_band_3_frequency__bass);
-static DEVICE_ATTR(wah_enable, S_IWUGO | S_IRUGO, pod_get_wah_enable, pod_set_wah_enable);
-static DEVICE_ATTR(modulation_lo_cut, S_IWUGO | S_IRUGO, pod_get_modulation_lo_cut, pod_set_modulation_lo_cut);
-static DEVICE_ATTR(delay_reverb_lo_cut, S_IWUGO | S_IRUGO, pod_get_delay_reverb_lo_cut, pod_set_delay_reverb_lo_cut);
-static DEVICE_ATTR(volume_pedal_minimum, S_IWUGO | S_IRUGO, pod_get_volume_pedal_minimum, pod_set_volume_pedal_minimum);
-static DEVICE_ATTR(eq_pre_post, S_IWUGO | S_IRUGO, pod_get_eq_pre_post, pod_set_eq_pre_post);
-static DEVICE_ATTR(volume_pre_post, S_IWUGO | S_IRUGO, pod_get_volume_pre_post, pod_set_volume_pre_post);
-static DEVICE_ATTR(di_model, S_IWUGO | S_IRUGO, pod_get_di_model, pod_set_di_model);
-static DEVICE_ATTR(di_delay, S_IWUGO | S_IRUGO, pod_get_di_delay, pod_set_di_delay);
-static DEVICE_ATTR(mod_enable, S_IWUGO | S_IRUGO, pod_get_mod_enable, pod_set_mod_enable);
-static DEVICE_ATTR(mod_param_1_note_value, S_IWUGO | S_IRUGO, pod_get_mod_param_1_note_value, pod_set_mod_param_1_note_value);
-static DEVICE_ATTR(mod_param_2, S_IWUGO | S_IRUGO, pod_get_mod_param_2, pod_set_mod_param_2);
-static DEVICE_ATTR(mod_param_3, S_IWUGO | S_IRUGO, pod_get_mod_param_3, pod_set_mod_param_3);
-static DEVICE_ATTR(mod_param_4, S_IWUGO | S_IRUGO, pod_get_mod_param_4, pod_set_mod_param_4);
-static DEVICE_ATTR(mod_param_5, S_IWUGO | S_IRUGO, pod_get_mod_param_5, pod_set_mod_param_5);
-static DEVICE_ATTR(mod_volume_mix, S_IWUGO | S_IRUGO, pod_get_mod_volume_mix, pod_set_mod_volume_mix);
-static DEVICE_ATTR(mod_pre_post, S_IWUGO | S_IRUGO, pod_get_mod_pre_post, pod_set_mod_pre_post);
-static DEVICE_ATTR(modulation_model, S_IWUGO | S_IRUGO, pod_get_modulation_model, pod_set_modulation_model);
-static DEVICE_ATTR(band_3_frequency, S_IWUGO | S_IRUGO, pod_get_band_3_frequency, pod_set_band_3_frequency);
-static DEVICE_ATTR2(band_4_frequency__bass, band_4_frequency, S_IWUGO | S_IRUGO, pod_get_band_4_frequency__bass, pod_set_band_4_frequency__bass);
-static DEVICE_ATTR(mod_param_1_double_precision, S_IWUGO | S_IRUGO, pod_get_mod_param_1_double_precision, pod_set_mod_param_1_double_precision);
-static DEVICE_ATTR(delay_param_1_double_precision, S_IWUGO | S_IRUGO, pod_get_delay_param_1_double_precision, pod_set_delay_param_1_double_precision);
-static DEVICE_ATTR(eq_enable, S_IWUGO | S_IRUGO, pod_get_eq_enable, pod_set_eq_enable);
-static DEVICE_ATTR(tap, S_IWUGO | S_IRUGO, pod_get_tap, pod_set_tap);
-static DEVICE_ATTR(volume_tweak_pedal_assign, S_IWUGO | S_IRUGO, pod_get_volume_tweak_pedal_assign, pod_set_volume_tweak_pedal_assign);
-static DEVICE_ATTR(band_5_frequency, S_IWUGO | S_IRUGO, pod_get_band_5_frequency, pod_set_band_5_frequency);
-static DEVICE_ATTR(tuner, S_IWUGO | S_IRUGO, pod_get_tuner, pod_set_tuner);
-static DEVICE_ATTR(mic_selection, S_IWUGO | S_IRUGO, pod_get_mic_selection, pod_set_mic_selection);
-static DEVICE_ATTR(cabinet_model, S_IWUGO | S_IRUGO, pod_get_cabinet_model, pod_set_cabinet_model);
-static DEVICE_ATTR(stomp_model, S_IWUGO | S_IRUGO, pod_get_stomp_model, pod_set_stomp_model);
-static DEVICE_ATTR(roomlevel, S_IWUGO | S_IRUGO, pod_get_roomlevel, pod_set_roomlevel);
-static DEVICE_ATTR(band_4_frequency, S_IWUGO | S_IRUGO, pod_get_band_4_frequency, pod_set_band_4_frequency);
-static DEVICE_ATTR(band_6_frequency, S_IWUGO | S_IRUGO, pod_get_band_6_frequency, pod_set_band_6_frequency);
-static DEVICE_ATTR(stomp_param_1_note_value, S_IWUGO | S_IRUGO, pod_get_stomp_param_1_note_value, pod_set_stomp_param_1_note_value);
-static DEVICE_ATTR(stomp_param_2, S_IWUGO | S_IRUGO, pod_get_stomp_param_2, pod_set_stomp_param_2);
-static DEVICE_ATTR(stomp_param_3, S_IWUGO | S_IRUGO, pod_get_stomp_param_3, pod_set_stomp_param_3);
-static DEVICE_ATTR(stomp_param_4, S_IWUGO | S_IRUGO, pod_get_stomp_param_4, pod_set_stomp_param_4);
-static DEVICE_ATTR(stomp_param_5, S_IWUGO | S_IRUGO, pod_get_stomp_param_5, pod_set_stomp_param_5);
-static DEVICE_ATTR(stomp_param_6, S_IWUGO | S_IRUGO, pod_get_stomp_param_6, pod_set_stomp_param_6);
-static DEVICE_ATTR(amp_switch_select, S_IWUGO | S_IRUGO, pod_get_amp_switch_select, pod_set_amp_switch_select);
-static DEVICE_ATTR(delay_param_4, S_IWUGO | S_IRUGO, pod_get_delay_param_4, pod_set_delay_param_4);
-static DEVICE_ATTR(delay_param_5, S_IWUGO | S_IRUGO, pod_get_delay_param_5, pod_set_delay_param_5);
-static DEVICE_ATTR(delay_pre_post, S_IWUGO | S_IRUGO, pod_get_delay_pre_post, pod_set_delay_pre_post);
-static DEVICE_ATTR(delay_model, S_IWUGO | S_IRUGO, pod_get_delay_model, pod_set_delay_model);
-static DEVICE_ATTR(delay_verb_model, S_IWUGO | S_IRUGO, pod_get_delay_verb_model, pod_set_delay_verb_model);
-static DEVICE_ATTR(tempo_msb, S_IWUGO | S_IRUGO, pod_get_tempo_msb, pod_set_tempo_msb);
-static DEVICE_ATTR(tempo_lsb, S_IWUGO | S_IRUGO, pod_get_tempo_lsb, pod_set_tempo_lsb);
-static DEVICE_ATTR(wah_model, S_IWUGO | S_IRUGO, pod_get_wah_model, pod_set_wah_model);
-static DEVICE_ATTR(bypass_volume, S_IWUGO | S_IRUGO, pod_get_bypass_volume, pod_set_bypass_volume);
-static DEVICE_ATTR(fx_loop_on_off, S_IWUGO | S_IRUGO, pod_get_fx_loop_on_off, pod_set_fx_loop_on_off);
-static DEVICE_ATTR(tweak_param_select, S_IWUGO | S_IRUGO, pod_get_tweak_param_select, pod_set_tweak_param_select);
-static DEVICE_ATTR(amp1_engage, S_IWUGO | S_IRUGO, pod_get_amp1_engage, pod_set_amp1_engage);
-static DEVICE_ATTR(band_1_gain, S_IWUGO | S_IRUGO, pod_get_band_1_gain, pod_set_band_1_gain);
-static DEVICE_ATTR2(band_2_gain__bass, band_2_gain, S_IWUGO | S_IRUGO, pod_get_band_2_gain__bass, pod_set_band_2_gain__bass);
-static DEVICE_ATTR(band_2_gain, S_IWUGO | S_IRUGO, pod_get_band_2_gain, pod_set_band_2_gain);
-static DEVICE_ATTR2(band_3_gain__bass, band_3_gain, S_IWUGO | S_IRUGO, pod_get_band_3_gain__bass, pod_set_band_3_gain__bass);
-static DEVICE_ATTR(band_3_gain, S_IWUGO | S_IRUGO, pod_get_band_3_gain, pod_set_band_3_gain);
-static DEVICE_ATTR2(band_4_gain__bass, band_4_gain, S_IWUGO | S_IRUGO, pod_get_band_4_gain__bass, pod_set_band_4_gain__bass);
-static DEVICE_ATTR2(band_5_gain__bass, band_5_gain, S_IWUGO | S_IRUGO, pod_get_band_5_gain__bass, pod_set_band_5_gain__bass);
-static DEVICE_ATTR(band_4_gain, S_IWUGO | S_IRUGO, pod_get_band_4_gain, pod_set_band_4_gain);
-static DEVICE_ATTR2(band_6_gain__bass, band_6_gain, S_IWUGO | S_IRUGO, pod_get_band_6_gain__bass, pod_set_band_6_gain__bass);
-static DEVICE_ATTR(body, S_IRUGO, variax_get_body, line6_nop_write);
-static DEVICE_ATTR(pickup1_enable, S_IRUGO, variax_get_pickup1_enable, line6_nop_write);
-static DEVICE_ATTR(pickup1_type, S_IRUGO, variax_get_pickup1_type, line6_nop_write);
-static DEVICE_ATTR(pickup1_position, S_IRUGO, variax_get_pickup1_position, line6_nop_write);
-static DEVICE_ATTR(pickup1_angle, S_IRUGO, variax_get_pickup1_angle, line6_nop_write);
-static DEVICE_ATTR(pickup1_level, S_IRUGO, variax_get_pickup1_level, line6_nop_write);
-static DEVICE_ATTR(pickup2_enable, S_IRUGO, variax_get_pickup2_enable, line6_nop_write);
-static DEVICE_ATTR(pickup2_type, S_IRUGO, variax_get_pickup2_type, line6_nop_write);
-static DEVICE_ATTR(pickup2_position, S_IRUGO, variax_get_pickup2_position, line6_nop_write);
-static DEVICE_ATTR(pickup2_angle, S_IRUGO, variax_get_pickup2_angle, line6_nop_write);
-static DEVICE_ATTR(pickup2_level, S_IRUGO, variax_get_pickup2_level, line6_nop_write);
-static DEVICE_ATTR(pickup_phase, S_IRUGO, variax_get_pickup_phase, line6_nop_write);
-static DEVICE_ATTR(capacitance, S_IRUGO, variax_get_capacitance, line6_nop_write);
-static DEVICE_ATTR(tone_resistance, S_IRUGO, variax_get_tone_resistance, line6_nop_write);
-static DEVICE_ATTR(volume_resistance, S_IRUGO, variax_get_volume_resistance, line6_nop_write);
-static DEVICE_ATTR(taper, S_IRUGO, variax_get_taper, line6_nop_write);
-static DEVICE_ATTR(tone_dump, S_IRUGO, variax_get_tone_dump, line6_nop_write);
-static DEVICE_ATTR(save_tone, S_IRUGO, variax_get_save_tone, line6_nop_write);
-static DEVICE_ATTR(volume_dump, S_IRUGO, variax_get_volume_dump, line6_nop_write);
-static DEVICE_ATTR(tuning_enable, S_IRUGO, variax_get_tuning_enable, line6_nop_write);
-static DEVICE_ATTR(tuning6, S_IRUGO, variax_get_tuning6, line6_nop_write);
-static DEVICE_ATTR(tuning5, S_IRUGO, variax_get_tuning5, line6_nop_write);
-static DEVICE_ATTR(tuning4, S_IRUGO, variax_get_tuning4, line6_nop_write);
-static DEVICE_ATTR(tuning3, S_IRUGO, variax_get_tuning3, line6_nop_write);
-static DEVICE_ATTR(tuning2, S_IRUGO, variax_get_tuning2, line6_nop_write);
-static DEVICE_ATTR(tuning1, S_IRUGO, variax_get_tuning1, line6_nop_write);
-static DEVICE_ATTR(detune6, S_IRUGO, variax_get_detune6, line6_nop_write);
-static DEVICE_ATTR(detune5, S_IRUGO, variax_get_detune5, line6_nop_write);
-static DEVICE_ATTR(detune4, S_IRUGO, variax_get_detune4, line6_nop_write);
-static DEVICE_ATTR(detune3, S_IRUGO, variax_get_detune3, line6_nop_write);
-static DEVICE_ATTR(detune2, S_IRUGO, variax_get_detune2, line6_nop_write);
-static DEVICE_ATTR(detune1, S_IRUGO, variax_get_detune1, line6_nop_write);
-static DEVICE_ATTR(mix6, S_IRUGO, variax_get_mix6, line6_nop_write);
-static DEVICE_ATTR(mix5, S_IRUGO, variax_get_mix5, line6_nop_write);
-static DEVICE_ATTR(mix4, S_IRUGO, variax_get_mix4, line6_nop_write);
-static DEVICE_ATTR(mix3, S_IRUGO, variax_get_mix3, line6_nop_write);
-static DEVICE_ATTR(mix2, S_IRUGO, variax_get_mix2, line6_nop_write);
-static DEVICE_ATTR(mix1, S_IRUGO, variax_get_mix1, line6_nop_write);
-static DEVICE_ATTR(pickup_wiring, S_IRUGO, variax_get_pickup_wiring, line6_nop_write);
-
-int pod_create_files(int firmware, int type, struct device *dev)
-{
- int err;
- CHECK_RETURN(device_create_file(dev, &dev_attr_tweak));
- CHECK_RETURN(device_create_file(dev, &dev_attr_wah_position));
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_compression_gain));
- CHECK_RETURN(device_create_file(dev, &dev_attr_vol_pedal_position));
- CHECK_RETURN(device_create_file(dev, &dev_attr_compression_threshold));
- CHECK_RETURN(device_create_file(dev, &dev_attr_pan));
- CHECK_RETURN(device_create_file(dev, &dev_attr_amp_model_setup));
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_amp_model));
- CHECK_RETURN(device_create_file(dev, &dev_attr_drive));
- CHECK_RETURN(device_create_file(dev, &dev_attr_bass));
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_mid));
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_lowmid));
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_treble));
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_highmid));
- CHECK_RETURN(device_create_file(dev, &dev_attr_chan_vol));
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_reverb_mix));
- CHECK_RETURN(device_create_file(dev, &dev_attr_effect_setup));
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_band_1_frequency));
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_presence));
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_treble__bass));
- CHECK_RETURN(device_create_file(dev, &dev_attr_noise_gate_enable));
- CHECK_RETURN(device_create_file(dev, &dev_attr_gate_threshold));
- CHECK_RETURN(device_create_file(dev, &dev_attr_gate_decay_time));
- CHECK_RETURN(device_create_file(dev, &dev_attr_stomp_enable));
- CHECK_RETURN(device_create_file(dev, &dev_attr_comp_enable));
- CHECK_RETURN(device_create_file(dev, &dev_attr_stomp_time));
- CHECK_RETURN(device_create_file(dev, &dev_attr_delay_enable));
- CHECK_RETURN(device_create_file(dev, &dev_attr_mod_param_1));
- CHECK_RETURN(device_create_file(dev, &dev_attr_delay_param_1));
- CHECK_RETURN(device_create_file(dev, &dev_attr_delay_param_1_note_value));
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_band_2_frequency__bass));
- CHECK_RETURN(device_create_file(dev, &dev_attr_delay_param_2));
- CHECK_RETURN(device_create_file(dev, &dev_attr_delay_volume_mix));
- CHECK_RETURN(device_create_file(dev, &dev_attr_delay_param_3));
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_reverb_enable));
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_reverb_type));
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_reverb_decay));
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_reverb_tone));
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_reverb_pre_delay));
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_reverb_pre_post));
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_band_2_frequency));
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_band_3_frequency__bass));
- CHECK_RETURN(device_create_file(dev, &dev_attr_wah_enable));
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_modulation_lo_cut));
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_delay_reverb_lo_cut));
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_volume_pedal_minimum));
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_eq_pre_post));
- CHECK_RETURN(device_create_file(dev, &dev_attr_volume_pre_post));
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_di_model));
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_di_delay));
- CHECK_RETURN(device_create_file(dev, &dev_attr_mod_enable));
- CHECK_RETURN(device_create_file(dev, &dev_attr_mod_param_1_note_value));
- CHECK_RETURN(device_create_file(dev, &dev_attr_mod_param_2));
- CHECK_RETURN(device_create_file(dev, &dev_attr_mod_param_3));
- CHECK_RETURN(device_create_file(dev, &dev_attr_mod_param_4));
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_mod_param_5));
- CHECK_RETURN(device_create_file(dev, &dev_attr_mod_volume_mix));
- CHECK_RETURN(device_create_file(dev, &dev_attr_mod_pre_post));
- CHECK_RETURN(device_create_file(dev, &dev_attr_modulation_model));
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_band_3_frequency));
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_band_4_frequency__bass));
- CHECK_RETURN(device_create_file(dev, &dev_attr_mod_param_1_double_precision));
- CHECK_RETURN(device_create_file(dev, &dev_attr_delay_param_1_double_precision));
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_eq_enable));
- CHECK_RETURN(device_create_file(dev, &dev_attr_tap));
- CHECK_RETURN(device_create_file(dev, &dev_attr_volume_tweak_pedal_assign));
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_band_5_frequency));
- CHECK_RETURN(device_create_file(dev, &dev_attr_tuner));
- CHECK_RETURN(device_create_file(dev, &dev_attr_mic_selection));
- CHECK_RETURN(device_create_file(dev, &dev_attr_cabinet_model));
- CHECK_RETURN(device_create_file(dev, &dev_attr_stomp_model));
- CHECK_RETURN(device_create_file(dev, &dev_attr_roomlevel));
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_band_4_frequency));
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_band_6_frequency));
- CHECK_RETURN(device_create_file(dev, &dev_attr_stomp_param_1_note_value));
- CHECK_RETURN(device_create_file(dev, &dev_attr_stomp_param_2));
- CHECK_RETURN(device_create_file(dev, &dev_attr_stomp_param_3));
- CHECK_RETURN(device_create_file(dev, &dev_attr_stomp_param_4));
- CHECK_RETURN(device_create_file(dev, &dev_attr_stomp_param_5));
- CHECK_RETURN(device_create_file(dev, &dev_attr_stomp_param_6));
- if ((type & (LINE6_BITS_LIVE)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_amp_switch_select));
- CHECK_RETURN(device_create_file(dev, &dev_attr_delay_param_4));
- CHECK_RETURN(device_create_file(dev, &dev_attr_delay_param_5));
- CHECK_RETURN(device_create_file(dev, &dev_attr_delay_pre_post));
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_delay_model));
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_delay_verb_model));
- CHECK_RETURN(device_create_file(dev, &dev_attr_tempo_msb));
- CHECK_RETURN(device_create_file(dev, &dev_attr_tempo_lsb));
- if (firmware >= 300)
- CHECK_RETURN(device_create_file(dev, &dev_attr_wah_model));
- if (firmware >= 214)
- CHECK_RETURN(device_create_file(dev, &dev_attr_bypass_volume));
- if ((type & (LINE6_BITS_PRO)) != 0)
- CHECK_RETURN(device_create_file(dev, &dev_attr_fx_loop_on_off));
- CHECK_RETURN(device_create_file(dev, &dev_attr_tweak_param_select));
- CHECK_RETURN(device_create_file(dev, &dev_attr_amp1_engage));
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_band_1_gain));
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_band_2_gain__bass));
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_band_2_gain));
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_band_3_gain__bass));
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_band_3_gain));
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_band_4_gain__bass));
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_band_5_gain__bass));
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_band_4_gain));
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- CHECK_RETURN(device_create_file(dev, &dev_attr_band_6_gain__bass));
- return 0;
-}
-
-void pod_remove_files(int firmware, int type, struct device *dev)
-{
- device_remove_file(dev, &dev_attr_tweak);
- device_remove_file(dev, &dev_attr_wah_position);
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_compression_gain);
- device_remove_file(dev, &dev_attr_vol_pedal_position);
- device_remove_file(dev, &dev_attr_compression_threshold);
- device_remove_file(dev, &dev_attr_pan);
- device_remove_file(dev, &dev_attr_amp_model_setup);
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_amp_model);
- device_remove_file(dev, &dev_attr_drive);
- device_remove_file(dev, &dev_attr_bass);
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_mid);
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_lowmid);
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_treble);
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_highmid);
- device_remove_file(dev, &dev_attr_chan_vol);
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_reverb_mix);
- device_remove_file(dev, &dev_attr_effect_setup);
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_band_1_frequency);
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_presence);
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_treble__bass);
- device_remove_file(dev, &dev_attr_noise_gate_enable);
- device_remove_file(dev, &dev_attr_gate_threshold);
- device_remove_file(dev, &dev_attr_gate_decay_time);
- device_remove_file(dev, &dev_attr_stomp_enable);
- device_remove_file(dev, &dev_attr_comp_enable);
- device_remove_file(dev, &dev_attr_stomp_time);
- device_remove_file(dev, &dev_attr_delay_enable);
- device_remove_file(dev, &dev_attr_mod_param_1);
- device_remove_file(dev, &dev_attr_delay_param_1);
- device_remove_file(dev, &dev_attr_delay_param_1_note_value);
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_band_2_frequency__bass);
- device_remove_file(dev, &dev_attr_delay_param_2);
- device_remove_file(dev, &dev_attr_delay_volume_mix);
- device_remove_file(dev, &dev_attr_delay_param_3);
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_reverb_enable);
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_reverb_type);
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_reverb_decay);
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_reverb_tone);
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_reverb_pre_delay);
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_reverb_pre_post);
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_band_2_frequency);
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_band_3_frequency__bass);
- device_remove_file(dev, &dev_attr_wah_enable);
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_modulation_lo_cut);
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_delay_reverb_lo_cut);
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_volume_pedal_minimum);
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_eq_pre_post);
- device_remove_file(dev, &dev_attr_volume_pre_post);
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_di_model);
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_di_delay);
- device_remove_file(dev, &dev_attr_mod_enable);
- device_remove_file(dev, &dev_attr_mod_param_1_note_value);
- device_remove_file(dev, &dev_attr_mod_param_2);
- device_remove_file(dev, &dev_attr_mod_param_3);
- device_remove_file(dev, &dev_attr_mod_param_4);
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_mod_param_5);
- device_remove_file(dev, &dev_attr_mod_volume_mix);
- device_remove_file(dev, &dev_attr_mod_pre_post);
- device_remove_file(dev, &dev_attr_modulation_model);
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_band_3_frequency);
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_band_4_frequency__bass);
- device_remove_file(dev, &dev_attr_mod_param_1_double_precision);
- device_remove_file(dev, &dev_attr_delay_param_1_double_precision);
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_eq_enable);
- device_remove_file(dev, &dev_attr_tap);
- device_remove_file(dev, &dev_attr_volume_tweak_pedal_assign);
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_band_5_frequency);
- device_remove_file(dev, &dev_attr_tuner);
- device_remove_file(dev, &dev_attr_mic_selection);
- device_remove_file(dev, &dev_attr_cabinet_model);
- device_remove_file(dev, &dev_attr_stomp_model);
- device_remove_file(dev, &dev_attr_roomlevel);
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_band_4_frequency);
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_band_6_frequency);
- device_remove_file(dev, &dev_attr_stomp_param_1_note_value);
- device_remove_file(dev, &dev_attr_stomp_param_2);
- device_remove_file(dev, &dev_attr_stomp_param_3);
- device_remove_file(dev, &dev_attr_stomp_param_4);
- device_remove_file(dev, &dev_attr_stomp_param_5);
- device_remove_file(dev, &dev_attr_stomp_param_6);
- if ((type & (LINE6_BITS_LIVE)) != 0)
- device_remove_file(dev, &dev_attr_amp_switch_select);
- device_remove_file(dev, &dev_attr_delay_param_4);
- device_remove_file(dev, &dev_attr_delay_param_5);
- device_remove_file(dev, &dev_attr_delay_pre_post);
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_delay_model);
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- device_remove_file(dev, &dev_attr_delay_verb_model);
- device_remove_file(dev, &dev_attr_tempo_msb);
- device_remove_file(dev, &dev_attr_tempo_lsb);
- if (firmware >= 300)
- device_remove_file(dev, &dev_attr_wah_model);
- if (firmware >= 214)
- device_remove_file(dev, &dev_attr_bypass_volume);
- if ((type & (LINE6_BITS_PRO)) != 0)
- device_remove_file(dev, &dev_attr_fx_loop_on_off);
- device_remove_file(dev, &dev_attr_tweak_param_select);
- device_remove_file(dev, &dev_attr_amp1_engage);
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_band_1_gain);
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_band_2_gain__bass);
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_band_2_gain);
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_band_3_gain__bass);
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_band_3_gain);
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_band_4_gain__bass);
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_band_5_gain__bass);
- if ((type & (LINE6_BITS_PODXTALL)) != 0)
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_band_4_gain);
- if ((type & (LINE6_BITS_BASSPODXTALL)) != 0)
- if (firmware >= 200)
- device_remove_file(dev, &dev_attr_band_6_gain__bass);
-}
-
-EXPORT_SYMBOL(pod_create_files);
-EXPORT_SYMBOL(pod_remove_files);
-
-int variax_create_files(int firmware, int type, struct device *dev)
-{
- int err;
- CHECK_RETURN(device_create_file(dev, &dev_attr_body));
- CHECK_RETURN(device_create_file(dev, &dev_attr_pickup1_enable));
- CHECK_RETURN(device_create_file(dev, &dev_attr_pickup1_type));
- CHECK_RETURN(device_create_file(dev, &dev_attr_pickup1_position));
- CHECK_RETURN(device_create_file(dev, &dev_attr_pickup1_angle));
- CHECK_RETURN(device_create_file(dev, &dev_attr_pickup1_level));
- CHECK_RETURN(device_create_file(dev, &dev_attr_pickup2_enable));
- CHECK_RETURN(device_create_file(dev, &dev_attr_pickup2_type));
- CHECK_RETURN(device_create_file(dev, &dev_attr_pickup2_position));
- CHECK_RETURN(device_create_file(dev, &dev_attr_pickup2_angle));
- CHECK_RETURN(device_create_file(dev, &dev_attr_pickup2_level));
- CHECK_RETURN(device_create_file(dev, &dev_attr_pickup_phase));
- CHECK_RETURN(device_create_file(dev, &dev_attr_capacitance));
- CHECK_RETURN(device_create_file(dev, &dev_attr_tone_resistance));
- CHECK_RETURN(device_create_file(dev, &dev_attr_volume_resistance));
- CHECK_RETURN(device_create_file(dev, &dev_attr_taper));
- CHECK_RETURN(device_create_file(dev, &dev_attr_tone_dump));
- CHECK_RETURN(device_create_file(dev, &dev_attr_save_tone));
- CHECK_RETURN(device_create_file(dev, &dev_attr_volume_dump));
- CHECK_RETURN(device_create_file(dev, &dev_attr_tuning_enable));
- CHECK_RETURN(device_create_file(dev, &dev_attr_tuning6));
- CHECK_RETURN(device_create_file(dev, &dev_attr_tuning5));
- CHECK_RETURN(device_create_file(dev, &dev_attr_tuning4));
- CHECK_RETURN(device_create_file(dev, &dev_attr_tuning3));
- CHECK_RETURN(device_create_file(dev, &dev_attr_tuning2));
- CHECK_RETURN(device_create_file(dev, &dev_attr_tuning1));
- CHECK_RETURN(device_create_file(dev, &dev_attr_detune6));
- CHECK_RETURN(device_create_file(dev, &dev_attr_detune5));
- CHECK_RETURN(device_create_file(dev, &dev_attr_detune4));
- CHECK_RETURN(device_create_file(dev, &dev_attr_detune3));
- CHECK_RETURN(device_create_file(dev, &dev_attr_detune2));
- CHECK_RETURN(device_create_file(dev, &dev_attr_detune1));
- CHECK_RETURN(device_create_file(dev, &dev_attr_mix6));
- CHECK_RETURN(device_create_file(dev, &dev_attr_mix5));
- CHECK_RETURN(device_create_file(dev, &dev_attr_mix4));
- CHECK_RETURN(device_create_file(dev, &dev_attr_mix3));
- CHECK_RETURN(device_create_file(dev, &dev_attr_mix2));
- CHECK_RETURN(device_create_file(dev, &dev_attr_mix1));
- CHECK_RETURN(device_create_file(dev, &dev_attr_pickup_wiring));
- return 0;
-}
-
-void variax_remove_files(int firmware, int type, struct device *dev)
-{
- device_remove_file(dev, &dev_attr_body);
- device_remove_file(dev, &dev_attr_pickup1_enable);
- device_remove_file(dev, &dev_attr_pickup1_type);
- device_remove_file(dev, &dev_attr_pickup1_position);
- device_remove_file(dev, &dev_attr_pickup1_angle);
- device_remove_file(dev, &dev_attr_pickup1_level);
- device_remove_file(dev, &dev_attr_pickup2_enable);
- device_remove_file(dev, &dev_attr_pickup2_type);
- device_remove_file(dev, &dev_attr_pickup2_position);
- device_remove_file(dev, &dev_attr_pickup2_angle);
- device_remove_file(dev, &dev_attr_pickup2_level);
- device_remove_file(dev, &dev_attr_pickup_phase);
- device_remove_file(dev, &dev_attr_capacitance);
- device_remove_file(dev, &dev_attr_tone_resistance);
- device_remove_file(dev, &dev_attr_volume_resistance);
- device_remove_file(dev, &dev_attr_taper);
- device_remove_file(dev, &dev_attr_tone_dump);
- device_remove_file(dev, &dev_attr_save_tone);
- device_remove_file(dev, &dev_attr_volume_dump);
- device_remove_file(dev, &dev_attr_tuning_enable);
- device_remove_file(dev, &dev_attr_tuning6);
- device_remove_file(dev, &dev_attr_tuning5);
- device_remove_file(dev, &dev_attr_tuning4);
- device_remove_file(dev, &dev_attr_tuning3);
- device_remove_file(dev, &dev_attr_tuning2);
- device_remove_file(dev, &dev_attr_tuning1);
- device_remove_file(dev, &dev_attr_detune6);
- device_remove_file(dev, &dev_attr_detune5);
- device_remove_file(dev, &dev_attr_detune4);
- device_remove_file(dev, &dev_attr_detune3);
- device_remove_file(dev, &dev_attr_detune2);
- device_remove_file(dev, &dev_attr_detune1);
- device_remove_file(dev, &dev_attr_mix6);
- device_remove_file(dev, &dev_attr_mix5);
- device_remove_file(dev, &dev_attr_mix4);
- device_remove_file(dev, &dev_attr_mix3);
- device_remove_file(dev, &dev_attr_mix2);
- device_remove_file(dev, &dev_attr_mix1);
- device_remove_file(dev, &dev_attr_pickup_wiring);
-}
-
-EXPORT_SYMBOL(variax_create_files);
-EXPORT_SYMBOL(variax_remove_files);
diff --git a/drivers/staging/line6/control.h b/drivers/staging/line6/control.h
deleted file mode 100644
index 2f19665d95a..00000000000
--- a/drivers/staging/line6/control.h
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.8.0
- *
- * Copyright (C) 2004-2009 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 LINE6_CONTROL_H
-#define LINE6_CONTROL_H
-
-
-/**
- List of PODxt Pro controls.
- See Appendix C of the "PODxt (Pro) Pilot's Handbook" by Line6.
- Comments after the number refer to the PODxt Pro firmware version required
- for this feature.
-*/
-enum {
- POD_tweak = 1,
- POD_wah_position = 4,
- POD_compression_gain = 5, /* device: LINE6_BITS_PODXTALL */
- POD_vol_pedal_position = 7,
- POD_compression_threshold = 9,
- POD_pan = 10,
- POD_amp_model_setup = 11,
- POD_amp_model = 12, /* firmware: 2.0 */
- POD_drive = 13,
- POD_bass = 14,
- POD_mid = 15, /* device: LINE6_BITS_PODXTALL */
- POD_lowmid = 15, /* device: LINE6_BITS_BASSPODXTALL */
- POD_treble = 16, /* device: LINE6_BITS_PODXTALL */
- POD_highmid = 16, /* device: LINE6_BITS_BASSPODXTALL */
- POD_chan_vol = 17,
- POD_reverb_mix = 18, /* device: LINE6_BITS_PODXTALL */
- POD_effect_setup = 19,
- POD_band_1_frequency = 20, /* firmware: 2.0 */
- POD_presence = 21, /* device: LINE6_BITS_PODXTALL */
- POD_treble__bass = 21, /* device: LINE6_BITS_BASSPODXTALL */
- POD_noise_gate_enable = 22,
- POD_gate_threshold = 23,
- POD_gate_decay_time = 24,
- POD_stomp_enable = 25,
- POD_comp_enable = 26,
- POD_stomp_time = 27,
- POD_delay_enable = 28,
- POD_mod_param_1 = 29,
- POD_delay_param_1 = 30,
- POD_delay_param_1_note_value = 31,
- POD_band_2_frequency__bass = 32, /* device: LINE6_BITS_BASSPODXTALL */ /* firmware: 2.0 */
- POD_delay_param_2 = 33,
- POD_delay_volume_mix = 34,
- POD_delay_param_3 = 35,
- POD_reverb_enable = 36, /* device: LINE6_BITS_PODXTALL */
- POD_reverb_type = 37, /* device: LINE6_BITS_PODXTALL */
- POD_reverb_decay = 38, /* device: LINE6_BITS_PODXTALL */
- POD_reverb_tone = 39, /* device: LINE6_BITS_PODXTALL */
- POD_reverb_pre_delay = 40, /* device: LINE6_BITS_PODXTALL */
- POD_reverb_pre_post = 41, /* device: LINE6_BITS_PODXTALL */
- POD_band_2_frequency = 42, /* device: LINE6_BITS_PODXTALL */ /* firmware: 2.0 */
- POD_band_3_frequency__bass = 42, /* device: LINE6_BITS_BASSPODXTALL */ /* firmware: 2.0 */
- POD_wah_enable = 43,
- POD_modulation_lo_cut = 44, /* device: LINE6_BITS_BASSPODXTALL */
- POD_delay_reverb_lo_cut = 45, /* device: LINE6_BITS_BASSPODXTALL */
- POD_volume_pedal_minimum = 46, /* device: LINE6_BITS_PODXTALL */ /* firmware: 2.0 */
- POD_eq_pre_post = 46, /* device: LINE6_BITS_BASSPODXTALL */ /* firmware: 2.0 */
- POD_volume_pre_post = 47,
- POD_di_model = 48, /* device: LINE6_BITS_BASSPODXTALL */
- POD_di_delay = 49, /* device: LINE6_BITS_BASSPODXTALL */
- POD_mod_enable = 50,
- POD_mod_param_1_note_value = 51,
- POD_mod_param_2 = 52,
- POD_mod_param_3 = 53,
- POD_mod_param_4 = 54,
- POD_mod_param_5 = 55, /* device: LINE6_BITS_BASSPODXTALL */
- POD_mod_volume_mix = 56,
- POD_mod_pre_post = 57,
- POD_modulation_model = 58,
- POD_band_3_frequency = 60, /* device: LINE6_BITS_PODXTALL */ /* firmware: 2.0 */
- POD_band_4_frequency__bass = 60, /* device: LINE6_BITS_BASSPODXTALL */ /* firmware: 2.0 */
- POD_mod_param_1_double_precision = 61,
- POD_delay_param_1_double_precision = 62,
- POD_eq_enable = 63, /* firmware: 2.0 */
- POD_tap = 64,
- POD_volume_tweak_pedal_assign = 65,
- POD_band_5_frequency = 68, /* device: LINE6_BITS_BASSPODXTALL */ /* firmware: 2.0 */
- POD_tuner = 69,
- POD_mic_selection = 70,
- POD_cabinet_model = 71,
- POD_stomp_model = 75,
- POD_roomlevel = 76,
- POD_band_4_frequency = 77, /* device: LINE6_BITS_PODXTALL */ /* firmware: 2.0 */
- POD_band_6_frequency = 77, /* device: LINE6_BITS_BASSPODXTALL */ /* firmware: 2.0 */
- POD_stomp_param_1_note_value = 78,
- POD_stomp_param_2 = 79,
- POD_stomp_param_3 = 80,
- POD_stomp_param_4 = 81,
- POD_stomp_param_5 = 82,
- POD_stomp_param_6 = 83,
- POD_amp_switch_select = 84, /* device: LINE6_BITS_LIVE */
- POD_delay_param_4 = 85,
- POD_delay_param_5 = 86,
- POD_delay_pre_post = 87,
- POD_delay_model = 88, /* device: LINE6_BITS_PODXTALL */
- POD_delay_verb_model = 88, /* device: LINE6_BITS_BASSPODXTALL */
- POD_tempo_msb = 89,
- POD_tempo_lsb = 90,
- POD_wah_model = 91, /* firmware: 3.0 */
- POD_bypass_volume = 105, /* firmware: 2.14 */
- POD_fx_loop_on_off = 107, /* device: LINE6_BITS_PRO */
- POD_tweak_param_select = 108,
- POD_amp1_engage = 111,
- POD_band_1_gain = 114, /* firmware: 2.0 */
- POD_band_2_gain__bass = 115, /* device: LINE6_BITS_BASSPODXTALL */ /* firmware: 2.0 */
- POD_band_2_gain = 116, /* device: LINE6_BITS_PODXTALL */ /* firmware: 2.0 */
- POD_band_3_gain__bass = 116, /* device: LINE6_BITS_BASSPODXTALL */ /* firmware: 2.0 */
- POD_band_3_gain = 117, /* device: LINE6_BITS_PODXTALL */ /* firmware: 2.0 */
- POD_band_4_gain__bass = 117, /* device: LINE6_BITS_BASSPODXTALL */ /* firmware: 2.0 */
- POD_band_5_gain__bass = 118, /* device: LINE6_BITS_BASSPODXTALL */ /* firmware: 2.0 */
- POD_band_4_gain = 119, /* device: LINE6_BITS_PODXTALL */ /* firmware: 2.0 */
- POD_band_6_gain__bass = 119 /* device: LINE6_BITS_BASSPODXTALL */ /* firmware: 2.0 */
-};
-
-/**
- List of Variax workbench controls (dump).
-*/
-enum {
- VARIAX_body = 3,
- VARIAX_pickup1_enable = 4, /* 0: enabled, 1: disabled */
- VARIAX_pickup1_type = 8,
- VARIAX_pickup1_position = 9, /* type: 24 bit float */
- VARIAX_pickup1_angle = 12, /* type: 24 bit float */
- VARIAX_pickup1_level = 15, /* type: 24 bit float */
- VARIAX_pickup2_enable = 18, /* 0: enabled, 1: disabled */
- VARIAX_pickup2_type = 22,
- VARIAX_pickup2_position = 23, /* type: 24 bit float */
- VARIAX_pickup2_angle = 26, /* type: 24 bit float */
- VARIAX_pickup2_level = 29, /* type: 24 bit float */
- VARIAX_pickup_phase = 32, /* 0: in phase, 1: out of phase */
- VARIAX_capacitance = 33, /* type: 24 bit float */
- VARIAX_tone_resistance = 36, /* type: 24 bit float */
- VARIAX_volume_resistance = 39, /* type: 24 bit float */
- VARIAX_taper = 42, /* 0: Linear, 1: Audio */
- VARIAX_tone_dump = 43, /* type: 24 bit float */
- VARIAX_save_tone = 46,
- VARIAX_volume_dump = 47, /* type: 24 bit float */
- VARIAX_tuning_enable = 50,
- VARIAX_tuning6 = 51,
- VARIAX_tuning5 = 52,
- VARIAX_tuning4 = 53,
- VARIAX_tuning3 = 54,
- VARIAX_tuning2 = 55,
- VARIAX_tuning1 = 56,
- VARIAX_detune6 = 57, /* type: 24 bit float */
- VARIAX_detune5 = 60, /* type: 24 bit float */
- VARIAX_detune4 = 63, /* type: 24 bit float */
- VARIAX_detune3 = 66, /* type: 24 bit float */
- VARIAX_detune2 = 69, /* type: 24 bit float */
- VARIAX_detune1 = 72, /* type: 24 bit float */
- VARIAX_mix6 = 75, /* type: 24 bit float */
- VARIAX_mix5 = 78, /* type: 24 bit float */
- VARIAX_mix4 = 81, /* type: 24 bit float */
- VARIAX_mix3 = 84, /* type: 24 bit float */
- VARIAX_mix2 = 87, /* type: 24 bit float */
- VARIAX_mix1 = 90, /* type: 24 bit float */
- VARIAX_pickup_wiring = 96 /* 0: parallel, 1: series */
-};
-
-/**
- List of Variax workbench controls (MIDI).
-*/
-enum {
- VARIAXMIDI_volume = 7,
- VARIAXMIDI_tone = 79,
-};
-
-
-extern int pod_create_files(int firmware, int type, struct device *dev);
-extern void pod_remove_files(int firmware, int type, struct device *dev);
-extern int variax_create_files(int firmware, int type, struct device *dev);
-extern void variax_remove_files(int firmware, int type, struct device *dev);
-
-
-#endif
diff --git a/drivers/staging/line6/driver.c b/drivers/staging/line6/driver.c
index f188ecee502..ef511c76a6e 100644
--- a/drivers/staging/line6/driver.c
+++ b/drivers/staging/line6/driver.c
@@ -1,7 +1,7 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -9,75 +9,97 @@
*
*/
-#include "driver.h"
-
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/slab.h>
#include <linux/usb.h>
#include "audio.h"
#include "capture.h"
-#include "control.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.8.0"
-
+#define DRIVER_VERSION "0.9.1beta" DRIVER_REVISION
/* table of devices that work with this driver */
-static struct usb_device_id line6_id_table[] = {
- { USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXT) },
- { USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXTLIVE) },
- { USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXTPRO) },
- { USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_GUITARPORT) },
- { USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_POCKETPOD) },
- { USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODX3) },
- { USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODX3LIVE) },
- { USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXT) },
- { USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXTLIVE) },
- { USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXTPRO) },
- { USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_GX) },
- { USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_UX1) },
- { USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_UX2) },
- { USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_VARIAX) },
- { },
+static const struct usb_device_id line6_id_table[] = {
+ {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXT)},
+ {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXTLIVE)},
+ {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_BASSPODXTPRO)},
+ {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_GUITARPORT)},
+ {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_POCKETPOD)},
+ {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD300)},
+ {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD400)},
+ {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODHD500)},
+ {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_GX)},
+ {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_UX1)},
+ {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODSTUDIO_UX2)},
+ {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODX3)},
+ {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODX3LIVE)},
+ {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXT)},
+ {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXTLIVE)},
+ {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_PODXTPRO)},
+ {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_GX)},
+ {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_UX1)},
+ {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_TONEPORT_UX2)},
+ {USB_DEVICE(LINE6_VENDOR_ID, LINE6_DEVID_VARIAX)},
+ {},
};
+
MODULE_DEVICE_TABLE(usb, line6_id_table);
-static struct line6_properties line6_properties_table[] = {
- { "BassPODxt", LINE6_BIT_BASSPODXT, LINE6_BIT_CONTROL_PCM },
- { "BassPODxt Live", LINE6_BIT_BASSPODXTLIVE, LINE6_BIT_CONTROL_PCM },
- { "BassPODxt Pro", LINE6_BIT_BASSPODXTPRO, LINE6_BIT_CONTROL_PCM },
- { "GuitarPort", LINE6_BIT_GUITARPORT, LINE6_BIT_PCM },
- { "Pocket POD", LINE6_BIT_POCKETPOD, LINE6_BIT_CONTROL_PCM },
- { "POD X3", LINE6_BIT_PODX3, LINE6_BIT_PCM },
- { "POD X3 Live", LINE6_BIT_PODX3LIVE, LINE6_BIT_PCM },
- { "PODxt", LINE6_BIT_PODXT, LINE6_BIT_CONTROL_PCM },
- { "PODxt Live", LINE6_BIT_PODXTLIVE, LINE6_BIT_CONTROL_PCM },
- { "PODxt Pro", LINE6_BIT_PODXTPRO, LINE6_BIT_CONTROL_PCM },
- { "TonePort GX", LINE6_BIT_TONEPORT_GX, LINE6_BIT_PCM },
- { "TonePort UX1", LINE6_BIT_TONEPORT_UX1, LINE6_BIT_PCM },
- { "TonePort UX2", LINE6_BIT_TONEPORT_UX2, LINE6_BIT_PCM },
- { "Variax Workbench", LINE6_BIT_VARIAX, LINE6_BIT_CONTROL }
+#define L6PROP(dev_bit, dev_id, dev_name, dev_cap)\
+ {.device_bit = LINE6_BIT_##dev_bit, .id = dev_id,\
+ .name = dev_name, .capabilities = LINE6_BIT_##dev_cap}
+
+/* *INDENT-OFF* */
+static const struct line6_properties line6_properties_table[] = {
+ L6PROP(BASSPODXT, "BassPODxt", "BassPODxt", CTRL_PCM_HW),
+ L6PROP(BASSPODXTLIVE, "BassPODxtLive", "BassPODxt Live", CTRL_PCM_HW),
+ L6PROP(BASSPODXTPRO, "BassPODxtPro", "BassPODxt Pro", CTRL_PCM_HW),
+ L6PROP(GUITARPORT, "GuitarPort", "GuitarPort", PCM),
+ L6PROP(POCKETPOD, "PocketPOD", "Pocket POD", CONTROL),
+ L6PROP(PODHD300, "PODHD300", "POD HD300", CTRL_PCM_HW),
+ L6PROP(PODHD400, "PODHD400", "POD HD400", CTRL_PCM_HW),
+ L6PROP(PODHD500, "PODHD500", "POD HD500", CTRL_PCM_HW),
+ L6PROP(PODSTUDIO_GX, "PODStudioGX", "POD Studio GX", PCM),
+ L6PROP(PODSTUDIO_UX1, "PODStudioUX1", "POD Studio UX1", PCM),
+ L6PROP(PODSTUDIO_UX2, "PODStudioUX2", "POD Studio UX2", PCM),
+ L6PROP(PODX3, "PODX3", "POD X3", PCM),
+ L6PROP(PODX3LIVE, "PODX3Live", "POD X3 Live", PCM),
+ L6PROP(PODXT, "PODxt", "PODxt", CTRL_PCM_HW),
+ L6PROP(PODXTLIVE, "PODxtLive", "PODxt Live", CTRL_PCM_HW),
+ L6PROP(PODXTPRO, "PODxtPro", "PODxt Pro", CTRL_PCM_HW),
+ L6PROP(TONEPORT_GX, "TonePortGX", "TonePort GX", PCM),
+ L6PROP(TONEPORT_UX1, "TonePortUX1", "TonePort UX1", PCM),
+ L6PROP(TONEPORT_UX2, "TonePortUX2", "TonePort UX2", PCM),
+ L6PROP(VARIAX, "Variax", "Variax Workbench", CONTROL),
};
-
+/* *INDENT-ON* */
/*
This is Line6's MIDI manufacturer ID.
*/
-const unsigned char line6_midi_id[] = { 0x00, 0x01, 0x0c };
-
-struct usb_line6 *line6_devices[LINE6_MAX_DEVICES];
-struct workqueue_struct *line6_workqueue;
+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.
@@ -89,7 +111,6 @@ struct message {
int done;
};
-
/*
Forward declarations.
*/
@@ -97,75 +118,29 @@ 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->ep_control_read),
line6->buffer_listen, LINE6_BUFSIZE_LISTEN,
line6_data_received, line6, line6->interval);
line6->urb_listen->actual_length = 0;
- return usb_submit_urb(line6->urb_listen, GFP_KERNEL);
-}
-
-#if DO_DUMP_ANY
-/*
- Write hexdump to syslog.
-*/
-void line6_write_hexdump(struct usb_line6 *line6, char dir,
- const unsigned char *buffer, int size)
-{
- static const int BYTES_PER_LINE = 8;
- char hexdump[100];
- char asc[BYTES_PER_LINE + 1];
- int i, j;
-
- for (i = 0; i < size; i += BYTES_PER_LINE) {
- int hexdumpsize = sizeof(hexdump);
- char *p = hexdump;
- int n = min(size - i, BYTES_PER_LINE);
- asc[n] = 0;
-
- for (j = 0; j < BYTES_PER_LINE; ++j) {
- int bytes;
-
- if (j < n) {
- unsigned char val = buffer[i + j];
- bytes = snprintf(p, hexdumpsize, " %02X", val);
- asc[j] = ((val >= 0x20) && (val < 0x7f)) ? val : '.';
- } else
- bytes = snprintf(p, hexdumpsize, " ");
-
- if (bytes > hexdumpsize)
- break; /* buffer overflow */
-
- p += bytes;
- hexdumpsize -= bytes;
- }
-
- dev_info(line6->ifcdev, "%c%04X:%s %s\n", dir, i, hexdump, asc);
- }
+ err = usb_submit_urb(line6->urb_listen, GFP_ATOMIC);
+ return err;
}
-#endif
-#if DO_DUMP_URB_RECEIVE
/*
- Dump URB data to syslog.
+ Stop listening on endpoint.
*/
-static void line6_dump_urb(struct urb *urb)
+static void line6_stop_listen(struct usb_line6 *line6)
{
- struct usb_line6 *line6 = (struct usb_line6 *)urb->context;
-
- if (urb->status < 0)
- return;
-
- line6_write_hexdump(line6, 'R', (unsigned char *)urb->transfer_buffer,
- urb->actual_length);
+ usb_kill_urb(line6->urb_listen);
}
-#endif
/*
Send raw message in pieces of wMaxPacketSize bytes.
@@ -175,10 +150,6 @@ int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
{
int i, done = 0;
-#if DO_DUMP_URB_SEND
- line6_write_hexdump(line6, 'S', buffer, size);
-#endif
-
for (i = 0; i < size; i += line6->max_packet_size) {
int partial;
const char *frag_buf = buffer + i;
@@ -186,10 +157,10 @@ int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
int retval;
retval = usb_interrupt_msg(line6->usbdev,
- usb_sndintpipe(line6->usbdev,
- line6->ep_control_write),
- (char *)frag_buf, frag_size,
- &partial, LINE6_TIMEOUT * HZ);
+ usb_sndintpipe(line6->usbdev,
+ line6->ep_control_write),
+ (char *)frag_buf, frag_size,
+ &partial, LINE6_TIMEOUT * HZ);
if (retval) {
dev_err(line6->ifcdev,
@@ -233,10 +204,6 @@ static int line6_send_raw_message_async_part(struct message *msg,
(char *)msg->buffer + done, bytes,
line6_async_request_sent, msg, line6->interval);
-#if DO_DUMP_URB_SEND
- line6_write_hexdump(line6, 'S', (char *)msg->buffer + done, bytes);
-#endif
-
msg->done += bytes;
retval = usb_submit_urb(urb, GFP_ATOMIC);
@@ -245,13 +212,24 @@ static int line6_send_raw_message_async_part(struct message *msg,
__func__, retval);
usb_free_urb(urb);
kfree(msg);
- return -EINVAL;
+ 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,
@@ -262,11 +240,8 @@ int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer,
/* create message: */
msg = kmalloc(sizeof(struct message), GFP_ATOMIC);
-
- if (msg == NULL) {
- dev_err(line6->ifcdev, "Out of memory\n");
+ if (msg == NULL)
return -ENOMEM;
- }
/* create URB: */
urb = usb_alloc_urb(0, GFP_ATOMIC);
@@ -288,12 +263,35 @@ int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer,
}
/*
+ 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;
+ return line6_send_raw_message(line6, buffer,
+ size + SYSEX_EXTRA_SIZE) -
+ SYSEX_EXTRA_SIZE;
}
/*
@@ -304,12 +302,10 @@ int line6_send_sysex_message(struct usb_line6 *line6, const char *buffer,
char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2,
int size)
{
- char *buffer = kmalloc(size + SYSEX_EXTRA_SIZE, GFP_KERNEL);
+ char *buffer = kmalloc(size + SYSEX_EXTRA_SIZE, GFP_ATOMIC);
- if (!buffer) {
- dev_err(line6->ifcdev, "out of memory\n");
+ if (!buffer)
return NULL;
- }
buffer[0] = LINE6_SYSEX_BEGIN;
memcpy(buffer + 1, line6_midi_id, sizeof(line6_midi_id));
@@ -325,66 +321,71 @@ char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2,
static void line6_data_received(struct urb *urb)
{
struct usb_line6 *line6 = (struct usb_line6 *)urb->context;
- struct MidiBuffer *mb = &line6->line6midi->midibuf_in;
+ struct midi_buffer *mb = &line6->line6midi->midibuf_in;
int done;
if (urb->status == -ESHUTDOWN)
return;
-#if DO_DUMP_URB_RECEIVE
- line6_dump_urb(urb);
-#endif
-
- done = midibuf_write(mb, urb->transfer_buffer, urb->actual_length);
+ done =
+ line6_midibuf_write(mb, urb->transfer_buffer, urb->actual_length);
if (done < urb->actual_length) {
- midibuf_ignore(mb, done);
- DEBUG_MESSAGES(dev_err(line6->ifcdev, "%d %d buffer overflow - message skipped\n", 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 = midibuf_read(mb, line6->buffer_message, LINE6_MESSAGE_MAXLEN);
+ done =
+ line6_midibuf_read(mb, line6->buffer_message,
+ LINE6_MESSAGE_MAXLEN);
if (done == 0)
break;
- /* MIDI input filter */
- if (midibuf_skip_message(mb, line6->line6midi->midi_mask_receive))
- continue;
-
line6->message_length = done;
-#if DO_DUMP_MIDI_RECEIVE
- line6_write_hexdump(line6, 'r', line6->buffer_message, done);
-#endif
line6_midi_receive(line6, line6->buffer_message, done);
- switch (line6->usbdev->descriptor.idProduct) {
+ switch (le16_to_cpu(line6->usbdev->descriptor.idProduct)) {
case LINE6_DEVID_BASSPODXT:
case LINE6_DEVID_BASSPODXTLIVE:
case LINE6_DEVID_BASSPODXTPRO:
case LINE6_DEVID_PODXT:
case LINE6_DEVID_PODXTPRO:
case LINE6_DEVID_POCKETPOD:
- pod_process_message((struct usb_line6_pod *)line6);
+ line6_pod_process_message((struct usb_line6_pod *)
+ line6);
break;
+ case LINE6_DEVID_PODHD300:
+ case LINE6_DEVID_PODHD400:
+ case LINE6_DEVID_PODHD500:
+ break; /* let userspace handle MIDI */
+
case LINE6_DEVID_PODXTLIVE:
switch (line6->interface_number) {
case PODXTLIVE_INTERFACE_POD:
- pod_process_message((struct usb_line6_pod *)line6);
+ line6_pod_process_message((struct usb_line6_pod
+ *)line6);
break;
case PODXTLIVE_INTERFACE_VARIAX:
- variax_process_message((struct usb_line6_variax *)line6);
+ line6_variax_process_message((struct
+ usb_line6_variax
+ *)line6);
break;
default:
- dev_err(line6->ifcdev, "PODxt Live interface %d not supported\n", line6->interface_number);
+ dev_err(line6->ifcdev,
+ "PODxt Live interface %d not supported\n",
+ line6->interface_number);
}
break;
case LINE6_DEVID_VARIAX:
- variax_process_message((struct usb_line6_variax *)line6);
+ line6_variax_process_message((struct usb_line6_variax *)
+ line6);
break;
default:
@@ -398,33 +399,27 @@ static void line6_data_received(struct urb *urb)
/*
Send channel number (i.e., switch to a different sound).
*/
-int line6_send_program(struct usb_line6 *line6, int value)
+int line6_send_program(struct usb_line6 *line6, u8 value)
{
int retval;
unsigned char *buffer;
- unsigned int partial;
+ int partial;
buffer = kmalloc(2, GFP_KERNEL);
-
- if (!buffer) {
- dev_err(line6->ifcdev, "out of memory\n");
+ if (!buffer)
return -ENOMEM;
- }
buffer[0] = LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST;
buffer[1] = value;
-#if DO_DUMP_URB_SEND
- line6_write_hexdump(line6, 'S', buffer, 2);
-#endif
-
retval = usb_interrupt_msg(line6->usbdev,
usb_sndintpipe(line6->usbdev,
line6->ep_control_write),
buffer, 2, &partial, LINE6_TIMEOUT * HZ);
if (retval)
- dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n", retval);
+ dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n",
+ retval);
kfree(buffer);
return retval;
@@ -433,33 +428,28 @@ int line6_send_program(struct usb_line6 *line6, int value)
/*
Transmit Line6 control parameter.
*/
-int line6_transmit_parameter(struct usb_line6 *line6, int param, int value)
+int line6_transmit_parameter(struct usb_line6 *line6, int param, u8 value)
{
int retval;
unsigned char *buffer;
- unsigned int partial;
+ int partial;
buffer = kmalloc(3, GFP_KERNEL);
-
- if (!buffer) {
- dev_err(line6->ifcdev, "out of memory\n");
+ if (!buffer)
return -ENOMEM;
- }
buffer[0] = LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST;
buffer[1] = param;
buffer[2] = value;
-#if DO_DUMP_URB_SEND
- line6_write_hexdump(line6, 'S', buffer, 3);
-#endif
-
retval = usb_interrupt_msg(line6->usbdev,
- usb_sndintpipe(line6->usbdev, line6->ep_control_write),
- buffer, 3, &partial, LINE6_TIMEOUT * HZ);
+ usb_sndintpipe(line6->usbdev,
+ line6->ep_control_write),
+ buffer, 3, &partial, LINE6_TIMEOUT * HZ);
if (retval)
- dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n", retval);
+ dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n",
+ retval);
kfree(buffer);
return retval;
@@ -468,7 +458,8 @@ int line6_transmit_parameter(struct usb_line6 *line6, int param, int value)
/*
Read data from device.
*/
-int line6_read_data(struct usb_line6 *line6, int address, void *data, size_t datalen)
+int line6_read_data(struct usb_line6 *line6, int address, void *data,
+ size_t datalen)
{
struct usb_device *usbdev = line6->usbdev;
int ret;
@@ -476,15 +467,16 @@ int line6_read_data(struct usb_line6 *line6, int address, void *data, size_t dat
/* 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);
+ 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 a couple of 0xff until length arrives. */
+ /* 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 |
@@ -496,9 +488,7 @@ int line6_read_data(struct usb_line6 *line6, int address, void *data, size_t dat
"receive length failed (error %d)\n", ret);
return ret;
}
- }
- while (len == 0xff)
- ;
+ } while (len == 0xff);
if (len != datalen) {
/* should be equal or something went wrong */
@@ -556,9 +546,7 @@ int line6_write_data(struct usb_line6 *line6, int address, void *data,
"receiving status failed (error %d)\n", ret);
return ret;
}
- }
- while (status == 0xff)
- ;
+ } while (status == 0xff);
if (status != 0) {
dev_err(line6->ifcdev, "write failed (error %d)\n", ret);
@@ -574,7 +562,8 @@ int line6_write_data(struct usb_line6 *line6, int address, void *data,
*/
int line6_read_serial_number(struct usb_line6 *line6, int *serial_number)
{
- return line6_read_data(line6, 0x80d0, serial_number, sizeof(*serial_number));
+ return line6_read_data(line6, 0x80d0, serial_number,
+ sizeof(*serial_number));
}
/*
@@ -587,29 +576,6 @@ ssize_t line6_nop_read(struct device *dev, struct device_attribute *attr,
}
/*
- No operation (i.e., unsupported).
-*/
-ssize_t line6_nop_write(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- return count;
-}
-
-/*
- "write" request on "raw" special file.
-*/
-#if CREATE_RAW_FILE
-ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6 *line6 = usb_get_intfdata(interface);
- line6_send_raw_message(line6, buf, count);
- return count;
-}
-#endif
-
-/*
Generic destructor.
*/
static void line6_destruct(struct usb_interface *interface)
@@ -636,31 +602,16 @@ static void line6_destruct(struct usb_interface *interface)
kfree(line6);
}
-static void line6_list_devices(void)
-{
- int i;
-
- for (i = 0; i < LINE6_MAX_DEVICES; ++i) {
- struct usb_line6 *dev = line6_devices[i];
- printk(KERN_INFO "Line6 device %d: ", i);
-
- if (dev == NULL)
- printk("(not used)\n");
- else
- printk("%s:%d\n", dev->properties->name, dev->interface_number);
- }
-}
-
/*
Probe USB device.
*/
-static int line6_probe(struct usb_interface *interface, const struct usb_device_id *id)
+static int line6_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
{
int devtype;
- struct usb_device *usbdev = NULL;
- struct usb_line6 *line6 = NULL;
+ struct usb_device *usbdev;
+ struct usb_line6 *line6;
const struct line6_properties *properties;
- int devnum;
int interface_number, alternate = 0;
int product;
int size = 0;
@@ -673,30 +624,26 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_
if (usbdev == NULL)
return -ENODEV;
- /* increment reference counters: */
- usb_get_intf(interface);
- usb_get_dev(usbdev);
-
/* we don't handle multiple configurations */
- if (usbdev->descriptor.bNumConfigurations != 1)
- return -ENODEV;
+ if (usbdev->descriptor.bNumConfigurations != 1) {
+ ret = -ENODEV;
+ goto err_put;
+ }
/* check vendor and product id */
- for (devtype = ARRAY_SIZE(line6_id_table) - 1; devtype--;)
- if ((le16_to_cpu(usbdev->descriptor.idVendor) == line6_id_table[devtype].idVendor) &&
- (le16_to_cpu(usbdev->descriptor.idProduct) == line6_id_table[devtype].idProduct))
- break;
+ for (devtype = ARRAY_SIZE(line6_id_table) - 1; devtype--;) {
+ u16 idVendor = le16_to_cpu(usbdev->descriptor.idVendor);
+ u16 idProduct = le16_to_cpu(usbdev->descriptor.idProduct);
- if (devtype < 0)
- return -ENODEV;
-
- /* find free slot in device table: */
- for (devnum = 0; devnum < LINE6_MAX_DEVICES; ++devnum)
- if (line6_devices[devnum] == NULL)
+ if (idVendor == line6_id_table[devtype].idVendor &&
+ idProduct == line6_id_table[devtype].idProduct)
break;
+ }
- if (devnum == LINE6_MAX_DEVICES)
- return -ENODEV;
+ if (devtype < 0) {
+ ret = -ENODEV;
+ goto err_put;
+ }
/* initialize device info: */
properties = &line6_properties_table[devtype];
@@ -708,12 +655,24 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_
switch (product) {
case LINE6_DEVID_BASSPODXTLIVE:
- case LINE6_DEVID_POCKETPOD:
case LINE6_DEVID_PODXTLIVE:
case LINE6_DEVID_VARIAX:
alternate = 1;
break;
+ case LINE6_DEVID_POCKETPOD:
+ switch (interface_number) {
+ case 0:
+ return 0; /* this interface has no endpoints */
+ case 1:
+ alternate = 0;
+ break;
+ default:
+ MISSING_CASE;
+ }
+ break;
+
+ case LINE6_DEVID_PODHD500:
case LINE6_DEVID_PODX3:
case LINE6_DEVID_PODX3LIVE:
switch (interface_number) {
@@ -732,24 +691,32 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_
case LINE6_DEVID_BASSPODXTPRO:
case LINE6_DEVID_PODXT:
case LINE6_DEVID_PODXTPRO:
+ case LINE6_DEVID_PODHD300:
+ case LINE6_DEVID_PODHD400:
alternate = 5;
break;
- case LINE6_DEVID_TONEPORT_GX:
case LINE6_DEVID_GUITARPORT:
- alternate = 2; /* 1..4 seem to be ok */
+ case LINE6_DEVID_PODSTUDIO_GX:
+ case LINE6_DEVID_PODSTUDIO_UX1:
+ case LINE6_DEVID_TONEPORT_GX:
+ case LINE6_DEVID_TONEPORT_UX1:
+ alternate = 2; /* 1..4 seem to be ok */
break;
- case LINE6_DEVID_TONEPORT_UX1:
case LINE6_DEVID_TONEPORT_UX2:
+ case LINE6_DEVID_PODSTUDIO_UX2:
switch (interface_number) {
case 0:
/* defaults to 44.1kHz, 16-bit */
alternate = 2;
break;
case 1:
- alternate = 0;
- break;
+ /* don't know yet what this is ...
+ alternate = 1;
+ break;
+ */
+ return -ENODEV;
default:
MISSING_CASE;
}
@@ -757,13 +724,14 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_
default:
MISSING_CASE;
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_put;
}
ret = usb_set_interface(usbdev, interface_number, alternate);
if (ret < 0) {
dev_err(&interface->dev, "set_interface failed\n");
- return ret;
+ goto err_put;
}
/* initialize device data based on product id: */
@@ -771,22 +739,43 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_
case LINE6_DEVID_BASSPODXT:
case LINE6_DEVID_BASSPODXTLIVE:
case LINE6_DEVID_BASSPODXTPRO:
- case LINE6_DEVID_POCKETPOD:
case LINE6_DEVID_PODXT:
case LINE6_DEVID_PODXTPRO:
size = sizeof(struct usb_line6_pod);
- ep_read = 0x84;
+ ep_read = 0x84;
+ ep_write = 0x03;
+ break;
+
+ case LINE6_DEVID_PODHD300:
+ case LINE6_DEVID_PODHD400:
+ size = sizeof(struct usb_line6_podhd);
+ ep_read = 0x84;
ep_write = 0x03;
break;
+ case LINE6_DEVID_PODHD500:
+ size = sizeof(struct usb_line6_podhd);
+ ep_read = 0x81;
+ ep_write = 0x01;
+ break;
+
+ case LINE6_DEVID_POCKETPOD:
+ size = sizeof(struct usb_line6_pod);
+ ep_read = 0x82;
+ ep_write = 0x02;
+ break;
+
case LINE6_DEVID_PODX3:
case LINE6_DEVID_PODX3LIVE:
/* currently unused! */
size = sizeof(struct usb_line6_pod);
- ep_read = 0x81;
+ ep_read = 0x81;
ep_write = 0x01;
break;
+ case LINE6_DEVID_PODSTUDIO_GX:
+ case LINE6_DEVID_PODSTUDIO_UX1:
+ case LINE6_DEVID_PODSTUDIO_UX2:
case LINE6_DEVID_TONEPORT_GX:
case LINE6_DEVID_TONEPORT_UX1:
case LINE6_DEVID_TONEPORT_UX2:
@@ -799,42 +788,45 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_
switch (interface_number) {
case PODXTLIVE_INTERFACE_POD:
size = sizeof(struct usb_line6_pod);
- ep_read = 0x84;
+ ep_read = 0x84;
ep_write = 0x03;
break;
case PODXTLIVE_INTERFACE_VARIAX:
size = sizeof(struct usb_line6_variax);
- ep_read = 0x86;
+ ep_read = 0x86;
ep_write = 0x05;
break;
default:
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_put;
}
break;
case LINE6_DEVID_VARIAX:
size = sizeof(struct usb_line6_variax);
- ep_read = 0x82;
+ ep_read = 0x82;
ep_write = 0x01;
break;
default:
MISSING_CASE;
- return -ENODEV;
+ ret = -ENODEV;
+ goto err_put;
}
if (size == 0) {
- dev_err(line6->ifcdev, "driver bug: interface data size not set\n");
- return -ENODEV;
+ 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) {
- dev_err(&interface->dev, "Out of memory\n");
- return -ENOMEM;
+ ret = -ENODEV;
+ goto err_put;
}
/* store basic data: */
@@ -849,16 +841,19 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_
/* get data from endpoint descriptor (see usb_maxpacket): */
{
struct usb_host_endpoint *ep;
- unsigned epnum = usb_pipeendpoint(usb_rcvintpipe(usbdev, ep_read));
+ unsigned epnum =
+ usb_pipeendpoint(usb_rcvintpipe(usbdev, ep_read));
ep = usbdev->ep_in[epnum];
if (ep != NULL) {
line6->interval = ep->desc.bInterval;
- line6->max_packet_size = le16_to_cpu(ep->desc.wMaxPacketSize);
+ 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");
+ dev_err(line6->ifcdev,
+ "endpoint not available, using fallback values");
}
}
@@ -866,20 +861,18 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_
if (properties->capabilities & LINE6_BIT_CONTROL) {
/* initialize USB buffers: */
- line6->buffer_listen = kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL);
-
+ line6->buffer_listen =
+ kmalloc(LINE6_BUFSIZE_LISTEN, GFP_KERNEL);
if (line6->buffer_listen == NULL) {
- dev_err(&interface->dev, "Out of memory\n");
- line6_destruct(interface);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_destruct;
}
- line6->buffer_message = kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL);
-
+ line6->buffer_message =
+ kmalloc(LINE6_MESSAGE_MAXLEN, GFP_KERNEL);
if (line6->buffer_message == NULL) {
- dev_err(&interface->dev, "Out of memory\n");
- line6_destruct(interface);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_destruct;
}
line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL);
@@ -887,15 +880,15 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_
if (line6->urb_listen == NULL) {
dev_err(&interface->dev, "Out of memory\n");
line6_destruct(interface);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_destruct;
}
ret = line6_start_listen(line6);
if (ret < 0) {
dev_err(&interface->dev, "%s: usb_submit_urb failed\n",
__func__);
- line6_destruct(interface);
- return ret;
+ goto err_destruct;
}
}
@@ -909,17 +902,28 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_
case LINE6_DEVID_PODX3LIVE:
case LINE6_DEVID_PODXT:
case LINE6_DEVID_PODXTPRO:
- ret = pod_init(interface, (struct usb_line6_pod *)line6);
+ ret = line6_pod_init(interface, (struct usb_line6_pod *)line6);
+ break;
+
+ case LINE6_DEVID_PODHD300:
+ case LINE6_DEVID_PODHD400:
+ case LINE6_DEVID_PODHD500:
+ ret = line6_podhd_init(interface,
+ (struct usb_line6_podhd *)line6);
break;
case LINE6_DEVID_PODXTLIVE:
switch (interface_number) {
case PODXTLIVE_INTERFACE_POD:
- ret = pod_init(interface, (struct usb_line6_pod *)line6);
+ ret =
+ line6_pod_init(interface,
+ (struct usb_line6_pod *)line6);
break;
case PODXTLIVE_INTERFACE_VARIAX:
- ret = variax_init(interface, (struct usb_line6_variax *)line6);
+ ret =
+ line6_variax_init(interface,
+ (struct usb_line6_variax *)line6);
break;
default:
@@ -932,14 +936,21 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_
break;
case LINE6_DEVID_VARIAX:
- ret = variax_init(interface, (struct usb_line6_variax *)line6);
+ ret =
+ line6_variax_init(interface,
+ (struct usb_line6_variax *)line6);
break;
+ case LINE6_DEVID_PODSTUDIO_GX:
+ case LINE6_DEVID_PODSTUDIO_UX1:
+ case LINE6_DEVID_PODSTUDIO_UX2:
case LINE6_DEVID_TONEPORT_GX:
case LINE6_DEVID_TONEPORT_UX1:
case LINE6_DEVID_TONEPORT_UX2:
case LINE6_DEVID_GUITARPORT:
- ret = toneport_init(interface, (struct usb_line6_toneport *)line6);
+ ret =
+ line6_toneport_init(interface,
+ (struct usb_line6_toneport *)line6);
break;
default:
@@ -947,22 +958,36 @@ static int line6_probe(struct usb_interface *interface, const struct usb_device_
ret = -ENODEV;
}
- if (ret < 0) {
- line6_destruct(interface);
- return ret;
- }
+ if (ret < 0)
+ goto err_destruct;
ret = sysfs_create_link(&interface->dev.kobj, &usbdev->dev.kobj,
"usb_device");
- if (ret < 0) {
- line6_destruct(interface);
- return ret;
- }
+ 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);
- line6_devices[devnum] = line6;
- line6_list_devices();
+
+ switch (product) {
+ case LINE6_DEVID_PODX3:
+ case LINE6_DEVID_PODX3LIVE:
+ dev_info(&interface->dev,
+ "NOTE: the Line6 %s is detected, but not yet supported\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;
}
@@ -973,7 +998,7 @@ static void line6_disconnect(struct usb_interface *interface)
{
struct usb_line6 *line6;
struct usb_device *usbdev;
- int interface_number, i;
+ int interface_number;
if (interface == NULL)
return;
@@ -981,6 +1006,8 @@ static void line6_disconnect(struct usb_interface *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;
@@ -988,13 +1015,13 @@ static void line6_disconnect(struct usb_interface *interface)
if (line6 != NULL) {
if (line6->urb_listen != NULL)
- usb_kill_urb(line6->urb_listen);
+ line6_stop_listen(line6);
if (usbdev != line6->usbdev)
dev_err(line6->ifcdev,
"driver bug: inconsistent usb device\n");
- switch (line6->usbdev->descriptor.idProduct) {
+ switch (le16_to_cpu(line6->usbdev->descriptor.idProduct)) {
case LINE6_DEVID_BASSPODXT:
case LINE6_DEVID_BASSPODXTLIVE:
case LINE6_DEVID_BASSPODXTPRO:
@@ -1003,42 +1030,48 @@ static void line6_disconnect(struct usb_interface *interface)
case LINE6_DEVID_PODX3LIVE:
case LINE6_DEVID_PODXT:
case LINE6_DEVID_PODXTPRO:
- pod_disconnect(interface);
+ line6_pod_disconnect(interface);
+ break;
+
+ case LINE6_DEVID_PODHD300:
+ case LINE6_DEVID_PODHD400:
+ case LINE6_DEVID_PODHD500:
+ line6_podhd_disconnect(interface);
break;
case LINE6_DEVID_PODXTLIVE:
switch (interface_number) {
case PODXTLIVE_INTERFACE_POD:
- pod_disconnect(interface);
+ line6_pod_disconnect(interface);
break;
case PODXTLIVE_INTERFACE_VARIAX:
- variax_disconnect(interface);
+ line6_variax_disconnect(interface);
break;
}
break;
case LINE6_DEVID_VARIAX:
- variax_disconnect(interface);
+ line6_variax_disconnect(interface);
break;
+ case LINE6_DEVID_PODSTUDIO_GX:
+ case LINE6_DEVID_PODSTUDIO_UX1:
+ case LINE6_DEVID_PODSTUDIO_UX2:
case LINE6_DEVID_TONEPORT_GX:
case LINE6_DEVID_TONEPORT_UX1:
case LINE6_DEVID_TONEPORT_UX2:
case LINE6_DEVID_GUITARPORT:
- toneport_disconnect(interface);
+ line6_toneport_disconnect(interface);
break;
default:
MISSING_CASE;
}
- dev_info(&interface->dev, "Line6 %s now disconnected\n", line6->properties->name);
-
- for (i = LINE6_MAX_DEVICES; i--;)
- if (line6_devices[i] == line6)
- line6_devices[i] = NULL;
+ dev_info(&interface->dev, "Line6 %s now disconnected\n",
+ line6->properties->name);
}
line6_destruct(interface);
@@ -1046,55 +1079,82 @@ static void line6_disconnect(struct usb_interface *interface)
/* decrement reference counters: */
usb_put_intf(interface);
usb_put_dev(usbdev);
-
- line6_list_devices();
}
-static struct usb_driver line6_driver = {
- .name = DRIVER_NAME,
- .probe = line6_probe,
- .disconnect = line6_disconnect,
- .id_table = line6_id_table,
-};
+#ifdef CONFIG_PM
/*
- Module initialization.
+ Suspend Line6 device.
*/
-static int __init line6_init(void)
+static int line6_suspend(struct usb_interface *interface, pm_message_t message)
{
- int i, retval;
+ struct usb_line6 *line6 = usb_get_intfdata(interface);
+ struct snd_line6_pcm *line6pcm = line6->line6pcm;
- printk(KERN_INFO "%s driver version %s%s\n",
- DRIVER_NAME, DRIVER_VERSION, DRIVER_REVISION);
- line6_workqueue = create_workqueue(DRIVER_NAME);
+ snd_power_change_state(line6->card, SNDRV_CTL_POWER_D3hot);
- if (line6_workqueue == NULL) {
- err("couldn't create workqueue");
- return -EINVAL;
+ if (line6->properties->capabilities & LINE6_BIT_CONTROL)
+ line6_stop_listen(line6);
+
+ if (line6pcm != NULL) {
+ snd_pcm_suspend_all(line6pcm->pcm);
+ line6_pcm_disconnect(line6pcm);
+ line6pcm->flags = 0;
}
- for (i = LINE6_MAX_DEVICES; i--;)
- line6_devices[i] = NULL;
+ return 0;
+}
- retval = usb_register(&line6_driver);
+/*
+ Resume Line6 device.
+*/
+static int line6_resume(struct usb_interface *interface)
+{
+ struct usb_line6 *line6 = usb_get_intfdata(interface);
- if (retval)
- err("usb_register failed. Error number %d", retval);
+ if (line6->properties->capabilities & LINE6_BIT_CONTROL)
+ line6_start_listen(line6);
- return retval;
+ snd_power_change_state(line6->card, SNDRV_CTL_POWER_D0);
+ return 0;
}
/*
- Module cleanup.
+ Resume Line6 device after reset.
*/
-static void __exit line6_exit(void)
+static int line6_reset_resume(struct usb_interface *interface)
{
- destroy_workqueue(line6_workqueue);
- usb_deregister(&line6_driver);
+ struct usb_line6 *line6 = usb_get_intfdata(interface);
+
+ switch (le16_to_cpu(line6->usbdev->descriptor.idProduct)) {
+ case LINE6_DEVID_PODSTUDIO_GX:
+ case LINE6_DEVID_PODSTUDIO_UX1:
+ case LINE6_DEVID_PODSTUDIO_UX2:
+ case LINE6_DEVID_TONEPORT_GX:
+ case LINE6_DEVID_TONEPORT_UX1:
+ case LINE6_DEVID_TONEPORT_UX2:
+ case LINE6_DEVID_GUITARPORT:
+ line6_toneport_reset_resume((struct usb_line6_toneport *)line6);
+ }
+
+ return line6_resume(interface);
}
-module_init(line6_init);
-module_exit(line6_exit);
+#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);
diff --git a/drivers/staging/line6/driver.h b/drivers/staging/line6/driver.h
index 9908bfa6afa..16e3fc2f1f1 100644
--- a/drivers/staging/line6/driver.h
+++ b/drivers/staging/line6/driver.h
@@ -1,7 +1,7 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -12,12 +12,8 @@
#ifndef DRIVER_H
#define DRIVER_H
-
-#include "config.h"
-
#include <linux/spinlock.h>
#include <linux/usb.h>
-#include <linux/wait.h>
#include <sound/core.h>
#include "midi.h"
@@ -25,11 +21,9 @@
#define DRIVER_NAME "line6usb"
#define LINE6_TIMEOUT 1
-#define LINE6_MAX_DEVICES 8
#define LINE6_BUFSIZE_LISTEN 32
#define LINE6_MESSAGE_MAXLEN 256
-
/*
Line6 MIDI control commands
*/
@@ -50,16 +44,14 @@
*/
#define LINE6_CHANNEL_DEVICE 0x02
-#define LINE6_CHANNEL_UNKNOWN 5 /* don't know yet what this is good for */
+#define LINE6_CHANNEL_UNKNOWN 5 /* don't know yet what this is good for */
#define LINE6_CHANNEL_MASK 0x0f
-
#define MISSING_CASE \
- printk(KERN_ERR "line6usb driver bug: missing case in %s:%d\n", \
+ pr_err("line6usb driver bug: missing case in %s:%d\n", \
__FILE__, __LINE__)
-
#define CHECK_RETURN(x) \
do { \
err = x; \
@@ -67,21 +59,43 @@ do { \
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];
-extern struct usb_line6 *line6_devices[LINE6_MAX_DEVICES];
-extern struct workqueue_struct *line6_workqueue;
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 {
- const char *name;
+ /**
+ Bit identifying this device in the line6usb driver.
+ */
int device_bit;
+
+ /**
+ 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;
};
@@ -172,19 +186,15 @@ struct usb_line6 {
int message_length;
};
-
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 ssize_t line6_nop_write(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count);
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, int value);
+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,
@@ -193,12 +203,13 @@ 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,
- int value);
+ 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);
-extern void line6_write_hexdump(struct usb_line6 *line6, char dir,
- const unsigned char *buffer, int size);
-
#endif
diff --git a/drivers/staging/line6/dumprequest.c b/drivers/staging/line6/dumprequest.c
deleted file mode 100644
index decbaa971b6..00000000000
--- a/drivers/staging/line6/dumprequest.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.8.0
- *
- * Copyright (C) 2004-2009 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 "driver.h"
-#include "dumprequest.h"
-
-
-/*
- Set "dump in progress" flag.
-*/
-void line6_dump_started(struct line6_dump_request *l6dr, int dest)
-{
- l6dr->in_progress = dest;
-}
-
-/*
- Invalidate current channel, i.e., set "dump in progress" flag.
- Reading from the "dump" special file blocks until dump is completed.
-*/
-void line6_invalidate_current(struct line6_dump_request *l6dr)
-{
- line6_dump_started(l6dr, LINE6_DUMP_CURRENT);
-}
-
-/*
- Clear "dump in progress" flag and notify waiting processes.
-*/
-void line6_dump_finished(struct line6_dump_request *l6dr)
-{
- l6dr->in_progress = LINE6_DUMP_NONE;
- wake_up_interruptible(&l6dr->wait);
-}
-
-/*
- Send an asynchronous channel dump request.
-*/
-int line6_dump_request_async(struct line6_dump_request *l6dr,
- struct usb_line6 *line6, int num)
-{
- int ret;
- line6_invalidate_current(l6dr);
- ret = line6_send_raw_message_async(line6, l6dr->reqbufs[num].buffer,
- l6dr->reqbufs[num].length);
-
- if (ret < 0)
- line6_dump_finished(l6dr);
-
- return ret;
-}
-
-/*
- Send an asynchronous dump request after a given interval.
-*/
-void line6_startup_delayed(struct line6_dump_request *l6dr, int seconds,
- void (*function)(unsigned long), void *data)
-{
- l6dr->timer.expires = jiffies + seconds * HZ;
- l6dr->timer.function = function;
- l6dr->timer.data = (unsigned long)data;
- add_timer(&l6dr->timer);
-}
-
-/*
- Wait for completion.
-*/
-int line6_wait_dump(struct line6_dump_request *l6dr, int nonblock)
-{
- int retval = 0;
- DECLARE_WAITQUEUE(wait, current);
- add_wait_queue(&l6dr->wait, &wait);
- current->state = TASK_INTERRUPTIBLE;
-
- while (l6dr->in_progress) {
- if (nonblock) {
- retval = -EAGAIN;
- break;
- }
-
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- } else
- schedule();
- }
-
- current->state = TASK_RUNNING;
- remove_wait_queue(&l6dr->wait, &wait);
- return retval;
-}
-
-/*
- Initialize dump request buffer.
-*/
-int line6_dumpreq_initbuf(struct line6_dump_request *l6dr, const void *buf,
- size_t len, int num)
-{
- l6dr->reqbufs[num].buffer = kmalloc(len, GFP_KERNEL);
- if (l6dr->reqbufs[num].buffer == NULL)
- return -ENOMEM;
- memcpy(l6dr->reqbufs[num].buffer, buf, len);
- l6dr->reqbufs[num].length = len;
- return 0;
-}
-
-/*
- Initialize dump request data structure (including one buffer).
-*/
-int line6_dumpreq_init(struct line6_dump_request *l6dr, const void *buf,
- size_t len)
-{
- int ret;
- ret = line6_dumpreq_initbuf(l6dr, buf, len, 0);
- if (ret < 0)
- return ret;
- init_waitqueue_head(&l6dr->wait);
- init_timer(&l6dr->timer);
- return 0;
-}
-
-/*
- Destruct dump request data structure.
-*/
-void line6_dumpreq_destructbuf(struct line6_dump_request *l6dr, int num)
-{
- if (l6dr == NULL)
- return;
- if (l6dr->reqbufs[num].buffer == NULL)
- return;
- kfree(l6dr->reqbufs[num].buffer);
- l6dr->reqbufs[num].buffer = NULL;
-}
-
-/*
- Destruct dump request data structure.
-*/
-void line6_dumpreq_destruct(struct line6_dump_request *l6dr)
-{
- if (l6dr->reqbufs[0].buffer == NULL)
- return;
- line6_dumpreq_destructbuf(l6dr, 0);
- l6dr->ok = 1;
- del_timer_sync(&l6dr->timer);
-}
diff --git a/drivers/staging/line6/dumprequest.h b/drivers/staging/line6/dumprequest.h
deleted file mode 100644
index 1975d54b3c2..00000000000
--- a/drivers/staging/line6/dumprequest.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Line6 Linux USB driver - 0.8.0
- *
- * Copyright (C) 2004-2009 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 DUMPREQUEST_H
-#define DUMPREQUEST_H
-
-
-#include <linux/usb.h>
-#include <linux/wait.h>
-
-#include <sound/core.h>
-
-
-enum {
- LINE6_DUMP_NONE,
- LINE6_DUMP_CURRENT
-};
-
-
-struct line6_dump_reqbuf {
- /**
- Buffer for dump requests.
- */
- unsigned char *buffer;
-
- /**
- Size of dump request.
- */
- size_t length;
-};
-
-/**
- Provides the functionality to request channel/model/... dump data from a
- Line6 device.
-*/
-struct line6_dump_request {
- /**
- Wait queue for access to program dump data.
- */
- wait_queue_head_t wait;
-
- /**
- Indicates an unfinished program dump request.
- 0: no dump
- 1: dump current settings
- Other device-specific values are also allowed.
- */
- int in_progress;
-
- /**
- Timer for delayed dump request.
- */
- struct timer_list timer;
-
- /**
- Flag if initial dump request has been successful.
- */
- char ok;
-
- /**
- Dump request buffers
- */
- struct line6_dump_reqbuf reqbufs[1];
-};
-
-extern void line6_dump_finished(struct line6_dump_request *l6dr);
-extern int line6_dump_request_async(struct line6_dump_request *l6dr,
- struct usb_line6 *line6, int num);
-extern void line6_dump_started(struct line6_dump_request *l6dr, int dest);
-extern void line6_dumpreq_destruct(struct line6_dump_request *l6dr);
-extern void line6_dumpreq_destructbuf(struct line6_dump_request *l6dr, int num);
-extern int line6_dumpreq_init(struct line6_dump_request *l6dr, const void *buf,
- size_t len);
-extern int line6_dumpreq_initbuf(struct line6_dump_request *l6dr,
- const void *buf, size_t len, int num);
-extern void line6_invalidate_current(struct line6_dump_request *l6dr);
-extern void line6_startup_delayed(struct line6_dump_request *l6dr, int seconds,
- void (*function)(unsigned long), void *data);
-extern int line6_wait_dump(struct line6_dump_request *l6dr, int nonblock);
-
-
-#endif
diff --git a/drivers/staging/line6/midi.c b/drivers/staging/line6/midi.c
index 89a2b17e9ca..1ac343b649c 100644
--- a/drivers/staging/line6/midi.c
+++ b/drivers/staging/line6/midi.c
@@ -1,7 +1,7 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -9,31 +9,23 @@
*
*/
-#include "driver.h"
-
+#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 USE_MIDIBUF 1
-#define OUTPUT_DUMP_ONLY 0
-
-
#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.
*/
@@ -50,38 +42,34 @@ void line6_midi_receive(struct usb_line6 *line6, unsigned char *data,
*/
static void line6_midi_transmit(struct snd_rawmidi_substream *substream)
{
- struct usb_line6 *line6 = line6_rawmidi_substream_midi(substream)->line6;
+ struct usb_line6 *line6 =
+ line6_rawmidi_substream_midi(substream)->line6;
struct snd_line6_midi *line6midi = line6->line6midi;
- struct MidiBuffer *mb = &line6midi->midibuf_out;
+ struct midi_buffer *mb = &line6midi->midibuf_out;
unsigned long flags;
- unsigned char chunk[line6->max_packet_size];
+ unsigned char chunk[LINE6_FALLBACK_MAXPACKETSIZE];
int req, done;
spin_lock_irqsave(&line6->line6midi->midi_transmit_lock, flags);
for (;;) {
- req = min(midibuf_bytes_free(mb), line6->max_packet_size);
+ req = min(line6_midibuf_bytes_free(mb), line6->max_packet_size);
done = snd_rawmidi_transmit_peek(substream, chunk, req);
if (done == 0)
break;
-#if DO_DUMP_MIDI_SEND
- line6_write_hexdump(line6, 's', chunk, done);
-#endif
- midibuf_write(mb, chunk, done);
+ line6_midibuf_write(mb, chunk, done);
snd_rawmidi_transmit_ack(substream, done);
}
for (;;) {
- done = midibuf_read(mb, chunk, line6->max_packet_size);
+ done = line6_midibuf_read(mb, chunk,
+ LINE6_FALLBACK_MAXPACKETSIZE);
if (done == 0)
break;
- if (midibuf_skip_message(mb, line6midi->midi_mask_transmit))
- continue;
-
send_midi_async(line6, chunk, done);
}
@@ -114,7 +102,7 @@ static void midi_sent(struct urb *urb)
}
if (num == 0)
- wake_up_interruptible(&line6->line6midi->send_wait);
+ wake_up(&line6->line6midi->send_wait);
spin_unlock_irqrestore(&line6->line6midi->send_urb_lock, flags);
}
@@ -133,24 +121,19 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
urb = usb_alloc_urb(0, GFP_ATOMIC);
- if (urb == 0) {
+ if (urb == NULL) {
dev_err(line6->ifcdev, "Out of memory\n");
return -ENOMEM;
}
-#if DO_DUMP_URB_SEND
- line6_write_hexdump(line6, 'S', data, length);
-#endif
+ transfer_buffer = kmemdup(data, length, GFP_ATOMIC);
- transfer_buffer = kmalloc(length, GFP_ATOMIC);
-
- if (transfer_buffer == 0) {
+ if (transfer_buffer == NULL) {
usb_free_urb(urb);
dev_err(line6->ifcdev, "Out of memory\n");
return -ENOMEM;
}
- memcpy(transfer_buffer, data, length);
usb_fill_int_urb(urb, line6->usbdev,
usb_sndbulkpipe(line6->usbdev,
line6->ep_control_write),
@@ -162,27 +145,10 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
if (retval < 0) {
dev_err(line6->ifcdev, "usb_submit_urb failed\n");
usb_free_urb(urb);
- return -EINVAL;
+ return retval;
}
++line6->line6midi->num_active_send_urbs;
-
- switch (line6->usbdev->descriptor.idProduct) {
- case LINE6_DEVID_BASSPODXT:
- case LINE6_DEVID_BASSPODXTLIVE:
- case LINE6_DEVID_BASSPODXTPRO:
- case LINE6_DEVID_PODXT:
- case LINE6_DEVID_PODXTLIVE:
- case LINE6_DEVID_PODXTPRO:
- case LINE6_DEVID_POCKETPOD:
- pod_midi_postprocess((struct usb_line6_pod *)line6, data,
- length);
- break;
-
- default:
- MISSING_CASE;
- }
-
return 0;
}
@@ -200,7 +166,8 @@ 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;
+ struct usb_line6 *line6 =
+ line6_rawmidi_substream_midi(substream)->line6;
line6->line6midi->substream_transmit = substream;
spin_lock_irqsave(&line6->line6midi->send_urb_lock, flags);
@@ -213,20 +180,12 @@ static void line6_midi_output_trigger(struct snd_rawmidi_substream *substream,
static void line6_midi_output_drain(struct snd_rawmidi_substream *substream)
{
- struct usb_line6 *line6 = line6_rawmidi_substream_midi(substream)->line6;
- wait_queue_head_t *head = &line6->line6midi->send_wait;
- DECLARE_WAITQUEUE(wait, current);
- add_wait_queue(head, &wait);
- current->state = TASK_INTERRUPTIBLE;
-
- while (line6->line6midi->num_active_send_urbs > 0)
- if (signal_pending(current))
- break;
- else
- schedule();
+ struct usb_line6 *line6 =
+ line6_rawmidi_substream_midi(substream)->line6;
+ struct snd_line6_midi *midi = line6->line6midi;
- current->state = TASK_RUNNING;
- remove_wait_queue(head, &wait);
+ wait_event_interruptible(midi->send_wait,
+ midi->num_active_send_urbs == 0);
}
static int line6_midi_input_open(struct snd_rawmidi_substream *substream)
@@ -242,12 +201,13 @@ static int line6_midi_input_close(struct snd_rawmidi_substream *substream)
static void line6_midi_input_trigger(struct snd_rawmidi_substream *substream,
int up)
{
- struct usb_line6 *line6 = line6_rawmidi_substream_midi(substream)->line6;
+ struct usb_line6 *line6 =
+ line6_rawmidi_substream_midi(substream)->line6;
if (up)
line6->line6midi->substream_receive = substream;
else
- line6->line6midi->substream_receive = 0;
+ line6->line6midi->substream_receive = NULL;
}
static struct snd_rawmidi_ops line6_midi_output_ops = {
@@ -283,12 +243,12 @@ static int snd_line6_new_midi(struct snd_line6_midi *line6midi)
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;
+ 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);
@@ -297,69 +257,13 @@ static int snd_line6_new_midi(struct snd_line6_midi *line6midi)
return 0;
}
-/*
- "read" request on "midi_mask_transmit" special file.
-*/
-static ssize_t midi_get_midi_mask_transmit(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6 *line6 = usb_get_intfdata(interface);
- return sprintf(buf, "%d\n", line6->line6midi->midi_mask_transmit);
-}
-
-/*
- "write" request on "midi_mask" special file.
-*/
-static ssize_t midi_set_midi_mask_transmit(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6 *line6 = usb_get_intfdata(interface);
- int value = simple_strtoul(buf, NULL, 10);
- line6->line6midi->midi_mask_transmit = value;
- return count;
-}
-
-/*
- "read" request on "midi_mask_receive" special file.
-*/
-static ssize_t midi_get_midi_mask_receive(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6 *line6 = usb_get_intfdata(interface);
- return sprintf(buf, "%d\n", line6->line6midi->midi_mask_receive);
-}
-
-/*
- "write" request on "midi_mask" special file.
-*/
-static ssize_t midi_set_midi_mask_receive(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6 *line6 = usb_get_intfdata(interface);
- int value = simple_strtoul(buf, NULL, 10);
- line6->line6midi->midi_mask_receive = value;
- return count;
-}
-
-static DEVICE_ATTR(midi_mask_transmit, S_IWUGO | S_IRUGO, midi_get_midi_mask_transmit, midi_set_midi_mask_transmit);
-static DEVICE_ATTR(midi_mask_receive, S_IWUGO | S_IRUGO, midi_get_midi_mask_receive, midi_set_midi_mask_receive);
-
/* MIDI device destructor */
static int snd_line6_midi_free(struct snd_device *device)
{
struct snd_line6_midi *line6midi = device->device_data;
- device_remove_file(line6midi->line6->ifcdev, &dev_attr_midi_mask_transmit);
- device_remove_file(line6midi->line6->ifcdev, &dev_attr_midi_mask_receive);
- midibuf_destroy(&line6midi->midibuf_in);
- midibuf_destroy(&line6midi->midibuf_out);
+
+ line6_midibuf_destroy(&line6midi->midibuf_in);
+ line6_midibuf_destroy(&line6midi->midibuf_out);
return 0;
}
@@ -375,25 +279,30 @@ int line6_init_midi(struct usb_line6 *line6)
int err;
struct snd_line6_midi *line6midi;
- if (!(line6->properties->capabilities & LINE6_BIT_CONTROL))
- return 0; /* skip MIDI initialization and report success */
+ if (!(line6->properties->capabilities & LINE6_BIT_CONTROL)) {
+ /* skip MIDI initialization and report success */
+ return 0;
+ }
line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL);
if (line6midi == NULL)
return -ENOMEM;
- err = midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0);
- if (err < 0)
+ err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0);
+ if (err < 0) {
+ kfree(line6midi);
return err;
+ }
- err = midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1);
- if (err < 0)
+ 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;
- line6midi->midi_mask_transmit = 1;
- line6midi->midi_mask_receive = 4;
line6->line6midi = line6midi;
err = snd_device_new(line6->card, SNDRV_DEV_RAWMIDI, line6midi,
@@ -401,20 +310,10 @@ int line6_init_midi(struct usb_line6 *line6)
if (err < 0)
return err;
- snd_card_set_dev(line6->card, line6->ifcdev);
-
err = snd_line6_new_midi(line6midi);
if (err < 0)
return err;
- err = device_create_file(line6->ifcdev, &dev_attr_midi_mask_transmit);
- if (err < 0)
- return err;
-
- err = device_create_file(line6->ifcdev, &dev_attr_midi_mask_receive);
- 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);
diff --git a/drivers/staging/line6/midi.h b/drivers/staging/line6/midi.h
index c69fd118957..78f903fb4d4 100644
--- a/drivers/staging/line6/midi.h
+++ b/drivers/staging/line6/midi.h
@@ -1,7 +1,7 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -12,15 +12,12 @@
#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.
@@ -58,30 +55,18 @@ struct snd_line6_midi {
wait_queue_head_t send_wait;
/**
- Bit mask for output MIDI channels.
- */
- int midi_mask_transmit;
-
- /**
- Bit mask for input MIDI channels.
- */
- int midi_mask_receive;
-
- /**
Buffer for incoming MIDI stream.
*/
- struct MidiBuffer midibuf_in;
+ struct midi_buffer midibuf_in;
/**
Buffer for outgoing MIDI stream.
*/
- struct MidiBuffer midibuf_out;
+ 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
index ab0a5f30fbc..f0adb7baa60 100644
--- a/drivers/staging/line6/midibuf.c
+++ b/drivers/staging/line6/midibuf.c
@@ -1,7 +1,7 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -9,13 +9,10 @@
*
*/
-#include "config.h"
-
#include <linux/slab.h>
#include "midibuf.h"
-
static int midibuf_message_length(unsigned char code)
{
if (code < 0x80)
@@ -25,23 +22,34 @@ static int midibuf_message_length(unsigned char code)
return 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.
- */
+ 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 };
+ 1, 1, 1, -1, 1, 1
+ };
return length[code & 0x0f];
}
}
-void midibuf_reset(struct MidiBuffer *this)
+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 midibuf_init(struct MidiBuffer *this, int size, int split)
+int line6_midibuf_init(struct midi_buffer *this, int size, int split)
{
this->buf = kmalloc(size, GFP_KERNEL);
@@ -50,44 +58,37 @@ int midibuf_init(struct MidiBuffer *this, int size, int split)
this->size = size;
this->split = split;
- midibuf_reset(this);
+ line6_midibuf_reset(this);
return 0;
}
-void midibuf_status(struct MidiBuffer *this)
+void line6_midibuf_status(struct midi_buffer *this)
{
- printk(KERN_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);
-}
-
-static int midibuf_is_empty(struct MidiBuffer *this)
-{
- return (this->pos_read == this->pos_write) && !this->full;
-}
-
-static int midibuf_is_full(struct MidiBuffer *this)
-{
- return this->full;
+ 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 midibuf_bytes_free(struct MidiBuffer *this)
+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;
+ midibuf_is_full(this) ?
+ 0 :
+ (this->pos_read - this->pos_write + this->size - 1) % this->size +
+ 1;
}
-int midibuf_bytes_used(struct MidiBuffer *this)
+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;
+ midibuf_is_empty(this) ?
+ 0 :
+ (this->pos_write - this->pos_read + this->size - 1) % this->size +
+ 1;
}
-int midibuf_write(struct MidiBuffer *this, unsigned char *data, int length)
+int line6_midibuf_write(struct midi_buffer *this, unsigned char *data,
+ int length)
{
int bytes_free;
int length1, length2;
@@ -102,7 +103,7 @@ int midibuf_write(struct MidiBuffer *this, unsigned char *data, int length)
skip_active_sense = 1;
}
- bytes_free = midibuf_bytes_free(this);
+ bytes_free = line6_midibuf_bytes_free(this);
if (length > bytes_free)
length = bytes_free;
@@ -129,7 +130,8 @@ int midibuf_write(struct MidiBuffer *this, unsigned char *data, int length)
return length + skip_active_sense;
}
-int midibuf_read(struct MidiBuffer *this, unsigned char *data, int length)
+int line6_midibuf_read(struct midi_buffer *this, unsigned char *data,
+ int length)
{
int bytes_used;
int length1, length2;
@@ -145,7 +147,7 @@ int midibuf_read(struct MidiBuffer *this, unsigned char *data, int length)
if (midibuf_is_empty(this))
return 0;
- bytes_used = midibuf_bytes_used(this);
+ bytes_used = line6_midibuf_bytes_used(this);
if (length > bytes_used)
length = bytes_used;
@@ -160,7 +162,8 @@ int midibuf_read(struct MidiBuffer *this, unsigned char *data, int length)
this->command_prev = command;
} else {
if (this->command_prev > 0) {
- int midi_length_prev = midibuf_message_length(this->command_prev);
+ int midi_length_prev =
+ midibuf_message_length(this->command_prev);
if (midi_length_prev > 0) {
midi_length = midi_length_prev - 1;
@@ -200,15 +203,15 @@ int midibuf_read(struct MidiBuffer *this, unsigned char *data, int length)
}
if (midi_length == length)
- midi_length = -1; /* end of message not found */
+ midi_length = -1; /* end of message not found */
}
if (midi_length < 0) {
if (!this->split)
- return 0; /* command is not yet complete */
+ return 0; /* command is not yet complete */
} else {
if (length < midi_length)
- return 0; /* command is not yet complete */
+ return 0; /* command is not yet complete */
length = midi_length;
}
@@ -232,9 +235,9 @@ int midibuf_read(struct MidiBuffer *this, unsigned char *data, int length)
return length + repeat;
}
-int midibuf_ignore(struct MidiBuffer *this, int length)
+int line6_midibuf_ignore(struct midi_buffer *this, int length)
{
- int bytes_used = midibuf_bytes_used(this);
+ int bytes_used = line6_midibuf_bytes_used(this);
if (length > bytes_used)
length = bytes_used;
@@ -244,7 +247,7 @@ int midibuf_ignore(struct MidiBuffer *this, int length)
return length;
}
-int midibuf_skip_message(struct MidiBuffer *this, unsigned short mask)
+int line6_midibuf_skip_message(struct midi_buffer *this, unsigned short mask)
{
int cmd = this->command_prev;
@@ -255,7 +258,7 @@ int midibuf_skip_message(struct MidiBuffer *this, unsigned short mask)
return 0;
}
-void midibuf_destroy(struct MidiBuffer *this)
+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
index 9877581bcd9..707482b940e 100644
--- a/drivers/staging/line6/midibuf.h
+++ b/drivers/staging/line6/midibuf.h
@@ -1,7 +1,7 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -12,8 +12,7 @@
#ifndef MIDIBUF_H
#define MIDIBUF_H
-
-struct MidiBuffer {
+struct midi_buffer {
unsigned char *buf;
int size;
int split;
@@ -22,18 +21,18 @@ struct MidiBuffer {
int command_prev;
};
-
-extern int midibuf_bytes_used(struct MidiBuffer *mb);
-extern int midibuf_bytes_free(struct MidiBuffer *mb);
-extern void midibuf_destroy(struct MidiBuffer *mb);
-extern int midibuf_ignore(struct MidiBuffer *mb, int length);
-extern int midibuf_init(struct MidiBuffer *mb, int size, int split);
-extern int midibuf_read(struct MidiBuffer *mb, unsigned char *data, int length);
-extern void midibuf_reset(struct MidiBuffer *mb);
-extern int midibuf_skip_message(struct MidiBuffer *mb, unsigned short mask);
-extern void midibuf_status(struct MidiBuffer *mb);
-extern int midibuf_write(struct MidiBuffer *mb, unsigned char *data,
- int length);
-
+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
index fc4113f3315..a3136b189ee 100644
--- a/drivers/staging/line6/pcm.c
+++ b/drivers/staging/line6/pcm.c
@@ -1,7 +1,7 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -9,8 +9,7 @@
*
*/
-#include "driver.h"
-
+#include <linux/slab.h>
#include <sound/core.h>
#include <sound/control.h>
#include <sound/pcm.h>
@@ -18,9 +17,212 @@
#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)
@@ -31,12 +233,12 @@ int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
unsigned long flags;
spin_lock_irqsave(&line6pcm->lock_trigger, flags);
- clear_bit(BIT_PREPARED, &line6pcm->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(s, cmd);
+ err = snd_line6_playback_trigger(line6pcm, cmd);
if (err < 0) {
spin_unlock_irqrestore(&line6pcm->lock_trigger,
@@ -47,7 +249,7 @@ int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
break;
case SNDRV_PCM_STREAM_CAPTURE:
- err = snd_line6_capture_trigger(s, cmd);
+ err = snd_line6_capture_trigger(line6pcm, cmd);
if (err < 0) {
spin_unlock_irqrestore(&line6pcm->lock_trigger,
@@ -58,8 +260,8 @@ int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
break;
default:
- dev_err(s2m(substream), "Unknown stream direction %d\n",
- s->stream);
+ dev_err(line6pcm->line6->ifcdev,
+ "Unknown stream direction %d\n", s->stream);
}
}
@@ -68,8 +270,8 @@ int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
}
/* control info callback */
-static int snd_line6_control_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
+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;
@@ -79,28 +281,30 @@ static int snd_line6_control_info(struct snd_kcontrol *kcontrol,
}
/* control get callback */
-static int snd_line6_control_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+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[i];
+ ucontrol->value.integer.value[i] = line6pcm->volume_playback[i];
return 0;
}
/* control put callback */
-static int snd_line6_control_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+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[i] != ucontrol->value.integer.value[i]) {
- line6pcm->volume[i] = ucontrol->value.integer.value[i];
+ if (line6pcm->volume_playback[i] !=
+ ucontrol->value.integer.value[i]) {
+ line6pcm->volume_playback[i] =
+ ucontrol->value.integer.value[i];
changed = 1;
}
@@ -108,14 +312,14 @@ static int snd_line6_control_put(struct snd_kcontrol *kcontrol,
}
/* control definition */
-static struct snd_kcontrol_new line6_control = {
+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_info,
- .get = snd_line6_control_get,
- .put = snd_line6_control_put
+ .info = snd_line6_control_playback_info,
+ .get = snd_line6_control_playback_get,
+ .put = snd_line6_control_playback_put
};
/*
@@ -126,6 +330,11 @@ 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]);
@@ -145,8 +354,8 @@ static int snd_line6_new_pcm(struct snd_line6_pcm *line6pcm)
int err;
err = snd_pcm_new(line6pcm->line6->card,
- (char *)line6pcm->line6->properties->name,
- 0, 1, 1, &pcm);
+ (char *)line6pcm->line6->properties->name,
+ 0, 1, 1, &pcm);
if (err < 0)
return err;
@@ -156,13 +365,15 @@ static int snd_line6_new_pcm(struct snd_line6_pcm *line6pcm)
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_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);
+ snd_dma_continuous_data
+ (GFP_KERNEL), 64 * 1024,
+ 128 * 1024);
return 0;
}
@@ -174,6 +385,31 @@ static int snd_line6_pcm_free(struct snd_device *device)
}
/*
+ 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.
*/
@@ -189,7 +425,7 @@ int line6_init_pcm(struct usb_line6 *line6,
struct snd_line6_pcm *line6pcm;
if (!(line6->properties->capabilities & LINE6_BIT_PCM))
- return 0; /* skip PCM initialization and report success */
+ return 0; /* skip PCM initialization and report success */
/* initialize PCM subsystem based on product id: */
switch (line6->product) {
@@ -199,54 +435,64 @@ int line6_init_pcm(struct usb_line6 *line6,
case LINE6_DEVID_PODXT:
case LINE6_DEVID_PODXTLIVE:
case LINE6_DEVID_PODXTPRO:
- ep_read = 0x82;
+ case LINE6_DEVID_PODHD300:
+ case LINE6_DEVID_PODHD400:
+ ep_read = 0x82;
ep_write = 0x01;
break;
+ case LINE6_DEVID_PODHD500:
case LINE6_DEVID_PODX3:
case LINE6_DEVID_PODX3LIVE:
- ep_read = 0x86;
+ ep_read = 0x86;
ep_write = 0x02;
break;
case LINE6_DEVID_POCKETPOD:
- ep_read = 0x82;
+ ep_read = 0x82;
ep_write = 0x02;
break;
case LINE6_DEVID_GUITARPORT:
+ case LINE6_DEVID_PODSTUDIO_GX:
+ case LINE6_DEVID_PODSTUDIO_UX1:
+ case LINE6_DEVID_PODSTUDIO_UX2:
case LINE6_DEVID_TONEPORT_GX:
- ep_read = 0x82;
- ep_write = 0x01;
- break;
-
case LINE6_DEVID_TONEPORT_UX1:
- ep_read = 0x00;
- ep_write = 0x00;
+ case LINE6_DEVID_TONEPORT_UX2:
+ ep_read = 0x82;
+ ep_write = 0x01;
break;
+ /* this is for interface_number == 1:
case LINE6_DEVID_TONEPORT_UX2:
+ case LINE6_DEVID_PODSTUDIO_UX2:
ep_read = 0x87;
ep_write = 0x00;
- break;
+ break; */
default:
MISSING_CASE;
}
- line6pcm = kzalloc(sizeof(struct snd_line6_pcm), GFP_KERNEL);
+ line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL);
if (line6pcm == NULL)
return -ENOMEM;
- line6pcm->volume[0] = line6pcm->volume[1] = 128;
+ line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255;
+ line6pcm->volume_monitor = 255;
line6pcm->line6 = line6;
line6pcm->ep_audio_read = ep_read;
line6pcm->ep_audio_write = ep_write;
- line6pcm->max_packet_size = usb_maxpacket(line6->usbdev,
- usb_rcvintpipe(line6->usbdev,
- ep_read),
- 0);
+
+ /* 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;
@@ -255,8 +501,6 @@ int line6_init_pcm(struct usb_line6 *line6,
if (err < 0)
return err;
- snd_card_set_dev(line6->card, line6->ifcdev);
-
err = snd_line6_new_pcm(line6pcm);
if (err < 0)
return err;
@@ -265,19 +509,34 @@ int line6_init_pcm(struct usb_line6 *line6,
spin_lock_init(&line6pcm->lock_audio_in);
spin_lock_init(&line6pcm->lock_trigger);
- err = create_audio_out_urbs(line6pcm);
+ err = line6_create_audio_out_urbs(line6pcm);
if (err < 0)
return err;
- err = create_audio_in_urbs(line6pcm);
+ err = line6_create_audio_in_urbs(line6pcm);
if (err < 0)
return err;
/* mixer: */
- err = snd_ctl_add(line6->card, snd_ctl_new1(&line6_control, line6pcm));
+ 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;
}
@@ -286,13 +545,29 @@ int snd_line6_prepare(struct snd_pcm_substream *substream)
{
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
- if (!test_and_set_bit(BIT_PREPARED, &line6pcm->flags)) {
- unlink_wait_clear_audio_out_urbs(line6pcm);
+ 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;
-
- unlink_wait_clear_audio_in_urbs(line6pcm);
line6pcm->bytes_out = 0;
+ line6pcm->count_in = 0;
line6pcm->pos_in_done = 0;
line6pcm->bytes_in = 0;
}
diff --git a/drivers/staging/line6/pcm.h b/drivers/staging/line6/pcm.h
index 53db217cd42..6aa0d46a289 100644
--- a/drivers/staging/line6/pcm.h
+++ b/drivers/staging/line6/pcm.h
@@ -1,7 +1,7 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -16,38 +16,161 @@
#ifndef PCM_H
#define PCM_H
-
#include <sound/pcm.h>
#include "driver.h"
#include "usbdefs.h"
-
/* number of URBs */
-#define LINE6_ISO_BUFFERS 8
+#define LINE6_ISO_BUFFERS 2
-/* number of USB frames per URB */
-#define LINE6_ISO_PACKETS 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
-/* this should be queried dynamically from the USB interface! */
-#define LINE6_ISO_PACKET_SIZE_MAX 252
+#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)
/*
- Extract the messaging device from the substream instance
+ 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).
*/
-#define s2m(s) (((struct snd_line6_pcm *) \
- snd_pcm_substream_chip(s))->line6->ifcdev)
+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,
+
+ /* 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 ,
-enum {
- BIT_RUNNING_PLAYBACK,
- BIT_RUNNING_CAPTURE,
- BIT_PAUSE_PLAYBACK,
- BIT_PREPARED
+ 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 {
@@ -83,9 +206,11 @@ struct snd_line6_pcm {
struct urb *urb_audio_in[LINE6_ISO_BUFFERS];
/**
- Temporary buffer to hold data when playback buffer wraps.
+ 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 *wrap_out;
+ unsigned char *buffer_out;
/**
Temporary buffer for capture.
@@ -95,6 +220,16 @@ struct snd_line6_pcm {
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;
@@ -204,19 +339,44 @@ struct snd_line6_pcm {
/**
PCM playback volume (left and right).
*/
- int volume[2];
+ 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;
/**
- Several status bits (see BIT_*).
+ 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
index acb06126a6a..2ca8900e68c 100644
--- a/drivers/staging/line6/playback.c
+++ b/drivers/staging/line6/playback.c
@@ -1,7 +1,7 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -9,18 +9,18 @@
*
*/
-#include "driver.h"
-
+#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.
*/
@@ -30,10 +30,11 @@ static void change_volume(struct urb *urb_out, int volume[],
int chn = 0;
if (volume[0] == 256 && volume[1] == 256)
- return; /* maximum volume - no change */
+ 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);
@@ -43,11 +44,13 @@ static void change_volume(struct urb *urb_out, int volume[],
}
} 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;
@@ -58,27 +61,103 @@ static void change_volume(struct urb *urb_out, int volume[],
}
}
+#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_pcm_substream *substream)
+static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
{
int index;
unsigned long flags;
int i, urb_size, urb_frames;
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
+ 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 snd_pcm_runtime *runtime = substream->runtime;
+ 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);
+ 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(s2m(substream), "no free URB found\n");
+ dev_err(line6pcm->line6->ifcdev, "no free URB found\n");
return -EINVAL;
}
@@ -87,61 +166,119 @@ static int submit_audio_out_urb(struct snd_pcm_substream *substream)
for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
/* compute frame size for given sampling rate */
- int n, fs;
- struct usb_iso_packet_descriptor *fout = &urb_out->iso_frame_desc[i];
- line6pcm->count_out += frame_increment;
- n = line6pcm->count_out / frame_factor;
- line6pcm->count_out -= n * frame_factor;
- fs = n * bytes_per_frame;
+ 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 = fs;
- urb_size += fs;
+ 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 (test_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags)) {
- urb_out->transfer_buffer = line6pcm->wrap_out;
- memset(line6pcm->wrap_out, 0, urb_size);
- } else {
if (line6pcm->pos_out + urb_frames > runtime->buffer_size) {
/*
- The transferred area goes over buffer boundary,
- copy the data to the temp buffer.
- */
+ The transferred area goes over buffer boundary,
+ copy the data to the temp buffer.
+ */
int len;
+
len = runtime->buffer_size - line6pcm->pos_out;
- urb_out->transfer_buffer = line6pcm->wrap_out;
if (len > 0) {
- memcpy(line6pcm->wrap_out, runtime->dma_area + line6pcm->pos_out * bytes_per_frame, len * bytes_per_frame);
- memcpy(line6pcm->wrap_out + len * bytes_per_frame, runtime->dma_area, (urb_frames - len) * bytes_per_frame);
+ 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(s2m(substream), "driver bug: len = %d\n", len); /* this is somewhat paranoid */
+ dev_err(line6pcm->line6->ifcdev, "driver bug: len = %d\n",
+ len);
} else {
- /* set the buffer pointer */
- urb_out->transfer_buffer = runtime->dma_area + line6pcm->pos_out * bytes_per_frame;
+ memcpy(urb_out->transfer_buffer,
+ runtime->dma_area +
+ line6pcm->pos_out * bytes_per_frame,
+ urb_out->transfer_buffer_length);
}
- }
-
- if ((line6pcm->pos_out += urb_frames) >= runtime->buffer_size)
- line6pcm->pos_out -= runtime->buffer_size;
- urb_out->transfer_buffer_length = urb_size;
- urb_out->context = substream;
- change_volume(urb_out, line6pcm->volume, bytes_per_frame);
-
-#if DO_DUMP_PCM_SEND
- for (i = 0; i < LINE6_ISO_PACKETS; ++i) {
- struct usb_iso_packet_descriptor *fout = &urb_out->iso_frame_desc[i];
- line6_write_hexdump(line6pcm->line6, 'P', urb_out->transfer_buffer + fout->offset, fout->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_BIT_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 (usb_submit_urb(urb_out, GFP_ATOMIC) == 0)
+ if (ret == 0)
set_bit(index, &line6pcm->active_urb_out);
else
- dev_err(s2m(substream), "URB out #%d submission failed\n", index);
+ dev_err(line6pcm->line6->ifcdev,
+ "URB out #%d submission failed (%d)\n", index, ret);
spin_unlock_irqrestore(&line6pcm->lock_audio_out, flags);
return 0;
@@ -150,12 +287,12 @@ static int submit_audio_out_urb(struct snd_pcm_substream *substream)
/*
Submit all currently available playback URBs.
*/
-static int submit_audio_out_all_urbs(struct snd_pcm_substream *substream)
+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(substream);
+ ret = submit_audio_out_urb(line6pcm);
if (ret < 0)
return ret;
}
@@ -166,7 +303,7 @@ static int submit_audio_out_all_urbs(struct snd_pcm_substream *substream)
/*
Unlink all currently active playback URBs.
*/
-static void unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm)
+void line6_unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm)
{
unsigned int i;
@@ -174,6 +311,7 @@ static void unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm)
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);
}
}
@@ -181,9 +319,10 @@ static void unlink_audio_out_urbs(struct snd_line6_pcm *line6pcm)
}
/*
- Wait until unlinking of all currently active playback URBs has been finished.
+ Wait until unlinking of all currently active playback URBs has been
+ finished.
*/
-static void wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
+void line6_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
{
int timeout = HZ;
unsigned int i;
@@ -202,18 +341,21 @@ static void wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
} while (--timeout > 0);
if (alive)
snd_printk(KERN_ERR "timeout: still %d active urbs..\n", alive);
-
- line6pcm->active_urb_out = 0;
- line6pcm->unlink_urb_out = 0;
}
/*
Unlink all currently active playback URBs, and wait for finishing.
*/
-void unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm)
+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)
{
- unlink_audio_out_urbs(line6pcm);
- wait_clear_audio_out_urbs(line6pcm);
+ kfree(line6pcm->buffer_out);
+ line6pcm->buffer_out = NULL;
}
/*
@@ -223,10 +365,15 @@ 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);
- struct snd_pcm_substream *substream = (struct snd_pcm_substream *)urb->context;
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
- struct snd_pcm_runtime *runtime = substream->runtime;
+#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--;)
@@ -234,36 +381,46 @@ static void audio_out_callback(struct urb *urb)
break;
if (index < 0)
- return; /* URB has been unlinked asynchronously */
+ 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);
- 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;
+ 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 == -ESHUTDOWN) {
+ if (urb->iso_frame_desc[i].status == -EXDEV) {
shutdown = 1;
break;
}
- if (test_bit(index, &line6pcm->unlink_urb_out))
+ 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(substream);
-
- if ((line6pcm->bytes_out += length) >= line6pcm->period_out) {
- line6pcm->bytes_out -= line6pcm->period_out;
- snd_pcm_period_elapsed(substream);
+ 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);
+ }
}
}
}
@@ -276,7 +433,8 @@ static int snd_line6_playback_open(struct snd_pcm_substream *substream)
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));
+ (&line6pcm->
+ properties->snd_line6_rates));
if (err < 0)
return err;
@@ -291,7 +449,8 @@ static int snd_line6_playback_close(struct snd_pcm_substream *substream)
}
/* hw_params playback callback */
-static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params)
+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);
@@ -308,19 +467,19 @@ static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream, str
}
/* -- [FD] end */
- ret = snd_pcm_lib_malloc_pages(substream,
- params_buffer_bytes(hw_params));
+ ret = line6_pcm_acquire(line6pcm, LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER);
+
if (ret < 0)
return ret;
- line6pcm->period_out = params_period_bytes(hw_params);
- line6pcm->wrap_out = kmalloc(2 * LINE6_ISO_PACKET_SIZE_MAX, GFP_KERNEL);
-
- if (!line6pcm->wrap_out) {
- dev_err(s2m(substream), "cannot malloc wrap_out\n");
- return -ENOMEM;
+ 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;
}
@@ -328,46 +487,47 @@ static int snd_line6_playback_hw_params(struct snd_pcm_substream *substream, str
static int snd_line6_playback_hw_free(struct snd_pcm_substream *substream)
{
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
- unlink_wait_clear_audio_out_urbs(line6pcm);
-
- kfree(line6pcm->wrap_out);
- line6pcm->wrap_out = NULL;
+ 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_pcm_substream *substream, int cmd)
+int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd)
{
- struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
int err;
- line6pcm->count_out = 0;
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- if (!test_and_set_bit(BIT_RUNNING_PLAYBACK, &line6pcm->flags)) {
- err = submit_audio_out_all_urbs(substream);
+#ifdef CONFIG_PM
+ case SNDRV_PCM_TRIGGER_RESUME:
+#endif
+ err = line6_pcm_acquire(line6pcm,
+ LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM);
- if (err < 0) {
- clear_bit(BIT_RUNNING_PLAYBACK, &line6pcm->flags);
- return err;
- }
- }
+ if (err < 0)
+ return err;
break;
case SNDRV_PCM_TRIGGER_STOP:
- if (test_and_clear_bit(BIT_RUNNING_PLAYBACK, &line6pcm->flags))
- unlink_audio_out_urbs(line6pcm);
+#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(BIT_PAUSE_PLAYBACK, &line6pcm->flags);
+ set_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags);
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- clear_bit(BIT_PAUSE_PLAYBACK, &line6pcm->flags);
+ clear_bit(LINE6_INDEX_PAUSE_PLAYBACK, &line6pcm->flags);
break;
default:
@@ -382,22 +542,23 @@ 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,
+ .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 create_audio_out_urbs(struct snd_line6_pcm *line6pcm)
+int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm)
{
int i;
@@ -406,7 +567,8 @@ int create_audio_out_urbs(struct snd_line6_pcm *line6pcm)
struct urb *urb;
/* URB for audio out: */
- urb = line6pcm->urb_audio_out[i] = usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
+ urb = line6pcm->urb_audio_out[i] =
+ usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
if (urb == NULL) {
dev_err(line6pcm->line6->ifcdev, "Out of memory\n");
@@ -414,7 +576,10 @@ int create_audio_out_urbs(struct snd_line6_pcm *line6pcm)
}
urb->dev = line6pcm->line6->usbdev;
- urb->pipe = usb_sndisocpipe(line6pcm->line6->usbdev, line6pcm->ep_audio_write & USB_ENDPOINT_NUMBER_MASK);
+ urb->pipe =
+ usb_sndisocpipe(line6pcm->line6->usbdev,
+ line6pcm->ep_audio_write &
+ USB_ENDPOINT_NUMBER_MASK);
urb->transfer_flags = URB_ISO_ASAP;
urb->start_frame = -1;
urb->number_of_packets = LINE6_ISO_PACKETS;
diff --git a/drivers/staging/line6/playback.h b/drivers/staging/line6/playback.h
index db1e48b3596..743bd6f74c5 100644
--- a/drivers/staging/line6/playback.h
+++ b/drivers/staging/line6/playback.h
@@ -1,7 +1,7 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -12,19 +12,30 @@
#ifndef PLAYBACK_H
#define PLAYBACK_H
+#include <sound/pcm.h>
#include "driver.h"
-#include <sound/pcm.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 create_audio_out_urbs(struct snd_line6_pcm *line6pcm);
-extern int snd_line6_playback_trigger(struct snd_pcm_substream *substream,
- int cmd);
-extern void unlink_wait_clear_audio_out_urbs(struct snd_line6_pcm *line6pcm);
-
+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
index 4c5b9d58400..44f4b2f9857 100644
--- a/drivers/staging/line6/pod.c
+++ b/drivers/staging/line6/pod.c
@@ -1,7 +1,7 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -9,21 +9,22 @@
*
*/
-#include "driver.h"
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <sound/control.h>
#include "audio.h"
#include "capture.h"
-#include "control.h"
+#include "driver.h"
#include "playback.h"
#include "pod.h"
-
#define POD_SYSEX_CODE 3
-#define POD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */
+#define POD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */
+/* *INDENT-OFF* */
enum {
- POD_SYSEX_CLIP = 0x0f,
POD_SYSEX_SAVE = 0x24,
POD_SYSEX_SYSTEM = 0x56,
POD_SYSEX_SYSTEMREQ = 0x57,
@@ -33,19 +34,18 @@ enum {
POD_SYSEX_DUMPMEM = 0x73,
POD_SYSEX_DUMP = 0x74,
POD_SYSEX_DUMPREQ = 0x75
- /* POD_SYSEX_DUMPMEM2 = 0x76 */ /* dumps entire internal memory of PODxt Pro */
+
+ /* dumps entire internal memory of PODxt Pro */
+ /* POD_SYSEX_DUMPMEM2 = 0x76 */
};
enum {
- POD_monitor_level = 0x04,
- POD_routing = 0x05,
- POD_tuner_mute = 0x13,
- POD_tuner_freq = 0x15,
- POD_tuner_note = 0x16,
- POD_tuner_pitch = 0x17,
- POD_system_invalid = 0x7fff
+ POD_MONITOR_LEVEL = 0x04,
+ POD_SYSTEM_INVALID = 0x10000
};
+/* *INDENT-ON* */
+
enum {
POD_DUMP_MEMORY = 2
};
@@ -58,7 +58,6 @@ enum {
POD_BUSY_MIDISEND
};
-
static struct snd_ratden pod_ratden = {
.num_min = 78125,
.num_max = 78125,
@@ -67,879 +66,269 @@ static struct snd_ratden pod_ratden = {
};
static struct line6_pcm_properties pod_pcm_properties = {
- .snd_line6_playback_hw = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_PAUSE |
- SNDRV_PCM_INFO_SYNC_START),
- .formats = SNDRV_PCM_FMTBIT_S24_3LE,
- .rates = SNDRV_PCM_RATE_KNOT,
- .rate_min = 39062,
- .rate_max = 39063,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 60000,
- .period_bytes_min = LINE6_ISO_PACKET_SIZE_MAX * POD_BYTES_PER_FRAME, /* at least one URB must fit into one period */
- .period_bytes_max = 8192,
- .periods_min = 1,
- .periods_max = 1024
- },
- .snd_line6_capture_hw = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_SYNC_START),
- .formats = SNDRV_PCM_FMTBIT_S24_3LE,
- .rates = SNDRV_PCM_RATE_KNOT,
- .rate_min = 39062,
- .rate_max = 39063,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 60000,
- .period_bytes_min = LINE6_ISO_PACKET_SIZE_MAX * POD_BYTES_PER_FRAME, /* at least one URB must fit into one period */
- .period_bytes_max = 8192,
- .periods_min = 1,
- .periods_max = 1024
- },
+ .snd_line6_playback_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+#ifdef CONFIG_PM
+ SNDRV_PCM_INFO_RESUME |
+#endif
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .rate_min = 39062,
+ .rate_max = 39063,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 60000,
+ .period_bytes_min = 64,
+ .period_bytes_max = 8192,
+ .periods_min = 1,
+ .periods_max = 1024},
+ .snd_line6_capture_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+#ifdef CONFIG_PM
+ SNDRV_PCM_INFO_RESUME |
+#endif
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .rates = SNDRV_PCM_RATE_KNOT,
+ .rate_min = 39062,
+ .rate_max = 39063,
+ .channels_min = 2,
+ .channels_max = 2,
+ .buffer_bytes_max = 60000,
+ .period_bytes_min = 64,
+ .period_bytes_max = 8192,
+ .periods_min = 1,
+ .periods_max = 1024},
.snd_line6_rates = {
- .nrats = 1,
- .rats = &pod_ratden
- },
+ .nrats = 1,
+ .rats = &pod_ratden},
.bytes_per_frame = POD_BYTES_PER_FRAME
};
-static const char pod_request_version[] = { 0xf0, 0x7e, 0x7f, 0x06, 0x01, 0xf7 };
-static const char pod_request_channel[] = { 0xf0, 0x00, 0x01, 0x0c, 0x03, 0x75, 0xf7 };
-static const char pod_version_header[] = { 0xf2, 0x7e, 0x7f, 0x06, 0x02 };
-
-
-/*
- Mark all parameters as dirty and notify waiting processes.
-*/
-static void pod_mark_batch_all_dirty(struct usb_line6_pod *pod)
-{
- int i;
-
- for (i = 0; i < POD_CONTROL_SIZE; i++)
- set_bit(i, pod->param_dirty);
-}
-
-/*
- Send an asynchronous request for the POD firmware version and device ID.
-*/
-static int pod_version_request_async(struct usb_line6_pod *pod)
-{
- return line6_send_raw_message_async(&pod->line6, pod->buffer_versionreq, sizeof(pod_request_version));
-}
-
-static void pod_create_files_work(struct work_struct *work)
-{
- struct usb_line6_pod *pod = container_of(work, struct usb_line6_pod, create_files_work);
-
- pod_create_files(pod->firmware_version, pod->line6.properties->device_bit, pod->line6.ifcdev);
-}
-
-static void pod_startup_timeout(unsigned long arg)
-{
- enum {
- REQUEST_NONE,
- REQUEST_DUMP,
- REQUEST_VERSION
- };
-
- int request = REQUEST_NONE;
- struct usb_line6_pod *pod = (struct usb_line6_pod *)arg;
-
- if (pod->dumpreq.ok) {
- if (!pod->versionreq_ok)
- request = REQUEST_VERSION;
- } else {
- if (pod->versionreq_ok)
- request = REQUEST_DUMP;
- else if (pod->startup_count++ & 1)
- request = REQUEST_DUMP;
- else
- request = REQUEST_VERSION;
- }
-
- switch (request) {
- case REQUEST_DUMP:
- line6_dump_request_async(&pod->dumpreq, &pod->line6, 0);
- break;
-
- case REQUEST_VERSION:
- pod_version_request_async(pod);
- break;
-
- default:
- return;
- }
-
- line6_startup_delayed(&pod->dumpreq, 1, pod_startup_timeout, pod);
-}
-
-static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code, int size)
-{
- return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code, size);
-}
-
-/*
- Send channel dump data to the PODxt Pro.
-*/
-static void pod_dump(struct usb_line6_pod *pod, const unsigned char *data)
-{
- int size = 1 + sizeof(pod->prog_data);
- char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_DUMP, size);
- if (!sysex)
- return;
- /* Don't know what this is good for, but PODxt Pro transmits it, so we
- * also do... */
- sysex[SYSEX_DATA_OFS] = 5;
- memcpy(sysex + SYSEX_DATA_OFS + 1, data, sizeof(pod->prog_data));
- line6_send_sysex_message(&pod->line6, sysex, size);
- memcpy(&pod->prog_data, data, sizeof(pod->prog_data));
- pod_mark_batch_all_dirty(pod);
- kfree(sysex);
-}
+static const char pod_version_header[] = {
+ 0xf2, 0x7e, 0x7f, 0x06, 0x02
+};
-/*
- Store parameter value in driver memory and mark it as dirty.
-*/
-static void pod_store_parameter(struct usb_line6_pod *pod, int param, int value)
-{
- pod->prog_data.control[param] = value;
- set_bit(param, pod->param_dirty);
- pod->dirty = 1;
-}
+/* forward declarations: */
+static void pod_startup2(unsigned long data);
+static void pod_startup3(struct usb_line6_pod *pod);
-/*
- Handle SAVE button
-*/
-static void pod_save_button_pressed(struct usb_line6_pod *pod, int type, int index)
+static char *pod_alloc_sysex_buffer(struct usb_line6_pod *pod, int code,
+ int size)
{
- pod->dirty = 0;
- set_bit(POD_SAVE_PRESSED, &pod->atomic_flags);
+ return line6_alloc_sysex_buffer(&pod->line6, POD_SYSEX_CODE, code,
+ size);
}
/*
Process a completely received message.
*/
-void pod_process_message(struct usb_line6_pod *pod)
+void line6_pod_process_message(struct usb_line6_pod *pod)
{
const unsigned char *buf = pod->line6.buffer_message;
- /* filter messages by type */
- switch (buf[0] & 0xf0) {
- case LINE6_PARAM_CHANGE:
- case LINE6_PROGRAM_CHANGE:
- case LINE6_SYSEX_BEGIN:
- break; /* handle these further down */
-
- default:
- return; /* ignore all others */
+ 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;
}
- /* process all remaining messages */
- switch (buf[0]) {
- case LINE6_PARAM_CHANGE | LINE6_CHANNEL_DEVICE:
- pod_store_parameter(pod, buf[1], buf[2]);
- /* intentionally no break here! */
-
- case LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST:
- if ((buf[1] == POD_amp_model_setup) ||
- (buf[1] == POD_effect_setup))
- /* these also affect other settings */
- line6_dump_request_async(&pod->dumpreq, &pod->line6, 0);
-
- break;
-
- case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_DEVICE:
- case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST:
- pod->channel_num = buf[1];
- pod->dirty = 0;
- set_bit(POD_CHANNEL_DIRTY, &pod->atomic_flags);
- line6_dump_request_async(&pod->dumpreq, &pod->line6, 0);
- break;
-
- case LINE6_SYSEX_BEGIN | LINE6_CHANNEL_DEVICE:
- case LINE6_SYSEX_BEGIN | LINE6_CHANNEL_UNKNOWN:
- if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) == 0) {
- switch (buf[5]) {
- case POD_SYSEX_DUMP:
- if (pod->line6.message_length == sizeof(pod->prog_data) + 7) {
- switch (pod->dumpreq.in_progress) {
- case LINE6_DUMP_CURRENT:
- memcpy(&pod->prog_data, buf + 7, sizeof(pod->prog_data));
- pod_mark_batch_all_dirty(pod);
- pod->dumpreq.ok = 1;
- break;
-
- case POD_DUMP_MEMORY:
- memcpy(&pod->prog_data_buf, buf + 7, sizeof(pod->prog_data_buf));
- break;
-
- default:
- DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "unknown dump code %02X\n", pod->dumpreq.in_progress));
- }
-
- line6_dump_finished(&pod->dumpreq);
- } else
- DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "wrong size of channel dump message (%d instead of %d)\n",
- pod->line6.message_length, (int)sizeof(pod->prog_data) + 7));
-
- break;
-
- case POD_SYSEX_SYSTEM: {
- short value = ((int)buf[7] << 12) | ((int)buf[8] << 8) | ((int)buf[9] << 4) | (int)buf[10];
-
-#define PROCESS_SYSTEM_PARAM(x) \
- case POD_ ## x: \
- pod->x.value = value; \
- wake_up_interruptible(&pod->x.wait); \
- break;
-
- switch (buf[6]) {
- PROCESS_SYSTEM_PARAM(monitor_level);
- PROCESS_SYSTEM_PARAM(routing);
- PROCESS_SYSTEM_PARAM(tuner_mute);
- PROCESS_SYSTEM_PARAM(tuner_freq);
- PROCESS_SYSTEM_PARAM(tuner_note);
- PROCESS_SYSTEM_PARAM(tuner_pitch);
-
-#undef PROCESS_SYSTEM_PARAM
-
- default:
- DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "unknown tuner/system response %02X\n", buf[6]));
- }
-
- break;
- }
-
- case POD_SYSEX_FINISH:
- /* do we need to respond to this? */
- break;
-
- case POD_SYSEX_SAVE:
- pod_save_button_pressed(pod, buf[6], buf[7]);
- break;
-
- case POD_SYSEX_CLIP:
- DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "audio clipped\n"));
- pod->clipping.value = 1;
- wake_up_interruptible(&pod->clipping.wait);
- break;
-
- case POD_SYSEX_STORE:
- DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "message %02X not yet implemented\n", buf[5]));
- break;
-
- default:
- DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "unknown sysex message %02X\n", buf[5]));
- }
- } else if (memcmp(buf, pod_version_header, sizeof(pod_version_header)) == 0) {
- if (pod->versionreq_ok == 0) {
- pod->firmware_version = buf[13] * 100 + buf[14] * 10 + buf[15];
- pod->device_id = ((int)buf[8] << 16) | ((int)buf[9] << 8) | (int)buf[10];
- pod->versionreq_ok = 1;
-
- /* Now we know the firmware version, so we schedule a bottom half
- handler to create the special files: */
- INIT_WORK(&pod->create_files_work, pod_create_files_work);
- queue_work(line6_workqueue, &pod->create_files_work);
- } else
- DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "multiple firmware version message\n"));
- } else
- DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "unknown sysex header\n"));
-
- break;
-
- case LINE6_SYSEX_END:
- break;
-
- default:
- DEBUG_MESSAGES(dev_err(pod->line6.ifcdev, "POD: unknown message %02X\n", buf[0]));
+ /* 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;
}
-}
-
-/*
- Detect some cases that require a channel dump after sending a command to the
- device. Important notes:
- *) The actual dump request can not be sent here since we are not allowed to
- wait for the completion of the first message in this context, and sending
- the dump request before completion of the previous message leaves the POD
- in an undefined state. The dump request will be sent when the echoed
- commands are received.
- *) This method fails if a param change message is "chopped" after the first
- byte.
-*/
-void pod_midi_postprocess(struct usb_line6_pod *pod, unsigned char *data, int length)
-{
- int i;
-
- if (!pod->midi_postprocess)
+ if (memcmp(buf + 1, line6_midi_id, sizeof(line6_midi_id)) != 0)
return;
- for (i = 0; i < length; ++i) {
- if (data[i] == (LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST)) {
- line6_invalidate_current(&pod->dumpreq);
- break;
- } else if ((data[i] == (LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST)) && (i < length - 1))
- if ((data[i + 1] == POD_amp_model_setup) || (data[i + 1] == POD_effect_setup)) {
- line6_invalidate_current(&pod->dumpreq);
- break;
- }
+ 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 channel number (i.e., switch to a different sound).
-*/
-static void pod_send_channel(struct usb_line6_pod *pod, int value)
-{
- line6_invalidate_current(&pod->dumpreq);
-
- if (line6_send_program(&pod->line6, value) == 0)
- pod->channel_num = value;
- else
- line6_dump_finished(&pod->dumpreq);
-}
-
-/*
Transmit PODxt Pro control parameter.
*/
-void pod_transmit_parameter(struct usb_line6_pod *pod, int param, int value)
-{
- if (line6_transmit_parameter(&pod->line6, param, value) == 0)
- pod_store_parameter(pod, param, value);
-
- if ((param == POD_amp_model_setup) || (param == POD_effect_setup)) /* these also affect other settings */
- line6_invalidate_current(&pod->dumpreq);
-}
-
-/*
- Resolve value to memory location.
-*/
-static void pod_resolve(const char *buf, short block0, short block1, unsigned char *location)
-{
- int value = simple_strtoul(buf, NULL, 10);
- short block = (value < 0x40) ? block0 : block1;
- value &= 0x3f;
- location[0] = block >> 7;
- location[1] = value | (block & 0x7f);
-}
-
-/*
- Send command to store channel/effects setup/amp setup to PODxt Pro.
-*/
-static ssize_t pod_send_store_command(struct device *dev, const char *buf, size_t count, short block0, short block1)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6_pod *pod = usb_get_intfdata(interface);
-
- int size = 3 + sizeof(pod->prog_data_buf);
- char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_STORE, size);
- if (!sysex)
- return 0;
-
- sysex[SYSEX_DATA_OFS] = 5; /* see pod_dump() */
- pod_resolve(buf, block0, block1, sysex + SYSEX_DATA_OFS + 1);
- memcpy(sysex + SYSEX_DATA_OFS + 3, &pod->prog_data_buf, sizeof(pod->prog_data_buf));
-
- line6_send_sysex_message(&pod->line6, sysex, size);
- kfree(sysex);
- /* needs some delay here on AMD64 platform */
- return count;
-}
-
-/*
- Send command to retrieve channel/effects setup/amp setup to PODxt Pro.
-*/
-static ssize_t pod_send_retrieve_command(struct device *dev, const char *buf, size_t count, short block0, short block1)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6_pod *pod = usb_get_intfdata(interface);
- int size = 4;
- char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_DUMPMEM, size);
-
- if (!sysex)
- return 0;
-
- pod_resolve(buf, block0, block1, sysex + SYSEX_DATA_OFS);
- sysex[SYSEX_DATA_OFS + 2] = 0;
- sysex[SYSEX_DATA_OFS + 3] = 0;
- line6_dump_started(&pod->dumpreq, POD_DUMP_MEMORY);
-
- if (line6_send_sysex_message(&pod->line6, sysex, size) < size)
- line6_dump_finished(&pod->dumpreq);
-
- kfree(sysex);
- /* needs some delay here on AMD64 platform */
- return count;
-}
-
-/*
- Generic get name function.
-*/
-static ssize_t get_name_generic(struct usb_line6_pod *pod, const char *str, char *buf)
-{
- int length = 0;
- const char *p1;
- char *p2;
- char *last_non_space = buf;
-
- int retval = line6_wait_dump(&pod->dumpreq, 0);
- if (retval < 0)
- return retval;
-
- for (p1 = str, p2 = buf; *p1; ++p1, ++p2) {
- *p2 = *p1;
- if (*p2 != ' ')
- last_non_space = p2;
- if (++length == POD_NAME_LENGTH)
- break;
- }
-
- *(last_non_space + 1) = '\n';
- return last_non_space - buf + 2;
-}
-
-/*
- "read" request on "channel" special file.
-*/
-static ssize_t pod_get_channel(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->channel_num);
-}
-
-/*
- "write" request on "channel" special file.
-*/
-static ssize_t pod_set_channel(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6_pod *pod = usb_get_intfdata(interface);
- int value = simple_strtoul(buf, NULL, 10);
- pod_send_channel(pod, value);
- return count;
-}
-
-/*
- "read" request on "name" special file.
-*/
-static ssize_t pod_get_name(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 get_name_generic(pod, pod->prog_data.header + POD_NAME_OFFSET, buf);
-}
-
-/*
- "read" request on "name" special file.
-*/
-static ssize_t pod_get_name_buf(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 get_name_generic(pod, pod->prog_data_buf.header + POD_NAME_OFFSET, buf);
-}
-
-/*
- "read" request on "dump" special file.
-*/
-static ssize_t pod_get_dump(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);
- int retval = line6_wait_dump(&pod->dumpreq, 0);
- if (retval < 0)
- return retval;
- memcpy(buf, &pod->prog_data, sizeof(pod->prog_data));
- return sizeof(pod->prog_data);
-}
-
-/*
- "write" request on "dump" special file.
-*/
-static ssize_t pod_set_dump(struct device *dev, struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6_pod *pod = usb_get_intfdata(interface);
-
- if (count != sizeof(pod->prog_data)) {
- dev_err(pod->line6.ifcdev,
- "data block must be exactly %d bytes\n",
- sizeof(pod->prog_data));
- return -EINVAL;
- }
-
- pod_dump(pod, buf);
- return sizeof(pod->prog_data);
-}
-
-/*
- Request system parameter.
- @param tuner non-zero, if code refers to a tuner parameter
-*/
-static ssize_t pod_get_system_param(struct usb_line6_pod *pod, char *buf, int code, struct ValueWait *param, int tuner, int sign)
+void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param,
+ u8 value)
{
- char *sysex;
- int value;
- static const int size = 1;
- int retval = 0;
- DECLARE_WAITQUEUE(wait, current);
-
- if (((pod->prog_data.control[POD_tuner] & 0x40) == 0) && tuner)
- return -ENODEV;
-
- /* send value request to tuner: */
- param->value = POD_system_invalid;
- sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEMREQ, size);
- if (!sysex)
- return 0;
- sysex[SYSEX_DATA_OFS] = code;
- line6_send_sysex_message(&pod->line6, sysex, size);
- kfree(sysex);
-
- /* wait for tuner to respond: */
- add_wait_queue(&param->wait, &wait);
- current->state = TASK_INTERRUPTIBLE;
-
- while (param->value == POD_system_invalid) {
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- } else
- schedule();
- }
-
- current->state = TASK_RUNNING;
- remove_wait_queue(&param->wait, &wait);
-
- if (retval < 0)
- return retval;
-
- value = sign ? (int)(signed short)param->value : (int)(unsigned short)param->value;
- return sprintf(buf, "%d\n", value);
+ line6_transmit_parameter(&pod->line6, param, value);
}
/*
- Send system parameter.
- @param tuner non-zero, if code refers to a tuner parameter
+ Send system parameter (from integer).
*/
-static ssize_t pod_set_system_param(struct usb_line6_pod *pod, const char *buf,
- int count, int code, unsigned short mask,
- int tuner)
+static int pod_set_system_param_int(struct usb_line6_pod *pod, int value,
+ int code)
{
char *sysex;
static const int size = 5;
- unsigned short value;
-
- if (((pod->prog_data.control[POD_tuner] & 0x40) == 0) && tuner)
- return -EINVAL;
- /* send value to tuner: */
sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_SYSTEM, size);
if (!sysex)
- return 0;
- value = simple_strtoul(buf, NULL, 10) & mask;
+ return -ENOMEM;
sysex[SYSEX_DATA_OFS] = code;
sysex[SYSEX_DATA_OFS + 1] = (value >> 12) & 0x0f;
- sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f;
- sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f;
- sysex[SYSEX_DATA_OFS + 4] = (value ) & 0x0f;
+ sysex[SYSEX_DATA_OFS + 2] = (value >> 8) & 0x0f;
+ sysex[SYSEX_DATA_OFS + 3] = (value >> 4) & 0x0f;
+ sysex[SYSEX_DATA_OFS + 4] = (value) & 0x0f;
line6_send_sysex_message(&pod->line6, sysex, size);
kfree(sysex);
- return count;
+ return 0;
}
/*
- "read" request on "dump_buf" special file.
+ "read" request on "serial_number" special file.
*/
-static ssize_t pod_get_dump_buf(struct device *dev,
- struct device_attribute *attr, char *buf)
+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);
- int retval = line6_wait_dump(&pod->dumpreq, 0);
- if (retval < 0)
- return retval;
- memcpy(buf, &pod->prog_data_buf, sizeof(pod->prog_data_buf));
- return sizeof(pod->prog_data_buf);
+
+ return sprintf(buf, "%d\n", pod->serial_number);
}
/*
- "write" request on "dump_buf" special file.
+ "read" request on "firmware_version" special file.
*/
-static ssize_t pod_set_dump_buf(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+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);
- if (count != sizeof(pod->prog_data)) {
- dev_err(pod->line6.ifcdev,
- "data block must be exactly %d bytes\n",
- sizeof(pod->prog_data));
- return -EINVAL;
- }
-
- memcpy(&pod->prog_data_buf, buf, sizeof(pod->prog_data));
- return sizeof(pod->prog_data);
+ return sprintf(buf, "%d.%02d\n", pod->firmware_version / 100,
+ pod->firmware_version % 100);
}
/*
- "write" request on "finish" special file.
+ "read" request on "device_id" special file.
*/
-static ssize_t pod_set_finish(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+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);
- int size = 0;
- char *sysex = pod_alloc_sysex_buffer(pod, POD_SYSEX_FINISH, size);
- if (!sysex)
- return 0;
- line6_send_sysex_message(&pod->line6, sysex, size);
- kfree(sysex);
- return count;
-}
-/*
- "write" request on "store_channel" special file.
-*/
-static ssize_t pod_set_store_channel(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- return pod_send_store_command(dev, buf, count, 0x0000, 0x00c0);
+ return sprintf(buf, "%d\n", pod->device_id);
}
/*
- "write" request on "store_effects_setup" special file.
+ 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 ssize_t pod_set_store_effects_setup(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- return pod_send_store_command(dev, buf, count, 0x0080, 0x0080);
-}
-/*
- "write" request on "store_amp_setup" special file.
-*/
-static ssize_t pod_set_store_amp_setup(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static void pod_startup1(struct usb_line6_pod *pod)
{
- return pod_send_store_command(dev, buf, count, 0x0040, 0x0100);
-}
+ CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_INIT);
-/*
- "write" request on "retrieve_channel" special file.
-*/
-static ssize_t pod_set_retrieve_channel(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- return pod_send_retrieve_command(dev, buf, count, 0x0000, 0x00c0);
+ /* delay startup procedure: */
+ line6_start_timer(&pod->startup_timer, POD_STARTUP_DELAY, pod_startup2,
+ (unsigned long)pod);
}
-/*
- "write" request on "retrieve_effects_setup" special file.
-*/
-static ssize_t pod_set_retrieve_effects_setup(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static void pod_startup2(unsigned long data)
{
- return pod_send_retrieve_command(dev, buf, count, 0x0080, 0x0080);
-}
+ struct usb_line6_pod *pod = (struct usb_line6_pod *)data;
+ struct usb_line6 *line6 = &pod->line6;
-/*
- "write" request on "retrieve_amp_setup" special file.
-*/
-static ssize_t pod_set_retrieve_amp_setup(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- return pod_send_retrieve_command(dev, buf, count, 0x0040, 0x0100);
-}
+ CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_VERSIONREQ);
-/*
- "read" request on "dirty" special file.
-*/
-static ssize_t pod_get_dirty(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);
- buf[0] = pod->dirty ? '1' : '0';
- buf[1] = '\n';
- return 2;
+ /* request firmware version: */
+ line6_version_request_async(line6);
}
-/*
- "read" request on "midi_postprocess" special file.
-*/
-static ssize_t pod_get_midi_postprocess(struct device *dev,
- struct device_attribute *attr,
- char *buf)
+static void pod_startup3(struct usb_line6_pod *pod)
{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6_pod *pod = usb_get_intfdata(interface);
- return sprintf(buf, "%d\n", pod->midi_postprocess);
-}
+ CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_WORKQUEUE);
-/*
- "write" request on "midi_postprocess" special file.
-*/
-static ssize_t pod_set_midi_postprocess(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct usb_interface *interface = to_usb_interface(dev);
- struct usb_line6_pod *pod = usb_get_intfdata(interface);
- int value = simple_strtoul(buf, NULL, 10);
- pod->midi_postprocess = value ? 1 : 0;
- return count;
+ /* schedule work for global work queue: */
+ schedule_work(&pod->startup_work);
}
-/*
- "read" request on "serial_number" special file.
-*/
-static ssize_t pod_get_serial_number(struct device *dev,
- struct device_attribute *attr, char *buf)
+static void pod_startup4(struct work_struct *work)
{
- 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);
-}
+ struct usb_line6_pod *pod =
+ container_of(work, struct usb_line6_pod, startup_work);
+ struct usb_line6 *line6 = &pod->line6;
-/*
- "read" request on "firmware_version" special file.
-*/
-static ssize_t pod_get_firmware_version(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);
-}
+ CHECK_STARTUP_PROGRESS(pod->startup_progress, POD_STARTUP_SETUP);
-/*
- "read" request on "device_id" special file.
-*/
-static ssize_t pod_get_device_id(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);
-}
+ /* serial number: */
+ line6_read_serial_number(&pod->line6, &pod->serial_number);
-/*
- "read" request on "clip" special file.
-*/
-static ssize_t pod_wait_for_clip(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);
- int err = 0;
- DECLARE_WAITQUEUE(wait, current);
- pod->clipping.value = 0;
- add_wait_queue(&pod->clipping.wait, &wait);
- current->state = TASK_INTERRUPTIBLE;
-
- while (pod->clipping.value == 0) {
- if (signal_pending(current)) {
- err = -ERESTARTSYS;
- break;
- } else
- schedule();
- }
-
- current->state = TASK_RUNNING;
- remove_wait_queue(&pod->clipping.wait, &wait);
- return err;
+ /* ALSA audio interface: */
+ line6_register_audio(line6);
}
-#define POD_GET_SYSTEM_PARAM(code, tuner, sign) \
-static ssize_t pod_get_ ## code(struct device *dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct usb_interface *interface = to_usb_interface(dev); \
- struct usb_line6_pod *pod = usb_get_intfdata(interface); \
- return pod_get_system_param(pod, buf, POD_ ## code, &pod->code, \
- tuner, sign); \
+/* 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;
}
-#define POD_GET_SET_SYSTEM_PARAM(code, mask, tuner, sign) \
-POD_GET_SYSTEM_PARAM(code, tuner, sign) \
-static ssize_t pod_set_ ## code(struct device *dev, \
- struct device_attribute *attr, \
- const char *buf, size_t count) \
-{ \
- struct usb_interface *interface = to_usb_interface(dev); \
- struct usb_line6_pod *pod = usb_get_intfdata(interface); \
- return pod_set_system_param(pod, buf, count, POD_ ## code, mask, \
- tuner); \
+/* 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;
}
-POD_GET_SET_SYSTEM_PARAM(monitor_level, 0xffff, 0, 0);
-POD_GET_SET_SYSTEM_PARAM(routing, 0x0003, 0, 0);
-POD_GET_SET_SYSTEM_PARAM(tuner_mute, 0x0001, 1, 0);
-POD_GET_SET_SYSTEM_PARAM(tuner_freq, 0xffff, 1, 0);
-POD_GET_SYSTEM_PARAM(tuner_note, 1, 1);
-POD_GET_SYSTEM_PARAM(tuner_pitch, 1, 1);
+/* 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;
-#undef GET_SET_SYSTEM_PARAM
-#undef GET_SYSTEM_PARAM
+ if (ucontrol->value.integer.value[0] == pod->monitor_level)
+ return 0;
-/* POD special files: */
-static DEVICE_ATTR(channel, S_IWUGO | S_IRUGO, pod_get_channel, pod_set_channel);
-static DEVICE_ATTR(clip, S_IRUGO, pod_wait_for_clip, line6_nop_write);
-static DEVICE_ATTR(device_id, S_IRUGO, pod_get_device_id, line6_nop_write);
-static DEVICE_ATTR(dirty, S_IRUGO, pod_get_dirty, line6_nop_write);
-static DEVICE_ATTR(dump, S_IWUGO | S_IRUGO, pod_get_dump, pod_set_dump);
-static DEVICE_ATTR(dump_buf, S_IWUGO | S_IRUGO, pod_get_dump_buf, pod_set_dump_buf);
-static DEVICE_ATTR(finish, S_IWUGO, line6_nop_read, pod_set_finish);
-static DEVICE_ATTR(firmware_version, S_IRUGO, pod_get_firmware_version, line6_nop_write);
-static DEVICE_ATTR(midi_postprocess, S_IWUGO | S_IRUGO, pod_get_midi_postprocess, pod_set_midi_postprocess);
-static DEVICE_ATTR(monitor_level, S_IWUGO | S_IRUGO, pod_get_monitor_level, pod_set_monitor_level);
-static DEVICE_ATTR(name, S_IRUGO, pod_get_name, line6_nop_write);
-static DEVICE_ATTR(name_buf, S_IRUGO, pod_get_name_buf, line6_nop_write);
-static DEVICE_ATTR(retrieve_amp_setup, S_IWUGO, line6_nop_read, pod_set_retrieve_amp_setup);
-static DEVICE_ATTR(retrieve_channel, S_IWUGO, line6_nop_read, pod_set_retrieve_channel);
-static DEVICE_ATTR(retrieve_effects_setup, S_IWUGO, line6_nop_read, pod_set_retrieve_effects_setup);
-static DEVICE_ATTR(routing, S_IWUGO | S_IRUGO, pod_get_routing, pod_set_routing);
-static DEVICE_ATTR(serial_number, S_IRUGO, pod_get_serial_number, line6_nop_write);
-static DEVICE_ATTR(store_amp_setup, S_IWUGO, line6_nop_read, pod_set_store_amp_setup);
-static DEVICE_ATTR(store_channel, S_IWUGO, line6_nop_read, pod_set_store_channel);
-static DEVICE_ATTR(store_effects_setup, S_IWUGO, line6_nop_read, pod_set_store_effects_setup);
-static DEVICE_ATTR(tuner_freq, S_IWUGO | S_IRUGO, pod_get_tuner_freq, pod_set_tuner_freq);
-static DEVICE_ATTR(tuner_mute, S_IWUGO | S_IRUGO, pod_get_tuner_mute, pod_set_tuner_mute);
-static DEVICE_ATTR(tuner_note, S_IRUGO, pod_get_tuner_note, line6_nop_write);
-static DEVICE_ATTR(tuner_pitch, S_IRUGO, pod_get_tuner_pitch, line6_nop_write);
-
-#if CREATE_RAW_FILE
-static DEVICE_ATTR(raw, S_IWUGO, line6_nop_read, line6_set_raw);
-#endif
+ 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.
@@ -947,19 +336,13 @@ static DEVICE_ATTR(raw, S_IWUGO, line6_nop_read, line6_set_raw);
static void pod_destruct(struct usb_interface *interface)
{
struct usb_line6_pod *pod = usb_get_intfdata(interface);
- struct usb_line6 *line6;
if (pod == NULL)
return;
- line6 = &pod->line6;
- if (line6 == NULL)
- return;
- line6_cleanup_audio(line6);
+ line6_cleanup_audio(&pod->line6);
- /* free dump request data: */
- line6_dumpreq_destruct(&pod->dumpreq);
-
- kfree(pod->buffer_versionreq);
+ del_timer(&pod->startup_timer);
+ cancel_work_sync(&pod->startup_work);
}
/*
@@ -969,132 +352,86 @@ static int pod_create_files2(struct device *dev)
{
int err;
- CHECK_RETURN(device_create_file(dev, &dev_attr_channel));
- CHECK_RETURN(device_create_file(dev, &dev_attr_clip));
CHECK_RETURN(device_create_file(dev, &dev_attr_device_id));
- CHECK_RETURN(device_create_file(dev, &dev_attr_dirty));
- CHECK_RETURN(device_create_file(dev, &dev_attr_dump));
- CHECK_RETURN(device_create_file(dev, &dev_attr_dump_buf));
- CHECK_RETURN(device_create_file(dev, &dev_attr_finish));
CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version));
- CHECK_RETURN(device_create_file(dev, &dev_attr_midi_postprocess));
- CHECK_RETURN(device_create_file(dev, &dev_attr_monitor_level));
- CHECK_RETURN(device_create_file(dev, &dev_attr_name));
- CHECK_RETURN(device_create_file(dev, &dev_attr_name_buf));
- CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_amp_setup));
- CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_channel));
- CHECK_RETURN(device_create_file(dev, &dev_attr_retrieve_effects_setup));
- CHECK_RETURN(device_create_file(dev, &dev_attr_routing));
CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number));
- CHECK_RETURN(device_create_file(dev, &dev_attr_store_amp_setup));
- CHECK_RETURN(device_create_file(dev, &dev_attr_store_channel));
- CHECK_RETURN(device_create_file(dev, &dev_attr_store_effects_setup));
- CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_freq));
- CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_mute));
- CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_note));
- CHECK_RETURN(device_create_file(dev, &dev_attr_tuner_pitch));
-
-#if CREATE_RAW_FILE
- CHECK_RETURN(device_create_file(dev, &dev_attr_raw));
-#endif
-
return 0;
}
/*
- Init POD device.
+ Try to init POD device.
*/
-int pod_init(struct usb_interface *interface, struct usb_line6_pod *pod)
+static int pod_try_init(struct usb_interface *interface,
+ struct usb_line6_pod *pod)
{
int err;
struct usb_line6 *line6 = &pod->line6;
+ init_timer(&pod->startup_timer);
+ INIT_WORK(&pod->startup_work, pod_startup4);
+
if ((interface == NULL) || (pod == NULL))
return -ENODEV;
- pod->channel_num = 255;
-
- /* initialize wait queues: */
- init_waitqueue_head(&pod->monitor_level.wait);
- init_waitqueue_head(&pod->routing.wait);
- init_waitqueue_head(&pod->tuner_mute.wait);
- init_waitqueue_head(&pod->tuner_freq.wait);
- init_waitqueue_head(&pod->tuner_note.wait);
- init_waitqueue_head(&pod->tuner_pitch.wait);
- init_waitqueue_head(&pod->clipping.wait);
-
- memset(pod->param_dirty, 0xff, sizeof(pod->param_dirty));
-
- /* initialize USB buffers: */
- err = line6_dumpreq_init(&pod->dumpreq, pod_request_channel,
- sizeof(pod_request_channel));
- if (err < 0) {
- dev_err(&interface->dev, "Out of memory\n");
- pod_destruct(interface);
- return -ENOMEM;
- }
-
- pod->buffer_versionreq = kmalloc(sizeof(pod_request_version),
- GFP_KERNEL);
-
- if (pod->buffer_versionreq == NULL) {
- dev_err(&interface->dev, "Out of memory\n");
- pod_destruct(interface);
- return -ENOMEM;
- }
-
- memcpy(pod->buffer_versionreq, pod_request_version,
- sizeof(pod_request_version));
-
/* create sysfs entries: */
err = pod_create_files2(&interface->dev);
- if (err < 0) {
- pod_destruct(interface);
+ if (err < 0)
return err;
- }
/* initialize audio system: */
err = line6_init_audio(line6);
- if (err < 0) {
- pod_destruct(interface);
+ if (err < 0)
return err;
- }
/* initialize MIDI subsystem: */
err = line6_init_midi(line6);
- if (err < 0) {
- pod_destruct(interface);
+ if (err < 0)
return err;
- }
/* initialize PCM subsystem: */
err = line6_init_pcm(line6, &pod_pcm_properties);
- if (err < 0) {
- pod_destruct(interface);
+ if (err < 0)
return err;
- }
- /* register audio system: */
- err = line6_register_audio(line6);
- if (err < 0) {
- pod_destruct(interface);
+ /* register monitor control: */
+ err = snd_ctl_add(line6->card,
+ snd_ctl_new1(&pod_control_monitor, line6->line6pcm));
+ if (err < 0)
return err;
- }
+
+ /*
+ When the sound card is registered at this point, the PODxt Live
+ displays "Invalid Code Error 07", so we do it later in the event
+ handler.
+ */
if (pod->line6.properties->capabilities & LINE6_BIT_CONTROL) {
- /* query some data: */
- line6_startup_delayed(&pod->dumpreq, POD_STARTUP_DELAY,
- pod_startup_timeout, pod);
- line6_read_serial_number(&pod->line6, &pod->serial_number);
+ pod->monitor_level = POD_SYSTEM_INVALID;
+
+ /* initiate startup procedure: */
+ pod_startup1(pod);
}
return 0;
}
/*
+ Init POD device (and clean up in case of failure).
+*/
+int line6_pod_init(struct usb_interface *interface, struct usb_line6_pod *pod)
+{
+ int err = pod_try_init(interface, pod);
+
+ if (err < 0)
+ pod_destruct(interface);
+
+ return err;
+}
+
+/*
POD device disconnected.
*/
-void pod_disconnect(struct usb_interface *interface)
+void line6_pod_disconnect(struct usb_interface *interface)
{
struct usb_line6_pod *pod;
@@ -1106,44 +443,14 @@ void pod_disconnect(struct usb_interface *interface)
struct snd_line6_pcm *line6pcm = pod->line6.line6pcm;
struct device *dev = &interface->dev;
- if (line6pcm != NULL) {
- unlink_wait_clear_audio_out_urbs(line6pcm);
- unlink_wait_clear_audio_in_urbs(line6pcm);
- }
+ if (line6pcm != NULL)
+ line6_pcm_disconnect(line6pcm);
if (dev != NULL) {
/* remove sysfs entries: */
- if (pod->versionreq_ok)
- pod_remove_files(pod->firmware_version, pod->line6.properties->device_bit, dev);
-
- device_remove_file(dev, &dev_attr_channel);
- device_remove_file(dev, &dev_attr_clip);
device_remove_file(dev, &dev_attr_device_id);
- device_remove_file(dev, &dev_attr_dirty);
- device_remove_file(dev, &dev_attr_dump);
- device_remove_file(dev, &dev_attr_dump_buf);
- device_remove_file(dev, &dev_attr_finish);
device_remove_file(dev, &dev_attr_firmware_version);
- device_remove_file(dev, &dev_attr_midi_postprocess);
- device_remove_file(dev, &dev_attr_monitor_level);
- device_remove_file(dev, &dev_attr_name);
- device_remove_file(dev, &dev_attr_name_buf);
- device_remove_file(dev, &dev_attr_retrieve_amp_setup);
- device_remove_file(dev, &dev_attr_retrieve_channel);
- device_remove_file(dev, &dev_attr_retrieve_effects_setup);
- device_remove_file(dev, &dev_attr_routing);
device_remove_file(dev, &dev_attr_serial_number);
- device_remove_file(dev, &dev_attr_store_amp_setup);
- device_remove_file(dev, &dev_attr_store_channel);
- device_remove_file(dev, &dev_attr_store_effects_setup);
- device_remove_file(dev, &dev_attr_tuner_freq);
- device_remove_file(dev, &dev_attr_tuner_mute);
- device_remove_file(dev, &dev_attr_tuner_note);
- device_remove_file(dev, &dev_attr_tuner_pitch);
-
-#if CREATE_RAW_FILE
- device_remove_file(dev, &dev_attr_raw);
-#endif
}
}
diff --git a/drivers/staging/line6/pod.h b/drivers/staging/line6/pod.h
index 7051ca61381..3e3f1671337 100644
--- a/drivers/staging/line6/pod.h
+++ b/drivers/staging/line6/pod.h
@@ -1,7 +1,7 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -12,18 +12,13 @@
#ifndef POD_H
#define POD_H
-
-#include "driver.h"
-
+#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/usb.h>
-#include <linux/wait.h>
-#include <linux/workqueue.h>
#include <sound/core.h>
-#include "dumprequest.h"
-
+#include "driver.h"
/*
PODxt Live interfaces
@@ -42,163 +37,66 @@
*/
#define POD_CONTROL_SIZE 0x80
#define POD_BUFSIZE_DUMPREQ 7
-#define POD_STARTUP_DELAY 3
-
-
-/**
- Data structure for values that need to be requested explicitly.
- This is the case for system and tuner settings.
-*/
-struct ValueWait {
- unsigned short value;
- wait_queue_head_t wait;
-};
+#define POD_STARTUP_DELAY 1000
-/**
- Binary PodXT Pro program dump
+/*
+ Stages of POD startup procedure
*/
-struct pod_program {
- /**
- Header information (including program name).
- */
- unsigned char header[0x20];
-
- /**
- Program parameters.
- */
- unsigned char control[POD_CONTROL_SIZE];
+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.
+ Generic Line6 USB data.
*/
struct usb_line6 line6;
/**
- Dump request structure.
- */
- struct line6_dump_request dumpreq;
-
- /**
- Current program number.
- */
- unsigned char channel_num;
-
- /**
- Current program settings.
- */
- struct pod_program prog_data;
-
- /**
- Buffer for data retrieved from or to be stored on PODxt Pro.
- */
- struct pod_program prog_data_buf;
-
- /**
- Buffer for requesting version number.
- */
- unsigned char *buffer_versionreq;
-
- /**
- Tuner mute mode.
- */
- struct ValueWait tuner_mute;
-
- /**
- Tuner base frequency (typically 440Hz).
- */
- struct ValueWait tuner_freq;
-
- /**
- Note received from tuner.
- */
- struct ValueWait tuner_note;
-
- /**
- Pitch value received from tuner.
+ Instrument monitor level.
*/
- struct ValueWait tuner_pitch;
+ int monitor_level;
/**
- Instrument monitor level.
+ Timer for device initializaton.
*/
- struct ValueWait monitor_level;
+ struct timer_list startup_timer;
/**
- Audio routing mode.
- 0: send processed guitar
- 1: send clean guitar
- 2: send clean guitar re-amp playback
- 3: send re-amp playback
+ Work handler for device initializaton.
*/
- struct ValueWait routing;
+ struct work_struct startup_work;
/**
- Wait for audio clipping event.
+ Current progress in startup procedure.
*/
- struct ValueWait clipping;
+ int startup_progress;
/**
- Bottom-half for creation of sysfs special files.
- */
- struct work_struct create_files_work;
-
- /**
- Dirty flags for access to parameter data.
- */
- unsigned long param_dirty[POD_CONTROL_SIZE / sizeof(unsigned long)];
-
- /**
- Some atomic flags.
- */
- unsigned long atomic_flags;
-
- /**
- Counter for startup process.
- */
- int startup_count;
-
- /**
- Serial number of device.
+ Serial number of device.
*/
int serial_number;
/**
- Firmware version (x 100).
+ Firmware version (x 100).
*/
int firmware_version;
/**
- Device ID.
+ Device ID.
*/
int device_id;
-
- /**
- Flag to indicate modification of current program settings.
- */
- char dirty;
-
- /**
- Flag if initial firmware version request has been successful.
- */
- char versionreq_ok;
-
- /**
- Flag to enable MIDI postprocessing.
- */
- char midi_postprocess;
};
-
-extern void pod_disconnect(struct usb_interface *interface);
-extern int pod_init(struct usb_interface *interface, struct usb_line6_pod *pod);
-extern void pod_midi_postprocess(struct usb_line6_pod *pod,
- unsigned char *data, int length);
-extern void pod_process_message(struct usb_line6_pod *pod);
-extern void pod_receive_parameter(struct usb_line6_pod *pod, int param);
-extern void pod_transmit_parameter(struct usb_line6_pod *pod, int param,
- int value);
-
+extern void line6_pod_disconnect(struct usb_interface *interface);
+extern int line6_pod_init(struct usb_interface *interface,
+ struct usb_line6_pod *pod);
+extern void line6_pod_process_message(struct usb_line6_pod *pod);
+extern void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param,
+ u8 value);
#endif
diff --git a/drivers/staging/line6/podhd.c b/drivers/staging/line6/podhd.c
new file mode 100644
index 00000000000..7ef45437b4f
--- /dev/null
+++ b/drivers/staging/line6/podhd.c
@@ -0,0 +1,154 @@
+/*
+ * 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);
+}
+
+/*
+ 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;
+
+ /* 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_podhd *podhd)
+{
+ int err = podhd_try_init(interface, podhd);
+
+ if (err < 0)
+ podhd_destruct(interface);
+
+ return err;
+}
+
+/*
+ POD HD device disconnected.
+*/
+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);
+}
diff --git a/drivers/staging/line6/podhd.h b/drivers/staging/line6/podhd.h
new file mode 100644
index 00000000000..652f74056bb
--- /dev/null
+++ b/drivers/staging/line6/podhd.h
@@ -0,0 +1,30 @@
+/*
+ * 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 void line6_podhd_disconnect(struct usb_interface *interface);
+extern int line6_podhd_init(struct usb_interface *interface,
+ struct usb_line6_podhd *podhd);
+
+#endif /* PODHD_H */
diff --git a/drivers/staging/line6/revision.h b/drivers/staging/line6/revision.h
index b2a0a85efe6..b4eee2b7383 100644
--- a/drivers/staging/line6/revision.h
+++ b/drivers/staging/line6/revision.h
@@ -1,4 +1,4 @@
#ifndef DRIVER_REVISION
/* current subversion revision */
-#define DRIVER_REVISION " (revision 529)"
+#define DRIVER_REVISION " (904)"
#endif
diff --git a/drivers/staging/line6/toneport.c b/drivers/staging/line6/toneport.c
index eaa1229002a..69437158d38 100644
--- a/drivers/staging/line6/toneport.c
+++ b/drivers/staging/line6/toneport.c
@@ -1,7 +1,7 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
* Emil Myhrman (emil.myhrman@gmail.com)
*
* This program is free software; you can redistribute it and/or
@@ -10,16 +10,18 @@
*
*/
-#include "driver.h"
+#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,
@@ -29,47 +31,50 @@ static struct snd_ratden toneport_ratden = {
};
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 |
- 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 = 180 * 4,
- .period_bytes_max = 8192,
- .periods_min = 1,
- .periods_max = 1024
- },
- .snd_line6_capture_hw = {
- .info = (SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_SYNC_START),
- .formats = SNDRV_PCM_FMTBIT_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 = 188 * 4,
- .period_bytes_max = 8192,
- .periods_min = 1,
- .periods_max = 1024
- },
+ .snd_line6_playback_hw = {
+ .info = (SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_PAUSE |
+#ifdef CONFIG_PM
+ SNDRV_PCM_INFO_RESUME |
+#endif
+ SNDRV_PCM_INFO_SYNC_START),
+ .formats = SNDRV_PCM_FMTBIT_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
- },
+ .nrats = 1,
+ .rats = &toneport_ratden},
.bytes_per_frame = 4
};
@@ -82,6 +87,24 @@ static struct line6_pcm_properties toneport_pcm_properties = {
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(short product)
+{
+ return
+ (product == LINE6_DEVID_GUITARPORT) ||
+ (product == LINE6_DEVID_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);
@@ -101,8 +124,12 @@ static ssize_t toneport_set_led_red(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- char *c;
- led_red = simple_strtol(buf, &c, 10);
+ int retval;
+
+ retval = kstrtoint(buf, 10, &led_red);
+ if (retval)
+ return retval;
+
toneport_update_led(dev);
return count;
}
@@ -111,15 +138,20 @@ static ssize_t toneport_set_led_green(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
- char *c;
- led_green = simple_strtol(buf, &c, 10);
+ int retval;
+
+ retval = kstrtoint(buf, 10, &led_green);
+ if (retval)
+ return retval;
+
toneport_update_led(dev);
return count;
}
-static DEVICE_ATTR(led_red, S_IWUGO | S_IRUGO, line6_nop_read, toneport_set_led_red);
-static DEVICE_ATTR(led_green, S_IWUGO | S_IRUGO, line6_nop_read, toneport_set_led_green);
-
+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)
{
@@ -130,100 +162,287 @@ static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2)
cmd1, cmd2, NULL, 0, LINE6_TIMEOUT * HZ);
if (ret < 0) {
- err("send failed (error %d)\n", ret);
+ 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);
- struct usb_line6 *line6;
if (toneport == NULL)
return;
- line6 = &toneport->line6;
- if (line6 == NULL)
- return;
- line6_cleanup_audio(line6);
+ line6_cleanup_audio(&toneport->line6);
}
/*
- Init Toneport device.
+ Setup Toneport device.
*/
-int toneport_init(struct usb_interface *interface,
- struct usb_line6_toneport *toneport)
+static void toneport_setup(struct usb_line6_toneport *toneport)
{
- int err, ticks;
+ int ticks;
struct usb_line6 *line6 = &toneport->line6;
- struct usb_device *usbdev;
+ struct usb_device *usbdev = line6->usbdev;
+ u16 idProduct = le16_to_cpu(usbdev->descriptor.idProduct);
+
+ /* 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 (le16_to_cpu(usbdev->descriptor.idProduct)) {
+ case LINE6_DEVID_TONEPORT_UX1:
+ case LINE6_DEVID_TONEPORT_UX2:
+ case LINE6_DEVID_PODSTUDIO_UX1:
+ case LINE6_DEVID_PODSTUDIO_UX2:
+ toneport_send_cmd(usbdev,
+ toneport_source_info[toneport->source].code,
+ 0x0000);
+ }
+
+ if (toneport_has_led(idProduct))
+ toneport_update_led(&usbdev->dev);
+}
+
+/*
+ Try to init Toneport device.
+*/
+static int toneport_try_init(struct usb_interface *interface,
+ struct usb_line6_toneport *toneport)
+{
+ int err;
+ struct usb_line6 *line6 = &toneport->line6;
+ struct usb_device *usbdev = line6->usbdev;
+ u16 idProduct = le16_to_cpu(usbdev->descriptor.idProduct);
if ((interface == NULL) || (toneport == NULL))
return -ENODEV;
/* initialize audio system: */
err = line6_init_audio(line6);
- if (err < 0) {
- toneport_destruct(interface);
+ if (err < 0)
return err;
- }
/* initialize PCM subsystem: */
err = line6_init_pcm(line6, &toneport_pcm_properties);
- if (err < 0) {
- toneport_destruct(interface);
+ 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 (le16_to_cpu(usbdev->descriptor.idProduct)) {
+ case LINE6_DEVID_TONEPORT_UX1:
+ case LINE6_DEVID_TONEPORT_UX2:
+ case LINE6_DEVID_PODSTUDIO_UX1:
+ case LINE6_DEVID_PODSTUDIO_UX2:
+ err =
+ snd_ctl_add(line6->card,
+ snd_ctl_new1(&toneport_control_source,
+ line6->line6pcm));
+ if (err < 0)
+ return err;
}
/* register audio system: */
err = line6_register_audio(line6);
- if (err < 0) {
- toneport_destruct(interface);
+ if (err < 0)
return err;
- }
- usbdev = line6->usbdev;
line6_read_serial_number(line6, &toneport->serial_number);
line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1);
- /* sync time on device with host: */
- ticks = (int)get_seconds();
- line6_write_data(line6, 0x80c6, &ticks, 4);
+ if (toneport_has_led(idProduct)) {
+ CHECK_RETURN(device_create_file
+ (&interface->dev, &dev_attr_led_red));
+ CHECK_RETURN(device_create_file
+ (&interface->dev, &dev_attr_led_green));
+ }
- /*
- seems to work without the first two...
- */
- /* toneport_send_cmd(usbdev, 0x0201, 0x0002); */
- /* toneport_send_cmd(usbdev, 0x0801, 0x0000); */
- /* only one that works for me; on GP, TP might be different? */
- toneport_send_cmd(usbdev, 0x0301, 0x0000);
+ toneport_setup(toneport);
- if (usbdev->descriptor.idProduct != LINE6_DEVID_GUITARPORT) {
- CHECK_RETURN(device_create_file(&interface->dev, &dev_attr_led_red));
- CHECK_RETURN(device_create_file(&interface->dev, &dev_attr_led_green));
- toneport_update_led(&usbdev->dev);
- }
+ 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_toneport *toneport)
+{
+ int err = toneport_try_init(interface, toneport);
+
+ 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);
+}
+
+/*
Toneport device disconnected.
*/
-void toneport_disconnect(struct usb_interface *interface)
+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->line6.usbdev->descriptor.idProduct != LINE6_DEVID_GUITARPORT) {
+ if (toneport_has_led(idProduct)) {
device_remove_file(&interface->dev, &dev_attr_led_red);
device_remove_file(&interface->dev, &dev_attr_led_green);
}
@@ -232,8 +451,8 @@ void toneport_disconnect(struct usb_interface *interface)
struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm;
if (line6pcm != NULL) {
- unlink_wait_clear_audio_out_urbs(line6pcm);
- unlink_wait_clear_audio_in_urbs(line6pcm);
+ line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
+ line6_pcm_disconnect(line6pcm);
}
}
diff --git a/drivers/staging/line6/toneport.h b/drivers/staging/line6/toneport.h
index bddc58dd7e3..8576b726364 100644
--- a/drivers/staging/line6/toneport.h
+++ b/drivers/staging/line6/toneport.h
@@ -1,7 +1,7 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -12,34 +12,41 @@
#ifndef TONEPORT_H
#define TONEPORT_H
-
-#include "driver.h"
-
#include <linux/usb.h>
#include <sound/core.h>
+#include "driver.h"
struct usb_line6_toneport {
/**
- Generic Line6 USB data.
+ Generic Line6 USB data.
*/
struct usb_line6 line6;
/**
- Serial number of device.
+ Source selector.
+ */
+ int source;
+
+ /**
+ Serial number of device.
*/
int serial_number;
/**
- Firmware version (x 100).
+ Firmware version (x 100).
*/
int firmware_version;
-};
-
-extern void toneport_disconnect(struct usb_interface *interface);
-extern int toneport_init(struct usb_interface *interface,
- struct usb_line6_toneport *toneport);
+ /**
+ Timer for delayed PCM startup.
+ */
+ struct timer_list timer;
+};
+extern void line6_toneport_disconnect(struct usb_interface *interface);
+extern int line6_toneport_init(struct usb_interface *interface,
+ struct usb_line6_toneport *toneport);
+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
index c38f31f2f42..2d1cc472bea 100644
--- a/drivers/staging/line6/usbdefs.h
+++ b/drivers/staging/line6/usbdefs.h
@@ -1,5 +1,5 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
* Copyright (C) 2005-2008 Markus Grabner (grabner@icg.tugraz.at)
*
@@ -12,7 +12,6 @@
#ifndef USBDEFS_H
#define USBDEFS_H
-
#define LINE6_VENDOR_ID 0x0e41
#define USB_INTERVALS_PER_SECOND 1000
@@ -25,6 +24,12 @@
#define LINE6_DEVID_BASSPODXTPRO 0x4252
#define LINE6_DEVID_GUITARPORT 0x4750
#define LINE6_DEVID_POCKETPOD 0x5051
+#define LINE6_DEVID_PODHD300 0x5057
+#define LINE6_DEVID_PODHD400 0x5058
+#define LINE6_DEVID_PODHD500 0x414D
+#define LINE6_DEVID_PODSTUDIO_GX 0x4153
+#define LINE6_DEVID_PODSTUDIO_UX1 0x4150
+#define LINE6_DEVID_PODSTUDIO_UX2 0x4151
#define LINE6_DEVID_PODX3 0x414a
#define LINE6_DEVID_PODX3LIVE 0x414b
#define LINE6_DEVID_PODXT 0x5044
@@ -35,40 +40,77 @@
#define LINE6_DEVID_TONEPORT_UX2 0x4142
#define LINE6_DEVID_VARIAX 0x534d
-#define LINE6_BIT_BASSPODXT (1 << 0)
-#define LINE6_BIT_BASSPODXTLIVE (1 << 1)
-#define LINE6_BIT_BASSPODXTPRO (1 << 2)
-#define LINE6_BIT_GUITARPORT (1 << 3)
-#define LINE6_BIT_POCKETPOD (1 << 4)
-#define LINE6_BIT_PODX3 (1 << 5)
-#define LINE6_BIT_PODX3LIVE (1 << 6)
-#define LINE6_BIT_PODXT (1 << 7)
-#define LINE6_BIT_PODXTLIVE (1 << 8)
-#define LINE6_BIT_PODXTPRO (1 << 9)
-#define LINE6_BIT_TONEPORT_GX (1 << 10)
-#define LINE6_BIT_TONEPORT_UX1 (1 << 11)
-#define LINE6_BIT_TONEPORT_UX2 (1 << 12)
-#define LINE6_BIT_VARIAX (1 << 13)
+#define LINE6_BIT(x) LINE6_BIT_ ## x = 1 << LINE6_INDEX_ ## x
+
+enum {
+ LINE6_INDEX_BASSPODXT,
+ LINE6_INDEX_BASSPODXTLIVE,
+ LINE6_INDEX_BASSPODXTPRO,
+ LINE6_INDEX_GUITARPORT,
+ LINE6_INDEX_POCKETPOD,
+ LINE6_INDEX_PODHD300,
+ LINE6_INDEX_PODHD400,
+ LINE6_INDEX_PODHD500,
+ LINE6_INDEX_PODSTUDIO_GX,
+ LINE6_INDEX_PODSTUDIO_UX1,
+ LINE6_INDEX_PODSTUDIO_UX2,
+ LINE6_INDEX_PODX3,
+ LINE6_INDEX_PODX3LIVE,
+ LINE6_INDEX_PODXT,
+ LINE6_INDEX_PODXTLIVE,
+ LINE6_INDEX_PODXTPRO,
+ LINE6_INDEX_TONEPORT_GX,
+ LINE6_INDEX_TONEPORT_UX1,
+ LINE6_INDEX_TONEPORT_UX2,
+ LINE6_INDEX_VARIAX,
-#define LINE6_BITS_PRO (LINE6_BIT_BASSPODXTPRO | \
- LINE6_BIT_PODXTPRO)
-#define LINE6_BITS_LIVE (LINE6_BIT_BASSPODXTLIVE | \
- LINE6_BIT_PODXTLIVE | \
- LINE6_BIT_PODX3LIVE)
-#define LINE6_BITS_PODXTALL (LINE6_BIT_PODXT | \
- LINE6_BIT_PODXTLIVE | \
- LINE6_BIT_PODXTPRO)
-#define LINE6_BITS_BASSPODXTALL (LINE6_BIT_BASSPODXT | \
- LINE6_BIT_BASSPODXTLIVE | \
- LINE6_BIT_BASSPODXTPRO)
+ LINE6_BIT(BASSPODXT),
+ LINE6_BIT(BASSPODXTLIVE),
+ LINE6_BIT(BASSPODXTPRO),
+ LINE6_BIT(GUITARPORT),
+ LINE6_BIT(POCKETPOD),
+ LINE6_BIT(PODHD300),
+ LINE6_BIT(PODHD400),
+ LINE6_BIT(PODHD500),
+ LINE6_BIT(PODSTUDIO_GX),
+ LINE6_BIT(PODSTUDIO_UX1),
+ LINE6_BIT(PODSTUDIO_UX2),
+ LINE6_BIT(PODX3),
+ LINE6_BIT(PODX3LIVE),
+ LINE6_BIT(PODXT),
+ LINE6_BIT(PODXTLIVE),
+ LINE6_BIT(PODXTPRO),
+ LINE6_BIT(TONEPORT_GX),
+ LINE6_BIT(TONEPORT_UX1),
+ LINE6_BIT(TONEPORT_UX2),
+ LINE6_BIT(VARIAX),
+
+ LINE6_BITS_PRO = LINE6_BIT_BASSPODXTPRO | LINE6_BIT_PODXTPRO,
+ LINE6_BITS_LIVE = LINE6_BIT_BASSPODXTLIVE | LINE6_BIT_PODXTLIVE |
+ LINE6_BIT_PODX3LIVE,
+ LINE6_BITS_PODXTALL = LINE6_BIT_PODXT | LINE6_BIT_PODXTLIVE |
+ LINE6_BIT_PODXTPRO,
+ LINE6_BITS_PODX3ALL = LINE6_BIT_PODX3 | LINE6_BIT_PODX3LIVE,
+ LINE6_BITS_PODHDALL = LINE6_BIT_PODHD300 |
+ LINE6_BIT_PODHD400 |
+ LINE6_BIT_PODHD500,
+ LINE6_BITS_BASSPODXTALL = LINE6_BIT_BASSPODXT |
+ LINE6_BIT_BASSPODXTLIVE |
+ LINE6_BIT_BASSPODXTPRO
+};
/* device supports settings parameter via USB */
-#define LINE6_BIT_CONTROL (1 << 0)
+#define LINE6_BIT_CONTROL (1 << 0)
/* device supports PCM input/output via USB */
-#define LINE6_BIT_PCM (1 << 1)
-#define LINE6_BIT_CONTROL_PCM (LINE6_BIT_CONTROL | LINE6_BIT_PCM)
+#define LINE6_BIT_PCM (1 << 1)
+/* device support hardware monitoring */
+#define LINE6_BIT_HWMON (1 << 2)
+
+#define LINE6_BIT_CTRL_PCM_HW (LINE6_BIT_CONTROL | \
+ LINE6_BIT_PCM | \
+ LINE6_BIT_HWMON)
-#define LINE6_FALLBACK_INTERVAL 10
-#define LINE6_FALLBACK_MAXPACKETSIZE 16
+#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
index f9d96984733..ae2be99f9a9 100644
--- a/drivers/staging/line6/variax.c
+++ b/drivers/staging/line6/variax.c
@@ -1,7 +1,7 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -9,538 +9,227 @@
*
*/
-#include "driver.h"
+#include <linux/slab.h>
#include "audio.h"
-#include "control.h"
+#include "driver.h"
#include "variax.h"
-
-#define VARIAX_SYSEX_CODE 7
-#define VARIAX_SYSEX_PARAM 0x3b
-#define VARIAX_SYSEX_ACTIVATE 0x2a
-#define VARIAX_MODEL_HEADER_LENGTH 7
-#define VARIAX_MODEL_MESSAGE_LENGTH 199
#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
};
-static const char variax_request_bank[] = {
- 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x6d, 0xf7
-};
-static const char variax_request_model1[] = {
- 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x3c, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x05, 0x03,
- 0x00, 0x00, 0x00, 0xf7
-};
-static const char variax_request_model2[] = {
- 0xf0, 0x00, 0x01, 0x0c, 0x07, 0x00, 0x3c, 0x00,
- 0x02, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x03,
- 0x00, 0x00, 0x00, 0xf7
-};
+/* forward declarations: */
+static void variax_startup2(unsigned long data);
+static void variax_startup4(unsigned long data);
+static void variax_startup5(unsigned long data);
-/*
- Decode data transmitted by workbench.
-*/
-static void variax_decode(const unsigned char *raw_data, unsigned char *data,
- int raw_size)
-{
- for (; raw_size > 0; raw_size -= 6) {
- data[2] = raw_data[0] | (raw_data[1] << 4);
- data[1] = raw_data[2] | (raw_data[3] << 4);
- data[0] = raw_data[4] | (raw_data[5] << 4);
- raw_data += 6;
- data += 3;
- }
-}
-
-static void variax_activate_timeout(unsigned long arg)
+static void variax_activate_async(struct usb_line6_variax *variax, int a)
{
- struct usb_line6_variax *variax = (struct usb_line6_variax *)arg;
- variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = 1;
+ variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = a;
line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
sizeof(variax_activate));
}
/*
- Send an asynchronous activation request after a given interval.
+ 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_activate_delayed(struct usb_line6_variax *variax,
- int seconds)
-{
- variax->activate_timer.expires = jiffies + seconds * HZ;
- variax->activate_timer.function = variax_activate_timeout;
- variax->activate_timer.data = (unsigned long)variax;
- add_timer(&variax->activate_timer);
-}
-
-static void variax_startup_timeout(unsigned long arg)
-{
- struct usb_line6_variax *variax = (struct usb_line6_variax *)arg;
-
- if (variax->dumpreq.ok)
- return;
- line6_dump_request_async(&variax->dumpreq, &variax->line6, 0);
- line6_startup_delayed(&variax->dumpreq, 1, variax_startup_timeout,
- variax);
-}
-
-/*
- Process a completely received message.
-*/
-void variax_process_message(struct usb_line6_variax *variax)
+static void variax_startup1(struct usb_line6_variax *variax)
{
- const unsigned char *buf = variax->line6.buffer_message;
-
- switch (buf[0]) {
- case LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST:
- switch (buf[1]) {
- case VARIAXMIDI_volume:
- variax->volume = buf[2];
- break;
-
- case VARIAXMIDI_tone:
- variax->tone = buf[2];
- }
-
- break;
-
- case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_DEVICE:
- case LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST:
- variax->model = buf[1];
- line6_dump_request_async(&variax->dumpreq, &variax->line6, 0);
- break;
-
- case LINE6_RESET:
- dev_info(variax->line6.ifcdev, "VARIAX reset\n");
- variax_activate_delayed(variax, VARIAX_ACTIVATE_DELAY);
- break;
-
- case LINE6_SYSEX_BEGIN:
- if (memcmp(buf + 1, variax_request_model1 + 1,
- VARIAX_MODEL_HEADER_LENGTH - 1) == 0) {
- if (variax->line6.message_length ==
- VARIAX_MODEL_MESSAGE_LENGTH) {
- switch (variax->dumpreq.in_progress) {
- case VARIAX_DUMP_PASS1:
- variax_decode(buf + VARIAX_MODEL_HEADER_LENGTH, (unsigned char *)&variax->model_data,
- (sizeof(variax->model_data.name) + sizeof(variax->model_data.control) / 2) * 2);
- line6_dump_request_async(&variax->dumpreq, &variax->line6, 1);
- line6_dump_started(&variax->dumpreq, VARIAX_DUMP_PASS2);
- break;
-
- case VARIAX_DUMP_PASS2:
- /* model name is transmitted twice, so skip it here: */
- variax_decode(buf + VARIAX_MODEL_HEADER_LENGTH,
- (unsigned char *)&variax->model_data.control + sizeof(variax->model_data.control) / 2,
- sizeof(variax->model_data.control) / 2 * 2);
- variax->dumpreq.ok = 1;
- line6_dump_request_async(&variax->dumpreq, &variax->line6, 2);
- line6_dump_started(&variax->dumpreq, VARIAX_DUMP_PASS3);
- }
- } else {
- DEBUG_MESSAGES(dev_err(variax->line6.ifcdev, "illegal length %d of model data\n", variax->line6.message_length));
- line6_dump_finished(&variax->dumpreq);
- }
- } else if (memcmp(buf + 1, variax_request_bank + 1,
- sizeof(variax_request_bank) - 2) == 0) {
- memcpy(variax->bank,
- buf + sizeof(variax_request_bank) - 1,
- sizeof(variax->bank));
- variax->dumpreq.ok = 1;
- line6_dump_finished(&variax->dumpreq);
- }
-
- break;
-
- case LINE6_SYSEX_END:
- break;
-
- default:
- DEBUG_MESSAGES(dev_err(variax->line6.ifcdev, "Variax: unknown message %02X\n", buf[0]));
- }
-}
+ CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_INIT);
-/*
- "read" request on "volume" special file.
-*/
-static ssize_t variax_get_volume(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
- return sprintf(buf, "%d\n", variax->volume);
+ /* delay startup procedure: */
+ line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
+ variax_startup2, (unsigned long)variax);
}
-/*
- "write" request on "volume" special file.
-*/
-static ssize_t variax_set_volume(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static void variax_startup2(unsigned long data)
{
- struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
- int value = simple_strtoul(buf, NULL, 10);
+ struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
+ struct usb_line6 *line6 = &variax->line6;
- if (line6_transmit_parameter(&variax->line6, VARIAXMIDI_volume,
- value) == 0)
- variax->volume = value;
+ /* schedule another startup procedure until startup is complete: */
+ if (variax->startup_progress >= VARIAX_STARTUP_LAST)
+ return;
- return count;
-}
+ variax->startup_progress = VARIAX_STARTUP_VERSIONREQ;
+ line6_start_timer(&variax->startup_timer1, VARIAX_STARTUP_DELAY1,
+ variax_startup2, (unsigned long)variax);
-/*
- "read" request on "model" special file.
-*/
-static ssize_t variax_get_model(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
- return sprintf(buf, "%d\n", variax->model);
+ /* request firmware version: */
+ line6_version_request_async(line6);
}
-/*
- "write" request on "model" special file.
-*/
-static ssize_t variax_set_model(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static void variax_startup3(struct usb_line6_variax *variax)
{
- struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
- int value = simple_strtoul(buf, NULL, 10);
-
- if (line6_send_program(&variax->line6, value) == 0)
- variax->model = value;
+ CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_WAIT);
- return count;
+ /* delay startup procedure: */
+ line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY3,
+ variax_startup4, (unsigned long)variax);
}
-/*
- "read" request on "active" special file.
-*/
-static ssize_t variax_get_active(struct device *dev,
- struct device_attribute *attr, char *buf)
+static void variax_startup4(unsigned long data)
{
- struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
- return sprintf(buf, "%d\n", variax->buffer_activate[VARIAX_OFFSET_ACTIVATE]);
-}
+ struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
-/*
- "write" request on "active" special file.
-*/
-static ssize_t variax_set_active(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
- int value = simple_strtoul(buf, NULL, 10) ? 1 : 0;
- variax->buffer_activate[VARIAX_OFFSET_ACTIVATE] = value;
- line6_send_raw_message_async(&variax->line6, variax->buffer_activate,
- sizeof(variax_activate));
- return count;
-}
+ CHECK_STARTUP_PROGRESS(variax->startup_progress,
+ VARIAX_STARTUP_ACTIVATE);
-/*
- "read" request on "tone" special file.
-*/
-static ssize_t variax_get_tone(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
- return sprintf(buf, "%d\n", variax->tone);
+ /* activate device: */
+ variax_activate_async(variax, 1);
+ line6_start_timer(&variax->startup_timer2, VARIAX_STARTUP_DELAY4,
+ variax_startup5, (unsigned long)variax);
}
-/*
- "write" request on "tone" special file.
-*/
-static ssize_t variax_set_tone(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
+static void variax_startup5(unsigned long data)
{
- struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
- int value = simple_strtoul(buf, NULL, 10);
+ struct usb_line6_variax *variax = (struct usb_line6_variax *)data;
- if (line6_transmit_parameter(&variax->line6, VARIAXMIDI_tone,
- value) == 0)
- variax->tone = value;
+ CHECK_STARTUP_PROGRESS(variax->startup_progress,
+ VARIAX_STARTUP_WORKQUEUE);
- return count;
+ /* schedule work for global work queue: */
+ schedule_work(&variax->startup_work);
}
-static ssize_t get_string(char *buf, const char *data, int length)
+static void variax_startup6(struct work_struct *work)
{
- int i;
- memcpy(buf, data, length);
-
- for (i = length; i--;) {
- char c = buf[i];
+ struct usb_line6_variax *variax =
+ container_of(work, struct usb_line6_variax, startup_work);
- if ((c != 0) && (c != ' '))
- break;
- }
-
- buf[i + 1] = '\n';
- return i + 2;
-}
-
-/*
- "read" request on "name" special file.
-*/
-static ssize_t variax_get_name(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
- line6_wait_dump(&variax->dumpreq, 0);
- return get_string(buf, variax->model_data.name,
- sizeof(variax->model_data.name));
-}
+ CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
-/*
- "read" request on "bank" special file.
-*/
-static ssize_t variax_get_bank(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
- line6_wait_dump(&variax->dumpreq, 0);
- return get_string(buf, variax->bank, sizeof(variax->bank));
+ /* ALSA audio interface: */
+ line6_register_audio(&variax->line6);
}
/*
- "read" request on "dump" special file.
+ Process a completely received message.
*/
-static ssize_t variax_get_dump(struct device *dev,
- struct device_attribute *attr, char *buf)
+void line6_variax_process_message(struct usb_line6_variax *variax)
{
- struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
- int retval;
- retval = line6_wait_dump(&variax->dumpreq, 0);
- if (retval < 0)
- return retval;
- memcpy(buf, &variax->model_data.control,
- sizeof(variax->model_data.control));
- return sizeof(variax->model_data.control);
-}
+ const unsigned char *buf = variax->line6.buffer_message;
-#if CREATE_RAW_FILE
+ switch (buf[0]) {
+ case LINE6_RESET:
+ dev_info(variax->line6.ifcdev, "VARIAX reset\n");
+ break;
-/*
- "write" request on "raw" special file.
-*/
-static ssize_t variax_set_raw2(struct device *dev,
- struct device_attribute *attr,
- const char *buf, size_t count)
-{
- struct usb_line6_variax *variax = usb_get_intfdata(to_usb_interface(dev));
- int size;
- int i;
- char *sysex;
-
- count -= count % 3;
- size = count * 2;
- sysex = variax_alloc_sysex_buffer(variax, VARIAX_SYSEX_PARAM, size);
-
- if (!sysex)
- return 0;
-
- for (i = 0; i < count; i += 3) {
- const unsigned char *p1 = buf + i;
- char *p2 = sysex + SYSEX_DATA_OFS + i * 2;
- p2[0] = p1[2] & 0x0f;
- p2[1] = p1[2] >> 4;
- p2[2] = p1[1] & 0x0f;
- p2[3] = p1[1] >> 4;
- p2[4] = p1[0] & 0x0f;
- p2[5] = p1[0] >> 4;
+ 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;
}
-
- line6_send_sysex_message(&variax->line6, sysex, size);
- kfree(sysex);
- return count;
}
-#endif
-
-/* Variax workbench special files: */
-static DEVICE_ATTR(model, S_IWUGO | S_IRUGO, variax_get_model, variax_set_model);
-static DEVICE_ATTR(volume, S_IWUGO | S_IRUGO, variax_get_volume, variax_set_volume);
-static DEVICE_ATTR(tone, S_IWUGO | S_IRUGO, variax_get_tone, variax_set_tone);
-static DEVICE_ATTR(name, S_IRUGO, variax_get_name, line6_nop_write);
-static DEVICE_ATTR(bank, S_IRUGO, variax_get_bank, line6_nop_write);
-static DEVICE_ATTR(dump, S_IRUGO, variax_get_dump, line6_nop_write);
-static DEVICE_ATTR(active, S_IWUGO | S_IRUGO, variax_get_active, variax_set_active);
-
-#if CREATE_RAW_FILE
-static DEVICE_ATTR(raw, S_IWUGO, line6_nop_read, line6_set_raw);
-static DEVICE_ATTR(raw2, S_IWUGO, line6_nop_read, variax_set_raw2);
-#endif
-
-
/*
Variax destructor.
*/
static void variax_destruct(struct usb_interface *interface)
{
struct usb_line6_variax *variax = usb_get_intfdata(interface);
- struct usb_line6 *line6;
if (variax == NULL)
return;
- line6 = &variax->line6;
- if (line6 == NULL)
- return;
- line6_cleanup_audio(line6);
+ line6_cleanup_audio(&variax->line6);
- /* free dump request data: */
- line6_dumpreq_destructbuf(&variax->dumpreq, 2);
- line6_dumpreq_destructbuf(&variax->dumpreq, 1);
- line6_dumpreq_destruct(&variax->dumpreq);
+ del_timer(&variax->startup_timer1);
+ del_timer(&variax->startup_timer2);
+ cancel_work_sync(&variax->startup_work);
kfree(variax->buffer_activate);
- del_timer_sync(&variax->activate_timer);
}
/*
- Create sysfs entries.
+ Try to init workbench device.
*/
-static int variax_create_files2(struct device *dev)
+static int variax_try_init(struct usb_interface *interface,
+ struct usb_line6_variax *variax)
{
int err;
- CHECK_RETURN(device_create_file(dev, &dev_attr_model));
- CHECK_RETURN(device_create_file(dev, &dev_attr_volume));
- CHECK_RETURN(device_create_file(dev, &dev_attr_tone));
- CHECK_RETURN(device_create_file(dev, &dev_attr_name));
- CHECK_RETURN(device_create_file(dev, &dev_attr_bank));
- CHECK_RETURN(device_create_file(dev, &dev_attr_dump));
- CHECK_RETURN(device_create_file(dev, &dev_attr_active));
-#if CREATE_RAW_FILE
- CHECK_RETURN(device_create_file(dev, &dev_attr_raw));
- CHECK_RETURN(device_create_file(dev, &dev_attr_raw2));
-#endif
- return 0;
-}
-/*
- Init workbench device.
-*/
-int variax_init(struct usb_interface *interface,
- struct usb_line6_variax *variax)
-{
- int err;
+ 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: */
- err = line6_dumpreq_init(&variax->dumpreq, variax_request_model1,
- sizeof(variax_request_model1));
-
- if (err < 0) {
- dev_err(&interface->dev, "Out of memory\n");
- variax_destruct(interface);
- return err;
- }
-
- err = line6_dumpreq_initbuf(&variax->dumpreq, variax_request_model2,
- sizeof(variax_request_model2), 1);
-
- if (err < 0) {
- dev_err(&interface->dev, "Out of memory\n");
- variax_destruct(interface);
- return err;
- }
-
- err = line6_dumpreq_initbuf(&variax->dumpreq, variax_request_bank,
- sizeof(variax_request_bank), 2);
-
- if (err < 0) {
- dev_err(&interface->dev, "Out of memory\n");
- variax_destruct(interface);
- return err;
- }
-
- variax->buffer_activate = kmalloc(sizeof(variax_activate), GFP_KERNEL);
+ variax->buffer_activate = kmemdup(variax_activate,
+ sizeof(variax_activate), GFP_KERNEL);
if (variax->buffer_activate == NULL) {
dev_err(&interface->dev, "Out of memory\n");
- variax_destruct(interface);
return -ENOMEM;
}
- memcpy(variax->buffer_activate, variax_activate,
- sizeof(variax_activate));
- init_timer(&variax->activate_timer);
-
- /* create sysfs entries: */
- err = variax_create_files(0, 0, &interface->dev);
- if (err < 0) {
- variax_destruct(interface);
- return err;
- }
-
- err = variax_create_files2(&interface->dev);
- if (err < 0) {
- variax_destruct(interface);
- return err;
- }
-
/* initialize audio system: */
err = line6_init_audio(&variax->line6);
- if (err < 0) {
- variax_destruct(interface);
+ if (err < 0)
return err;
- }
/* initialize MIDI subsystem: */
err = line6_init_midi(&variax->line6);
- if (err < 0) {
- variax_destruct(interface);
+ if (err < 0)
return err;
- }
- /* register audio system: */
- err = line6_register_audio(&variax->line6);
- if (err < 0) {
+ /* 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_variax *variax)
+{
+ int err = variax_try_init(interface, variax);
+
+ if (err < 0)
variax_destruct(interface);
- return err;
- }
- variax_activate_delayed(variax, VARIAX_ACTIVATE_DELAY);
- line6_startup_delayed(&variax->dumpreq, VARIAX_STARTUP_DELAY,
- variax_startup_timeout, variax);
- return 0;
+ return err;
}
/*
Workbench device disconnected.
*/
-void variax_disconnect(struct usb_interface *interface)
+void line6_variax_disconnect(struct usb_interface *interface)
{
- struct device *dev;
-
if (interface == NULL)
return;
- dev = &interface->dev;
-
- if (dev != NULL) {
- /* remove sysfs entries: */
- variax_remove_files(0, 0, dev);
- device_remove_file(dev, &dev_attr_model);
- device_remove_file(dev, &dev_attr_volume);
- device_remove_file(dev, &dev_attr_tone);
- device_remove_file(dev, &dev_attr_name);
- device_remove_file(dev, &dev_attr_bank);
- device_remove_file(dev, &dev_attr_dump);
- device_remove_file(dev, &dev_attr_active);
-#if CREATE_RAW_FILE
- device_remove_file(dev, &dev_attr_raw);
- device_remove_file(dev, &dev_attr_raw2);
-#endif
- }
variax_destruct(interface);
}
diff --git a/drivers/staging/line6/variax.h b/drivers/staging/line6/variax.h
index ee330ba3089..24de79620d8 100644
--- a/drivers/staging/line6/variax.h
+++ b/drivers/staging/line6/variax.h
@@ -1,7 +1,7 @@
/*
- * Line6 Linux USB driver - 0.8.0
+ * Line6 Linux USB driver - 0.9.1beta
*
- * Copyright (C) 2004-2009 Markus Grabner (grabner@icg.tugraz.at)
+ * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
@@ -12,97 +12,61 @@
#ifndef VARIAX_H
#define VARIAX_H
-
-#include "driver.h"
-
#include <linux/spinlock.h>
#include <linux/usb.h>
#include <linux/wait.h>
-
#include <sound/core.h>
-#include "dumprequest.h"
-
-
-#define VARIAX_ACTIVATE_DELAY 10
-#define VARIAX_STARTUP_DELAY 3
-
-
-enum {
- VARIAX_DUMP_PASS1 = LINE6_DUMP_CURRENT,
- VARIAX_DUMP_PASS2,
- VARIAX_DUMP_PASS3
-};
+#include "driver.h"
+#define VARIAX_STARTUP_DELAY1 1000
+#define VARIAX_STARTUP_DELAY3 100
+#define VARIAX_STARTUP_DELAY4 100
-/**
- Binary Variax model dump
+/*
+ Stages of Variax startup procedure
*/
-struct variax_model {
- /**
- Header information (including program name).
- */
- unsigned char name[18];
-
- /**
- Model parameters.
- */
- unsigned char control[78 * 2];
+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.
+ Generic Line6 USB data.
*/
struct usb_line6 line6;
/**
- Dump request structure.
- Append two extra buffers for 3-pass data query.
- */
- struct line6_dump_request dumpreq; struct line6_dump_reqbuf extrabuf[2];
-
- /**
- Buffer for activation code.
+ Buffer for activation code.
*/
unsigned char *buffer_activate;
/**
- Model number.
- */
- int model;
-
- /**
- Current model settings.
+ Handler for device initializaton.
*/
- struct variax_model model_data;
+ struct work_struct startup_work;
/**
- Name of current model bank.
+ Timers for device initializaton.
*/
- unsigned char bank[18];
+ struct timer_list startup_timer1;
+ struct timer_list startup_timer2;
/**
- Position of volume dial.
+ Current progress in startup procedure.
*/
- int volume;
-
- /**
- Position of tone control dial.
- */
- int tone;
-
- /**
- Timer for delayed activation request.
- */
- struct timer_list activate_timer;
+ int startup_progress;
};
-
-extern void variax_disconnect(struct usb_interface *interface);
-extern int variax_init(struct usb_interface *interface,
- struct usb_line6_variax *variax);
-extern void variax_process_message(struct usb_line6_variax *variax);
-
+extern void line6_variax_disconnect(struct usb_interface *interface);
+extern int line6_variax_init(struct usb_interface *interface,
+ struct usb_line6_variax *variax);
+extern void line6_variax_process_message(struct usb_line6_variax *variax);
#endif