Commit 1027f476 authored by Markus Grabner's avatar Markus Grabner Committed by Greg Kroah-Hartman

staging: line6: sync with upstream

Big upstream sync.
Signed-off-by: default avatarMarkus Grabner <grabner@icg.tugraz.at>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 4498dbcd
config LINE6_USB
menuconfig LINE6_USB
tristate "Line6 USB support"
depends on USB && SND
select SND_RAWMIDI
......@@ -18,5 +18,68 @@ 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_DEBUG
bool "print debug messages"
default n
help
Say Y here to write debug messages to the syslog.
If unsure, say N.
config LINE6_USB_DUMP_CTRL
bool "dump control messages"
default n
help
Say Y here to write control messages sent to and received from
Line6 devices to the syslog.
If unsure, say N.
config LINE6_USB_DUMP_MIDI
bool "dump MIDI messages"
default n
help
Say Y here to write MIDI messages sent to and received from
Line6 devices to the syslog.
If unsure, say N.
config LINE6_USB_DUMP_PCM
bool "dump PCM data"
default n
help
Say Y here to write PCM data sent to and received from Line6
devices to the syslog. This will produce a huge amount of
syslog data during playback and capture.
If unsure, say N.
config LINE6_USB_RAW
bool "raw data communication"
default n
help
Say Y here to create special files which allow to send raw data
to the device. This bypasses any sanity checks, so if you discover
the code to erase the firmware, feel free to render your device
useless, but only after reading the GPL section "NO WARRANTY".
If unsure, say N.
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
/*
* Line6 Linux USB driver - 0.8.0
* Line6 Linux USB driver - 0.9.0
*
* 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,12 +9,12 @@
*
*/
#include "driver.h"
#include "audio.h"
#include <sound/core.h>
#include <sound/initval.h>
#include "driver.h"
#include "audio.h"
static int line6_index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static char *line6_id[SNDRV_CARDS] = SNDRV_DEFAULT_STR;
......@@ -36,8 +36,9 @@ int line6_init_audio(struct usb_line6 *line6)
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);
sprintf(card->longname, "Line6 %s at USB %s", line6->properties->name,
dev_name(line6->ifcdev)); /* 80 chars - see asound.h */
return 0;
......
/*
* Line6 Linux USB driver - 0.8.0
* Line6 Linux USB driver - 0.9.0
*
* 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
......
This diff is collapsed.
/*
* Line6 Linux USB driver - 0.8.0
* Line6 Linux USB driver - 0.9.0
*
* 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
......@@ -13,20 +13,21 @@
#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 int line6_create_audio_in_urbs(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 int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd);
#endif
/*
* Line6 Linux USB driver - 0.8.0
* Line6 Linux USB driver - 0.9.0
*
* 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,11 +9,10 @@
*
*/
#include "driver.h"
#include <linux/usb.h>
#include "control.h"
#include "driver.h"
#include "pod.h"
#include "usbdefs.h"
#include "variax.h"
......@@ -45,7 +44,7 @@ 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);
int retval = line6_dump_wait_interruptible(&pod->dumpreq);
if (retval < 0)
return retval;
return sprintf(buf, "%d\n", pod->prog_data.control[param]);
......@@ -63,7 +62,7 @@ static ssize_t pod_set_param_int(struct device *dev, const char *buf,
if (retval)
return retval;
pod_transmit_parameter(pod, param, value);
line6_pod_transmit_parameter(pod, param, value);
return count;
}
......@@ -71,7 +70,7 @@ 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);
int retval = line6_dump_wait_interruptible(&variax->dumpreq);
if (retval < 0)
return retval;
return sprintf(buf, "%d\n", variax->model_data.control[param]);
......@@ -80,12 +79,11 @@ static ssize_t variax_get_param_int(struct device *dev, char *buf, int 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)
We do our own floating point handling here since at the time
this code was written (Jan 2006) it was highly discouraged to
use floating point arithmetic in the kernel. If you think that
this no longer applies, feel free to replace this by generic
floating point code.
*/
static const int BIAS = 0x7f;
......@@ -97,7 +95,7 @@ static ssize_t variax_get_param_float(struct device *dev, char *buf, int param)
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);
int retval = line6_dump_wait_interruptible(&variax->dumpreq);
if (retval < 0)
return retval;
......@@ -530,7 +528,7 @@ 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 line6_pod_create_files(int firmware, int type, struct device *dev)
{
int err;
CHECK_RETURN(device_create_file(dev, &dev_attr_tweak));
......@@ -733,9 +731,10 @@ int pod_create_files(int firmware, int type, struct device *dev)
(dev, &dev_attr_band_6_gain__bass));
return 0;
}
EXPORT_SYMBOL(pod_create_files);
void pod_remove_files(int firmware, int type, struct device *dev)
EXPORT_SYMBOL(line6_pod_create_files);
void line6_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);
......@@ -908,9 +907,10 @@ void pod_remove_files(int firmware, int type, struct device *dev)
if (firmware >= 200)
device_remove_file(dev, &dev_attr_band_6_gain__bass);
}
EXPORT_SYMBOL(pod_remove_files);
int variax_create_files(int firmware, int type, struct device *dev)
EXPORT_SYMBOL(line6_pod_remove_files);
int line6_variax_create_files(int firmware, int type, struct device *dev)
{
int err;
CHECK_RETURN(device_create_file(dev, &dev_attr_body));
......@@ -954,9 +954,10 @@ int variax_create_files(int firmware, int type, struct device *dev)
CHECK_RETURN(device_create_file(dev, &dev_attr_pickup_wiring));
return 0;
}
EXPORT_SYMBOL(variax_create_files);
void variax_remove_files(int firmware, int type, struct device *dev)
EXPORT_SYMBOL(line6_variax_create_files);
void line6_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);
......@@ -998,4 +999,5 @@ void variax_remove_files(int firmware, int type, struct device *dev)
device_remove_file(dev, &dev_attr_mix1);
device_remove_file(dev, &dev_attr_pickup_wiring);
}
EXPORT_SYMBOL(variax_remove_files);
EXPORT_SYMBOL(line6_variax_remove_files);
This diff is collapsed.
This diff is collapsed.
/*
* Line6 Linux USB driver - 0.8.0
* Line6 Linux USB driver - 0.9.0
*
* 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
......@@ -13,23 +13,24 @@
#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"
#define DRIVER_NAME "line6usb"
#if defined(CONFIG_LINE6_USB_DUMP_CTRL) || defined(CONFIG_LINE6_USB_DUMP_MIDI) || defined(CONFIG_LINE6_USB_DUMP_PCM)
#define CONFIG_LINE6_USB_DUMP_ANY
#endif
#define LINE6_TIMEOUT 1
#define LINE6_MAX_DEVICES 8
#define LINE6_BUFSIZE_LISTEN 32
#define LINE6_MESSAGE_MAXLEN 256
/*
Line6 MIDI control commands
*/
......@@ -54,6 +55,12 @@
#define LINE6_CHANNEL_MASK 0x0f
#ifdef CONFIG_LINE6_USB_DEBUG
#define DEBUG_MESSAGES(x) (x)
#else
#define DEBUG_MESSAGES(x)
#endif
#define MISSING_CASE \
printk(KERN_ERR "line6usb driver bug: missing case in %s:%d\n", \
......@@ -67,10 +74,14 @@ do { \
return err; \
} while (0)
#define CHECK_STARTUP_PROGRESS(x, n) \
if((x) >= (n)) \
return; \
x = (n);
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;
......@@ -80,8 +91,27 @@ static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4;
Common properties of Line6 devices.
*/
struct line6_properties {
/**
Card id string (maximum 16 characters).
This can be used to address the device in ALSA programs as
"default:CARD=<id>"
*/
const char *id;
/**
Card short name (maximum 32 characters).
*/
const char *name;
/**
Bit identifying this device in the line6usb driver.
*/
int device_bit;
/**
Bit vector defining this device's capabilities in the
line6usb driver.
*/
int capabilities;
};
......@@ -191,14 +221,22 @@ extern int line6_send_raw_message_async(struct usb_line6 *line6,
const char *buffer, int size);
extern int line6_send_sysex_message(struct usb_line6 *line6,
const char *buffer, int size);
extern int line6_send_sysex_message_async(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);
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);
#ifdef CONFIG_LINE6_USB_DUMP_ANY
extern void line6_write_hexdump(struct usb_line6 *line6, char dir,
const unsigned char *buffer, int size);
#endif
#endif
/*
* Line6 Linux USB driver - 0.8.0
* Line6 Linux USB driver - 0.9.0
*
* 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,10 +9,9 @@
*
*/
#include "driver.h"
#include <linux/slab.h>
#include "driver.h"
#include "dumprequest.h"
......@@ -39,17 +38,17 @@ void line6_invalidate_current(struct line6_dump_request *l6dr)
void line6_dump_finished(struct line6_dump_request *l6dr)
{
l6dr->in_progress = LINE6_DUMP_NONE;
wake_up_interruptible(&l6dr->wait);
wake_up(&l6dr->wait);
}
/*
Send an asynchronous channel dump request.
*/
int line6_dump_request_async(struct line6_dump_request *l6dr,
struct usb_line6 *line6, int num)
struct usb_line6 *line6, int num, int dest)
{
int ret;
line6_invalidate_current(l6dr);
line6_dump_started(l6dr, dest);
ret = line6_send_raw_message_async(line6, l6dr->reqbufs[num].buffer,
l6dr->reqbufs[num].length);
......@@ -60,43 +59,27 @@ int line6_dump_request_async(struct line6_dump_request *l6dr,
}
/*
Send an asynchronous dump request after a given interval.
Wait for completion (interruptible).
*/
void line6_startup_delayed(struct line6_dump_request *l6dr, int seconds,
void (*function)(unsigned long), void *data)
int line6_dump_wait_interruptible(struct line6_dump_request *l6dr)
{
l6dr->timer.expires = jiffies + seconds * HZ;
l6dr->timer.function = function;
l6dr->timer.data = (unsigned long)data;
add_timer(&l6dr->timer);
return wait_event_interruptible(l6dr->wait, l6dr->in_progress == LINE6_DUMP_NONE);
}
/*
Wait for completion.
*/
int line6_wait_dump(struct line6_dump_request *l6dr, int nonblock)
void line6_dump_wait(struct line6_dump_request *l6dr)
{
wait_event(l6dr->wait, l6dr->in_progress == LINE6_DUMP_NONE);
}
/*
Wait for completion (with timeout).
*/
int line6_dump_wait_timeout(struct line6_dump_request *l6dr, long timeout)
{
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;
return wait_event_timeout(l6dr->wait, l6dr->in_progress == LINE6_DUMP_NONE, timeout);
}
/*
......@@ -123,7 +106,6 @@ int line6_dumpreq_init(struct line6_dump_request *l6dr, const void *buf,
if (ret < 0)
return ret;
init_waitqueue_head(&l6dr->wait);
init_timer(&l6dr->timer);
return 0;
}
......@@ -148,6 +130,4 @@ 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);
}
/*
* Line6 Linux USB driver - 0.8.0
* Line6 Linux USB driver - 0.9.0
*
* 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
......@@ -15,7 +15,6 @@
#include <linux/usb.h>
#include <linux/wait.h>
#include <sound/core.h>
......@@ -55,16 +54,6 @@ struct line6_dump_request {
*/
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
*/
......@@ -73,7 +62,7 @@ struct line6_dump_request {
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);
struct usb_line6 *line6, int num, int dest);
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);
......@@ -82,9 +71,10 @@ extern int line6_dumpreq_init(struct line6_dump_request *l6dr, const void *buf,
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);
extern void line6_dump_wait(struct line6_dump_request *l6dr);
extern int line6_dump_wait_interruptible(struct line6_dump_request *l6dr);
extern int line6_dump_wait_timeout(struct line6_dump_request *l6dr,
long timeout);
#endif
/*
* Line6 Linux USB driver - 0.8.0
* Line6 Linux USB driver - 0.9.0
*
* 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,24 +9,18 @@
*
*/
#include "driver.h"
#include <linux/usb.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))
......@@ -61,26 +55,26 @@ static void line6_midi_transmit(struct snd_rawmidi_substream *substream)
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
#ifdef CONFIG_LINE6_USB_DUMP_MIDI
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->max_packet_size);
if (done == 0)
break;
if (midibuf_skip_message(mb, line6midi->midi_mask_transmit))
if (line6_midibuf_skip_message(mb, line6midi->midi_mask_transmit))
continue;
send_midi_async(line6, chunk, done);
......@@ -115,7 +109,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);
}
......@@ -139,7 +133,7 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
return -ENOMEM;
}
#if DO_DUMP_URB_SEND
#ifdef CONFIG_LINE6_USB_DUMP_CTRL
line6_write_hexdump(line6, 'S', data, length);
#endif
......@@ -176,8 +170,8 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
case LINE6_DEVID_PODXTLIVE:
case LINE6_DEVID_PODXTPRO:
case LINE6_DEVID_POCKETPOD:
pod_midi_postprocess((struct usb_line6_pod *)line6, data,
length);
line6_pod_midi_postprocess((struct usb_line6_pod *)line6, data,
length);
break;
default:
......@@ -215,19 +209,8 @@ 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();
current->state = TASK_RUNNING;
remove_wait_queue(head, &wait);
struct snd_line6_midi *midi = line6->line6midi;
wait_event_interruptible(midi->send_wait, midi->num_active_send_urbs == 0);
}
static int line6_midi_input_open(struct snd_rawmidi_substream *substream)
......@@ -284,6 +267,7 @@ 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 =
......@@ -371,8 +355,8 @@ 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;
}
......@@ -396,11 +380,11 @@ int line6_init_midi(struct usb_line6 *line6)
if (line6midi == NULL)
return -ENOMEM;
err = midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0);
err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0);
if (err < 0)
return err;
err = midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1);
err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1);
if (err < 0)
return err;
......
/*
* Line6 Linux USB driver - 0.8.0
* Line6 Linux USB driver - 0.9.0
*
* 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
......
/*
* Line6 Linux USB driver - 0.8.0
* Line6 Linux USB driver - 0.9.0
*
* 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,6 @@
*
*/
#include "config.h"
#include <linux/slab.h>
#include "midibuf.h"
......@@ -25,9 +23,9 @@ 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 };
......@@ -35,13 +33,23 @@ static int midibuf_message_length(unsigned char code)
}
}
void midibuf_reset(struct MidiBuffer *this)
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;
}
void line6_midibuf_reset(struct MidiBuffer *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 MidiBuffer *this, int size, int split)
{
this->buf = kmalloc(size, GFP_KERNEL);
......@@ -50,28 +58,18 @@ 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 MidiBuffer *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;
}
int midibuf_bytes_free(struct MidiBuffer *this)
int line6_midibuf_bytes_free(struct MidiBuffer *this)
{
return
midibuf_is_full(this) ?
......@@ -79,7 +77,7 @@ int midibuf_bytes_free(struct MidiBuffer *this)
(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 MidiBuffer *this)
{
return
midibuf_is_empty(this) ?
......@@ -87,7 +85,7 @@ int midibuf_bytes_used(struct MidiBuffer *this)
(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 MidiBuffer *this, unsigned char *data, int length)
{
int bytes_free;
int length1, length2;
......@@ -102,7 +100,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 +127,7 @@ 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 MidiBuffer *this, unsigned char *data, int length)
{
int bytes_used;
int length1, length2;
......@@ -145,7 +143,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;
......@@ -232,9 +230,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 MidiBuffer *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 +242,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 MidiBuffer *this, unsigned short mask)
{
int cmd = this->command_prev;
......@@ -255,7 +253,7 @@ int midibuf_skip_message(struct MidiBuffer *this, unsigned short mask)
return 0;
}
void midibuf_destroy(struct MidiBuffer *this)
void line6_midibuf_destroy(struct MidiBuffer *this)
{
kfree(this->buf);
this->buf = NULL;
......
/*
* Line6 Linux USB driver - 0.8.0
* Line6 Linux USB driver - 0.9.0
*
* 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
......@@ -23,17 +23,17 @@ struct MidiBuffer {
};
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 MidiBuffer *mb);
extern int line6_midibuf_bytes_free(struct MidiBuffer *mb);
extern void line6_midibuf_destroy(struct MidiBuffer *mb);
extern int line6_midibuf_ignore(struct MidiBuffer *mb, int length);
extern int line6_midibuf_init(struct MidiBuffer *mb, int size, int split);
extern int line6_midibuf_read(struct MidiBuffer *mb, unsigned char *data, int length);
extern void line6_midibuf_reset(struct MidiBuffer *mb);
extern int line6_midibuf_skip_message(struct MidiBuffer *mb, unsigned short mask);
extern void line6_midibuf_status(struct MidiBuffer *mb);
extern int line6_midibuf_write(struct MidiBuffer *mb, unsigned char *data,
int length);
#endif
This diff is collapsed.
/*
* Line6 Linux USB driver - 0.8.0
* Line6 Linux USB driver - 0.9.0
*
* 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
......@@ -24,30 +24,79 @@
/* 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
#define LINE6_BACKUP_MONITOR_SIGNAL 0
#define LINE6_REUSE_DMA_AREA_FOR_PLAYBACK 0
/*
Extract the messaging device from the substream instance
Get substream from Line6 PCM data structure
*/
#define s2m(s) (((struct snd_line6_pcm *) \
snd_pcm_substream_chip(s))->line6->ifcdev)
#define get_substream(line6pcm, stream) (line6pcm->pcm->streams[stream].substream)
/*
PCM mode bits and masks.
"ALSA": operations triggered by applications via ALSA
"MONITOR": software monitoring
"IMPULSE": optional impulse response operation
*/
enum {
BIT_RUNNING_PLAYBACK,
BIT_RUNNING_CAPTURE,
/* individual bits: */
BIT_PCM_ALSA_PLAYBACK,
BIT_PCM_ALSA_CAPTURE,
BIT_PCM_MONITOR_PLAYBACK,
BIT_PCM_MONITOR_CAPTURE,
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
BIT_PCM_IMPULSE_PLAYBACK,
BIT_PCM_IMPULSE_CAPTURE,
#endif
BIT_PAUSE_PLAYBACK,
BIT_PREPARED
BIT_PREPARED,
/* individual masks: */
MASK_PCM_ALSA_PLAYBACK = 1 << BIT_PCM_ALSA_PLAYBACK,
MASK_PCM_ALSA_CAPTURE = 1 << BIT_PCM_ALSA_CAPTURE,
MASK_PCM_MONITOR_PLAYBACK = 1 << BIT_PCM_MONITOR_PLAYBACK,
MASK_PCM_MONITOR_CAPTURE = 1 << BIT_PCM_MONITOR_CAPTURE,
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
MASK_PCM_IMPULSE_PLAYBACK = 1 << BIT_PCM_IMPULSE_PLAYBACK,
MASK_PCM_IMPULSE_CAPTURE = 1 << BIT_PCM_IMPULSE_CAPTURE,
#endif
MASK_PAUSE_PLAYBACK = 1 << BIT_PAUSE_PLAYBACK,
MASK_PREPARED = 1 << BIT_PREPARED,
/* combined masks (by operation): */
MASK_PCM_ALSA = MASK_PCM_ALSA_PLAYBACK | MASK_PCM_ALSA_CAPTURE,
MASK_PCM_MONITOR = MASK_PCM_MONITOR_PLAYBACK | MASK_PCM_MONITOR_CAPTURE,
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
MASK_PCM_IMPULSE = MASK_PCM_IMPULSE_PLAYBACK | MASK_PCM_IMPULSE_CAPTURE,
#endif
/* combined masks (by direction): */
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
MASK_PLAYBACK = MASK_PCM_ALSA_PLAYBACK | MASK_PCM_MONITOR_PLAYBACK | MASK_PCM_IMPULSE_PLAYBACK,
MASK_CAPTURE = MASK_PCM_ALSA_CAPTURE | MASK_PCM_MONITOR_CAPTURE | MASK_PCM_IMPULSE_CAPTURE
#else
MASK_PLAYBACK = MASK_PCM_ALSA_PLAYBACK | MASK_PCM_MONITOR_PLAYBACK,
MASK_CAPTURE = MASK_PCM_ALSA_CAPTURE | MASK_PCM_MONITOR_CAPTURE
#endif
};
struct line6_pcm_properties {
......@@ -83,9 +132,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.
......@@ -94,6 +145,21 @@ struct snd_line6_pcm {
*/
unsigned char *buffer_in;
/**
Temporary buffer index for playback.
*/
int index_out;
/**
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.
*/
......@@ -204,12 +270,36 @@ 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;
/**
Period of impulse response test signal.
*/
int impulse_period;
/**
Counter for impulse response test signal.
*/
int impulse_count;
#endif
/**
Several status bits (see BIT_*).
*/
unsigned long flags;
int last_frame_in, last_frame_out;
};
......@@ -217,6 +307,19 @@ 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_start(struct snd_line6_pcm *line6pcm, int channels);
extern int line6_pcm_stop(struct snd_line6_pcm *line6pcm, int channels);
#define PRINT_FRAME_DIFF(op) { \
static int diff_prev = 1000; \
int diff = line6pcm->last_frame_out - line6pcm->last_frame_in; \
if((diff != diff_prev) && (abs(diff) < 100)) { \
printk("%s frame diff = %d\n", op, diff); \
diff_prev = diff; \
} \
}
#endif
This diff is collapsed.
/*
* Line6 Linux USB driver - 0.8.0
* Line6 Linux USB driver - 0.9.0
*
* 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
......@@ -13,18 +13,29 @@
#define PLAYBACK_H
#include "driver.h"
#include <sound/pcm.h>
#include "driver.h"
extern struct snd_pcm_ops snd_line6_playback_ops;
/*
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 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 struct snd_pcm_ops snd_line6_playback_ops;
extern int line6_create_audio_out_urbs(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 int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd);
#endif
This diff is collapsed.
/*
* Line6 Linux USB driver - 0.8.0
* Line6 Linux USB driver - 0.9.0
*
* 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
......@@ -13,15 +13,14 @@
#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 "driver.h"
#include "dumprequest.h"
......@@ -42,163 +41,156 @@
*/
#define POD_CONTROL_SIZE 0x80
#define POD_BUFSIZE_DUMPREQ 7
#define POD_STARTUP_DELAY 3
#define POD_STARTUP_DELAY 3000
/**
Data structure for values that need to be requested explicitly.
This is the case for system and tuner settings.
Data structure for values that need to be requested explicitly.
This is the case for system and tuner settings.
*/
struct ValueWait {
unsigned short value;
int value;
wait_queue_head_t wait;
};
/**
Binary PodXT Pro program dump
Binary PODxt Pro program dump
*/
struct pod_program {
/**
Header information (including program name).
Header information (including program name).
*/
unsigned char header[0x20];
/**
Program parameters.
Program parameters.
*/
unsigned char control[POD_CONTROL_SIZE];
};
struct usb_line6_pod {
/**
Generic Line6 USB data.
Generic Line6 USB data.
*/
struct usb_line6 line6;
/**
Dump request structure.
Dump request structure.
*/
struct line6_dump_request dumpreq;
/**
Current program number.
Current program number.
*/
unsigned char channel_num;
/**
Current program settings.
Current program settings.
*/
struct pod_program prog_data;
/**
Buffer for data retrieved from or to be stored on PODxt Pro.
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.
Tuner mute mode.
*/
struct ValueWait tuner_mute;
/**
Tuner base frequency (typically 440Hz).
Tuner base frequency (typically 440Hz).
*/
struct ValueWait tuner_freq;
/**
Note received from tuner.
Note received from tuner.
*/
struct ValueWait tuner_note;
/**
Pitch value received from tuner.
Pitch value received from tuner.
*/
struct ValueWait tuner_pitch;
/**
Instrument monitor level.
Instrument monitor level.
*/
struct ValueWait monitor_level;
/**
Audio routing mode.
0: send processed guitar
1: send clean guitar
2: send clean guitar re-amp playback
3: send re-amp playback
Audio routing mode.
0: send processed guitar
1: send clean guitar
2: send clean guitar re-amp playback
3: send re-amp playback
*/
struct ValueWait routing;
/**
Wait for audio clipping event.
Wait for audio clipping event.
*/
struct ValueWait clipping;
/**
Bottom-half for creation of sysfs special files.
Timer for device initializaton.
*/
struct work_struct create_files_work;
struct timer_list startup_timer;
/**
Dirty flags for access to parameter data.
Work handler for device initializaton.
*/
unsigned long param_dirty[POD_CONTROL_SIZE / sizeof(unsigned long)];
struct work_struct startup_work;
/**
Some atomic flags.
Current progress in startup procedure.
*/
unsigned long atomic_flags;
int startup_progress;
/**
Counter for startup process.
Dirty flags for access to parameter data.
*/
int startup_count;
unsigned long param_dirty[POD_CONTROL_SIZE / sizeof(unsigned long)];
/**
Some atomic flags.
*/
unsigned long atomic_flags;
/**
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.
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.
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_midi_postprocess(struct usb_line6_pod *pod,
unsigned char *data, int length);
extern void line6_pod_process_message(struct usb_line6_pod *pod);
extern void line6_pod_transmit_parameter(struct usb_line6_pod *pod, int param,
int value);
#endif
#ifndef DRIVER_REVISION
/* current subversion revision */
#define DRIVER_REVISION " (revision 529)"
#define DRIVER_REVISION " (revision 665)"
#endif
This diff is collapsed.
/*
* Line6 Linux USB driver - 0.8.0
* Line6 Linux USB driver - 0.9.0
*
* 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
......@@ -13,33 +13,44 @@
#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;
/**
Timer for delayed PCM startup.
*/
struct timer_list timer;
};
extern void toneport_disconnect(struct usb_interface *interface);
extern int toneport_init(struct usb_interface *interface,
struct usb_line6_toneport *toneport);
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
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment