Commit 86b5f3ec authored by Takashi Iwai's avatar Takashi Iwai

Merge branch 'topic/line6' into for-next

parents 2a52b6ee c078a4aa
...@@ -25,4 +25,4 @@ obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o ...@@ -25,4 +25,4 @@ obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o
obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o
obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/ obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/
obj-$(CONFIG_LINE6_USB) += line6/ obj-$(CONFIG_SND_USB_LINE6) += line6/
menuconfig LINE6_USB config SND_USB_LINE6
tristate "Line6 USB support" tristate
depends on USB && SND
select SND_RAWMIDI select SND_RAWMIDI
select SND_PCM select SND_PCM
config SND_USB_POD
tristate "Line 6 POD USB support"
select SND_USB_LINE6
help help
This is a driver for the guitar amp, cab, and effects modeller This is a driver for PODxt and other similar devices,
PODxt Pro by Line6 (and similar devices), supporting the supporting the following features:
following features:
* Reading/writing individual parameters * Reading/writing individual parameters
* Reading/writing complete channel, effects setup, and amp * Reading/writing complete channel, effects setup, and amp
setup data setup data
...@@ -18,21 +20,21 @@ menuconfig LINE6_USB ...@@ -18,21 +20,21 @@ menuconfig LINE6_USB
* Signal routing (record clean/processed guitar signal, * Signal routing (record clean/processed guitar signal,
re-amping) re-amping)
Preliminary support for the Variax Workbench and TonePort config SND_USB_PODHD
devices is included. tristate "Line 6 POD HD300/400/500 USB support"
select SND_USB_LINE6
if LINE6_USB help
This is a driver for POD HD300, 400 and 500 devices.
config LINE6_USB_IMPULSE_RESPONSE config SND_USB_TONEPORT
bool "measure impulse response" tristate "TonePort GX, UX1 and UX2 USB support"
default n select SND_USB_LINE6
help help
Say Y here to add code to measure the impulse response of a Line6 This is a driver for TonePort GX, UX1 and UX2 devices.
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. config SND_USB_VARIAX
tristate "Variax Workbench USB support"
select SND_USB_LINE6
help
This is a driver for Variax Workbench device.
endif # LINE6_USB
obj-$(CONFIG_LINE6_USB) += line6usb.o snd-usb-line6-y := \
line6usb-y := \
audio.o \
capture.o \ capture.o \
driver.o \ driver.o \
midi.o \ midi.o \
midibuf.o \ midibuf.o \
pcm.o \ pcm.o \
playback.o \ playback.o
pod.o \
toneport.o \ snd-usb-pod-y := pod.o
variax.o \ snd-usb-podhd-y := podhd.o
podhd.o snd-usb-toneport-y := toneport.o
snd-usb-variax-y := variax.o
obj-$(CONFIG_SND_USB_LINE6) += snd-usb-line6.o
obj-$(CONFIG_SND_USB_POD) += snd-usb-pod.o
obj-$(CONFIG_SND_USB_PODHD) += snd-usb-podhd.o
obj-$(CONFIG_SND_USB_TONEPORT) += snd-usb-toneport.o
obj-$(CONFIG_SND_USB_VARIAX) += snd-usb-variax.o
/*
* Line6 Linux USB driver - 0.9.1beta
*
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2.
*
*/
#include <sound/core.h>
#include <sound/initval.h>
#include <linux/export.h>
#include "driver.h"
#include "audio.h"
/*
Initialize the Line6 USB audio system.
*/
int line6_init_audio(struct usb_line6 *line6)
{
struct snd_card *card;
int err;
err = snd_card_new(line6->ifcdev,
SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
THIS_MODULE, 0, &card);
if (err < 0)
return err;
line6->card = card;
strcpy(card->id, line6->properties->id);
strcpy(card->driver, DRIVER_NAME);
strcpy(card->shortname, line6->properties->name);
/* longname is 80 chars - see asound.h */
sprintf(card->longname, "Line6 %s at USB %s", line6->properties->name,
dev_name(line6->ifcdev));
return 0;
}
/*
Register the Line6 USB audio system.
*/
int line6_register_audio(struct usb_line6 *line6)
{
int err;
err = snd_card_register(line6->card);
if (err < 0)
return err;
return 0;
}
/*
Cleanup the Line6 USB audio system.
*/
void line6_cleanup_audio(struct usb_line6 *line6)
{
struct snd_card *card = line6->card;
if (card == NULL)
return;
snd_card_disconnect(card);
snd_card_free(card);
line6->card = NULL;
}
/*
* Line6 Linux USB driver - 0.9.1beta
*
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2.
*
*/
#ifndef AUDIO_H
#define AUDIO_H
#include "driver.h"
extern void line6_cleanup_audio(struct usb_line6 *);
extern int line6_init_audio(struct usb_line6 *);
extern int line6_register_audio(struct usb_line6 *);
#endif
/* /*
* Line6 Linux USB driver - 0.9.1beta * Line 6 Linux USB driver
* *
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
* *
...@@ -14,11 +14,9 @@ ...@@ -14,11 +14,9 @@
#include <sound/pcm.h> #include <sound/pcm.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include "audio.h"
#include "capture.h" #include "capture.h"
#include "driver.h" #include "driver.h"
#include "pcm.h" #include "pcm.h"
#include "pod.h"
/* /*
Find a free URB and submit it. Find a free URB and submit it.
...@@ -245,9 +243,7 @@ static void audio_in_callback(struct urb *urb) ...@@ -245,9 +243,7 @@ static void audio_in_callback(struct urb *urb)
line6pcm->prev_fbuf = fbuf; line6pcm->prev_fbuf = fbuf;
line6pcm->prev_fsize = fsize; line6pcm->prev_fsize = fsize;
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE)) if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
#endif
if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
&line6pcm->flags) && (fsize > 0)) &line6pcm->flags) && (fsize > 0))
line6_capture_copy(line6pcm, fbuf, fsize); line6_capture_copy(line6pcm, fbuf, fsize);
...@@ -263,9 +259,7 @@ static void audio_in_callback(struct urb *urb) ...@@ -263,9 +259,7 @@ static void audio_in_callback(struct urb *urb)
if (!shutdown) { if (!shutdown) {
submit_audio_in_urb(line6pcm); submit_audio_in_urb(line6pcm);
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE)) if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
#endif
if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM, if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
&line6pcm->flags)) &line6pcm->flags))
line6_capture_check_period(line6pcm, length); line6_capture_check_period(line6pcm, length);
...@@ -347,9 +341,7 @@ int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd) ...@@ -347,9 +341,7 @@ int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd)
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
#ifdef CONFIG_PM
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
#endif
err = line6_pcm_acquire(line6pcm, err = line6_pcm_acquire(line6pcm,
LINE6_BIT_PCM_ALSA_CAPTURE_STREAM); LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
...@@ -359,9 +351,7 @@ int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd) ...@@ -359,9 +351,7 @@ int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd)
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
#ifdef CONFIG_PM
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
#endif
err = line6_pcm_release(line6pcm, err = line6_pcm_release(line6pcm,
LINE6_BIT_PCM_ALSA_CAPTURE_STREAM); LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
...@@ -411,10 +401,8 @@ int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm) ...@@ -411,10 +401,8 @@ int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
urb = line6pcm->urb_audio_in[i] = urb = line6pcm->urb_audio_in[i] =
usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
if (urb == NULL) { if (urb == NULL)
dev_err(line6->ifcdev, "Out of memory\n");
return -ENOMEM; return -ENOMEM;
}
urb->dev = line6->usbdev; urb->dev = line6->usbdev;
urb->pipe = urb->pipe =
......
/* /*
* Line6 Linux USB driver - 0.9.1beta * Line 6 Linux USB driver
* *
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
* *
......
This diff is collapsed.
/* /*
* Line6 Linux USB driver - 0.9.1beta * Line 6 Linux USB driver
* *
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
* *
...@@ -20,35 +20,12 @@ ...@@ -20,35 +20,12 @@
#define DRIVER_NAME "line6usb" #define DRIVER_NAME "line6usb"
enum line6_device_type {
LINE6_BASSPODXT,
LINE6_BASSPODXTLIVE,
LINE6_BASSPODXTPRO,
LINE6_GUITARPORT,
LINE6_POCKETPOD,
LINE6_PODHD300,
LINE6_PODHD400,
LINE6_PODHD500_0,
LINE6_PODHD500_1,
LINE6_PODSTUDIO_GX,
LINE6_PODSTUDIO_UX1,
LINE6_PODSTUDIO_UX2,
LINE6_PODXT,
LINE6_PODXTLIVE_POD,
LINE6_PODXTLIVE_VARIAX,
LINE6_PODXTPRO,
LINE6_TONEPORT_GX,
LINE6_TONEPORT_UX1,
LINE6_TONEPORT_UX2,
LINE6_VARIAX
};
#define LINE6_TIMEOUT 1 #define LINE6_TIMEOUT 1
#define LINE6_BUFSIZE_LISTEN 32 #define LINE6_BUFSIZE_LISTEN 32
#define LINE6_MESSAGE_MAXLEN 256 #define LINE6_MESSAGE_MAXLEN 256
/* /*
Line6 MIDI control commands Line 6 MIDI control commands
*/ */
#define LINE6_PARAM_CHANGE 0xb0 #define LINE6_PARAM_CHANGE 0xb0
#define LINE6_PROGRAM_CHANGE 0xc0 #define LINE6_PROGRAM_CHANGE 0xc0
...@@ -71,17 +48,6 @@ enum line6_device_type { ...@@ -71,17 +48,6 @@ enum line6_device_type {
#define LINE6_CHANNEL_MASK 0x0f #define LINE6_CHANNEL_MASK 0x0f
#define MISSING_CASE \
pr_err("line6usb driver bug: missing case in %s:%d\n", \
__FILE__, __LINE__)
#define CHECK_RETURN(x) \
do { \
err = x; \
if (err < 0) \
return err; \
} while (0)
#define CHECK_STARTUP_PROGRESS(x, n) \ #define CHECK_STARTUP_PROGRESS(x, n) \
do { \ do { \
if ((x) >= (n)) \ if ((x) >= (n)) \
...@@ -95,7 +61,7 @@ static const int SYSEX_DATA_OFS = sizeof(line6_midi_id) + 3; ...@@ -95,7 +61,7 @@ static const int SYSEX_DATA_OFS = sizeof(line6_midi_id) + 3;
static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4; static const int SYSEX_EXTRA_SIZE = sizeof(line6_midi_id) + 4;
/** /**
Common properties of Line6 devices. Common properties of Line 6 devices.
*/ */
struct line6_properties { struct line6_properties {
/** /**
...@@ -125,7 +91,7 @@ struct line6_properties { ...@@ -125,7 +91,7 @@ struct line6_properties {
}; };
/** /**
Common data shared by all Line6 devices. Common data shared by all Line 6 devices.
Corresponds to a pair of USB endpoints. Corresponds to a pair of USB endpoints.
*/ */
struct usb_line6 { struct usb_line6 {
...@@ -134,11 +100,6 @@ struct usb_line6 { ...@@ -134,11 +100,6 @@ struct usb_line6 {
*/ */
struct usb_device *usbdev; struct usb_device *usbdev;
/**
Device type.
*/
enum line6_device_type type;
/** /**
Properties. Properties.
*/ */
...@@ -160,18 +121,18 @@ struct usb_line6 { ...@@ -160,18 +121,18 @@ struct usb_line6 {
struct device *ifcdev; struct device *ifcdev;
/** /**
Line6 sound card data structure. Line 6 sound card data structure.
Each device has at least MIDI or PCM. Each device has at least MIDI or PCM.
*/ */
struct snd_card *card; struct snd_card *card;
/** /**
Line6 PCM device data structure. Line 6 PCM device data structure.
*/ */
struct snd_line6_pcm *line6pcm; struct snd_line6_pcm *line6pcm;
/** /**
Line6 MIDI device data structure. Line 6 MIDI device data structure.
*/ */
struct snd_line6_midi *line6midi; struct snd_line6_midi *line6midi;
...@@ -207,9 +168,6 @@ extern int line6_read_data(struct usb_line6 *line6, int address, void *data, ...@@ -207,9 +168,6 @@ extern int line6_read_data(struct usb_line6 *line6, int address, void *data,
size_t datalen); size_t datalen);
extern int line6_read_serial_number(struct usb_line6 *line6, extern int line6_read_serial_number(struct usb_line6 *line6,
int *serial_number); int *serial_number);
extern int line6_send_program(struct usb_line6 *line6, u8 value);
extern int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
int size);
extern int line6_send_raw_message_async(struct usb_line6 *line6, extern int line6_send_raw_message_async(struct usb_line6 *line6,
const char *buffer, int size); const char *buffer, int size);
extern int line6_send_sysex_message(struct usb_line6 *line6, extern int line6_send_sysex_message(struct usb_line6 *line6,
...@@ -219,10 +177,19 @@ extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr, ...@@ -219,10 +177,19 @@ extern ssize_t line6_set_raw(struct device *dev, struct device_attribute *attr,
extern void line6_start_timer(struct timer_list *timer, unsigned int msecs, extern void line6_start_timer(struct timer_list *timer, unsigned int msecs,
void (*function)(unsigned long), void (*function)(unsigned long),
unsigned long data); unsigned long data);
extern int line6_transmit_parameter(struct usb_line6 *line6, int param,
u8 value);
extern int line6_version_request_async(struct usb_line6 *line6); extern int line6_version_request_async(struct usb_line6 *line6);
extern int line6_write_data(struct usb_line6 *line6, int address, void *data, extern int line6_write_data(struct usb_line6 *line6, int address, void *data,
size_t datalen); size_t datalen);
int line6_probe(struct usb_interface *interface,
struct usb_line6 *line6,
const struct line6_properties *properties,
int (*private_init)(struct usb_interface *, struct usb_line6 *));
void line6_disconnect(struct usb_interface *interface);
#ifdef CONFIG_PM
int line6_suspend(struct usb_interface *interface, pm_message_t message);
int line6_resume(struct usb_interface *interface);
#endif
#endif #endif
/* /*
* Line6 Linux USB driver - 0.9.1beta * Line 6 Linux USB driver
* *
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
* *
...@@ -11,13 +11,12 @@ ...@@ -11,13 +11,12 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/export.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/rawmidi.h> #include <sound/rawmidi.h>
#include "audio.h"
#include "driver.h" #include "driver.h"
#include "midi.h" #include "midi.h"
#include "pod.h"
#include "usbdefs.h" #include "usbdefs.h"
#define line6_rawmidi_substream_midi(substream) \ #define line6_rawmidi_substream_midi(substream) \
...@@ -121,16 +120,13 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data, ...@@ -121,16 +120,13 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
urb = usb_alloc_urb(0, GFP_ATOMIC); urb = usb_alloc_urb(0, GFP_ATOMIC);
if (urb == NULL) { if (urb == NULL)
dev_err(line6->ifcdev, "Out of memory\n");
return -ENOMEM; return -ENOMEM;
}
transfer_buffer = kmemdup(data, length, GFP_ATOMIC); transfer_buffer = kmemdup(data, length, GFP_ATOMIC);
if (transfer_buffer == NULL) { if (transfer_buffer == NULL) {
usb_free_urb(urb); usb_free_urb(urb);
dev_err(line6->ifcdev, "Out of memory\n");
return -ENOMEM; return -ENOMEM;
} }
...@@ -223,28 +219,20 @@ static struct snd_rawmidi_ops line6_midi_input_ops = { ...@@ -223,28 +219,20 @@ static struct snd_rawmidi_ops line6_midi_input_ops = {
.trigger = line6_midi_input_trigger, .trigger = line6_midi_input_trigger,
}; };
/*
Cleanup the Line6 MIDI device.
*/
static void line6_cleanup_midi(struct snd_rawmidi *rmidi)
{
}
/* Create a MIDI device */ /* Create a MIDI device */
static int snd_line6_new_midi(struct snd_line6_midi *line6midi) static int snd_line6_new_midi(struct usb_line6 *line6,
struct snd_rawmidi **rmidi_ret)
{ {
struct snd_rawmidi *rmidi; struct snd_rawmidi *rmidi;
int err; int err;
err = snd_rawmidi_new(line6midi->line6->card, "Line6 MIDI", 0, 1, 1, err = snd_rawmidi_new(line6->card, "Line 6 MIDI", 0, 1, 1, rmidi_ret);
&rmidi);
if (err < 0) if (err < 0)
return err; return err;
rmidi->private_data = line6midi; rmidi = *rmidi_ret;
rmidi->private_free = line6_cleanup_midi; strcpy(rmidi->id, line6->properties->id);
strcpy(rmidi->id, line6midi->line6->properties->id); strcpy(rmidi->name, line6->properties->name);
strcpy(rmidi->name, line6midi->line6->properties->name);
rmidi->info_flags = rmidi->info_flags =
SNDRV_RAWMIDI_INFO_OUTPUT | SNDRV_RAWMIDI_INFO_OUTPUT |
...@@ -258,25 +246,22 @@ static int snd_line6_new_midi(struct snd_line6_midi *line6midi) ...@@ -258,25 +246,22 @@ static int snd_line6_new_midi(struct snd_line6_midi *line6midi)
} }
/* MIDI device destructor */ /* MIDI device destructor */
static int snd_line6_midi_free(struct snd_device *device) static void snd_line6_midi_free(struct snd_rawmidi *rmidi)
{ {
struct snd_line6_midi *line6midi = device->device_data; struct snd_line6_midi *line6midi = rmidi->private_data;
line6_midibuf_destroy(&line6midi->midibuf_in); line6_midibuf_destroy(&line6midi->midibuf_in);
line6_midibuf_destroy(&line6midi->midibuf_out); line6_midibuf_destroy(&line6midi->midibuf_out);
return 0; kfree(line6midi);
} }
/* /*
Initialize the Line6 MIDI subsystem. Initialize the Line 6 MIDI subsystem.
*/ */
int line6_init_midi(struct usb_line6 *line6) int line6_init_midi(struct usb_line6 *line6)
{ {
static struct snd_device_ops midi_ops = {
.dev_free = snd_line6_midi_free,
};
int err; int err;
struct snd_rawmidi *rmidi;
struct snd_line6_midi *line6midi; struct snd_line6_midi *line6midi;
if (!(line6->properties->capabilities & LINE6_CAP_CONTROL)) { if (!(line6->properties->capabilities & LINE6_CAP_CONTROL)) {
...@@ -284,38 +269,31 @@ int line6_init_midi(struct usb_line6 *line6) ...@@ -284,38 +269,31 @@ int line6_init_midi(struct usb_line6 *line6)
return 0; return 0;
} }
line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL); err = snd_line6_new_midi(line6, &rmidi);
if (err < 0)
return err;
if (line6midi == NULL) line6midi = kzalloc(sizeof(struct snd_line6_midi), GFP_KERNEL);
if (!line6midi)
return -ENOMEM; return -ENOMEM;
err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0); rmidi->private_data = line6midi;
if (err < 0) { rmidi->private_free = snd_line6_midi_free;
kfree(line6midi);
return err;
}
err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1);
if (err < 0) {
kfree(line6midi->midibuf_in.buf);
kfree(line6midi);
return err;
}
init_waitqueue_head(&line6midi->send_wait);
spin_lock_init(&line6midi->send_urb_lock);
spin_lock_init(&line6midi->midi_transmit_lock);
line6midi->line6 = line6; line6midi->line6 = line6;
line6->line6midi = line6midi;
err = snd_device_new(line6->card, SNDRV_DEV_RAWMIDI, line6midi, err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0);
&midi_ops);
if (err < 0) if (err < 0)
return err; return err;
err = snd_line6_new_midi(line6midi); err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1);
if (err < 0) if (err < 0)
return err; return err;
init_waitqueue_head(&line6midi->send_wait); line6->line6midi = line6midi;
spin_lock_init(&line6midi->send_urb_lock);
spin_lock_init(&line6midi->midi_transmit_lock);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(line6_init_midi);
/* /*
* Line6 Linux USB driver - 0.9.1beta * Line 6 Linux USB driver
* *
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
* *
...@@ -20,7 +20,7 @@ ...@@ -20,7 +20,7 @@
struct snd_line6_midi { struct snd_line6_midi {
/** /**
Pointer back to the Line6 driver data structure. Pointer back to the Line 6 driver data structure.
*/ */
struct usb_line6 *line6; struct usb_line6 *line6;
......
/* /*
* Line6 Linux USB driver - 0.9.1beta * Line 6 Linux USB driver
* *
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
* *
...@@ -26,7 +26,7 @@ static int midibuf_message_length(unsigned char code) ...@@ -26,7 +26,7 @@ static int midibuf_message_length(unsigned char code)
} else { } else {
/* /*
Note that according to the MIDI specification 0xf2 is Note that according to the MIDI specification 0xf2 is
the "Song Position Pointer", but this is used by Line6 the "Song Position Pointer", but this is used by Line 6
to send sysex messages to the host. to send sysex messages to the host.
*/ */
static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1, static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1,
......
/* /*
* Line6 Linux USB driver - 0.9.1beta * Line 6 Linux USB driver
* *
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
* *
......
This diff is collapsed.
/* /*
* Line6 Linux USB driver - 0.9.1beta * Line 6 Linux USB driver
* *
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
* *
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
/* /*
number of USB frames per URB number of USB frames per URB
The Line6 Windows driver always transmits two frames per packet, but The Line 6 Windows driver always transmits two frames per packet, but
the Linux driver performs significantly better (i.e., lower latency) the Linux driver performs significantly better (i.e., lower latency)
with only one frame per packet. with only one frame per packet.
*/ */
...@@ -35,12 +35,10 @@ ...@@ -35,12 +35,10 @@
/* in a "full speed" device (such as the PODxt Pro) this means 1ms */ /* in a "full speed" device (such as the PODxt Pro) this means 1ms */
#define LINE6_ISO_INTERVAL 1 #define LINE6_ISO_INTERVAL 1
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
#define LINE6_IMPULSE_DEFAULT_PERIOD 100 #define LINE6_IMPULSE_DEFAULT_PERIOD 100
#endif
/* /*
Get substream from Line6 PCM data structure Get substream from Line 6 PCM data structure
*/ */
#define get_substream(line6pcm, stream) \ #define get_substream(line6pcm, stream) \
(line6pcm->pcm->streams[stream].substream) (line6pcm->pcm->streams[stream].substream)
...@@ -48,7 +46,7 @@ ...@@ -48,7 +46,7 @@
/* /*
PCM mode bits. PCM mode bits.
There are several features of the Line6 USB driver which require PCM There are several features of the Line 6 USB driver which require PCM
data to be exchanged with the device: data to be exchanged with the device:
*) PCM playback and capture via ALSA *) PCM playback and capture via ALSA
*) software monitoring (for devices without hardware monitoring) *) software monitoring (for devices without hardware monitoring)
...@@ -89,12 +87,10 @@ enum { ...@@ -89,12 +87,10 @@ enum {
LINE6_INDEX_PCM_MONITOR_PLAYBACK_STREAM, LINE6_INDEX_PCM_MONITOR_PLAYBACK_STREAM,
LINE6_INDEX_PCM_MONITOR_CAPTURE_BUFFER, LINE6_INDEX_PCM_MONITOR_CAPTURE_BUFFER,
LINE6_INDEX_PCM_MONITOR_CAPTURE_STREAM, LINE6_INDEX_PCM_MONITOR_CAPTURE_STREAM,
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
LINE6_INDEX_PCM_IMPULSE_PLAYBACK_BUFFER, LINE6_INDEX_PCM_IMPULSE_PLAYBACK_BUFFER,
LINE6_INDEX_PCM_IMPULSE_PLAYBACK_STREAM, LINE6_INDEX_PCM_IMPULSE_PLAYBACK_STREAM,
LINE6_INDEX_PCM_IMPULSE_CAPTURE_BUFFER, LINE6_INDEX_PCM_IMPULSE_CAPTURE_BUFFER,
LINE6_INDEX_PCM_IMPULSE_CAPTURE_STREAM, LINE6_INDEX_PCM_IMPULSE_CAPTURE_STREAM,
#endif
LINE6_INDEX_PAUSE_PLAYBACK, LINE6_INDEX_PAUSE_PLAYBACK,
LINE6_INDEX_PREPARED, LINE6_INDEX_PREPARED,
...@@ -109,12 +105,10 @@ enum { ...@@ -109,12 +105,10 @@ enum {
LINE6_BIT(PCM_MONITOR_PLAYBACK_STREAM), LINE6_BIT(PCM_MONITOR_PLAYBACK_STREAM),
LINE6_BIT(PCM_MONITOR_CAPTURE_BUFFER), LINE6_BIT(PCM_MONITOR_CAPTURE_BUFFER),
LINE6_BIT(PCM_MONITOR_CAPTURE_STREAM), LINE6_BIT(PCM_MONITOR_CAPTURE_STREAM),
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
LINE6_BIT(PCM_IMPULSE_PLAYBACK_BUFFER), LINE6_BIT(PCM_IMPULSE_PLAYBACK_BUFFER),
LINE6_BIT(PCM_IMPULSE_PLAYBACK_STREAM), LINE6_BIT(PCM_IMPULSE_PLAYBACK_STREAM),
LINE6_BIT(PCM_IMPULSE_CAPTURE_BUFFER), LINE6_BIT(PCM_IMPULSE_CAPTURE_BUFFER),
LINE6_BIT(PCM_IMPULSE_CAPTURE_STREAM), LINE6_BIT(PCM_IMPULSE_CAPTURE_STREAM),
#endif
LINE6_BIT(PAUSE_PLAYBACK), LINE6_BIT(PAUSE_PLAYBACK),
LINE6_BIT(PREPARED), LINE6_BIT(PREPARED),
...@@ -133,40 +127,30 @@ enum { ...@@ -133,40 +127,30 @@ enum {
LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER | LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER |
LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM, LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
LINE6_BITS_PCM_IMPULSE = LINE6_BITS_PCM_IMPULSE =
LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER | LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM | LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM |
LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER | LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER |
LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM, LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM,
#endif
/* combined bit masks (by direction): */ /* combined bit masks (by direction): */
LINE6_BITS_PLAYBACK_BUFFER = LINE6_BITS_PLAYBACK_BUFFER =
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER | LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
#endif
LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER | LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER |
LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER, LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER,
LINE6_BITS_PLAYBACK_STREAM = LINE6_BITS_PLAYBACK_STREAM =
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM | LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM |
#endif
LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM | LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM |
LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM, LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM,
LINE6_BITS_CAPTURE_BUFFER = LINE6_BITS_CAPTURE_BUFFER =
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER | LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER |
#endif
LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER | LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER |
LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER, LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER,
LINE6_BITS_CAPTURE_STREAM = LINE6_BITS_CAPTURE_STREAM =
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM | LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM |
#endif
LINE6_BIT_PCM_ALSA_CAPTURE_STREAM | LINE6_BIT_PCM_ALSA_CAPTURE_STREAM |
LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM, LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,
...@@ -183,7 +167,7 @@ struct line6_pcm_properties { ...@@ -183,7 +167,7 @@ struct line6_pcm_properties {
struct snd_line6_pcm { struct snd_line6_pcm {
/** /**
Pointer back to the Line6 driver data structure. Pointer back to the Line 6 driver data structure.
*/ */
struct usb_line6 *line6; struct usb_line6 *line6;
...@@ -338,7 +322,6 @@ struct snd_line6_pcm { ...@@ -338,7 +322,6 @@ struct snd_line6_pcm {
*/ */
int volume_monitor; int volume_monitor;
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
/** /**
Volume of impulse response test signal (if zero, test is disabled). Volume of impulse response test signal (if zero, test is disabled).
*/ */
...@@ -353,7 +336,6 @@ struct snd_line6_pcm { ...@@ -353,7 +336,6 @@ struct snd_line6_pcm {
Counter for impulse response test signal. Counter for impulse response test signal.
*/ */
int impulse_count; int impulse_count;
#endif
/** /**
Several status bits (see LINE6_BIT_*). Several status bits (see LINE6_BIT_*).
......
/* /*
* Line6 Linux USB driver - 0.9.1beta * Line 6 Linux USB driver
* *
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
* *
...@@ -14,11 +14,9 @@ ...@@ -14,11 +14,9 @@
#include <sound/pcm.h> #include <sound/pcm.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include "audio.h"
#include "capture.h" #include "capture.h"
#include "driver.h" #include "driver.h"
#include "pcm.h" #include "pcm.h"
#include "pod.h"
#include "playback.h" #include "playback.h"
/* /*
...@@ -61,8 +59,6 @@ static void change_volume(struct urb *urb_out, int volume[], ...@@ -61,8 +59,6 @@ static void change_volume(struct urb *urb_out, int volume[],
} }
} }
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
/* /*
Create signal for impulse response test. Create signal for impulse response test.
*/ */
...@@ -106,8 +102,6 @@ static void create_impulse_test_signal(struct snd_line6_pcm *line6pcm, ...@@ -106,8 +102,6 @@ static void create_impulse_test_signal(struct snd_line6_pcm *line6pcm,
} }
} }
#endif
/* /*
Add signal to buffer for software monitoring. Add signal to buffer for software monitoring.
*/ */
...@@ -244,7 +238,6 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) ...@@ -244,7 +238,6 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
change_volume(urb_out, line6pcm->volume_playback, bytes_per_frame); change_volume(urb_out, line6pcm->volume_playback, bytes_per_frame);
if (line6pcm->prev_fbuf != NULL) { if (line6pcm->prev_fbuf != NULL) {
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
if (line6pcm->flags & LINE6_BITS_PCM_IMPULSE) { if (line6pcm->flags & LINE6_BITS_PCM_IMPULSE) {
create_impulse_test_signal(line6pcm, urb_out, create_impulse_test_signal(line6pcm, urb_out,
bytes_per_frame); bytes_per_frame);
...@@ -258,7 +251,6 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) ...@@ -258,7 +251,6 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
urb_out->transfer_buffer_length); urb_out->transfer_buffer_length);
} }
} else { } else {
#endif
if (! if (!
(line6pcm->line6-> (line6pcm->line6->
properties->capabilities & LINE6_CAP_HWMON) properties->capabilities & LINE6_CAP_HWMON)
...@@ -267,9 +259,7 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm) ...@@ -267,9 +259,7 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
add_monitor_signal(urb_out, line6pcm->prev_fbuf, add_monitor_signal(urb_out, line6pcm->prev_fbuf,
line6pcm->volume_monitor, line6pcm->volume_monitor,
bytes_per_frame); bytes_per_frame);
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
} }
#endif
} }
ret = usb_submit_urb(urb_out, GFP_ATOMIC); ret = usb_submit_urb(urb_out, GFP_ATOMIC);
...@@ -499,9 +489,7 @@ int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd) ...@@ -499,9 +489,7 @@ int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd)
switch (cmd) { switch (cmd) {
case SNDRV_PCM_TRIGGER_START: case SNDRV_PCM_TRIGGER_START:
#ifdef CONFIG_PM
case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_RESUME:
#endif
err = line6_pcm_acquire(line6pcm, err = line6_pcm_acquire(line6pcm,
LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM); LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM);
...@@ -511,9 +499,7 @@ int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd) ...@@ -511,9 +499,7 @@ int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd)
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
#ifdef CONFIG_PM
case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_SUSPEND:
#endif
err = line6_pcm_release(line6pcm, err = line6_pcm_release(line6pcm,
LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM); LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM);
...@@ -571,10 +557,8 @@ int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm) ...@@ -571,10 +557,8 @@ int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm)
urb = line6pcm->urb_audio_out[i] = urb = line6pcm->urb_audio_out[i] =
usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL); usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
if (urb == NULL) { if (urb == NULL)
dev_err(line6->ifcdev, "Out of memory\n");
return -ENOMEM; return -ENOMEM;
}
urb->dev = line6->usbdev; urb->dev = line6->usbdev;
urb->pipe = urb->pipe =
......
/* /*
* Line6 Linux USB driver - 0.9.1beta * Line 6 Linux USB driver
* *
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
* *
......
/* /*
* Line6 Linux USB driver - 0.9.1beta * Line 6 Linux USB driver
* *
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
* *
...@@ -11,13 +11,93 @@ ...@@ -11,13 +11,93 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <sound/core.h>
#include <sound/control.h> #include <sound/control.h>
#include "audio.h"
#include "capture.h" #include "capture.h"
#include "driver.h" #include "driver.h"
#include "playback.h" #include "playback.h"
#include "pod.h" #include "usbdefs.h"
/*
Locate name in binary program dump
*/
#define POD_NAME_OFFSET 0
#define POD_NAME_LENGTH 16
/*
Other constants
*/
#define POD_CONTROL_SIZE 0x80
#define POD_BUFSIZE_DUMPREQ 7
#define POD_STARTUP_DELAY 1000
/*
Stages of POD startup procedure
*/
enum {
POD_STARTUP_INIT = 1,
POD_STARTUP_VERSIONREQ,
POD_STARTUP_WORKQUEUE,
POD_STARTUP_SETUP,
POD_STARTUP_LAST = POD_STARTUP_SETUP - 1
};
enum {
LINE6_BASSPODXT,
LINE6_BASSPODXTLIVE,
LINE6_BASSPODXTPRO,
LINE6_POCKETPOD,
LINE6_PODXT,
LINE6_PODXTLIVE_POD,
LINE6_PODXTPRO,
};
struct usb_line6_pod {
/**
Generic Line 6 USB data.
*/
struct usb_line6 line6;
/**
Instrument monitor level.
*/
int monitor_level;
/**
Timer for device initializaton.
*/
struct timer_list startup_timer;
/**
Work handler for device initializaton.
*/
struct work_struct startup_work;
/**
Current progress in startup procedure.
*/
int startup_progress;
/**
Serial number of device.
*/
int serial_number;
/**
Firmware version (x 100).
*/
int firmware_version;
/**
Device ID.
*/
int device_id;
};
#define POD_SYSEX_CODE 3 #define POD_SYSEX_CODE 3
#define POD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */ #define POD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */
...@@ -72,9 +152,6 @@ static struct line6_pcm_properties pod_pcm_properties = { ...@@ -72,9 +152,6 @@ static struct line6_pcm_properties pod_pcm_properties = {
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_PAUSE |
#ifdef CONFIG_PM
SNDRV_PCM_INFO_RESUME |
#endif
SNDRV_PCM_INFO_SYNC_START), SNDRV_PCM_INFO_SYNC_START),
.formats = SNDRV_PCM_FMTBIT_S24_3LE, .formats = SNDRV_PCM_FMTBIT_S24_3LE,
.rates = SNDRV_PCM_RATE_KNOT, .rates = SNDRV_PCM_RATE_KNOT,
...@@ -92,9 +169,6 @@ static struct line6_pcm_properties pod_pcm_properties = { ...@@ -92,9 +169,6 @@ static struct line6_pcm_properties pod_pcm_properties = {
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_MMAP_VALID |
#ifdef CONFIG_PM
SNDRV_PCM_INFO_RESUME |
#endif
SNDRV_PCM_INFO_SYNC_START), SNDRV_PCM_INFO_SYNC_START),
.formats = SNDRV_PCM_FMTBIT_S24_3LE, .formats = SNDRV_PCM_FMTBIT_S24_3LE,
.rates = SNDRV_PCM_RATE_KNOT, .rates = SNDRV_PCM_RATE_KNOT,
...@@ -265,7 +339,7 @@ static void pod_startup4(struct work_struct *work) ...@@ -265,7 +339,7 @@ static void pod_startup4(struct work_struct *work)
line6_read_serial_number(&pod->line6, &pod->serial_number); line6_read_serial_number(&pod->line6, &pod->serial_number);
/* ALSA audio interface: */ /* ALSA audio interface: */
line6_register_audio(line6); snd_card_register(line6->card);
} }
/* POD special files: */ /* POD special files: */
...@@ -322,21 +396,6 @@ static struct snd_kcontrol_new pod_control_monitor = { ...@@ -322,21 +396,6 @@ static struct snd_kcontrol_new pod_control_monitor = {
.put = snd_pod_control_monitor_put .put = snd_pod_control_monitor_put
}; };
/*
POD destructor.
*/
static void pod_destruct(struct usb_interface *interface)
{
struct usb_line6_pod *pod = usb_get_intfdata(interface);
if (pod == NULL)
return;
line6_cleanup_audio(&pod->line6);
del_timer(&pod->startup_timer);
cancel_work_sync(&pod->startup_work);
}
/* /*
POD device disconnected. POD device disconnected.
*/ */
...@@ -349,21 +408,18 @@ static void line6_pod_disconnect(struct usb_interface *interface) ...@@ -349,21 +408,18 @@ static void line6_pod_disconnect(struct usb_interface *interface)
pod = usb_get_intfdata(interface); pod = usb_get_intfdata(interface);
if (pod != NULL) { if (pod != NULL) {
struct snd_line6_pcm *line6pcm = pod->line6.line6pcm;
struct device *dev = &interface->dev; struct device *dev = &interface->dev;
if (line6pcm != NULL)
line6_pcm_disconnect(line6pcm);
if (dev != NULL) { if (dev != NULL) {
/* remove sysfs entries: */ /* remove sysfs entries: */
device_remove_file(dev, &dev_attr_device_id); device_remove_file(dev, &dev_attr_device_id);
device_remove_file(dev, &dev_attr_firmware_version); device_remove_file(dev, &dev_attr_firmware_version);
device_remove_file(dev, &dev_attr_serial_number); device_remove_file(dev, &dev_attr_serial_number);
} }
}
pod_destruct(interface); del_timer_sync(&pod->startup_timer);
cancel_work_sync(&pod->startup_work);
}
} }
/* /*
...@@ -373,16 +429,22 @@ static int pod_create_files2(struct device *dev) ...@@ -373,16 +429,22 @@ static int pod_create_files2(struct device *dev)
{ {
int err; int err;
CHECK_RETURN(device_create_file(dev, &dev_attr_device_id)); err = device_create_file(dev, &dev_attr_device_id);
CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version)); if (err < 0)
CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number)); return err;
err = device_create_file(dev, &dev_attr_firmware_version);
if (err < 0)
return err;
err = device_create_file(dev, &dev_attr_serial_number);
if (err < 0)
return err;
return 0; return 0;
} }
/* /*
Try to init POD device. Try to init POD device.
*/ */
static int pod_try_init(struct usb_interface *interface, static int pod_init(struct usb_interface *interface,
struct usb_line6 *line6) struct usb_line6 *line6)
{ {
int err; int err;
...@@ -402,11 +464,6 @@ static int pod_try_init(struct usb_interface *interface, ...@@ -402,11 +464,6 @@ static int pod_try_init(struct usb_interface *interface,
if (err < 0) if (err < 0)
return err; return err;
/* initialize audio system: */
err = line6_init_audio(line6);
if (err < 0)
return err;
/* initialize MIDI subsystem: */ /* initialize MIDI subsystem: */
err = line6_init_midi(line6); err = line6_init_midi(line6);
if (err < 0) if (err < 0)
...@@ -439,15 +496,136 @@ static int pod_try_init(struct usb_interface *interface, ...@@ -439,15 +496,136 @@ static int pod_try_init(struct usb_interface *interface,
return 0; return 0;
} }
#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
/* table of devices that work with this driver */
static const struct usb_device_id pod_id_table[] = {
{ LINE6_DEVICE(0x4250), .driver_info = LINE6_BASSPODXT },
{ LINE6_DEVICE(0x4642), .driver_info = LINE6_BASSPODXTLIVE },
{ LINE6_DEVICE(0x4252), .driver_info = LINE6_BASSPODXTPRO },
{ LINE6_IF_NUM(0x5051, 1), .driver_info = LINE6_POCKETPOD },
{ LINE6_DEVICE(0x5044), .driver_info = LINE6_PODXT },
{ LINE6_IF_NUM(0x4650, 0), .driver_info = LINE6_PODXTLIVE_POD },
{ LINE6_DEVICE(0x5050), .driver_info = LINE6_PODXTPRO },
{}
};
MODULE_DEVICE_TABLE(usb, pod_id_table);
static const struct line6_properties pod_properties_table[] = {
[LINE6_BASSPODXT] = {
.id = "BassPODxt",
.name = "BassPODxt",
.capabilities = LINE6_CAP_CONTROL
| LINE6_CAP_PCM
| LINE6_CAP_HWMON,
.altsetting = 5,
.ep_ctrl_r = 0x84,
.ep_ctrl_w = 0x03,
.ep_audio_r = 0x82,
.ep_audio_w = 0x01,
},
[LINE6_BASSPODXTLIVE] = {
.id = "BassPODxtLive",
.name = "BassPODxt Live",
.capabilities = LINE6_CAP_CONTROL
| LINE6_CAP_PCM
| LINE6_CAP_HWMON,
.altsetting = 1,
.ep_ctrl_r = 0x84,
.ep_ctrl_w = 0x03,
.ep_audio_r = 0x82,
.ep_audio_w = 0x01,
},
[LINE6_BASSPODXTPRO] = {
.id = "BassPODxtPro",
.name = "BassPODxt Pro",
.capabilities = LINE6_CAP_CONTROL
| LINE6_CAP_PCM
| LINE6_CAP_HWMON,
.altsetting = 5,
.ep_ctrl_r = 0x84,
.ep_ctrl_w = 0x03,
.ep_audio_r = 0x82,
.ep_audio_w = 0x01,
},
[LINE6_POCKETPOD] = {
.id = "PocketPOD",
.name = "Pocket POD",
.capabilities = LINE6_CAP_CONTROL,
.altsetting = 0,
.ep_ctrl_r = 0x82,
.ep_ctrl_w = 0x02,
/* no audio channel */
},
[LINE6_PODXT] = {
.id = "PODxt",
.name = "PODxt",
.capabilities = LINE6_CAP_CONTROL
| LINE6_CAP_PCM
| LINE6_CAP_HWMON,
.altsetting = 5,
.ep_ctrl_r = 0x84,
.ep_ctrl_w = 0x03,
.ep_audio_r = 0x82,
.ep_audio_w = 0x01,
},
[LINE6_PODXTLIVE_POD] = {
.id = "PODxtLive",
.name = "PODxt Live",
.capabilities = LINE6_CAP_CONTROL
| LINE6_CAP_PCM
| LINE6_CAP_HWMON,
.altsetting = 1,
.ep_ctrl_r = 0x84,
.ep_ctrl_w = 0x03,
.ep_audio_r = 0x82,
.ep_audio_w = 0x01,
},
[LINE6_PODXTPRO] = {
.id = "PODxtPro",
.name = "PODxt Pro",
.capabilities = LINE6_CAP_CONTROL
| LINE6_CAP_PCM
| LINE6_CAP_HWMON,
.altsetting = 5,
.ep_ctrl_r = 0x84,
.ep_ctrl_w = 0x03,
.ep_audio_r = 0x82,
.ep_audio_w = 0x01,
},
};
/* /*
Init POD device (and clean up in case of failure). Probe USB device.
*/ */
int line6_pod_init(struct usb_interface *interface, struct usb_line6 *line6) static int pod_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{ {
int err = pod_try_init(interface, line6); struct usb_line6_pod *pod;
if (err < 0)
pod_destruct(interface);
return err; pod = kzalloc(sizeof(*pod), GFP_KERNEL);
if (!pod)
return -ENODEV;
return line6_probe(interface, &pod->line6,
&pod_properties_table[id->driver_info],
pod_init);
} }
static struct usb_driver pod_driver = {
.name = KBUILD_MODNAME,
.probe = pod_probe,
.disconnect = line6_disconnect,
#ifdef CONFIG_PM
.suspend = line6_suspend,
.resume = line6_resume,
.reset_resume = line6_resume,
#endif
.id_table = pod_id_table,
};
module_usb_driver(pod_driver);
MODULE_DESCRIPTION("Line 6 POD USB driver");
MODULE_LICENSE("GPL");
/*
* Line6 Linux USB driver - 0.9.1beta
*
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2.
*
*/
#ifndef POD_H
#define POD_H
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/usb.h>
#include <sound/core.h>
#include "driver.h"
/*
Locate name in binary program dump
*/
#define POD_NAME_OFFSET 0
#define POD_NAME_LENGTH 16
/*
Other constants
*/
#define POD_CONTROL_SIZE 0x80
#define POD_BUFSIZE_DUMPREQ 7
#define POD_STARTUP_DELAY 1000
/*
Stages of POD startup procedure
*/
enum {
POD_STARTUP_INIT = 1,
POD_STARTUP_VERSIONREQ,
POD_STARTUP_WORKQUEUE,
POD_STARTUP_SETUP,
POD_STARTUP_LAST = POD_STARTUP_SETUP - 1
};
struct usb_line6_pod {
/**
Generic Line6 USB data.
*/
struct usb_line6 line6;
/**
Instrument monitor level.
*/
int monitor_level;
/**
Timer for device initializaton.
*/
struct timer_list startup_timer;
/**
Work handler for device initializaton.
*/
struct work_struct startup_work;
/**
Current progress in startup procedure.
*/
int startup_progress;
/**
Serial number of device.
*/
int serial_number;
/**
Firmware version (x 100).
*/
int firmware_version;
/**
Device ID.
*/
int device_id;
};
extern int line6_pod_init(struct usb_interface *interface,
struct usb_line6 *line6);
#endif
/* /*
* Line6 Pod HD * Line 6 Pod HD
* *
* Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com> * Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
* *
...@@ -9,13 +9,29 @@ ...@@ -9,13 +9,29 @@
* *
*/ */
#include <linux/usb.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#include "audio.h"
#include "driver.h" #include "driver.h"
#include "pcm.h" #include "pcm.h"
#include "podhd.h" #include "usbdefs.h"
enum {
LINE6_PODHD300,
LINE6_PODHD400,
LINE6_PODHD500_0,
LINE6_PODHD500_1,
};
struct usb_line6_podhd {
/**
Generic Line 6 USB data.
*/
struct usb_line6 line6;
};
#define PODHD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */ #define PODHD_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */
...@@ -33,9 +49,6 @@ static struct line6_pcm_properties podhd_pcm_properties = { ...@@ -33,9 +49,6 @@ static struct line6_pcm_properties podhd_pcm_properties = {
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_PAUSE |
#ifdef CONFIG_PM
SNDRV_PCM_INFO_RESUME |
#endif
SNDRV_PCM_INFO_SYNC_START), SNDRV_PCM_INFO_SYNC_START),
.formats = SNDRV_PCM_FMTBIT_S24_3LE, .formats = SNDRV_PCM_FMTBIT_S24_3LE,
.rates = SNDRV_PCM_RATE_48000, .rates = SNDRV_PCM_RATE_48000,
...@@ -53,9 +66,6 @@ static struct line6_pcm_properties podhd_pcm_properties = { ...@@ -53,9 +66,6 @@ static struct line6_pcm_properties podhd_pcm_properties = {
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_MMAP_VALID |
#ifdef CONFIG_PM
SNDRV_PCM_INFO_RESUME |
#endif
SNDRV_PCM_INFO_SYNC_START), SNDRV_PCM_INFO_SYNC_START),
.formats = SNDRV_PCM_FMTBIT_S24_3LE, .formats = SNDRV_PCM_FMTBIT_S24_3LE,
.rates = SNDRV_PCM_RATE_48000, .rates = SNDRV_PCM_RATE_48000,
...@@ -74,58 +84,18 @@ static struct line6_pcm_properties podhd_pcm_properties = { ...@@ -74,58 +84,18 @@ static struct line6_pcm_properties podhd_pcm_properties = {
.bytes_per_frame = PODHD_BYTES_PER_FRAME .bytes_per_frame = PODHD_BYTES_PER_FRAME
}; };
/*
POD HD destructor.
*/
static void podhd_destruct(struct usb_interface *interface)
{
struct usb_line6_podhd *podhd = usb_get_intfdata(interface);
if (podhd == NULL)
return;
line6_cleanup_audio(&podhd->line6);
}
/*
POD HD device disconnected.
*/
static void line6_podhd_disconnect(struct usb_interface *interface)
{
struct usb_line6_podhd *podhd;
if (interface == NULL)
return;
podhd = usb_get_intfdata(interface);
if (podhd != NULL) {
struct snd_line6_pcm *line6pcm = podhd->line6.line6pcm;
if (line6pcm != NULL)
line6_pcm_disconnect(line6pcm);
}
podhd_destruct(interface);
}
/* /*
Try to init POD HD device. Try to init POD HD device.
*/ */
static int podhd_try_init(struct usb_interface *interface, static int podhd_init(struct usb_interface *interface,
struct usb_line6_podhd *podhd) struct usb_line6 *line6)
{ {
struct usb_line6_podhd *podhd = (struct usb_line6_podhd *) line6;
int err; int err;
struct usb_line6 *line6 = &podhd->line6;
if ((interface == NULL) || (podhd == NULL)) if ((interface == NULL) || (podhd == NULL))
return -ENODEV; return -ENODEV;
line6->disconnect = line6_podhd_disconnect;
/* initialize audio system: */
err = line6_init_audio(line6);
if (err < 0)
return err;
/* initialize MIDI subsystem: */ /* initialize MIDI subsystem: */
err = line6_init_midi(line6); err = line6_init_midi(line6);
if (err < 0) if (err < 0)
...@@ -137,20 +107,103 @@ static int podhd_try_init(struct usb_interface *interface, ...@@ -137,20 +107,103 @@ static int podhd_try_init(struct usb_interface *interface,
return err; return err;
/* register USB audio system: */ /* register USB audio system: */
err = line6_register_audio(line6); return snd_card_register(line6->card);
return err;
} }
#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
/* table of devices that work with this driver */
static const struct usb_device_id podhd_id_table[] = {
{ LINE6_DEVICE(0x5057), .driver_info = LINE6_PODHD300 },
{ LINE6_DEVICE(0x5058), .driver_info = LINE6_PODHD400 },
{ LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500_0 },
{ LINE6_IF_NUM(0x414D, 1), .driver_info = LINE6_PODHD500_1 },
{}
};
MODULE_DEVICE_TABLE(usb, podhd_id_table);
static const struct line6_properties podhd_properties_table[] = {
[LINE6_PODHD300] = {
.id = "PODHD300",
.name = "POD HD300",
.capabilities = LINE6_CAP_CONTROL
| LINE6_CAP_PCM
| LINE6_CAP_HWMON,
.altsetting = 5,
.ep_ctrl_r = 0x84,
.ep_ctrl_w = 0x03,
.ep_audio_r = 0x82,
.ep_audio_w = 0x01,
},
[LINE6_PODHD400] = {
.id = "PODHD400",
.name = "POD HD400",
.capabilities = LINE6_CAP_CONTROL
| LINE6_CAP_PCM
| LINE6_CAP_HWMON,
.altsetting = 5,
.ep_ctrl_r = 0x84,
.ep_ctrl_w = 0x03,
.ep_audio_r = 0x82,
.ep_audio_w = 0x01,
},
[LINE6_PODHD500_0] = {
.id = "PODHD500",
.name = "POD HD500",
.capabilities = LINE6_CAP_CONTROL
| LINE6_CAP_PCM
| LINE6_CAP_HWMON,
.altsetting = 1,
.ep_ctrl_r = 0x81,
.ep_ctrl_w = 0x01,
.ep_audio_r = 0x86,
.ep_audio_w = 0x02,
},
[LINE6_PODHD500_1] = {
.id = "PODHD500",
.name = "POD HD500",
.capabilities = LINE6_CAP_CONTROL
| LINE6_CAP_PCM
| LINE6_CAP_HWMON,
.altsetting = 1,
.ep_ctrl_r = 0x81,
.ep_ctrl_w = 0x01,
.ep_audio_r = 0x86,
.ep_audio_w = 0x02,
},
};
/* /*
Init POD HD device (and clean up in case of failure). Probe USB device.
*/ */
int line6_podhd_init(struct usb_interface *interface, struct usb_line6 *line6) static int podhd_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{ {
struct usb_line6_podhd *podhd = (struct usb_line6_podhd *) line6; struct usb_line6_podhd *podhd;
int err = podhd_try_init(interface, podhd);
if (err < 0)
podhd_destruct(interface);
return err; podhd = kzalloc(sizeof(*podhd), GFP_KERNEL);
if (!podhd)
return -ENODEV;
return line6_probe(interface, &podhd->line6,
&podhd_properties_table[id->driver_info],
podhd_init);
} }
static struct usb_driver podhd_driver = {
.name = KBUILD_MODNAME,
.probe = podhd_probe,
.disconnect = line6_disconnect,
#ifdef CONFIG_PM
.suspend = line6_suspend,
.resume = line6_resume,
.reset_resume = line6_resume,
#endif
.id_table = podhd_id_table,
};
module_usb_driver(podhd_driver);
MODULE_DESCRIPTION("Line 6 PODHD USB driver");
MODULE_LICENSE("GPL");
/*
* Line6 Pod HD
*
* Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2.
*
*/
#ifndef PODHD_H
#define PODHD_H
#include <linux/usb.h>
#include "driver.h"
struct usb_line6_podhd {
/**
Generic Line6 USB data.
*/
struct usb_line6 line6;
};
extern int line6_podhd_init(struct usb_interface *interface,
struct usb_line6 *line6);
#endif /* PODHD_H */
/* /*
* Line6 Linux USB driver - 0.9.1beta * Line 6 Linux USB driver
* *
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
* Emil Myhrman (emil.myhrman@gmail.com) * Emil Myhrman (emil.myhrman@gmail.com)
...@@ -11,13 +11,58 @@ ...@@ -11,13 +11,58 @@
*/ */
#include <linux/wait.h> #include <linux/wait.h>
#include <linux/usb.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <sound/core.h>
#include <sound/control.h> #include <sound/control.h>
#include "audio.h"
#include "capture.h" #include "capture.h"
#include "driver.h" #include "driver.h"
#include "playback.h" #include "playback.h"
#include "toneport.h" #include "usbdefs.h"
enum line6_device_type {
LINE6_GUITARPORT,
LINE6_PODSTUDIO_GX,
LINE6_PODSTUDIO_UX1,
LINE6_PODSTUDIO_UX2,
LINE6_TONEPORT_GX,
LINE6_TONEPORT_UX1,
LINE6_TONEPORT_UX2,
};
struct usb_line6_toneport {
/**
Generic Line 6 USB data.
*/
struct usb_line6 line6;
/**
Source selector.
*/
int source;
/**
Serial number of device.
*/
int serial_number;
/**
Firmware version (x 100).
*/
int firmware_version;
/**
Timer for delayed PCM startup.
*/
struct timer_list timer;
/**
Device type.
*/
enum line6_device_type type;
};
static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2); static int toneport_send_cmd(struct usb_device *usbdev, int cmd1, int cmd2);
...@@ -37,9 +82,6 @@ static struct line6_pcm_properties toneport_pcm_properties = { ...@@ -37,9 +82,6 @@ static struct line6_pcm_properties toneport_pcm_properties = {
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_PAUSE |
#ifdef CONFIG_PM
SNDRV_PCM_INFO_RESUME |
#endif
SNDRV_PCM_INFO_SYNC_START), SNDRV_PCM_INFO_SYNC_START),
.formats = SNDRV_PCM_FMTBIT_S16_LE, .formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_KNOT, .rates = SNDRV_PCM_RATE_KNOT,
...@@ -57,9 +99,6 @@ static struct line6_pcm_properties toneport_pcm_properties = { ...@@ -57,9 +99,6 @@ static struct line6_pcm_properties toneport_pcm_properties = {
SNDRV_PCM_INFO_INTERLEAVED | SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER | SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP_VALID | SNDRV_PCM_INFO_MMAP_VALID |
#ifdef CONFIG_PM
SNDRV_PCM_INFO_RESUME |
#endif
SNDRV_PCM_INFO_SYNC_START), SNDRV_PCM_INFO_SYNC_START),
.formats = SNDRV_PCM_FMTBIT_S16_LE, .formats = SNDRV_PCM_FMTBIT_S16_LE,
.rates = SNDRV_PCM_RATE_KNOT, .rates = SNDRV_PCM_RATE_KNOT,
...@@ -290,18 +329,6 @@ static struct snd_kcontrol_new toneport_control_source = { ...@@ -290,18 +329,6 @@ static struct snd_kcontrol_new toneport_control_source = {
.put = snd_toneport_source_put .put = snd_toneport_source_put
}; };
/*
Toneport destructor.
*/
static void toneport_destruct(struct usb_interface *interface)
{
struct usb_line6_toneport *toneport = usb_get_intfdata(interface);
if (toneport == NULL)
return;
line6_cleanup_audio(&toneport->line6);
}
/* /*
Setup Toneport device. Setup Toneport device.
*/ */
...@@ -319,7 +346,7 @@ static void toneport_setup(struct usb_line6_toneport *toneport) ...@@ -319,7 +346,7 @@ static void toneport_setup(struct usb_line6_toneport *toneport)
toneport_send_cmd(usbdev, 0x0301, 0x0000); toneport_send_cmd(usbdev, 0x0301, 0x0000);
/* initialize source select: */ /* initialize source select: */
switch (line6->type) { switch (toneport->type) {
case LINE6_TONEPORT_UX1: case LINE6_TONEPORT_UX1:
case LINE6_TONEPORT_UX2: case LINE6_TONEPORT_UX2:
case LINE6_PODSTUDIO_UX1: case LINE6_PODSTUDIO_UX1:
...@@ -331,7 +358,7 @@ static void toneport_setup(struct usb_line6_toneport *toneport) ...@@ -331,7 +358,7 @@ static void toneport_setup(struct usb_line6_toneport *toneport)
break; break;
} }
if (toneport_has_led(line6->type)) if (toneport_has_led(toneport->type))
toneport_update_led(&usbdev->dev); toneport_update_led(&usbdev->dev);
} }
...@@ -354,24 +381,13 @@ static void line6_toneport_disconnect(struct usb_interface *interface) ...@@ -354,24 +381,13 @@ static void line6_toneport_disconnect(struct usb_interface *interface)
device_remove_file(&interface->dev, &dev_attr_led_red); device_remove_file(&interface->dev, &dev_attr_led_red);
device_remove_file(&interface->dev, &dev_attr_led_green); device_remove_file(&interface->dev, &dev_attr_led_green);
} }
if (toneport != NULL) {
struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm;
if (line6pcm != NULL) {
line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
line6_pcm_disconnect(line6pcm);
}
}
toneport_destruct(interface);
} }
/* /*
Try to init Toneport device. Try to init Toneport device.
*/ */
static int toneport_try_init(struct usb_interface *interface, static int toneport_init(struct usb_interface *interface,
struct usb_line6 *line6) struct usb_line6 *line6)
{ {
int err; int err;
...@@ -382,11 +398,6 @@ static int toneport_try_init(struct usb_interface *interface, ...@@ -382,11 +398,6 @@ static int toneport_try_init(struct usb_interface *interface,
line6->disconnect = line6_toneport_disconnect; line6->disconnect = line6_toneport_disconnect;
/* initialize audio system: */
err = line6_init_audio(line6);
if (err < 0)
return err;
/* initialize PCM subsystem: */ /* initialize PCM subsystem: */
err = line6_init_pcm(line6, &toneport_pcm_properties); err = line6_init_pcm(line6, &toneport_pcm_properties);
if (err < 0) if (err < 0)
...@@ -400,7 +411,7 @@ static int toneport_try_init(struct usb_interface *interface, ...@@ -400,7 +411,7 @@ static int toneport_try_init(struct usb_interface *interface,
return err; return err;
/* register source select control: */ /* register source select control: */
switch (line6->type) { switch (toneport->type) {
case LINE6_TONEPORT_UX1: case LINE6_TONEPORT_UX1:
case LINE6_TONEPORT_UX2: case LINE6_TONEPORT_UX2:
case LINE6_PODSTUDIO_UX1: case LINE6_PODSTUDIO_UX1:
...@@ -416,50 +427,152 @@ static int toneport_try_init(struct usb_interface *interface, ...@@ -416,50 +427,152 @@ static int toneport_try_init(struct usb_interface *interface,
break; break;
} }
/* register audio system: */
err = line6_register_audio(line6);
if (err < 0)
return err;
line6_read_serial_number(line6, &toneport->serial_number); line6_read_serial_number(line6, &toneport->serial_number);
line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1); line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1);
if (toneport_has_led(line6->type)) { if (toneport_has_led(toneport->type)) {
CHECK_RETURN(device_create_file err = device_create_file(&interface->dev, &dev_attr_led_red);
(&interface->dev, &dev_attr_led_red)); if (err < 0)
CHECK_RETURN(device_create_file return err;
(&interface->dev, &dev_attr_led_green)); err = device_create_file(&interface->dev, &dev_attr_led_green);
if (err < 0)
return err;
} }
toneport_setup(toneport); toneport_setup(toneport);
init_timer(&toneport->timer); setup_timer(&toneport->timer, toneport_start_pcm,
toneport->timer.expires = jiffies + TONEPORT_PCM_DELAY * HZ; (unsigned long)toneport);
toneport->timer.function = toneport_start_pcm; mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ);
toneport->timer.data = (unsigned long)toneport;
add_timer(&toneport->timer);
return 0; /* register audio system: */
return snd_card_register(line6->card);
} }
#ifdef CONFIG_PM
/* /*
Init Toneport device (and clean up in case of failure). Resume Toneport device after reset.
*/ */
int line6_toneport_init(struct usb_interface *interface, static int toneport_reset_resume(struct usb_interface *interface)
struct usb_line6 *line6)
{ {
int err = toneport_try_init(interface, line6); toneport_setup(usb_get_intfdata(interface));
return line6_resume(interface);
}
#endif
if (err < 0) #define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
toneport_destruct(interface); #define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
/* table of devices that work with this driver */
static const struct usb_device_id toneport_id_table[] = {
{ LINE6_DEVICE(0x4750), .driver_info = LINE6_GUITARPORT },
{ LINE6_DEVICE(0x4153), .driver_info = LINE6_PODSTUDIO_GX },
{ LINE6_DEVICE(0x4150), .driver_info = LINE6_PODSTUDIO_UX1 },
{ LINE6_IF_NUM(0x4151, 0), .driver_info = LINE6_PODSTUDIO_UX2 },
{ LINE6_DEVICE(0x4147), .driver_info = LINE6_TONEPORT_GX },
{ LINE6_DEVICE(0x4141), .driver_info = LINE6_TONEPORT_UX1 },
{ LINE6_IF_NUM(0x4142, 0), .driver_info = LINE6_TONEPORT_UX2 },
{}
};
return err; MODULE_DEVICE_TABLE(usb, toneport_id_table);
}
static const struct line6_properties toneport_properties_table[] = {
[LINE6_GUITARPORT] = {
.id = "GuitarPort",
.name = "GuitarPort",
.capabilities = LINE6_CAP_PCM,
.altsetting = 2, /* 1..4 seem to be ok */
/* no control channel */
.ep_audio_r = 0x82,
.ep_audio_w = 0x01,
},
[LINE6_PODSTUDIO_GX] = {
.id = "PODStudioGX",
.name = "POD Studio GX",
.capabilities = LINE6_CAP_PCM,
.altsetting = 2, /* 1..4 seem to be ok */
/* no control channel */
.ep_audio_r = 0x82,
.ep_audio_w = 0x01,
},
[LINE6_PODSTUDIO_UX1] = {
.id = "PODStudioUX1",
.name = "POD Studio UX1",
.capabilities = LINE6_CAP_PCM,
.altsetting = 2, /* 1..4 seem to be ok */
/* no control channel */
.ep_audio_r = 0x82,
.ep_audio_w = 0x01,
},
[LINE6_PODSTUDIO_UX2] = {
.id = "PODStudioUX2",
.name = "POD Studio UX2",
.capabilities = LINE6_CAP_PCM,
.altsetting = 2, /* defaults to 44.1kHz, 16-bit */
/* no control channel */
.ep_audio_r = 0x82,
.ep_audio_w = 0x01,
},
[LINE6_TONEPORT_GX] = {
.id = "TonePortGX",
.name = "TonePort GX",
.capabilities = LINE6_CAP_PCM,
.altsetting = 2, /* 1..4 seem to be ok */
/* no control channel */
.ep_audio_r = 0x82,
.ep_audio_w = 0x01,
},
[LINE6_TONEPORT_UX1] = {
.id = "TonePortUX1",
.name = "TonePort UX1",
.capabilities = LINE6_CAP_PCM,
.altsetting = 2, /* 1..4 seem to be ok */
/* no control channel */
.ep_audio_r = 0x82,
.ep_audio_w = 0x01,
},
[LINE6_TONEPORT_UX2] = {
.id = "TonePortUX2",
.name = "TonePort UX2",
.capabilities = LINE6_CAP_PCM,
.altsetting = 2, /* defaults to 44.1kHz, 16-bit */
/* no control channel */
.ep_audio_r = 0x82,
.ep_audio_w = 0x01,
},
};
/* /*
Resume Toneport device after reset. Probe USB device.
*/ */
void line6_toneport_reset_resume(struct usb_line6_toneport *toneport) static int toneport_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{ {
toneport_setup(toneport); struct usb_line6_toneport *toneport;
toneport = kzalloc(sizeof(*toneport), GFP_KERNEL);
if (!toneport)
return -ENODEV;
toneport->type = id->driver_info;
return line6_probe(interface, &toneport->line6,
&toneport_properties_table[id->driver_info],
toneport_init);
} }
static struct usb_driver toneport_driver = {
.name = KBUILD_MODNAME,
.probe = toneport_probe,
.disconnect = line6_disconnect,
#ifdef CONFIG_PM
.suspend = line6_suspend,
.resume = line6_resume,
.reset_resume = toneport_reset_resume,
#endif
.id_table = toneport_id_table,
};
module_usb_driver(toneport_driver);
MODULE_DESCRIPTION("TonePort USB driver");
MODULE_LICENSE("GPL");
/*
* Line6 Linux USB driver - 0.9.1beta
*
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2.
*
*/
#ifndef TONEPORT_H
#define TONEPORT_H
#include <linux/usb.h>
#include <sound/core.h>
#include "driver.h"
struct usb_line6_toneport {
/**
Generic Line6 USB data.
*/
struct usb_line6 line6;
/**
Source selector.
*/
int source;
/**
Serial number of device.
*/
int serial_number;
/**
Firmware version (x 100).
*/
int firmware_version;
/**
Timer for delayed PCM startup.
*/
struct timer_list timer;
};
extern int line6_toneport_init(struct usb_interface *interface,
struct usb_line6 *line6);
extern void line6_toneport_reset_resume(struct usb_line6_toneport *toneport);
#endif
/* /*
* Line6 Linux USB driver - 0.9.1beta * Line 6 Linux USB driver
* *
* Copyright (C) 2005-2008 Markus Grabner (grabner@icg.tugraz.at) * Copyright (C) 2005-2008 Markus Grabner (grabner@icg.tugraz.at)
* *
......
/* /*
* Line6 Linux USB driver - 0.9.1beta * Line 6 Linux USB driver
* *
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at) * Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
* *
...@@ -10,10 +10,64 @@ ...@@ -10,10 +10,64 @@
*/ */
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/usb.h>
#include <linux/wait.h>
#include <linux/module.h>
#include <sound/core.h>
#include "audio.h"
#include "driver.h" #include "driver.h"
#include "variax.h" #include "usbdefs.h"
#define VARIAX_STARTUP_DELAY1 1000
#define VARIAX_STARTUP_DELAY3 100
#define VARIAX_STARTUP_DELAY4 100
/*
Stages of Variax startup procedure
*/
enum {
VARIAX_STARTUP_INIT = 1,
VARIAX_STARTUP_VERSIONREQ,
VARIAX_STARTUP_WAIT,
VARIAX_STARTUP_ACTIVATE,
VARIAX_STARTUP_WORKQUEUE,
VARIAX_STARTUP_SETUP,
VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1
};
enum {
LINE6_PODXTLIVE_VARIAX,
LINE6_VARIAX
};
struct usb_line6_variax {
/**
Generic Line 6 USB data.
*/
struct usb_line6 line6;
/**
Buffer for activation code.
*/
unsigned char *buffer_activate;
/**
Handler for device initializaton.
*/
struct work_struct startup_work;
/**
Timers for device initializaton.
*/
struct timer_list startup_timer1;
struct timer_list startup_timer2;
/**
Current progress in startup procedure.
*/
int startup_progress;
};
#define VARIAX_OFFSET_ACTIVATE 7 #define VARIAX_OFFSET_ACTIVATE 7
...@@ -124,7 +178,7 @@ static void variax_startup6(struct work_struct *work) ...@@ -124,7 +178,7 @@ static void variax_startup6(struct work_struct *work)
CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP); CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
/* ALSA audio interface: */ /* ALSA audio interface: */
line6_register_audio(&variax->line6); snd_card_register(variax->line6.card);
} }
/* /*
...@@ -156,13 +210,16 @@ static void line6_variax_process_message(struct usb_line6 *line6) ...@@ -156,13 +210,16 @@ static void line6_variax_process_message(struct usb_line6 *line6)
/* /*
Variax destructor. Variax destructor.
*/ */
static void variax_destruct(struct usb_interface *interface) static void line6_variax_disconnect(struct usb_interface *interface)
{ {
struct usb_line6_variax *variax = usb_get_intfdata(interface); struct usb_line6_variax *variax;
if (!interface)
return;
if (variax == NULL) variax = usb_get_intfdata(interface);
if (!variax)
return; return;
line6_cleanup_audio(&variax->line6);
del_timer(&variax->startup_timer1); del_timer(&variax->startup_timer1);
del_timer(&variax->startup_timer2); del_timer(&variax->startup_timer2);
...@@ -171,21 +228,10 @@ static void variax_destruct(struct usb_interface *interface) ...@@ -171,21 +228,10 @@ static void variax_destruct(struct usb_interface *interface)
kfree(variax->buffer_activate); kfree(variax->buffer_activate);
} }
/*
Workbench device disconnected.
*/
static void line6_variax_disconnect(struct usb_interface *interface)
{
if (interface == NULL)
return;
variax_destruct(interface);
}
/* /*
Try to init workbench device. Try to init workbench device.
*/ */
static int variax_try_init(struct usb_interface *interface, static int variax_init(struct usb_interface *interface,
struct usb_line6 *line6) struct usb_line6 *line6)
{ {
struct usb_line6_variax *variax = (struct usb_line6_variax *) line6; struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
...@@ -205,15 +251,8 @@ static int variax_try_init(struct usb_interface *interface, ...@@ -205,15 +251,8 @@ static int variax_try_init(struct usb_interface *interface,
variax->buffer_activate = kmemdup(variax_activate, variax->buffer_activate = kmemdup(variax_activate,
sizeof(variax_activate), GFP_KERNEL); sizeof(variax_activate), GFP_KERNEL);
if (variax->buffer_activate == NULL) { if (variax->buffer_activate == NULL)
dev_err(&interface->dev, "Out of memory\n");
return -ENOMEM; return -ENOMEM;
}
/* initialize audio system: */
err = line6_init_audio(&variax->line6);
if (err < 0)
return err;
/* initialize MIDI subsystem: */ /* initialize MIDI subsystem: */
err = line6_init_midi(&variax->line6); err = line6_init_midi(&variax->line6);
...@@ -225,15 +264,71 @@ static int variax_try_init(struct usb_interface *interface, ...@@ -225,15 +264,71 @@ static int variax_try_init(struct usb_interface *interface,
return 0; return 0;
} }
#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
/* table of devices that work with this driver */
static const struct usb_device_id variax_id_table[] = {
{ LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX },
{ LINE6_DEVICE(0x534d), .driver_info = LINE6_VARIAX },
{}
};
MODULE_DEVICE_TABLE(usb, variax_id_table);
static const struct line6_properties variax_properties_table[] = {
[LINE6_PODXTLIVE_VARIAX] = {
.id = "PODxtLive",
.name = "PODxt Live",
.capabilities = LINE6_CAP_CONTROL
| LINE6_CAP_PCM
| LINE6_CAP_HWMON,
.altsetting = 1,
.ep_ctrl_r = 0x86,
.ep_ctrl_w = 0x05,
.ep_audio_r = 0x82,
.ep_audio_w = 0x01,
},
[LINE6_VARIAX] = {
.id = "Variax",
.name = "Variax Workbench",
.capabilities = LINE6_CAP_CONTROL,
.altsetting = 1,
.ep_ctrl_r = 0x82,
.ep_ctrl_w = 0x01,
/* no audio channel */
}
};
/* /*
Init workbench device (and clean up in case of failure). Probe USB device.
*/ */
int line6_variax_init(struct usb_interface *interface, struct usb_line6 *line6) static int variax_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{ {
int err = variax_try_init(interface, line6); struct usb_line6_variax *variax;
if (err < 0) variax = kzalloc(sizeof(*variax), GFP_KERNEL);
variax_destruct(interface); if (!variax)
return -ENODEV;
return err; return line6_probe(interface, &variax->line6,
&variax_properties_table[id->driver_info],
variax_init);
} }
static struct usb_driver variax_driver = {
.name = KBUILD_MODNAME,
.probe = variax_probe,
.disconnect = line6_disconnect,
#ifdef CONFIG_PM
.suspend = line6_suspend,
.resume = line6_resume,
.reset_resume = line6_resume,
#endif
.id_table = variax_id_table,
};
module_usb_driver(variax_driver);
MODULE_DESCRIPTION("Vairax Workbench USB driver");
MODULE_LICENSE("GPL");
/*
* Line6 Linux USB driver - 0.9.1beta
*
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2.
*
*/
#ifndef VARIAX_H
#define VARIAX_H
#include <linux/spinlock.h>
#include <linux/usb.h>
#include <linux/wait.h>
#include <sound/core.h>
#include "driver.h"
#define VARIAX_STARTUP_DELAY1 1000
#define VARIAX_STARTUP_DELAY3 100
#define VARIAX_STARTUP_DELAY4 100
/*
Stages of Variax startup procedure
*/
enum {
VARIAX_STARTUP_INIT = 1,
VARIAX_STARTUP_VERSIONREQ,
VARIAX_STARTUP_WAIT,
VARIAX_STARTUP_ACTIVATE,
VARIAX_STARTUP_WORKQUEUE,
VARIAX_STARTUP_SETUP,
VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1
};
struct usb_line6_variax {
/**
Generic Line6 USB data.
*/
struct usb_line6 line6;
/**
Buffer for activation code.
*/
unsigned char *buffer_activate;
/**
Handler for device initializaton.
*/
struct work_struct startup_work;
/**
Timers for device initializaton.
*/
struct timer_list startup_timer1;
struct timer_list startup_timer2;
/**
Current progress in startup procedure.
*/
int startup_progress;
};
extern int line6_variax_init(struct usb_interface *interface,
struct usb_line6 *line6);
#endif
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