Merge branch 'topic/line6' into for-next
This commit is contained in:
Коммит
86b5f3ec41
|
@ -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) += misc/ usx2y/ caiaq/ 6fire/ hiface/ bcd2000/
|
||||
obj-$(CONFIG_LINE6_USB) += line6/
|
||||
obj-$(CONFIG_SND_USB_LINE6) += line6/
|
||||
|
|
|
@ -1,12 +1,14 @@
|
|||
menuconfig LINE6_USB
|
||||
tristate "Line6 USB support"
|
||||
depends on USB && SND
|
||||
config SND_USB_LINE6
|
||||
tristate
|
||||
select SND_RAWMIDI
|
||||
select SND_PCM
|
||||
|
||||
config SND_USB_POD
|
||||
tristate "Line 6 POD USB support"
|
||||
select SND_USB_LINE6
|
||||
help
|
||||
This is a driver for the guitar amp, cab, and effects modeller
|
||||
PODxt Pro by Line6 (and similar devices), supporting the
|
||||
following features:
|
||||
This is a driver for PODxt and other similar devices,
|
||||
supporting the following features:
|
||||
* Reading/writing individual parameters
|
||||
* Reading/writing complete channel, effects setup, and amp
|
||||
setup data
|
||||
|
@ -18,21 +20,21 @@ menuconfig LINE6_USB
|
|||
* Signal routing (record clean/processed guitar signal,
|
||||
re-amping)
|
||||
|
||||
Preliminary support for the Variax Workbench and TonePort
|
||||
devices is included.
|
||||
|
||||
if LINE6_USB
|
||||
|
||||
config LINE6_USB_IMPULSE_RESPONSE
|
||||
bool "measure impulse response"
|
||||
default n
|
||||
config SND_USB_PODHD
|
||||
tristate "Line 6 POD HD300/400/500 USB support"
|
||||
select SND_USB_LINE6
|
||||
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.
|
||||
This is a driver for POD HD300, 400 and 500 devices.
|
||||
|
||||
If unsure, say N.
|
||||
config SND_USB_TONEPORT
|
||||
tristate "TonePort GX, UX1 and UX2 USB support"
|
||||
select SND_USB_LINE6
|
||||
help
|
||||
This is a driver for TonePort GX, UX1 and UX2 devices.
|
||||
|
||||
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
|
||||
|
|
|
@ -1,14 +1,18 @@
|
|||
obj-$(CONFIG_LINE6_USB) += line6usb.o
|
||||
|
||||
line6usb-y := \
|
||||
audio.o \
|
||||
snd-usb-line6-y := \
|
||||
capture.o \
|
||||
driver.o \
|
||||
midi.o \
|
||||
midibuf.o \
|
||||
pcm.o \
|
||||
playback.o \
|
||||
pod.o \
|
||||
toneport.o \
|
||||
variax.o \
|
||||
podhd.o
|
||||
playback.o
|
||||
|
||||
snd-usb-pod-y := pod.o
|
||||
snd-usb-podhd-y := 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
|
||||
|
|
|
@ -1,71 +0,0 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
#include <linux/export.h>
|
||||
|
||||
#include "driver.h"
|
||||
#include "audio.h"
|
||||
|
||||
/*
|
||||
Initialize the Line6 USB audio system.
|
||||
*/
|
||||
int line6_init_audio(struct usb_line6 *line6)
|
||||
{
|
||||
struct snd_card *card;
|
||||
int err;
|
||||
|
||||
err = snd_card_new(line6->ifcdev,
|
||||
SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
|
||||
THIS_MODULE, 0, &card);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
line6->card = card;
|
||||
|
||||
strcpy(card->id, line6->properties->id);
|
||||
strcpy(card->driver, DRIVER_NAME);
|
||||
strcpy(card->shortname, line6->properties->name);
|
||||
/* longname is 80 chars - see asound.h */
|
||||
sprintf(card->longname, "Line6 %s at USB %s", line6->properties->name,
|
||||
dev_name(line6->ifcdev));
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Register the Line6 USB audio system.
|
||||
*/
|
||||
int line6_register_audio(struct usb_line6 *line6)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = snd_card_register(line6->card);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Cleanup the Line6 USB audio system.
|
||||
*/
|
||||
void line6_cleanup_audio(struct usb_line6 *line6)
|
||||
{
|
||||
struct snd_card *card = line6->card;
|
||||
|
||||
if (card == NULL)
|
||||
return;
|
||||
|
||||
snd_card_disconnect(card);
|
||||
snd_card_free(card);
|
||||
line6->card = NULL;
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef AUDIO_H
|
||||
#define AUDIO_H
|
||||
|
||||
#include "driver.h"
|
||||
|
||||
extern void line6_cleanup_audio(struct usb_line6 *);
|
||||
extern int line6_init_audio(struct usb_line6 *);
|
||||
extern int line6_register_audio(struct usb_line6 *);
|
||||
|
||||
#endif
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
* Line 6 Linux USB driver
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
|
@ -14,11 +14,9 @@
|
|||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "audio.h"
|
||||
#include "capture.h"
|
||||
#include "driver.h"
|
||||
#include "pcm.h"
|
||||
#include "pod.h"
|
||||
|
||||
/*
|
||||
Find a free URB and submit it.
|
||||
|
@ -245,9 +243,7 @@ static void audio_in_callback(struct urb *urb)
|
|||
line6pcm->prev_fbuf = fbuf;
|
||||
line6pcm->prev_fsize = fsize;
|
||||
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
|
||||
#endif
|
||||
if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
|
||||
&line6pcm->flags) && (fsize > 0))
|
||||
line6_capture_copy(line6pcm, fbuf, fsize);
|
||||
|
@ -263,9 +259,7 @@ static void audio_in_callback(struct urb *urb)
|
|||
if (!shutdown) {
|
||||
submit_audio_in_urb(line6pcm);
|
||||
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
if (!(line6pcm->flags & LINE6_BITS_PCM_IMPULSE))
|
||||
#endif
|
||||
if (test_bit(LINE6_INDEX_PCM_ALSA_CAPTURE_STREAM,
|
||||
&line6pcm->flags))
|
||||
line6_capture_check_period(line6pcm, length);
|
||||
|
@ -347,9 +341,7 @@ int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd)
|
|||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
#ifdef CONFIG_PM
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
#endif
|
||||
err = line6_pcm_acquire(line6pcm,
|
||||
LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
|
||||
|
||||
|
@ -359,9 +351,7 @@ int snd_line6_capture_trigger(struct snd_line6_pcm *line6pcm, int cmd)
|
|||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
#ifdef CONFIG_PM
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
#endif
|
||||
err = line6_pcm_release(line6pcm,
|
||||
LINE6_BIT_PCM_ALSA_CAPTURE_STREAM);
|
||||
|
||||
|
@ -411,10 +401,8 @@ int line6_create_audio_in_urbs(struct snd_line6_pcm *line6pcm)
|
|||
urb = line6pcm->urb_audio_in[i] =
|
||||
usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
|
||||
|
||||
if (urb == NULL) {
|
||||
dev_err(line6->ifcdev, "Out of memory\n");
|
||||
if (urb == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
urb->dev = line6->usbdev;
|
||||
urb->pipe =
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
* Line 6 Linux USB driver
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
* Line 6 Linux USB driver
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
|
@ -11,277 +11,30 @@
|
|||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include "audio.h"
|
||||
#include <sound/core.h>
|
||||
#include <sound/initval.h>
|
||||
|
||||
#include "capture.h"
|
||||
#include "driver.h"
|
||||
#include "midi.h"
|
||||
#include "playback.h"
|
||||
#include "pod.h"
|
||||
#include "podhd.h"
|
||||
#include "revision.h"
|
||||
#include "toneport.h"
|
||||
#include "usbdefs.h"
|
||||
#include "variax.h"
|
||||
|
||||
#define DRIVER_AUTHOR "Markus Grabner <grabner@icg.tugraz.at>"
|
||||
#define DRIVER_DESC "Line6 USB Driver"
|
||||
#define DRIVER_VERSION "0.9.1beta" DRIVER_REVISION
|
||||
|
||||
#define LINE6_DEVICE(prod) USB_DEVICE(0x0e41, prod)
|
||||
#define LINE6_IF_NUM(prod, n) USB_DEVICE_INTERFACE_NUMBER(0x0e41, prod, n)
|
||||
|
||||
/* table of devices that work with this driver */
|
||||
static const struct usb_device_id line6_id_table[] = {
|
||||
{ LINE6_DEVICE(0x4250), .driver_info = LINE6_BASSPODXT },
|
||||
{ LINE6_DEVICE(0x4642), .driver_info = LINE6_BASSPODXTLIVE },
|
||||
{ LINE6_DEVICE(0x4252), .driver_info = LINE6_BASSPODXTPRO },
|
||||
{ LINE6_DEVICE(0x4750), .driver_info = LINE6_GUITARPORT },
|
||||
{ LINE6_IF_NUM(0x5051, 1), .driver_info = LINE6_POCKETPOD },
|
||||
{ LINE6_DEVICE(0x5057), .driver_info = LINE6_PODHD300 },
|
||||
{ LINE6_DEVICE(0x5058), .driver_info = LINE6_PODHD400 },
|
||||
{ LINE6_IF_NUM(0x414D, 0), .driver_info = LINE6_PODHD500_0 },
|
||||
{ LINE6_IF_NUM(0x414D, 1), .driver_info = LINE6_PODHD500_1 },
|
||||
{ LINE6_DEVICE(0x4153), .driver_info = LINE6_PODSTUDIO_GX },
|
||||
{ LINE6_DEVICE(0x4150), .driver_info = LINE6_PODSTUDIO_UX1 },
|
||||
{ LINE6_IF_NUM(0x4151, 0), .driver_info = LINE6_PODSTUDIO_UX2 },
|
||||
{ LINE6_DEVICE(0x5044), .driver_info = LINE6_PODXT },
|
||||
{ LINE6_IF_NUM(0x4650, 0), .driver_info = LINE6_PODXTLIVE_POD },
|
||||
{ LINE6_IF_NUM(0x4650, 1), .driver_info = LINE6_PODXTLIVE_VARIAX },
|
||||
{ LINE6_DEVICE(0x5050), .driver_info = LINE6_PODXTPRO },
|
||||
{ LINE6_DEVICE(0x4147), .driver_info = LINE6_TONEPORT_GX },
|
||||
{ LINE6_DEVICE(0x4141), .driver_info = LINE6_TONEPORT_UX1 },
|
||||
{ LINE6_IF_NUM(0x4142, 0), .driver_info = LINE6_TONEPORT_UX2 },
|
||||
{ LINE6_DEVICE(0x534d), .driver_info = LINE6_VARIAX },
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(usb, line6_id_table);
|
||||
|
||||
static const struct line6_properties line6_properties_table[] = {
|
||||
[LINE6_BASSPODXT] = {
|
||||
.id = "BassPODxt",
|
||||
.name = "BassPODxt",
|
||||
.capabilities = LINE6_CAP_CONTROL
|
||||
| LINE6_CAP_PCM
|
||||
| LINE6_CAP_HWMON,
|
||||
.altsetting = 5,
|
||||
.ep_ctrl_r = 0x84,
|
||||
.ep_ctrl_w = 0x03,
|
||||
.ep_audio_r = 0x82,
|
||||
.ep_audio_w = 0x01,
|
||||
},
|
||||
[LINE6_BASSPODXTLIVE] = {
|
||||
.id = "BassPODxtLive",
|
||||
.name = "BassPODxt Live",
|
||||
.capabilities = LINE6_CAP_CONTROL
|
||||
| LINE6_CAP_PCM
|
||||
| LINE6_CAP_HWMON,
|
||||
.altsetting = 1,
|
||||
.ep_ctrl_r = 0x84,
|
||||
.ep_ctrl_w = 0x03,
|
||||
.ep_audio_r = 0x82,
|
||||
.ep_audio_w = 0x01,
|
||||
},
|
||||
[LINE6_BASSPODXTPRO] = {
|
||||
.id = "BassPODxtPro",
|
||||
.name = "BassPODxt Pro",
|
||||
.capabilities = LINE6_CAP_CONTROL
|
||||
| LINE6_CAP_PCM
|
||||
| LINE6_CAP_HWMON,
|
||||
.altsetting = 5,
|
||||
.ep_ctrl_r = 0x84,
|
||||
.ep_ctrl_w = 0x03,
|
||||
.ep_audio_r = 0x82,
|
||||
.ep_audio_w = 0x01,
|
||||
},
|
||||
[LINE6_GUITARPORT] = {
|
||||
.id = "GuitarPort",
|
||||
.name = "GuitarPort",
|
||||
.capabilities = LINE6_CAP_PCM,
|
||||
.altsetting = 2, /* 1..4 seem to be ok */
|
||||
/* no control channel */
|
||||
.ep_audio_r = 0x82,
|
||||
.ep_audio_w = 0x01,
|
||||
},
|
||||
[LINE6_POCKETPOD] = {
|
||||
.id = "PocketPOD",
|
||||
.name = "Pocket POD",
|
||||
.capabilities = LINE6_CAP_CONTROL,
|
||||
.altsetting = 0,
|
||||
.ep_ctrl_r = 0x82,
|
||||
.ep_ctrl_w = 0x02,
|
||||
/* no audio channel */
|
||||
},
|
||||
[LINE6_PODHD300] = {
|
||||
.id = "PODHD300",
|
||||
.name = "POD HD300",
|
||||
.capabilities = LINE6_CAP_CONTROL
|
||||
| LINE6_CAP_PCM
|
||||
| LINE6_CAP_HWMON,
|
||||
.altsetting = 5,
|
||||
.ep_ctrl_r = 0x84,
|
||||
.ep_ctrl_w = 0x03,
|
||||
.ep_audio_r = 0x82,
|
||||
.ep_audio_w = 0x01,
|
||||
},
|
||||
[LINE6_PODHD400] = {
|
||||
.id = "PODHD400",
|
||||
.name = "POD HD400",
|
||||
.capabilities = LINE6_CAP_CONTROL
|
||||
| LINE6_CAP_PCM
|
||||
| LINE6_CAP_HWMON,
|
||||
.altsetting = 5,
|
||||
.ep_ctrl_r = 0x84,
|
||||
.ep_ctrl_w = 0x03,
|
||||
.ep_audio_r = 0x82,
|
||||
.ep_audio_w = 0x01,
|
||||
},
|
||||
[LINE6_PODHD500_0] = {
|
||||
.id = "PODHD500",
|
||||
.name = "POD HD500",
|
||||
.capabilities = LINE6_CAP_CONTROL
|
||||
| LINE6_CAP_PCM
|
||||
| LINE6_CAP_HWMON,
|
||||
.altsetting = 1,
|
||||
.ep_ctrl_r = 0x81,
|
||||
.ep_ctrl_w = 0x01,
|
||||
.ep_audio_r = 0x86,
|
||||
.ep_audio_w = 0x02,
|
||||
},
|
||||
[LINE6_PODHD500_1] = {
|
||||
.id = "PODHD500",
|
||||
.name = "POD HD500",
|
||||
.capabilities = LINE6_CAP_CONTROL
|
||||
| LINE6_CAP_PCM
|
||||
| LINE6_CAP_HWMON,
|
||||
.altsetting = 1,
|
||||
.ep_ctrl_r = 0x81,
|
||||
.ep_ctrl_w = 0x01,
|
||||
.ep_audio_r = 0x86,
|
||||
.ep_audio_w = 0x02,
|
||||
},
|
||||
[LINE6_PODSTUDIO_GX] = {
|
||||
.id = "PODStudioGX",
|
||||
.name = "POD Studio GX",
|
||||
.capabilities = LINE6_CAP_PCM,
|
||||
.altsetting = 2, /* 1..4 seem to be ok */
|
||||
/* no control channel */
|
||||
.ep_audio_r = 0x82,
|
||||
.ep_audio_w = 0x01,
|
||||
},
|
||||
[LINE6_PODSTUDIO_UX1] = {
|
||||
.id = "PODStudioUX1",
|
||||
.name = "POD Studio UX1",
|
||||
.capabilities = LINE6_CAP_PCM,
|
||||
.altsetting = 2, /* 1..4 seem to be ok */
|
||||
/* no control channel */
|
||||
.ep_audio_r = 0x82,
|
||||
.ep_audio_w = 0x01,
|
||||
},
|
||||
[LINE6_PODSTUDIO_UX2] = {
|
||||
.id = "PODStudioUX2",
|
||||
.name = "POD Studio UX2",
|
||||
.capabilities = LINE6_CAP_PCM,
|
||||
.altsetting = 2, /* defaults to 44.1kHz, 16-bit */
|
||||
/* no control channel */
|
||||
.ep_audio_r = 0x82,
|
||||
.ep_audio_w = 0x01,
|
||||
},
|
||||
[LINE6_PODXT] = {
|
||||
.id = "PODxt",
|
||||
.name = "PODxt",
|
||||
.capabilities = LINE6_CAP_CONTROL
|
||||
| LINE6_CAP_PCM
|
||||
| LINE6_CAP_HWMON,
|
||||
.altsetting = 5,
|
||||
.ep_ctrl_r = 0x84,
|
||||
.ep_ctrl_w = 0x03,
|
||||
.ep_audio_r = 0x82,
|
||||
.ep_audio_w = 0x01,
|
||||
},
|
||||
[LINE6_PODXTLIVE_POD] = {
|
||||
.id = "PODxtLive",
|
||||
.name = "PODxt Live",
|
||||
.capabilities = LINE6_CAP_CONTROL
|
||||
| LINE6_CAP_PCM
|
||||
| LINE6_CAP_HWMON,
|
||||
.altsetting = 1,
|
||||
.ep_ctrl_r = 0x84,
|
||||
.ep_ctrl_w = 0x03,
|
||||
.ep_audio_r = 0x82,
|
||||
.ep_audio_w = 0x01,
|
||||
},
|
||||
[LINE6_PODXTLIVE_VARIAX] = {
|
||||
.id = "PODxtLive",
|
||||
.name = "PODxt Live",
|
||||
.capabilities = LINE6_CAP_CONTROL
|
||||
| LINE6_CAP_PCM
|
||||
| LINE6_CAP_HWMON,
|
||||
.altsetting = 1,
|
||||
.ep_ctrl_r = 0x86,
|
||||
.ep_ctrl_w = 0x05,
|
||||
.ep_audio_r = 0x82,
|
||||
.ep_audio_w = 0x01,
|
||||
},
|
||||
[LINE6_PODXTPRO] = {
|
||||
.id = "PODxtPro",
|
||||
.name = "PODxt Pro",
|
||||
.capabilities = LINE6_CAP_CONTROL
|
||||
| LINE6_CAP_PCM
|
||||
| LINE6_CAP_HWMON,
|
||||
.altsetting = 5,
|
||||
.ep_ctrl_r = 0x84,
|
||||
.ep_ctrl_w = 0x03,
|
||||
.ep_audio_r = 0x82,
|
||||
.ep_audio_w = 0x01,
|
||||
},
|
||||
[LINE6_TONEPORT_GX] = {
|
||||
.id = "TonePortGX",
|
||||
.name = "TonePort GX",
|
||||
.capabilities = LINE6_CAP_PCM,
|
||||
.altsetting = 2, /* 1..4 seem to be ok */
|
||||
/* no control channel */
|
||||
.ep_audio_r = 0x82,
|
||||
.ep_audio_w = 0x01,
|
||||
},
|
||||
[LINE6_TONEPORT_UX1] = {
|
||||
.id = "TonePortUX1",
|
||||
.name = "TonePort UX1",
|
||||
.capabilities = LINE6_CAP_PCM,
|
||||
.altsetting = 2, /* 1..4 seem to be ok */
|
||||
/* no control channel */
|
||||
.ep_audio_r = 0x82,
|
||||
.ep_audio_w = 0x01,
|
||||
},
|
||||
[LINE6_TONEPORT_UX2] = {
|
||||
.id = "TonePortUX2",
|
||||
.name = "TonePort UX2",
|
||||
.capabilities = LINE6_CAP_PCM,
|
||||
.altsetting = 2, /* defaults to 44.1kHz, 16-bit */
|
||||
/* no control channel */
|
||||
.ep_audio_r = 0x82,
|
||||
.ep_audio_w = 0x01,
|
||||
},
|
||||
[LINE6_VARIAX] = {
|
||||
.id = "Variax",
|
||||
.name = "Variax Workbench",
|
||||
.capabilities = LINE6_CAP_CONTROL,
|
||||
.altsetting = 1,
|
||||
.ep_ctrl_r = 0x82,
|
||||
.ep_ctrl_w = 0x01,
|
||||
/* no audio channel */
|
||||
}
|
||||
};
|
||||
#define DRIVER_DESC "Line 6 USB Driver"
|
||||
|
||||
/*
|
||||
This is Line6's MIDI manufacturer ID.
|
||||
This is Line 6's MIDI manufacturer ID.
|
||||
*/
|
||||
const unsigned char line6_midi_id[] = {
|
||||
0x00, 0x01, 0x0c
|
||||
};
|
||||
EXPORT_SYMBOL_GPL(line6_midi_id);
|
||||
|
||||
/*
|
||||
Code to request version of POD, Variax interface
|
||||
|
@ -335,8 +88,8 @@ static void line6_stop_listen(struct usb_line6 *line6)
|
|||
/*
|
||||
Send raw message in pieces of wMaxPacketSize bytes.
|
||||
*/
|
||||
int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
|
||||
int size)
|
||||
static int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
|
||||
int size)
|
||||
{
|
||||
int i, done = 0;
|
||||
|
||||
|
@ -415,9 +168,9 @@ void line6_start_timer(struct timer_list *timer, unsigned int msecs,
|
|||
void (*function)(unsigned long), unsigned long data)
|
||||
{
|
||||
setup_timer(timer, function, data);
|
||||
timer->expires = jiffies + msecs * HZ / 1000;
|
||||
add_timer(timer);
|
||||
mod_timer(timer, jiffies + msecs * HZ / 1000);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(line6_start_timer);
|
||||
|
||||
/*
|
||||
Asynchronously send raw message.
|
||||
|
@ -438,7 +191,6 @@ int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer,
|
|||
|
||||
if (urb == NULL) {
|
||||
kfree(msg);
|
||||
dev_err(line6->ifcdev, "Out of memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -451,6 +203,7 @@ int line6_send_raw_message_async(struct usb_line6 *line6, const char *buffer,
|
|||
/* start sending: */
|
||||
return line6_send_raw_message_async_part(msg, urb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(line6_send_raw_message_async);
|
||||
|
||||
/*
|
||||
Send asynchronous device version request.
|
||||
|
@ -462,16 +215,15 @@ int line6_version_request_async(struct usb_line6 *line6)
|
|||
|
||||
buffer = kmemdup(line6_request_version,
|
||||
sizeof(line6_request_version), GFP_ATOMIC);
|
||||
if (buffer == NULL) {
|
||||
dev_err(line6->ifcdev, "Out of memory");
|
||||
if (buffer == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
retval = line6_send_raw_message_async(line6, buffer,
|
||||
sizeof(line6_request_version));
|
||||
kfree(buffer);
|
||||
return retval;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(line6_version_request_async);
|
||||
|
||||
/*
|
||||
Send sysex message in pieces of wMaxPacketSize bytes.
|
||||
|
@ -483,6 +235,7 @@ int line6_send_sysex_message(struct usb_line6 *line6, const char *buffer,
|
|||
size + SYSEX_EXTRA_SIZE) -
|
||||
SYSEX_EXTRA_SIZE;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(line6_send_sysex_message);
|
||||
|
||||
/*
|
||||
Allocate buffer for sysex message and prepare header.
|
||||
|
@ -504,9 +257,10 @@ char *line6_alloc_sysex_buffer(struct usb_line6 *line6, int code1, int code2,
|
|||
buffer[sizeof(line6_midi_id) + 3 + size] = LINE6_SYSEX_END;
|
||||
return buffer;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(line6_alloc_sysex_buffer);
|
||||
|
||||
/*
|
||||
Notification of data received from the Line6 device.
|
||||
Notification of data received from the Line 6 device.
|
||||
*/
|
||||
static void line6_data_received(struct urb *urb)
|
||||
{
|
||||
|
@ -544,65 +298,6 @@ static void line6_data_received(struct urb *urb)
|
|||
line6_start_listen(line6);
|
||||
}
|
||||
|
||||
/*
|
||||
Send channel number (i.e., switch to a different sound).
|
||||
*/
|
||||
int line6_send_program(struct usb_line6 *line6, u8 value)
|
||||
{
|
||||
int retval;
|
||||
unsigned char *buffer;
|
||||
int partial;
|
||||
|
||||
buffer = kmalloc(2, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
buffer[0] = LINE6_PROGRAM_CHANGE | LINE6_CHANNEL_HOST;
|
||||
buffer[1] = value;
|
||||
|
||||
retval = usb_interrupt_msg(line6->usbdev,
|
||||
usb_sndintpipe(line6->usbdev,
|
||||
line6->properties->ep_ctrl_w),
|
||||
buffer, 2, &partial, LINE6_TIMEOUT * HZ);
|
||||
|
||||
if (retval)
|
||||
dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n",
|
||||
retval);
|
||||
|
||||
kfree(buffer);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
Transmit Line6 control parameter.
|
||||
*/
|
||||
int line6_transmit_parameter(struct usb_line6 *line6, int param, u8 value)
|
||||
{
|
||||
int retval;
|
||||
unsigned char *buffer;
|
||||
int partial;
|
||||
|
||||
buffer = kmalloc(3, GFP_KERNEL);
|
||||
if (!buffer)
|
||||
return -ENOMEM;
|
||||
|
||||
buffer[0] = LINE6_PARAM_CHANGE | LINE6_CHANNEL_HOST;
|
||||
buffer[1] = param;
|
||||
buffer[2] = value;
|
||||
|
||||
retval = usb_interrupt_msg(line6->usbdev,
|
||||
usb_sndintpipe(line6->usbdev,
|
||||
line6->properties->ep_ctrl_w),
|
||||
buffer, 3, &partial, LINE6_TIMEOUT * HZ);
|
||||
|
||||
if (retval)
|
||||
dev_err(line6->ifcdev, "usb_interrupt_msg failed (%d)\n",
|
||||
retval);
|
||||
|
||||
kfree(buffer);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*
|
||||
Read data from device.
|
||||
*/
|
||||
|
@ -659,6 +354,7 @@ int line6_read_data(struct usb_line6 *line6, int address, void *data,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(line6_read_data);
|
||||
|
||||
/*
|
||||
Write data to device.
|
||||
|
@ -703,9 +399,10 @@ int line6_write_data(struct usb_line6 *line6, int address, void *data,
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(line6_write_data);
|
||||
|
||||
/*
|
||||
Read Line6 device serial number.
|
||||
Read Line 6 device serial number.
|
||||
(POD, TonePort, GuitarPort)
|
||||
*/
|
||||
int line6_read_serial_number(struct usb_line6 *line6, int *serial_number)
|
||||
|
@ -713,6 +410,7 @@ int line6_read_serial_number(struct usb_line6 *line6, int *serial_number)
|
|||
return line6_read_data(line6, 0x80d0, serial_number,
|
||||
sizeof(*serial_number));
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(line6_read_serial_number);
|
||||
|
||||
/*
|
||||
No operation (i.e., unsupported).
|
||||
|
@ -722,19 +420,19 @@ ssize_t line6_nop_read(struct device *dev, struct device_attribute *attr,
|
|||
{
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(line6_nop_read);
|
||||
|
||||
/*
|
||||
Generic destructor.
|
||||
Card destructor.
|
||||
*/
|
||||
static void line6_destruct(struct usb_interface *interface)
|
||||
static void line6_destruct(struct snd_card *card)
|
||||
{
|
||||
struct usb_line6 *line6;
|
||||
struct usb_line6 *line6 = card->private_data;
|
||||
struct usb_device *usbdev;
|
||||
|
||||
if (interface == NULL)
|
||||
return;
|
||||
line6 = usb_get_intfdata(interface);
|
||||
if (line6 == NULL)
|
||||
if (!line6)
|
||||
return;
|
||||
usbdev = line6->usbdev;
|
||||
|
||||
/* free buffer memory first: */
|
||||
kfree(line6->buffer_message);
|
||||
|
@ -743,44 +441,34 @@ static void line6_destruct(struct usb_interface *interface)
|
|||
/* then free URBs: */
|
||||
usb_free_urb(line6->urb_listen);
|
||||
|
||||
/* make sure the device isn't destructed twice: */
|
||||
usb_set_intfdata(interface, NULL);
|
||||
|
||||
/* free interface data: */
|
||||
kfree(line6);
|
||||
|
||||
/* decrement reference counters: */
|
||||
usb_put_dev(usbdev);
|
||||
}
|
||||
|
||||
/*
|
||||
Probe USB device.
|
||||
*/
|
||||
static int line6_probe(struct usb_interface *interface,
|
||||
const struct usb_device_id *id)
|
||||
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 *))
|
||||
{
|
||||
enum line6_device_type devtype;
|
||||
struct usb_device *usbdev;
|
||||
struct usb_line6 *line6;
|
||||
const struct line6_properties *properties;
|
||||
struct usb_device *usbdev = interface_to_usbdev(interface);
|
||||
struct snd_card *card;
|
||||
int interface_number;
|
||||
int size = 0;
|
||||
int ret;
|
||||
|
||||
if (interface == NULL)
|
||||
return -ENODEV;
|
||||
usbdev = interface_to_usbdev(interface);
|
||||
if (usbdev == NULL)
|
||||
return -ENODEV;
|
||||
|
||||
/* we don't handle multiple configurations */
|
||||
if (usbdev->descriptor.bNumConfigurations != 1) {
|
||||
ret = -ENODEV;
|
||||
goto err_put;
|
||||
}
|
||||
|
||||
devtype = id->driver_info;
|
||||
|
||||
/* initialize device info: */
|
||||
properties = &line6_properties_table[devtype];
|
||||
dev_info(&interface->dev, "Line6 %s found\n", properties->name);
|
||||
dev_info(&interface->dev, "Line 6 %s found\n", properties->name);
|
||||
|
||||
/* query interface number */
|
||||
interface_number = interface->cur_altsetting->desc.bInterfaceNumber;
|
||||
|
@ -792,76 +480,10 @@ static int line6_probe(struct usb_interface *interface,
|
|||
goto err_put;
|
||||
}
|
||||
|
||||
/* initialize device data based on device: */
|
||||
switch (devtype) {
|
||||
case LINE6_BASSPODXT:
|
||||
case LINE6_BASSPODXTLIVE:
|
||||
case LINE6_BASSPODXTPRO:
|
||||
case LINE6_PODXT:
|
||||
case LINE6_PODXTPRO:
|
||||
size = sizeof(struct usb_line6_pod);
|
||||
break;
|
||||
|
||||
case LINE6_PODHD300:
|
||||
case LINE6_PODHD400:
|
||||
size = sizeof(struct usb_line6_podhd);
|
||||
break;
|
||||
|
||||
case LINE6_PODHD500_0:
|
||||
case LINE6_PODHD500_1:
|
||||
size = sizeof(struct usb_line6_podhd);
|
||||
break;
|
||||
|
||||
case LINE6_POCKETPOD:
|
||||
size = sizeof(struct usb_line6_pod);
|
||||
break;
|
||||
|
||||
case LINE6_PODSTUDIO_GX:
|
||||
case LINE6_PODSTUDIO_UX1:
|
||||
case LINE6_PODSTUDIO_UX2:
|
||||
case LINE6_TONEPORT_GX:
|
||||
case LINE6_TONEPORT_UX1:
|
||||
case LINE6_TONEPORT_UX2:
|
||||
case LINE6_GUITARPORT:
|
||||
size = sizeof(struct usb_line6_toneport);
|
||||
break;
|
||||
|
||||
case LINE6_PODXTLIVE_POD:
|
||||
size = sizeof(struct usb_line6_pod);
|
||||
break;
|
||||
|
||||
case LINE6_PODXTLIVE_VARIAX:
|
||||
size = sizeof(struct usb_line6_variax);
|
||||
break;
|
||||
|
||||
case LINE6_VARIAX:
|
||||
size = sizeof(struct usb_line6_variax);
|
||||
break;
|
||||
|
||||
default:
|
||||
MISSING_CASE;
|
||||
ret = -ENODEV;
|
||||
goto err_put;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
dev_err(&interface->dev,
|
||||
"driver bug: interface data size not set\n");
|
||||
ret = -ENODEV;
|
||||
goto err_put;
|
||||
}
|
||||
|
||||
line6 = kzalloc(size, GFP_KERNEL);
|
||||
if (line6 == NULL) {
|
||||
ret = -ENODEV;
|
||||
goto err_put;
|
||||
}
|
||||
|
||||
/* store basic data: */
|
||||
line6->properties = properties;
|
||||
line6->usbdev = usbdev;
|
||||
line6->ifcdev = &interface->dev;
|
||||
line6->type = devtype;
|
||||
|
||||
/* get data from endpoint descriptor (see usb_maxpacket): */
|
||||
{
|
||||
|
@ -882,8 +504,26 @@ static int line6_probe(struct usb_interface *interface,
|
|||
}
|
||||
}
|
||||
|
||||
ret = snd_card_new(line6->ifcdev,
|
||||
SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1,
|
||||
THIS_MODULE, 0, &card);
|
||||
if (ret < 0)
|
||||
goto err_put;
|
||||
|
||||
line6->card = card;
|
||||
strcpy(card->id, line6->properties->id);
|
||||
strcpy(card->driver, DRIVER_NAME);
|
||||
strcpy(card->shortname, line6->properties->name);
|
||||
sprintf(card->longname, "Line 6 %s at USB %s", line6->properties->name,
|
||||
dev_name(line6->ifcdev));
|
||||
card->private_data = line6;
|
||||
card->private_free = line6_destruct;
|
||||
|
||||
usb_set_intfdata(interface, line6);
|
||||
|
||||
/* increment reference counters: */
|
||||
usb_get_dev(usbdev);
|
||||
|
||||
if (properties->capabilities & LINE6_CAP_CONTROL) {
|
||||
/* initialize USB buffers: */
|
||||
line6->buffer_listen =
|
||||
|
@ -903,8 +543,6 @@ static int line6_probe(struct usb_interface *interface,
|
|||
line6->urb_listen = usb_alloc_urb(0, GFP_KERNEL);
|
||||
|
||||
if (line6->urb_listen == NULL) {
|
||||
dev_err(&interface->dev, "Out of memory\n");
|
||||
line6_destruct(interface);
|
||||
ret = -ENOMEM;
|
||||
goto err_destruct;
|
||||
}
|
||||
|
@ -918,79 +556,28 @@ static int line6_probe(struct usb_interface *interface,
|
|||
}
|
||||
|
||||
/* initialize device data based on device: */
|
||||
switch (devtype) {
|
||||
case LINE6_BASSPODXT:
|
||||
case LINE6_BASSPODXTLIVE:
|
||||
case LINE6_BASSPODXTPRO:
|
||||
case LINE6_POCKETPOD:
|
||||
case LINE6_PODXT:
|
||||
case LINE6_PODXTPRO:
|
||||
ret = line6_pod_init(interface, line6);
|
||||
break;
|
||||
|
||||
case LINE6_PODHD300:
|
||||
case LINE6_PODHD400:
|
||||
case LINE6_PODHD500_0:
|
||||
case LINE6_PODHD500_1:
|
||||
ret = line6_podhd_init(interface, line6);
|
||||
break;
|
||||
|
||||
case LINE6_PODXTLIVE_POD:
|
||||
ret = line6_pod_init(interface, line6);
|
||||
break;
|
||||
|
||||
case LINE6_PODXTLIVE_VARIAX:
|
||||
ret = line6_variax_init(interface, line6);
|
||||
break;
|
||||
|
||||
case LINE6_VARIAX:
|
||||
ret = line6_variax_init(interface, line6);
|
||||
break;
|
||||
|
||||
case LINE6_PODSTUDIO_GX:
|
||||
case LINE6_PODSTUDIO_UX1:
|
||||
case LINE6_PODSTUDIO_UX2:
|
||||
case LINE6_TONEPORT_GX:
|
||||
case LINE6_TONEPORT_UX1:
|
||||
case LINE6_TONEPORT_UX2:
|
||||
case LINE6_GUITARPORT:
|
||||
ret = line6_toneport_init(interface, line6);
|
||||
break;
|
||||
|
||||
default:
|
||||
MISSING_CASE;
|
||||
ret = -ENODEV;
|
||||
}
|
||||
|
||||
if (ret < 0)
|
||||
goto err_destruct;
|
||||
|
||||
ret = sysfs_create_link(&interface->dev.kobj, &usbdev->dev.kobj,
|
||||
"usb_device");
|
||||
ret = private_init(interface, line6);
|
||||
if (ret < 0)
|
||||
goto err_destruct;
|
||||
|
||||
/* creation of additional special files should go here */
|
||||
|
||||
dev_info(&interface->dev, "Line6 %s now attached\n",
|
||||
dev_info(&interface->dev, "Line 6 %s now attached\n",
|
||||
line6->properties->name);
|
||||
|
||||
/* increment reference counters: */
|
||||
usb_get_intf(interface);
|
||||
usb_get_dev(usbdev);
|
||||
|
||||
return 0;
|
||||
|
||||
err_destruct:
|
||||
line6_destruct(interface);
|
||||
err_put:
|
||||
err_destruct:
|
||||
snd_card_free(card);
|
||||
err_put:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(line6_probe);
|
||||
|
||||
/*
|
||||
Line6 device disconnected.
|
||||
Line 6 device disconnected.
|
||||
*/
|
||||
static void line6_disconnect(struct usb_interface *interface)
|
||||
void line6_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct usb_line6 *line6;
|
||||
struct usb_device *usbdev;
|
||||
|
@ -1002,40 +589,39 @@ static void line6_disconnect(struct usb_interface *interface)
|
|||
if (usbdev == NULL)
|
||||
return;
|
||||
|
||||
/* removal of additional special files should go here */
|
||||
|
||||
sysfs_remove_link(&interface->dev.kobj, "usb_device");
|
||||
|
||||
interface_number = interface->cur_altsetting->desc.bInterfaceNumber;
|
||||
line6 = usb_get_intfdata(interface);
|
||||
if (!line6)
|
||||
return;
|
||||
|
||||
if (line6 != NULL) {
|
||||
if (line6->urb_listen != NULL)
|
||||
line6_stop_listen(line6);
|
||||
if (line6->urb_listen != NULL)
|
||||
line6_stop_listen(line6);
|
||||
|
||||
if (usbdev != line6->usbdev)
|
||||
dev_err(line6->ifcdev,
|
||||
"driver bug: inconsistent usb device\n");
|
||||
if (usbdev != line6->usbdev)
|
||||
dev_err(line6->ifcdev, "driver bug: inconsistent usb device\n");
|
||||
|
||||
snd_card_disconnect(line6->card);
|
||||
if (line6->line6pcm)
|
||||
line6_pcm_disconnect(line6->line6pcm);
|
||||
if (line6->disconnect)
|
||||
line6->disconnect(interface);
|
||||
|
||||
dev_info(&interface->dev, "Line6 %s now disconnected\n",
|
||||
line6->properties->name);
|
||||
}
|
||||
dev_info(&interface->dev, "Line 6 %s now disconnected\n",
|
||||
line6->properties->name);
|
||||
|
||||
line6_destruct(interface);
|
||||
/* make sure the device isn't destructed twice: */
|
||||
usb_set_intfdata(interface, NULL);
|
||||
|
||||
/* decrement reference counters: */
|
||||
usb_put_intf(interface);
|
||||
usb_put_dev(usbdev);
|
||||
snd_card_free_when_closed(line6->card);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(line6_disconnect);
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
|
||||
/*
|
||||
Suspend Line6 device.
|
||||
Suspend Line 6 device.
|
||||
*/
|
||||
static int line6_suspend(struct usb_interface *interface, pm_message_t message)
|
||||
int line6_suspend(struct usb_interface *interface, pm_message_t message)
|
||||
{
|
||||
struct usb_line6 *line6 = usb_get_intfdata(interface);
|
||||
struct snd_line6_pcm *line6pcm = line6->line6pcm;
|
||||
|
@ -1047,17 +633,17 @@ static int line6_suspend(struct usb_interface *interface, pm_message_t message)
|
|||
|
||||
if (line6pcm != NULL) {
|
||||
snd_pcm_suspend_all(line6pcm->pcm);
|
||||
line6_pcm_disconnect(line6pcm);
|
||||
line6pcm->flags = 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(line6_suspend);
|
||||
|
||||
/*
|
||||
Resume Line6 device.
|
||||
Resume Line 6 device.
|
||||
*/
|
||||
static int line6_resume(struct usb_interface *interface)
|
||||
int line6_resume(struct usb_interface *interface)
|
||||
{
|
||||
struct usb_line6 *line6 = usb_get_intfdata(interface);
|
||||
|
||||
|
@ -1067,48 +653,10 @@ static int line6_resume(struct usb_interface *interface)
|
|||
snd_power_change_state(line6->card, SNDRV_CTL_POWER_D0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Resume Line6 device after reset.
|
||||
*/
|
||||
static int line6_reset_resume(struct usb_interface *interface)
|
||||
{
|
||||
struct usb_line6 *line6 = usb_get_intfdata(interface);
|
||||
|
||||
switch (line6->type) {
|
||||
case LINE6_PODSTUDIO_GX:
|
||||
case LINE6_PODSTUDIO_UX1:
|
||||
case LINE6_PODSTUDIO_UX2:
|
||||
case LINE6_TONEPORT_GX:
|
||||
case LINE6_TONEPORT_UX1:
|
||||
case LINE6_TONEPORT_UX2:
|
||||
case LINE6_GUITARPORT:
|
||||
line6_toneport_reset_resume((struct usb_line6_toneport *)line6);
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return line6_resume(interface);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(line6_resume);
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
static struct usb_driver line6_driver = {
|
||||
.name = DRIVER_NAME,
|
||||
.probe = line6_probe,
|
||||
.disconnect = line6_disconnect,
|
||||
#ifdef CONFIG_PM
|
||||
.suspend = line6_suspend,
|
||||
.resume = line6_resume,
|
||||
.reset_resume = line6_reset_resume,
|
||||
#endif
|
||||
.id_table = line6_id_table,
|
||||
};
|
||||
|
||||
module_usb_driver(line6_driver);
|
||||
|
||||
MODULE_AUTHOR(DRIVER_AUTHOR);
|
||||
MODULE_DESCRIPTION(DRIVER_DESC);
|
||||
MODULE_LICENSE("GPL");
|
||||
MODULE_VERSION(DRIVER_VERSION);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
* Line 6 Linux USB driver
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
|
@ -20,35 +20,12 @@
|
|||
|
||||
#define DRIVER_NAME "line6usb"
|
||||
|
||||
enum line6_device_type {
|
||||
LINE6_BASSPODXT,
|
||||
LINE6_BASSPODXTLIVE,
|
||||
LINE6_BASSPODXTPRO,
|
||||
LINE6_GUITARPORT,
|
||||
LINE6_POCKETPOD,
|
||||
LINE6_PODHD300,
|
||||
LINE6_PODHD400,
|
||||
LINE6_PODHD500_0,
|
||||
LINE6_PODHD500_1,
|
||||
LINE6_PODSTUDIO_GX,
|
||||
LINE6_PODSTUDIO_UX1,
|
||||
LINE6_PODSTUDIO_UX2,
|
||||
LINE6_PODXT,
|
||||
LINE6_PODXTLIVE_POD,
|
||||
LINE6_PODXTLIVE_VARIAX,
|
||||
LINE6_PODXTPRO,
|
||||
LINE6_TONEPORT_GX,
|
||||
LINE6_TONEPORT_UX1,
|
||||
LINE6_TONEPORT_UX2,
|
||||
LINE6_VARIAX
|
||||
};
|
||||
|
||||
#define LINE6_TIMEOUT 1
|
||||
#define LINE6_BUFSIZE_LISTEN 32
|
||||
#define LINE6_MESSAGE_MAXLEN 256
|
||||
|
||||
/*
|
||||
Line6 MIDI control commands
|
||||
Line 6 MIDI control commands
|
||||
*/
|
||||
#define LINE6_PARAM_CHANGE 0xb0
|
||||
#define LINE6_PROGRAM_CHANGE 0xc0
|
||||
|
@ -71,17 +48,6 @@ enum line6_device_type {
|
|||
|
||||
#define LINE6_CHANNEL_MASK 0x0f
|
||||
|
||||
#define MISSING_CASE \
|
||||
pr_err("line6usb driver bug: missing case in %s:%d\n", \
|
||||
__FILE__, __LINE__)
|
||||
|
||||
#define CHECK_RETURN(x) \
|
||||
do { \
|
||||
err = x; \
|
||||
if (err < 0) \
|
||||
return err; \
|
||||
} while (0)
|
||||
|
||||
#define CHECK_STARTUP_PROGRESS(x, n) \
|
||||
do { \
|
||||
if ((x) >= (n)) \
|
||||
|
@ -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;
|
||||
|
||||
/**
|
||||
Common properties of Line6 devices.
|
||||
Common properties of Line 6 devices.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
struct usb_line6 {
|
||||
|
@ -134,11 +100,6 @@ struct usb_line6 {
|
|||
*/
|
||||
struct usb_device *usbdev;
|
||||
|
||||
/**
|
||||
Device type.
|
||||
*/
|
||||
enum line6_device_type type;
|
||||
|
||||
/**
|
||||
Properties.
|
||||
*/
|
||||
|
@ -160,18 +121,18 @@ struct usb_line6 {
|
|||
struct device *ifcdev;
|
||||
|
||||
/**
|
||||
Line6 sound card data structure.
|
||||
Line 6 sound card data structure.
|
||||
Each device has at least MIDI or PCM.
|
||||
*/
|
||||
struct snd_card *card;
|
||||
|
||||
/**
|
||||
Line6 PCM device data structure.
|
||||
Line 6 PCM device data structure.
|
||||
*/
|
||||
struct snd_line6_pcm *line6pcm;
|
||||
|
||||
/**
|
||||
Line6 MIDI device data structure.
|
||||
Line 6 MIDI device data structure.
|
||||
*/
|
||||
struct snd_line6_midi *line6midi;
|
||||
|
||||
|
@ -207,9 +168,6 @@ extern int line6_read_data(struct usb_line6 *line6, int address, void *data,
|
|||
size_t datalen);
|
||||
extern int line6_read_serial_number(struct usb_line6 *line6,
|
||||
int *serial_number);
|
||||
extern int line6_send_program(struct usb_line6 *line6, u8 value);
|
||||
extern int line6_send_raw_message(struct usb_line6 *line6, const char *buffer,
|
||||
int size);
|
||||
extern int line6_send_raw_message_async(struct usb_line6 *line6,
|
||||
const char *buffer, int size);
|
||||
extern int line6_send_sysex_message(struct usb_line6 *line6,
|
||||
|
@ -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,
|
||||
void (*function)(unsigned long),
|
||||
unsigned long data);
|
||||
extern int line6_transmit_parameter(struct usb_line6 *line6, int param,
|
||||
u8 value);
|
||||
extern int line6_version_request_async(struct usb_line6 *line6);
|
||||
extern int line6_write_data(struct usb_line6 *line6, int address, void *data,
|
||||
size_t datalen);
|
||||
|
||||
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
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
* Line 6 Linux USB driver
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
|
@ -11,13 +11,12 @@
|
|||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/export.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/rawmidi.h>
|
||||
|
||||
#include "audio.h"
|
||||
#include "driver.h"
|
||||
#include "midi.h"
|
||||
#include "pod.h"
|
||||
#include "usbdefs.h"
|
||||
|
||||
#define line6_rawmidi_substream_midi(substream) \
|
||||
|
@ -121,16 +120,13 @@ static int send_midi_async(struct usb_line6 *line6, unsigned char *data,
|
|||
|
||||
urb = usb_alloc_urb(0, GFP_ATOMIC);
|
||||
|
||||
if (urb == NULL) {
|
||||
dev_err(line6->ifcdev, "Out of memory\n");
|
||||
if (urb == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
transfer_buffer = kmemdup(data, length, GFP_ATOMIC);
|
||||
|
||||
if (transfer_buffer == NULL) {
|
||||
usb_free_urb(urb);
|
||||
dev_err(line6->ifcdev, "Out of memory\n");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -223,28 +219,20 @@ static struct snd_rawmidi_ops line6_midi_input_ops = {
|
|||
.trigger = line6_midi_input_trigger,
|
||||
};
|
||||
|
||||
/*
|
||||
Cleanup the Line6 MIDI device.
|
||||
*/
|
||||
static void line6_cleanup_midi(struct snd_rawmidi *rmidi)
|
||||
{
|
||||
}
|
||||
|
||||
/* Create a MIDI device */
|
||||
static int snd_line6_new_midi(struct snd_line6_midi *line6midi)
|
||||
static int snd_line6_new_midi(struct usb_line6 *line6,
|
||||
struct snd_rawmidi **rmidi_ret)
|
||||
{
|
||||
struct snd_rawmidi *rmidi;
|
||||
int err;
|
||||
|
||||
err = snd_rawmidi_new(line6midi->line6->card, "Line6 MIDI", 0, 1, 1,
|
||||
&rmidi);
|
||||
err = snd_rawmidi_new(line6->card, "Line 6 MIDI", 0, 1, 1, rmidi_ret);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
rmidi->private_data = line6midi;
|
||||
rmidi->private_free = line6_cleanup_midi;
|
||||
strcpy(rmidi->id, line6midi->line6->properties->id);
|
||||
strcpy(rmidi->name, line6midi->line6->properties->name);
|
||||
rmidi = *rmidi_ret;
|
||||
strcpy(rmidi->id, line6->properties->id);
|
||||
strcpy(rmidi->name, line6->properties->name);
|
||||
|
||||
rmidi->info_flags =
|
||||
SNDRV_RAWMIDI_INFO_OUTPUT |
|
||||
|
@ -258,25 +246,22 @@ static int snd_line6_new_midi(struct snd_line6_midi *line6midi)
|
|||
}
|
||||
|
||||
/* 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_out);
|
||||
return 0;
|
||||
kfree(line6midi);
|
||||
}
|
||||
|
||||
/*
|
||||
Initialize the Line6 MIDI subsystem.
|
||||
Initialize the Line 6 MIDI subsystem.
|
||||
*/
|
||||
int line6_init_midi(struct usb_line6 *line6)
|
||||
{
|
||||
static struct snd_device_ops midi_ops = {
|
||||
.dev_free = snd_line6_midi_free,
|
||||
};
|
||||
|
||||
int err;
|
||||
struct snd_rawmidi *rmidi;
|
||||
struct snd_line6_midi *line6midi;
|
||||
|
||||
if (!(line6->properties->capabilities & LINE6_CAP_CONTROL)) {
|
||||
|
@ -284,38 +269,31 @@ int line6_init_midi(struct usb_line6 *line6)
|
|||
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;
|
||||
|
||||
err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0);
|
||||
if (err < 0) {
|
||||
kfree(line6midi);
|
||||
return err;
|
||||
}
|
||||
|
||||
err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1);
|
||||
if (err < 0) {
|
||||
kfree(line6midi->midibuf_in.buf);
|
||||
kfree(line6midi);
|
||||
return err;
|
||||
}
|
||||
|
||||
line6midi->line6 = line6;
|
||||
line6->line6midi = line6midi;
|
||||
|
||||
err = snd_device_new(line6->card, SNDRV_DEV_RAWMIDI, line6midi,
|
||||
&midi_ops);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = snd_line6_new_midi(line6midi);
|
||||
if (err < 0)
|
||||
return err;
|
||||
rmidi->private_data = line6midi;
|
||||
rmidi->private_free = snd_line6_midi_free;
|
||||
|
||||
init_waitqueue_head(&line6midi->send_wait);
|
||||
spin_lock_init(&line6midi->send_urb_lock);
|
||||
spin_lock_init(&line6midi->midi_transmit_lock);
|
||||
line6midi->line6 = line6;
|
||||
|
||||
err = line6_midibuf_init(&line6midi->midibuf_in, MIDI_BUFFER_SIZE, 0);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = line6_midibuf_init(&line6midi->midibuf_out, MIDI_BUFFER_SIZE, 1);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
line6->line6midi = line6midi;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(line6_init_midi);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
* Line 6 Linux USB driver
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
|
@ -20,7 +20,7 @@
|
|||
|
||||
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;
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
* Line 6 Linux USB driver
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
|
@ -26,7 +26,7 @@ static int midibuf_message_length(unsigned char code)
|
|||
} else {
|
||||
/*
|
||||
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.
|
||||
*/
|
||||
static const int length[] = { -1, 2, -1, 2, -1, -1, 1, 1, 1, 1,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
* Line 6 Linux USB driver
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
* Line 6 Linux USB driver
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
|
@ -10,91 +10,85 @@
|
|||
*/
|
||||
|
||||
#include <linux/slab.h>
|
||||
#include <linux/export.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "audio.h"
|
||||
#include "capture.h"
|
||||
#include "driver.h"
|
||||
#include "playback.h"
|
||||
#include "pod.h"
|
||||
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
|
||||
static struct snd_line6_pcm *dev2pcm(struct device *dev)
|
||||
/* impulse response volume controls */
|
||||
static int snd_line6_impulse_volume_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
struct usb_interface *interface = to_usb_interface(dev);
|
||||
struct usb_line6 *line6 = usb_get_intfdata(interface);
|
||||
struct snd_line6_pcm *line6pcm = line6->line6pcm;
|
||||
return line6pcm;
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 255;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
"read" request on "impulse_volume" special file.
|
||||
*/
|
||||
static ssize_t impulse_volume_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
static int snd_line6_impulse_volume_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_volume);
|
||||
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
ucontrol->value.integer.value[0] = line6pcm->impulse_volume;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
"write" request on "impulse_volume" special file.
|
||||
*/
|
||||
static ssize_t impulse_volume_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
static int snd_line6_impulse_volume_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_line6_pcm *line6pcm = dev2pcm(dev);
|
||||
int value;
|
||||
int ret;
|
||||
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
|
||||
int value = ucontrol->value.integer.value[0];
|
||||
|
||||
ret = kstrtoint(buf, 10, &value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
if (line6pcm->impulse_volume == value)
|
||||
return 0;
|
||||
|
||||
line6pcm->impulse_volume = value;
|
||||
|
||||
if (value > 0)
|
||||
line6_pcm_acquire(line6pcm, LINE6_BITS_PCM_IMPULSE);
|
||||
else
|
||||
line6_pcm_release(line6pcm, LINE6_BITS_PCM_IMPULSE);
|
||||
|
||||
return count;
|
||||
return 1;
|
||||
}
|
||||
static DEVICE_ATTR_RW(impulse_volume);
|
||||
|
||||
/*
|
||||
"read" request on "impulse_period" special file.
|
||||
*/
|
||||
static ssize_t impulse_period_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
/* impulse response period controls */
|
||||
static int snd_line6_impulse_period_info(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo)
|
||||
{
|
||||
return sprintf(buf, "%d\n", dev2pcm(dev)->impulse_period);
|
||||
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
|
||||
uinfo->count = 1;
|
||||
uinfo->value.integer.min = 0;
|
||||
uinfo->value.integer.max = 2000;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
"write" request on "impulse_period" special file.
|
||||
*/
|
||||
static ssize_t impulse_period_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
static int snd_line6_impulse_period_get(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
int value;
|
||||
int ret;
|
||||
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
|
||||
|
||||
ret = kstrtoint(buf, 10, &value);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
dev2pcm(dev)->impulse_period = value;
|
||||
return count;
|
||||
ucontrol->value.integer.value[0] = line6pcm->impulse_period;
|
||||
return 0;
|
||||
}
|
||||
static DEVICE_ATTR_RW(impulse_period);
|
||||
|
||||
#endif
|
||||
static int snd_line6_impulse_period_put(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol)
|
||||
{
|
||||
struct snd_line6_pcm *line6pcm = snd_kcontrol_chip(kcontrol);
|
||||
int value = ucontrol->value.integer.value[0];
|
||||
|
||||
if (line6pcm->impulse_period == value)
|
||||
return 0;
|
||||
|
||||
line6pcm->impulse_period = value;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static bool test_flags(unsigned long flags0, unsigned long flags1,
|
||||
unsigned long mask)
|
||||
|
@ -195,6 +189,7 @@ pcm_acquire_error:
|
|||
line6_pcm_release(line6pcm, flags_final & channels);
|
||||
return err;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(line6_pcm_acquire);
|
||||
|
||||
int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels)
|
||||
{
|
||||
|
@ -223,6 +218,7 @@ int line6_pcm_release(struct snd_line6_pcm *line6pcm, int channels)
|
|||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(line6_pcm_release);
|
||||
|
||||
/* trigger callback */
|
||||
int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
|
||||
|
@ -230,19 +226,19 @@ int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
struct snd_line6_pcm *line6pcm = snd_pcm_substream_chip(substream);
|
||||
struct snd_pcm_substream *s;
|
||||
int err;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&line6pcm->lock_trigger, flags);
|
||||
spin_lock(&line6pcm->lock_trigger);
|
||||
clear_bit(LINE6_INDEX_PREPARED, &line6pcm->flags);
|
||||
|
||||
snd_pcm_group_for_each_entry(s, substream) {
|
||||
if (s->pcm->card != substream->pcm->card)
|
||||
continue;
|
||||
switch (s->stream) {
|
||||
case SNDRV_PCM_STREAM_PLAYBACK:
|
||||
err = snd_line6_playback_trigger(line6pcm, cmd);
|
||||
|
||||
if (err < 0) {
|
||||
spin_unlock_irqrestore(&line6pcm->lock_trigger,
|
||||
flags);
|
||||
spin_unlock(&line6pcm->lock_trigger);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -252,8 +248,7 @@ int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
err = snd_line6_capture_trigger(line6pcm, cmd);
|
||||
|
||||
if (err < 0) {
|
||||
spin_unlock_irqrestore(&line6pcm->lock_trigger,
|
||||
flags);
|
||||
spin_unlock(&line6pcm->lock_trigger);
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -265,7 +260,7 @@ int snd_line6_trigger(struct snd_pcm_substream *substream, int cmd)
|
|||
}
|
||||
}
|
||||
|
||||
spin_unlock_irqrestore(&line6pcm->lock_trigger, flags);
|
||||
spin_unlock(&line6pcm->lock_trigger);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -312,14 +307,28 @@ static int snd_line6_control_playback_put(struct snd_kcontrol *kcontrol,
|
|||
}
|
||||
|
||||
/* control definition */
|
||||
static struct snd_kcontrol_new line6_control_playback = {
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "PCM Playback Volume",
|
||||
.index = 0,
|
||||
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
|
||||
.info = snd_line6_control_playback_info,
|
||||
.get = snd_line6_control_playback_get,
|
||||
.put = snd_line6_control_playback_put
|
||||
static struct snd_kcontrol_new line6_controls[] = {
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "PCM Playback Volume",
|
||||
.info = snd_line6_control_playback_info,
|
||||
.get = snd_line6_control_playback_get,
|
||||
.put = snd_line6_control_playback_put
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Impulse Response Volume",
|
||||
.info = snd_line6_impulse_volume_info,
|
||||
.get = snd_line6_impulse_volume_get,
|
||||
.put = snd_line6_impulse_volume_put
|
||||
},
|
||||
{
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
|
||||
.name = "Impulse Response Period",
|
||||
.info = snd_line6_impulse_period_info,
|
||||
.get = snd_line6_impulse_period_get,
|
||||
.put = snd_line6_impulse_period_put
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -330,11 +339,6 @@ static void line6_cleanup_pcm(struct snd_pcm *pcm)
|
|||
int i;
|
||||
struct snd_line6_pcm *line6pcm = snd_pcm_chip(pcm);
|
||||
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_volume);
|
||||
device_remove_file(line6pcm->line6->ifcdev, &dev_attr_impulse_period);
|
||||
#endif
|
||||
|
||||
for (i = LINE6_ISO_BUFFERS; i--;) {
|
||||
if (line6pcm->urb_audio_out[i]) {
|
||||
usb_kill_urb(line6pcm->urb_audio_out[i]);
|
||||
|
@ -345,24 +349,21 @@ static void line6_cleanup_pcm(struct snd_pcm *pcm)
|
|||
usb_free_urb(line6pcm->urb_audio_in[i]);
|
||||
}
|
||||
}
|
||||
kfree(line6pcm);
|
||||
}
|
||||
|
||||
/* create a PCM device */
|
||||
static int snd_line6_new_pcm(struct snd_line6_pcm *line6pcm)
|
||||
static int snd_line6_new_pcm(struct usb_line6 *line6, struct snd_pcm **pcm_ret)
|
||||
{
|
||||
struct snd_pcm *pcm;
|
||||
int err;
|
||||
|
||||
err = snd_pcm_new(line6pcm->line6->card,
|
||||
(char *)line6pcm->line6->properties->name,
|
||||
0, 1, 1, &pcm);
|
||||
err = snd_pcm_new(line6->card, (char *)line6->properties->name,
|
||||
0, 1, 1, pcm_ret);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
pcm->private_data = line6pcm;
|
||||
pcm->private_free = line6_cleanup_pcm;
|
||||
line6pcm->pcm = pcm;
|
||||
strcpy(pcm->name, line6pcm->line6->properties->name);
|
||||
pcm = *pcm_ret;
|
||||
strcpy(pcm->name, line6->properties->name);
|
||||
|
||||
/* set operators */
|
||||
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK,
|
||||
|
@ -374,37 +375,14 @@ static int snd_line6_new_pcm(struct snd_line6_pcm *line6pcm)
|
|||
snd_dma_continuous_data
|
||||
(GFP_KERNEL), 64 * 1024,
|
||||
128 * 1024);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* PCM device destructor */
|
||||
static int snd_line6_pcm_free(struct snd_device *device)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Stop substream if still running.
|
||||
*/
|
||||
static void pcm_disconnect_substream(struct snd_pcm_substream *substream)
|
||||
{
|
||||
if (substream->runtime && snd_pcm_running(substream)) {
|
||||
snd_pcm_stream_lock_irq(substream);
|
||||
snd_pcm_stop(substream, SNDRV_PCM_STATE_DISCONNECTED);
|
||||
snd_pcm_stream_unlock_irq(substream);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Stop PCM stream.
|
||||
Sync with PCM stream stops.
|
||||
*/
|
||||
void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm)
|
||||
{
|
||||
pcm_disconnect_substream(get_substream
|
||||
(line6pcm, SNDRV_PCM_STREAM_CAPTURE));
|
||||
pcm_disconnect_substream(get_substream
|
||||
(line6pcm, SNDRV_PCM_STREAM_PLAYBACK));
|
||||
line6_unlink_wait_clear_audio_out_urbs(line6pcm);
|
||||
line6_unlink_wait_clear_audio_in_urbs(line6pcm);
|
||||
}
|
||||
|
@ -416,23 +394,25 @@ void line6_pcm_disconnect(struct snd_line6_pcm *line6pcm)
|
|||
int line6_init_pcm(struct usb_line6 *line6,
|
||||
struct line6_pcm_properties *properties)
|
||||
{
|
||||
static struct snd_device_ops pcm_ops = {
|
||||
.dev_free = snd_line6_pcm_free,
|
||||
};
|
||||
|
||||
int err;
|
||||
int i, err;
|
||||
unsigned ep_read = line6->properties->ep_audio_r;
|
||||
unsigned ep_write = line6->properties->ep_audio_w;
|
||||
struct snd_pcm *pcm;
|
||||
struct snd_line6_pcm *line6pcm;
|
||||
|
||||
if (!(line6->properties->capabilities & LINE6_CAP_PCM))
|
||||
return 0; /* skip PCM initialization and report success */
|
||||
|
||||
line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL);
|
||||
err = snd_line6_new_pcm(line6, &pcm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (line6pcm == NULL)
|
||||
line6pcm = kzalloc(sizeof(*line6pcm), GFP_KERNEL);
|
||||
if (!line6pcm)
|
||||
return -ENOMEM;
|
||||
|
||||
line6pcm->pcm = pcm;
|
||||
line6pcm->properties = properties;
|
||||
line6pcm->volume_playback[0] = line6pcm->volume_playback[1] = 255;
|
||||
line6pcm->volume_monitor = 255;
|
||||
line6pcm->line6 = line6;
|
||||
|
@ -444,21 +424,15 @@ int line6_init_pcm(struct usb_line6 *line6,
|
|||
usb_maxpacket(line6->usbdev,
|
||||
usb_sndisocpipe(line6->usbdev, ep_write), 1));
|
||||
|
||||
line6pcm->properties = properties;
|
||||
line6->line6pcm = line6pcm;
|
||||
|
||||
/* PCM device: */
|
||||
err = snd_device_new(line6->card, SNDRV_DEV_PCM, line6, &pcm_ops);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = snd_line6_new_pcm(line6pcm);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
spin_lock_init(&line6pcm->lock_audio_out);
|
||||
spin_lock_init(&line6pcm->lock_audio_in);
|
||||
spin_lock_init(&line6pcm->lock_trigger);
|
||||
line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
|
||||
|
||||
line6->line6pcm = line6pcm;
|
||||
|
||||
pcm->private_data = line6pcm;
|
||||
pcm->private_free = line6_cleanup_pcm;
|
||||
|
||||
err = line6_create_audio_out_urbs(line6pcm);
|
||||
if (err < 0)
|
||||
|
@ -469,27 +443,16 @@ int line6_init_pcm(struct usb_line6 *line6,
|
|||
return err;
|
||||
|
||||
/* mixer: */
|
||||
err =
|
||||
snd_ctl_add(line6->card,
|
||||
snd_ctl_new1(&line6_control_playback, line6pcm));
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
/* impulse response test: */
|
||||
err = device_create_file(line6->ifcdev, &dev_attr_impulse_volume);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
err = device_create_file(line6->ifcdev, &dev_attr_impulse_period);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
line6pcm->impulse_period = LINE6_IMPULSE_DEFAULT_PERIOD;
|
||||
#endif
|
||||
for (i = 0; i < ARRAY_SIZE(line6_controls); i++) {
|
||||
err = snd_ctl_add(line6->card,
|
||||
snd_ctl_new1(&line6_controls[i], line6pcm));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(line6_init_pcm);
|
||||
|
||||
/* prepare pcm callback */
|
||||
int snd_line6_prepare(struct snd_pcm_substream *substream)
|
||||
|
@ -508,9 +471,6 @@ int snd_line6_prepare(struct snd_pcm_substream *substream)
|
|||
line6_unlink_wait_clear_audio_in_urbs(line6pcm);
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
MISSING_CASE;
|
||||
}
|
||||
|
||||
if (!test_and_set_bit(LINE6_INDEX_PREPARED, &line6pcm->flags)) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
* Line 6 Linux USB driver
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
|
@ -26,7 +26,7 @@
|
|||
|
||||
/*
|
||||
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)
|
||||
with only one frame per packet.
|
||||
*/
|
||||
|
@ -35,12 +35,10 @@
|
|||
/* in a "full speed" device (such as the PODxt Pro) this means 1ms */
|
||||
#define LINE6_ISO_INTERVAL 1
|
||||
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
#define LINE6_IMPULSE_DEFAULT_PERIOD 100
|
||||
#endif
|
||||
|
||||
/*
|
||||
Get substream from Line6 PCM data structure
|
||||
Get substream from Line 6 PCM data structure
|
||||
*/
|
||||
#define get_substream(line6pcm, stream) \
|
||||
(line6pcm->pcm->streams[stream].substream)
|
||||
|
@ -48,7 +46,7 @@
|
|||
/*
|
||||
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:
|
||||
*) PCM playback and capture via ALSA
|
||||
*) software monitoring (for devices without hardware monitoring)
|
||||
|
@ -89,12 +87,10 @@ enum {
|
|||
LINE6_INDEX_PCM_MONITOR_PLAYBACK_STREAM,
|
||||
LINE6_INDEX_PCM_MONITOR_CAPTURE_BUFFER,
|
||||
LINE6_INDEX_PCM_MONITOR_CAPTURE_STREAM,
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
LINE6_INDEX_PCM_IMPULSE_PLAYBACK_BUFFER,
|
||||
LINE6_INDEX_PCM_IMPULSE_PLAYBACK_STREAM,
|
||||
LINE6_INDEX_PCM_IMPULSE_CAPTURE_BUFFER,
|
||||
LINE6_INDEX_PCM_IMPULSE_CAPTURE_STREAM,
|
||||
#endif
|
||||
LINE6_INDEX_PAUSE_PLAYBACK,
|
||||
LINE6_INDEX_PREPARED,
|
||||
|
||||
|
@ -109,12 +105,10 @@ enum {
|
|||
LINE6_BIT(PCM_MONITOR_PLAYBACK_STREAM),
|
||||
LINE6_BIT(PCM_MONITOR_CAPTURE_BUFFER),
|
||||
LINE6_BIT(PCM_MONITOR_CAPTURE_STREAM),
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
LINE6_BIT(PCM_IMPULSE_PLAYBACK_BUFFER),
|
||||
LINE6_BIT(PCM_IMPULSE_PLAYBACK_STREAM),
|
||||
LINE6_BIT(PCM_IMPULSE_CAPTURE_BUFFER),
|
||||
LINE6_BIT(PCM_IMPULSE_CAPTURE_STREAM),
|
||||
#endif
|
||||
LINE6_BIT(PAUSE_PLAYBACK),
|
||||
LINE6_BIT(PREPARED),
|
||||
|
||||
|
@ -133,40 +127,30 @@ enum {
|
|||
LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER |
|
||||
LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,
|
||||
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
LINE6_BITS_PCM_IMPULSE =
|
||||
LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
|
||||
LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM |
|
||||
LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER |
|
||||
LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM,
|
||||
#endif
|
||||
|
||||
/* combined bit masks (by direction): */
|
||||
LINE6_BITS_PLAYBACK_BUFFER =
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
LINE6_BIT_PCM_IMPULSE_PLAYBACK_BUFFER |
|
||||
#endif
|
||||
LINE6_BIT_PCM_ALSA_PLAYBACK_BUFFER |
|
||||
LINE6_BIT_PCM_MONITOR_PLAYBACK_BUFFER,
|
||||
|
||||
LINE6_BITS_PLAYBACK_STREAM =
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
LINE6_BIT_PCM_IMPULSE_PLAYBACK_STREAM |
|
||||
#endif
|
||||
LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM |
|
||||
LINE6_BIT_PCM_MONITOR_PLAYBACK_STREAM,
|
||||
|
||||
LINE6_BITS_CAPTURE_BUFFER =
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
LINE6_BIT_PCM_IMPULSE_CAPTURE_BUFFER |
|
||||
#endif
|
||||
LINE6_BIT_PCM_ALSA_CAPTURE_BUFFER |
|
||||
LINE6_BIT_PCM_MONITOR_CAPTURE_BUFFER,
|
||||
|
||||
LINE6_BITS_CAPTURE_STREAM =
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
LINE6_BIT_PCM_IMPULSE_CAPTURE_STREAM |
|
||||
#endif
|
||||
LINE6_BIT_PCM_ALSA_CAPTURE_STREAM |
|
||||
LINE6_BIT_PCM_MONITOR_CAPTURE_STREAM,
|
||||
|
||||
|
@ -183,7 +167,7 @@ struct line6_pcm_properties {
|
|||
|
||||
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;
|
||||
|
||||
|
@ -338,7 +322,6 @@ struct snd_line6_pcm {
|
|||
*/
|
||||
int volume_monitor;
|
||||
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
/**
|
||||
Volume of impulse response test signal (if zero, test is disabled).
|
||||
*/
|
||||
|
@ -353,7 +336,6 @@ struct snd_line6_pcm {
|
|||
Counter for impulse response test signal.
|
||||
*/
|
||||
int impulse_count;
|
||||
#endif
|
||||
|
||||
/**
|
||||
Several status bits (see LINE6_BIT_*).
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
* Line 6 Linux USB driver
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
|
@ -14,11 +14,9 @@
|
|||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_params.h>
|
||||
|
||||
#include "audio.h"
|
||||
#include "capture.h"
|
||||
#include "driver.h"
|
||||
#include "pcm.h"
|
||||
#include "pod.h"
|
||||
#include "playback.h"
|
||||
|
||||
/*
|
||||
|
@ -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.
|
||||
*/
|
||||
|
@ -106,8 +102,6 @@ static void create_impulse_test_signal(struct snd_line6_pcm *line6pcm,
|
|||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
Add signal to buffer for software monitoring.
|
||||
*/
|
||||
|
@ -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);
|
||||
|
||||
if (line6pcm->prev_fbuf != NULL) {
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
if (line6pcm->flags & LINE6_BITS_PCM_IMPULSE) {
|
||||
create_impulse_test_signal(line6pcm, urb_out,
|
||||
bytes_per_frame);
|
||||
|
@ -258,7 +251,6 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
|
|||
urb_out->transfer_buffer_length);
|
||||
}
|
||||
} else {
|
||||
#endif
|
||||
if (!
|
||||
(line6pcm->line6->
|
||||
properties->capabilities & LINE6_CAP_HWMON)
|
||||
|
@ -267,9 +259,7 @@ static int submit_audio_out_urb(struct snd_line6_pcm *line6pcm)
|
|||
add_monitor_signal(urb_out, line6pcm->prev_fbuf,
|
||||
line6pcm->volume_monitor,
|
||||
bytes_per_frame);
|
||||
#ifdef CONFIG_LINE6_USB_IMPULSE_RESPONSE
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
ret = usb_submit_urb(urb_out, GFP_ATOMIC);
|
||||
|
@ -499,9 +489,7 @@ int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd)
|
|||
|
||||
switch (cmd) {
|
||||
case SNDRV_PCM_TRIGGER_START:
|
||||
#ifdef CONFIG_PM
|
||||
case SNDRV_PCM_TRIGGER_RESUME:
|
||||
#endif
|
||||
err = line6_pcm_acquire(line6pcm,
|
||||
LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM);
|
||||
|
||||
|
@ -511,9 +499,7 @@ int snd_line6_playback_trigger(struct snd_line6_pcm *line6pcm, int cmd)
|
|||
break;
|
||||
|
||||
case SNDRV_PCM_TRIGGER_STOP:
|
||||
#ifdef CONFIG_PM
|
||||
case SNDRV_PCM_TRIGGER_SUSPEND:
|
||||
#endif
|
||||
err = line6_pcm_release(line6pcm,
|
||||
LINE6_BIT_PCM_ALSA_PLAYBACK_STREAM);
|
||||
|
||||
|
@ -571,10 +557,8 @@ int line6_create_audio_out_urbs(struct snd_line6_pcm *line6pcm)
|
|||
urb = line6pcm->urb_audio_out[i] =
|
||||
usb_alloc_urb(LINE6_ISO_PACKETS, GFP_KERNEL);
|
||||
|
||||
if (urb == NULL) {
|
||||
dev_err(line6->ifcdev, "Out of memory\n");
|
||||
if (urb == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
urb->dev = line6->usbdev;
|
||||
urb->pipe =
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
* Line 6 Linux USB driver
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
* Line 6 Linux USB driver
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
|
@ -11,13 +11,93 @@
|
|||
|
||||
#include <linux/slab.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 "audio.h"
|
||||
#include "capture.h"
|
||||
#include "driver.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_BYTES_PER_FRAME 6 /* 24bit audio (stereo) */
|
||||
|
@ -72,9 +152,6 @@ static struct line6_pcm_properties pod_pcm_properties = {
|
|||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
#ifdef CONFIG_PM
|
||||
SNDRV_PCM_INFO_RESUME |
|
||||
#endif
|
||||
SNDRV_PCM_INFO_SYNC_START),
|
||||
.formats = SNDRV_PCM_FMTBIT_S24_3LE,
|
||||
.rates = SNDRV_PCM_RATE_KNOT,
|
||||
|
@ -92,9 +169,6 @@ static struct line6_pcm_properties pod_pcm_properties = {
|
|||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
#ifdef CONFIG_PM
|
||||
SNDRV_PCM_INFO_RESUME |
|
||||
#endif
|
||||
SNDRV_PCM_INFO_SYNC_START),
|
||||
.formats = SNDRV_PCM_FMTBIT_S24_3LE,
|
||||
.rates = SNDRV_PCM_RATE_KNOT,
|
||||
|
@ -265,7 +339,7 @@ static void pod_startup4(struct work_struct *work)
|
|||
line6_read_serial_number(&pod->line6, &pod->serial_number);
|
||||
|
||||
/* ALSA audio interface: */
|
||||
line6_register_audio(line6);
|
||||
snd_card_register(line6->card);
|
||||
}
|
||||
|
||||
/* POD special files: */
|
||||
|
@ -322,21 +396,6 @@ static struct snd_kcontrol_new pod_control_monitor = {
|
|||
.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.
|
||||
*/
|
||||
|
@ -349,21 +408,18 @@ static void line6_pod_disconnect(struct usb_interface *interface)
|
|||
pod = usb_get_intfdata(interface);
|
||||
|
||||
if (pod != NULL) {
|
||||
struct snd_line6_pcm *line6pcm = pod->line6.line6pcm;
|
||||
struct device *dev = &interface->dev;
|
||||
|
||||
if (line6pcm != NULL)
|
||||
line6_pcm_disconnect(line6pcm);
|
||||
|
||||
if (dev != NULL) {
|
||||
/* remove sysfs entries: */
|
||||
device_remove_file(dev, &dev_attr_device_id);
|
||||
device_remove_file(dev, &dev_attr_firmware_version);
|
||||
device_remove_file(dev, &dev_attr_serial_number);
|
||||
}
|
||||
}
|
||||
|
||||
pod_destruct(interface);
|
||||
del_timer_sync(&pod->startup_timer);
|
||||
cancel_work_sync(&pod->startup_work);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -373,17 +429,23 @@ static int pod_create_files2(struct device *dev)
|
|||
{
|
||||
int err;
|
||||
|
||||
CHECK_RETURN(device_create_file(dev, &dev_attr_device_id));
|
||||
CHECK_RETURN(device_create_file(dev, &dev_attr_firmware_version));
|
||||
CHECK_RETURN(device_create_file(dev, &dev_attr_serial_number));
|
||||
err = device_create_file(dev, &dev_attr_device_id);
|
||||
if (err < 0)
|
||||
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;
|
||||
}
|
||||
|
||||
/*
|
||||
Try to init POD device.
|
||||
*/
|
||||
static int pod_try_init(struct usb_interface *interface,
|
||||
struct usb_line6 *line6)
|
||||
static int pod_init(struct usb_interface *interface,
|
||||
struct usb_line6 *line6)
|
||||
{
|
||||
int err;
|
||||
struct usb_line6_pod *pod = (struct usb_line6_pod *) line6;
|
||||
|
@ -402,11 +464,6 @@ static int pod_try_init(struct usb_interface *interface,
|
|||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* initialize audio system: */
|
||||
err = line6_init_audio(line6);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* initialize MIDI subsystem: */
|
||||
err = line6_init_midi(line6);
|
||||
if (err < 0)
|
||||
|
@ -439,15 +496,136 @@ static int pod_try_init(struct usb_interface *interface,
|
|||
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");
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef POD_H
|
||||
#define POD_H
|
||||
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include <sound/core.h>
|
||||
|
||||
#include "driver.h"
|
||||
|
||||
/*
|
||||
Locate name in binary program dump
|
||||
*/
|
||||
#define POD_NAME_OFFSET 0
|
||||
#define POD_NAME_LENGTH 16
|
||||
|
||||
/*
|
||||
Other constants
|
||||
*/
|
||||
#define POD_CONTROL_SIZE 0x80
|
||||
#define POD_BUFSIZE_DUMPREQ 7
|
||||
#define POD_STARTUP_DELAY 1000
|
||||
|
||||
/*
|
||||
Stages of POD startup procedure
|
||||
*/
|
||||
enum {
|
||||
POD_STARTUP_INIT = 1,
|
||||
POD_STARTUP_VERSIONREQ,
|
||||
POD_STARTUP_WORKQUEUE,
|
||||
POD_STARTUP_SETUP,
|
||||
POD_STARTUP_LAST = POD_STARTUP_SETUP - 1
|
||||
};
|
||||
|
||||
struct usb_line6_pod {
|
||||
/**
|
||||
Generic Line6 USB data.
|
||||
*/
|
||||
struct usb_line6 line6;
|
||||
|
||||
/**
|
||||
Instrument monitor level.
|
||||
*/
|
||||
int monitor_level;
|
||||
|
||||
/**
|
||||
Timer for device initializaton.
|
||||
*/
|
||||
struct timer_list startup_timer;
|
||||
|
||||
/**
|
||||
Work handler for device initializaton.
|
||||
*/
|
||||
struct work_struct startup_work;
|
||||
|
||||
/**
|
||||
Current progress in startup procedure.
|
||||
*/
|
||||
int startup_progress;
|
||||
|
||||
/**
|
||||
Serial number of device.
|
||||
*/
|
||||
int serial_number;
|
||||
|
||||
/**
|
||||
Firmware version (x 100).
|
||||
*/
|
||||
int firmware_version;
|
||||
|
||||
/**
|
||||
Device ID.
|
||||
*/
|
||||
int device_id;
|
||||
};
|
||||
|
||||
extern int line6_pod_init(struct usb_interface *interface,
|
||||
struct usb_line6 *line6);
|
||||
|
||||
#endif
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Line6 Pod HD
|
||||
* Line 6 Pod HD
|
||||
*
|
||||
* Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
|
||||
*
|
||||
|
@ -9,13 +9,29 @@
|
|||
*
|
||||
*/
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/module.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/pcm.h>
|
||||
|
||||
#include "audio.h"
|
||||
#include "driver.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) */
|
||||
|
||||
|
@ -33,9 +49,6 @@ static struct line6_pcm_properties podhd_pcm_properties = {
|
|||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
#ifdef CONFIG_PM
|
||||
SNDRV_PCM_INFO_RESUME |
|
||||
#endif
|
||||
SNDRV_PCM_INFO_SYNC_START),
|
||||
.formats = SNDRV_PCM_FMTBIT_S24_3LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
|
@ -53,9 +66,6 @@ static struct line6_pcm_properties podhd_pcm_properties = {
|
|||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
#ifdef CONFIG_PM
|
||||
SNDRV_PCM_INFO_RESUME |
|
||||
#endif
|
||||
SNDRV_PCM_INFO_SYNC_START),
|
||||
.formats = SNDRV_PCM_FMTBIT_S24_3LE,
|
||||
.rates = SNDRV_PCM_RATE_48000,
|
||||
|
@ -74,58 +84,18 @@ static struct line6_pcm_properties podhd_pcm_properties = {
|
|||
.bytes_per_frame = PODHD_BYTES_PER_FRAME
|
||||
};
|
||||
|
||||
/*
|
||||
POD HD destructor.
|
||||
*/
|
||||
static void podhd_destruct(struct usb_interface *interface)
|
||||
{
|
||||
struct usb_line6_podhd *podhd = usb_get_intfdata(interface);
|
||||
|
||||
if (podhd == NULL)
|
||||
return;
|
||||
line6_cleanup_audio(&podhd->line6);
|
||||
}
|
||||
|
||||
/*
|
||||
POD HD device disconnected.
|
||||
*/
|
||||
static void line6_podhd_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
struct usb_line6_podhd *podhd;
|
||||
|
||||
if (interface == NULL)
|
||||
return;
|
||||
podhd = usb_get_intfdata(interface);
|
||||
|
||||
if (podhd != NULL) {
|
||||
struct snd_line6_pcm *line6pcm = podhd->line6.line6pcm;
|
||||
|
||||
if (line6pcm != NULL)
|
||||
line6_pcm_disconnect(line6pcm);
|
||||
}
|
||||
|
||||
podhd_destruct(interface);
|
||||
}
|
||||
|
||||
/*
|
||||
Try to init POD HD device.
|
||||
*/
|
||||
static int podhd_try_init(struct usb_interface *interface,
|
||||
struct usb_line6_podhd *podhd)
|
||||
static int podhd_init(struct usb_interface *interface,
|
||||
struct usb_line6 *line6)
|
||||
{
|
||||
struct usb_line6_podhd *podhd = (struct usb_line6_podhd *) line6;
|
||||
int err;
|
||||
struct usb_line6 *line6 = &podhd->line6;
|
||||
|
||||
if ((interface == NULL) || (podhd == NULL))
|
||||
return -ENODEV;
|
||||
|
||||
line6->disconnect = line6_podhd_disconnect;
|
||||
|
||||
/* initialize audio system: */
|
||||
err = line6_init_audio(line6);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* initialize MIDI subsystem: */
|
||||
err = line6_init_midi(line6);
|
||||
if (err < 0)
|
||||
|
@ -137,20 +107,103 @@ static int podhd_try_init(struct usb_interface *interface,
|
|||
return err;
|
||||
|
||||
/* register USB audio system: */
|
||||
err = line6_register_audio(line6);
|
||||
return err;
|
||||
return snd_card_register(line6->card);
|
||||
}
|
||||
|
||||
#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;
|
||||
int err = podhd_try_init(interface, podhd);
|
||||
struct usb_line6_podhd *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");
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
/*
|
||||
* Line6 Pod HD
|
||||
*
|
||||
* Copyright (C) 2011 Stefan Hajnoczi <stefanha@gmail.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PODHD_H
|
||||
#define PODHD_H
|
||||
|
||||
#include <linux/usb.h>
|
||||
|
||||
#include "driver.h"
|
||||
|
||||
struct usb_line6_podhd {
|
||||
/**
|
||||
Generic Line6 USB data.
|
||||
*/
|
||||
struct usb_line6 line6;
|
||||
};
|
||||
|
||||
extern int line6_podhd_init(struct usb_interface *interface,
|
||||
struct usb_line6 *line6);
|
||||
|
||||
#endif /* PODHD_H */
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
* Line 6 Linux USB driver
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
* Emil Myhrman (emil.myhrman@gmail.com)
|
||||
|
@ -11,13 +11,58 @@
|
|||
*/
|
||||
|
||||
#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 "audio.h"
|
||||
#include "capture.h"
|
||||
#include "driver.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);
|
||||
|
||||
|
@ -37,9 +82,6 @@ static struct line6_pcm_properties toneport_pcm_properties = {
|
|||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
SNDRV_PCM_INFO_PAUSE |
|
||||
#ifdef CONFIG_PM
|
||||
SNDRV_PCM_INFO_RESUME |
|
||||
#endif
|
||||
SNDRV_PCM_INFO_SYNC_START),
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.rates = SNDRV_PCM_RATE_KNOT,
|
||||
|
@ -57,9 +99,6 @@ static struct line6_pcm_properties toneport_pcm_properties = {
|
|||
SNDRV_PCM_INFO_INTERLEAVED |
|
||||
SNDRV_PCM_INFO_BLOCK_TRANSFER |
|
||||
SNDRV_PCM_INFO_MMAP_VALID |
|
||||
#ifdef CONFIG_PM
|
||||
SNDRV_PCM_INFO_RESUME |
|
||||
#endif
|
||||
SNDRV_PCM_INFO_SYNC_START),
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.rates = SNDRV_PCM_RATE_KNOT,
|
||||
|
@ -290,18 +329,6 @@ static struct snd_kcontrol_new toneport_control_source = {
|
|||
.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.
|
||||
*/
|
||||
|
@ -319,7 +346,7 @@ static void toneport_setup(struct usb_line6_toneport *toneport)
|
|||
toneport_send_cmd(usbdev, 0x0301, 0x0000);
|
||||
|
||||
/* initialize source select: */
|
||||
switch (line6->type) {
|
||||
switch (toneport->type) {
|
||||
case LINE6_TONEPORT_UX1:
|
||||
case LINE6_TONEPORT_UX2:
|
||||
case LINE6_PODSTUDIO_UX1:
|
||||
|
@ -331,7 +358,7 @@ static void toneport_setup(struct usb_line6_toneport *toneport)
|
|||
break;
|
||||
}
|
||||
|
||||
if (toneport_has_led(line6->type))
|
||||
if (toneport_has_led(toneport->type))
|
||||
toneport_update_led(&usbdev->dev);
|
||||
}
|
||||
|
||||
|
@ -354,25 +381,14 @@ 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_green);
|
||||
}
|
||||
|
||||
if (toneport != NULL) {
|
||||
struct snd_line6_pcm *line6pcm = toneport->line6.line6pcm;
|
||||
|
||||
if (line6pcm != NULL) {
|
||||
line6_pcm_release(line6pcm, LINE6_BITS_PCM_MONITOR);
|
||||
line6_pcm_disconnect(line6pcm);
|
||||
}
|
||||
}
|
||||
|
||||
toneport_destruct(interface);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Try to init Toneport device.
|
||||
*/
|
||||
static int toneport_try_init(struct usb_interface *interface,
|
||||
struct usb_line6 *line6)
|
||||
static int toneport_init(struct usb_interface *interface,
|
||||
struct usb_line6 *line6)
|
||||
{
|
||||
int err;
|
||||
struct usb_line6_toneport *toneport = (struct usb_line6_toneport *) line6;
|
||||
|
@ -382,11 +398,6 @@ static int toneport_try_init(struct usb_interface *interface,
|
|||
|
||||
line6->disconnect = line6_toneport_disconnect;
|
||||
|
||||
/* initialize audio system: */
|
||||
err = line6_init_audio(line6);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* initialize PCM subsystem: */
|
||||
err = line6_init_pcm(line6, &toneport_pcm_properties);
|
||||
if (err < 0)
|
||||
|
@ -400,7 +411,7 @@ static int toneport_try_init(struct usb_interface *interface,
|
|||
return err;
|
||||
|
||||
/* register source select control: */
|
||||
switch (line6->type) {
|
||||
switch (toneport->type) {
|
||||
case LINE6_TONEPORT_UX1:
|
||||
case LINE6_TONEPORT_UX2:
|
||||
case LINE6_PODSTUDIO_UX1:
|
||||
|
@ -416,50 +427,152 @@ static int toneport_try_init(struct usb_interface *interface,
|
|||
break;
|
||||
}
|
||||
|
||||
/* register audio system: */
|
||||
err = line6_register_audio(line6);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
line6_read_serial_number(line6, &toneport->serial_number);
|
||||
line6_read_data(line6, 0x80c2, &toneport->firmware_version, 1);
|
||||
|
||||
if (toneport_has_led(line6->type)) {
|
||||
CHECK_RETURN(device_create_file
|
||||
(&interface->dev, &dev_attr_led_red));
|
||||
CHECK_RETURN(device_create_file
|
||||
(&interface->dev, &dev_attr_led_green));
|
||||
if (toneport_has_led(toneport->type)) {
|
||||
err = device_create_file(&interface->dev, &dev_attr_led_red);
|
||||
if (err < 0)
|
||||
return err;
|
||||
err = device_create_file(&interface->dev, &dev_attr_led_green);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
toneport_setup(toneport);
|
||||
|
||||
init_timer(&toneport->timer);
|
||||
toneport->timer.expires = jiffies + TONEPORT_PCM_DELAY * HZ;
|
||||
toneport->timer.function = toneport_start_pcm;
|
||||
toneport->timer.data = (unsigned long)toneport;
|
||||
add_timer(&toneport->timer);
|
||||
setup_timer(&toneport->timer, toneport_start_pcm,
|
||||
(unsigned long)toneport);
|
||||
mod_timer(&toneport->timer, jiffies + TONEPORT_PCM_DELAY * HZ);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Init Toneport device (and clean up in case of failure).
|
||||
*/
|
||||
int line6_toneport_init(struct usb_interface *interface,
|
||||
struct usb_line6 *line6)
|
||||
{
|
||||
int err = toneport_try_init(interface, line6);
|
||||
|
||||
if (err < 0)
|
||||
toneport_destruct(interface);
|
||||
|
||||
return err;
|
||||
/* register audio system: */
|
||||
return snd_card_register(line6->card);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
/*
|
||||
Resume Toneport device after reset.
|
||||
*/
|
||||
void line6_toneport_reset_resume(struct usb_line6_toneport *toneport)
|
||||
static int toneport_reset_resume(struct usb_interface *interface)
|
||||
{
|
||||
toneport_setup(toneport);
|
||||
toneport_setup(usb_get_intfdata(interface));
|
||||
return line6_resume(interface);
|
||||
}
|
||||
#endif
|
||||
|
||||
#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 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 },
|
||||
{}
|
||||
};
|
||||
|
||||
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,
|
||||
},
|
||||
};
|
||||
|
||||
/*
|
||||
Probe USB device.
|
||||
*/
|
||||
static int toneport_probe(struct usb_interface *interface,
|
||||
const struct usb_device_id *id)
|
||||
{
|
||||
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");
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef TONEPORT_H
|
||||
#define TONEPORT_H
|
||||
|
||||
#include <linux/usb.h>
|
||||
#include <sound/core.h>
|
||||
|
||||
#include "driver.h"
|
||||
|
||||
struct usb_line6_toneport {
|
||||
/**
|
||||
Generic Line6 USB data.
|
||||
*/
|
||||
struct usb_line6 line6;
|
||||
|
||||
/**
|
||||
Source selector.
|
||||
*/
|
||||
int source;
|
||||
|
||||
/**
|
||||
Serial number of device.
|
||||
*/
|
||||
int serial_number;
|
||||
|
||||
/**
|
||||
Firmware version (x 100).
|
||||
*/
|
||||
int firmware_version;
|
||||
|
||||
/**
|
||||
Timer for delayed PCM startup.
|
||||
*/
|
||||
struct timer_list timer;
|
||||
};
|
||||
|
||||
extern int line6_toneport_init(struct usb_interface *interface,
|
||||
struct usb_line6 *line6);
|
||||
extern void line6_toneport_reset_resume(struct usb_line6_toneport *toneport);
|
||||
|
||||
#endif
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
* Line 6 Linux USB driver
|
||||
*
|
||||
* Copyright (C) 2005-2008 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
* Line 6 Linux USB driver
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
|
@ -10,10 +10,64 @@
|
|||
*/
|
||||
|
||||
#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 "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
|
||||
|
||||
|
@ -124,7 +178,7 @@ static void variax_startup6(struct work_struct *work)
|
|||
CHECK_STARTUP_PROGRESS(variax->startup_progress, VARIAX_STARTUP_SETUP);
|
||||
|
||||
/* 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)
|
|||
/*
|
||||
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 (variax == NULL)
|
||||
if (!interface)
|
||||
return;
|
||||
|
||||
variax = usb_get_intfdata(interface);
|
||||
if (!variax)
|
||||
return;
|
||||
line6_cleanup_audio(&variax->line6);
|
||||
|
||||
del_timer(&variax->startup_timer1);
|
||||
del_timer(&variax->startup_timer2);
|
||||
|
@ -171,22 +228,11 @@ static void variax_destruct(struct usb_interface *interface)
|
|||
kfree(variax->buffer_activate);
|
||||
}
|
||||
|
||||
/*
|
||||
Workbench device disconnected.
|
||||
*/
|
||||
static void line6_variax_disconnect(struct usb_interface *interface)
|
||||
{
|
||||
if (interface == NULL)
|
||||
return;
|
||||
|
||||
variax_destruct(interface);
|
||||
}
|
||||
|
||||
/*
|
||||
Try to init workbench device.
|
||||
*/
|
||||
static int variax_try_init(struct usb_interface *interface,
|
||||
struct usb_line6 *line6)
|
||||
static int variax_init(struct usb_interface *interface,
|
||||
struct usb_line6 *line6)
|
||||
{
|
||||
struct usb_line6_variax *variax = (struct usb_line6_variax *) line6;
|
||||
int err;
|
||||
|
@ -205,15 +251,8 @@ static int variax_try_init(struct usb_interface *interface,
|
|||
variax->buffer_activate = kmemdup(variax_activate,
|
||||
sizeof(variax_activate), GFP_KERNEL);
|
||||
|
||||
if (variax->buffer_activate == NULL) {
|
||||
dev_err(&interface->dev, "Out of memory\n");
|
||||
if (variax->buffer_activate == NULL)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/* initialize audio system: */
|
||||
err = line6_init_audio(&variax->line6);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/* initialize MIDI subsystem: */
|
||||
err = line6_init_midi(&variax->line6);
|
||||
|
@ -225,15 +264,71 @@ static int variax_try_init(struct usb_interface *interface,
|
|||
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_destruct(interface);
|
||||
|
||||
return err;
|
||||
variax = kzalloc(sizeof(*variax), GFP_KERNEL);
|
||||
if (!variax)
|
||||
return -ENODEV;
|
||||
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");
|
||||
|
|
|
@ -1,70 +0,0 @@
|
|||
/*
|
||||
* Line6 Linux USB driver - 0.9.1beta
|
||||
*
|
||||
* Copyright (C) 2004-2010 Markus Grabner (grabner@icg.tugraz.at)
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License as
|
||||
* published by the Free Software Foundation, version 2.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef VARIAX_H
|
||||
#define VARIAX_H
|
||||
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/wait.h>
|
||||
#include <sound/core.h>
|
||||
|
||||
#include "driver.h"
|
||||
|
||||
#define VARIAX_STARTUP_DELAY1 1000
|
||||
#define VARIAX_STARTUP_DELAY3 100
|
||||
#define VARIAX_STARTUP_DELAY4 100
|
||||
|
||||
/*
|
||||
Stages of Variax startup procedure
|
||||
*/
|
||||
enum {
|
||||
VARIAX_STARTUP_INIT = 1,
|
||||
VARIAX_STARTUP_VERSIONREQ,
|
||||
VARIAX_STARTUP_WAIT,
|
||||
VARIAX_STARTUP_ACTIVATE,
|
||||
VARIAX_STARTUP_WORKQUEUE,
|
||||
VARIAX_STARTUP_SETUP,
|
||||
VARIAX_STARTUP_LAST = VARIAX_STARTUP_SETUP - 1
|
||||
};
|
||||
|
||||
struct usb_line6_variax {
|
||||
/**
|
||||
Generic Line6 USB data.
|
||||
*/
|
||||
struct usb_line6 line6;
|
||||
|
||||
/**
|
||||
Buffer for activation code.
|
||||
*/
|
||||
unsigned char *buffer_activate;
|
||||
|
||||
/**
|
||||
Handler for device initializaton.
|
||||
*/
|
||||
struct work_struct startup_work;
|
||||
|
||||
/**
|
||||
Timers for device initializaton.
|
||||
*/
|
||||
struct timer_list startup_timer1;
|
||||
struct timer_list startup_timer2;
|
||||
|
||||
/**
|
||||
Current progress in startup procedure.
|
||||
*/
|
||||
int startup_progress;
|
||||
};
|
||||
|
||||
extern int line6_variax_init(struct usb_interface *interface,
|
||||
struct usb_line6 *line6);
|
||||
|
||||
#endif
|
Загрузка…
Ссылка в новой задаче