Commit f09d045e authored by Jaroslav Kysela's avatar Jaroslav Kysela

Merge branch 'topic/usb' of...

Merge branch 'topic/usb' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6 into devel
parents dc57da38 27762b2c
This diff is collapsed.
...@@ -13,6 +13,9 @@ ...@@ -13,6 +13,9 @@
* Comments below reference relevant sections of that document: * Comments below reference relevant sections of that document:
* *
* http://www.usb.org/developers/devclass_docs/audio10.pdf * http://www.usb.org/developers/devclass_docs/audio10.pdf
*
* Types and defines in this file are either specific to version 1.0 of
* this standard or common for newer versions.
*/ */
#ifndef __LINUX_USB_AUDIO_H #ifndef __LINUX_USB_AUDIO_H
...@@ -20,14 +23,15 @@ ...@@ -20,14 +23,15 @@
#include <linux/types.h> #include <linux/types.h>
/* bInterfaceProtocol values to denote the version of the standard used */
#define UAC_VERSION_1 0x00
#define UAC_VERSION_2 0x20
/* A.2 Audio Interface Subclass Codes */ /* A.2 Audio Interface Subclass Codes */
#define USB_SUBCLASS_AUDIOCONTROL 0x01 #define USB_SUBCLASS_AUDIOCONTROL 0x01
#define USB_SUBCLASS_AUDIOSTREAMING 0x02 #define USB_SUBCLASS_AUDIOSTREAMING 0x02
#define USB_SUBCLASS_MIDISTREAMING 0x03 #define USB_SUBCLASS_MIDISTREAMING 0x03
#define UAC_VERSION_1 0x00
#define UAC_VERSION_2 0x20
/* A.5 Audio Class-Specific AC Interface Descriptor Subtypes */ /* A.5 Audio Class-Specific AC Interface Descriptor Subtypes */
#define UAC_HEADER 0x01 #define UAC_HEADER 0x01
#define UAC_INPUT_TERMINAL 0x02 #define UAC_INPUT_TERMINAL 0x02
...@@ -38,15 +42,6 @@ ...@@ -38,15 +42,6 @@
#define UAC_PROCESSING_UNIT_V1 0x07 #define UAC_PROCESSING_UNIT_V1 0x07
#define UAC_EXTENSION_UNIT_V1 0x08 #define UAC_EXTENSION_UNIT_V1 0x08
/* UAC v2.0 types */
#define UAC_EFFECT_UNIT 0x07
#define UAC_PROCESSING_UNIT_V2 0x08
#define UAC_EXTENSION_UNIT_V2 0x09
#define UAC_CLOCK_SOURCE 0x0a
#define UAC_CLOCK_SELECTOR 0x0b
#define UAC_CLOCK_MULTIPLIER 0x0c
#define UAC_SAMPLE_RATE_CONVERTER 0x0d
/* A.6 Audio Class-Specific AS Interface Descriptor Subtypes */ /* A.6 Audio Class-Specific AS Interface Descriptor Subtypes */
#define UAC_AS_GENERAL 0x01 #define UAC_AS_GENERAL 0x01
#define UAC_FORMAT_TYPE 0x02 #define UAC_FORMAT_TYPE 0x02
...@@ -78,10 +73,6 @@ ...@@ -78,10 +73,6 @@
#define UAC_GET_STAT 0xff #define UAC_GET_STAT 0xff
/* Audio class v2.0 handles all the parameter calls differently */
#define UAC2_CS_CUR 0x01
#define UAC2_CS_RANGE 0x02
/* MIDI - A.1 MS Class-Specific Interface Descriptor Subtypes */ /* MIDI - A.1 MS Class-Specific Interface Descriptor Subtypes */
#define UAC_MS_HEADER 0x01 #define UAC_MS_HEADER 0x01
#define UAC_MIDI_IN_JACK 0x02 #define UAC_MIDI_IN_JACK 0x02
...@@ -190,6 +181,156 @@ struct uac_feature_unit_descriptor_##ch { \ ...@@ -190,6 +181,156 @@ struct uac_feature_unit_descriptor_##ch { \
__u8 iFeature; \ __u8 iFeature; \
} __attribute__ ((packed)) } __attribute__ ((packed))
/* 4.3.2.3 Mixer Unit Descriptor */
struct uac_mixer_unit_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubtype;
__u8 bUnitID;
__u8 bNrInPins;
__u8 baSourceID[];
} __attribute__ ((packed));
static inline __u8 uac_mixer_unit_bNrChannels(struct uac_mixer_unit_descriptor *desc)
{
return desc->baSourceID[desc->bNrInPins];
}
static inline __u32 uac_mixer_unit_wChannelConfig(struct uac_mixer_unit_descriptor *desc,
int protocol)
{
if (protocol == UAC_VERSION_1)
return (desc->baSourceID[desc->bNrInPins + 2] << 8) |
desc->baSourceID[desc->bNrInPins + 1];
else
return (desc->baSourceID[desc->bNrInPins + 4] << 24) |
(desc->baSourceID[desc->bNrInPins + 3] << 16) |
(desc->baSourceID[desc->bNrInPins + 2] << 8) |
(desc->baSourceID[desc->bNrInPins + 1]);
}
static inline __u8 uac_mixer_unit_iChannelNames(struct uac_mixer_unit_descriptor *desc,
int protocol)
{
return (protocol == UAC_VERSION_1) ?
desc->baSourceID[desc->bNrInPins + 3] :
desc->baSourceID[desc->bNrInPins + 5];
}
static inline __u8 *uac_mixer_unit_bmControls(struct uac_mixer_unit_descriptor *desc,
int protocol)
{
return (protocol == UAC_VERSION_1) ?
&desc->baSourceID[desc->bNrInPins + 4] :
&desc->baSourceID[desc->bNrInPins + 6];
}
static inline __u8 uac_mixer_unit_iMixer(struct uac_mixer_unit_descriptor *desc)
{
__u8 *raw = (__u8 *) desc;
return raw[desc->bLength - 1];
}
/* 4.3.2.4 Selector Unit Descriptor */
struct uac_selector_unit_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubtype;
__u8 bUintID;
__u8 bNrInPins;
__u8 baSourceID[];
} __attribute__ ((packed));
static inline __u8 uac_selector_unit_iSelector(struct uac_selector_unit_descriptor *desc)
{
__u8 *raw = (__u8 *) desc;
return raw[desc->bLength - 1];
}
/* 4.3.2.5 Feature Unit Descriptor */
struct uac_feature_unit_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubtype;
__u8 bUnitID;
__u8 bSourceID;
__u8 bControlSize;
__u8 bmaControls[0]; /* variable length */
} __attribute__((packed));
static inline __u8 uac_feature_unit_iFeature(struct uac_feature_unit_descriptor *desc)
{
__u8 *raw = (__u8 *) desc;
return raw[desc->bLength - 1];
}
/* 4.3.2.6 Processing Unit Descriptors */
struct uac_processing_unit_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubtype;
__u8 bUnitID;
__u16 wProcessType;
__u8 bNrInPins;
__u8 baSourceID[];
} __attribute__ ((packed));
static inline __u8 uac_processing_unit_bNrChannels(struct uac_processing_unit_descriptor *desc)
{
return desc->baSourceID[desc->bNrInPins];
}
static inline __u32 uac_processing_unit_wChannelConfig(struct uac_processing_unit_descriptor *desc,
int protocol)
{
if (protocol == UAC_VERSION_1)
return (desc->baSourceID[desc->bNrInPins + 2] << 8) |
desc->baSourceID[desc->bNrInPins + 1];
else
return (desc->baSourceID[desc->bNrInPins + 4] << 24) |
(desc->baSourceID[desc->bNrInPins + 3] << 16) |
(desc->baSourceID[desc->bNrInPins + 2] << 8) |
(desc->baSourceID[desc->bNrInPins + 1]);
}
static inline __u8 uac_processing_unit_iChannelNames(struct uac_processing_unit_descriptor *desc,
int protocol)
{
return (protocol == UAC_VERSION_1) ?
desc->baSourceID[desc->bNrInPins + 3] :
desc->baSourceID[desc->bNrInPins + 5];
}
static inline __u8 uac_processing_unit_bControlSize(struct uac_processing_unit_descriptor *desc,
int protocol)
{
return (protocol == UAC_VERSION_1) ?
desc->baSourceID[desc->bNrInPins + 4] :
desc->baSourceID[desc->bNrInPins + 6];
}
static inline __u8 *uac_processing_unit_bmControls(struct uac_processing_unit_descriptor *desc,
int protocol)
{
return (protocol == UAC_VERSION_1) ?
&desc->baSourceID[desc->bNrInPins + 5] :
&desc->baSourceID[desc->bNrInPins + 7];
}
static inline __u8 uac_processing_unit_iProcessing(struct uac_processing_unit_descriptor *desc,
int protocol)
{
__u8 control_size = uac_processing_unit_bControlSize(desc, protocol);
return desc->baSourceID[desc->bNrInPins + control_size];
}
static inline __u8 *uac_processing_unit_specific(struct uac_processing_unit_descriptor *desc,
int protocol)
{
__u8 control_size = uac_processing_unit_bControlSize(desc, protocol);
return &desc->baSourceID[desc->bNrInPins + control_size + 1];
}
/* 4.5.2 Class-Specific AS Interface Descriptor */ /* 4.5.2 Class-Specific AS Interface Descriptor */
struct uac_as_header_descriptor_v1 { struct uac_as_header_descriptor_v1 {
__u8 bLength; /* in bytes: 7 */ __u8 bLength; /* in bytes: 7 */
...@@ -200,19 +341,6 @@ struct uac_as_header_descriptor_v1 { ...@@ -200,19 +341,6 @@ struct uac_as_header_descriptor_v1 {
__le16 wFormatTag; /* The Audio Data Format */ __le16 wFormatTag; /* The Audio Data Format */
} __attribute__ ((packed)); } __attribute__ ((packed));
struct uac_as_header_descriptor_v2 {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubtype;
__u8 bTerminalLink;
__u8 bmControls;
__u8 bFormatType;
__u32 bmFormats;
__u8 bNrChannels;
__u32 bmChannelConfig;
__u8 iChannelNames;
} __attribute__((packed));
#define UAC_DT_AS_HEADER_SIZE 7 #define UAC_DT_AS_HEADER_SIZE 7
/* Formats - A.1.1 Audio Data Format Type I Codes */ /* Formats - A.1.1 Audio Data Format Type I Codes */
...@@ -277,7 +405,6 @@ struct uac_format_type_i_ext_descriptor { ...@@ -277,7 +405,6 @@ struct uac_format_type_i_ext_descriptor {
__u8 bSideBandProtocol; __u8 bSideBandProtocol;
} __attribute__((packed)); } __attribute__((packed));
/* Formats - Audio Data Format Type I Codes */ /* Formats - Audio Data Format Type I Codes */
#define UAC_FORMAT_TYPE_II_MPEG 0x1001 #define UAC_FORMAT_TYPE_II_MPEG 0x1001
...@@ -336,31 +463,8 @@ struct uac_iso_endpoint_descriptor { ...@@ -336,31 +463,8 @@ struct uac_iso_endpoint_descriptor {
#define UAC_EP_CS_ATTR_PITCH_CONTROL 0x02 #define UAC_EP_CS_ATTR_PITCH_CONTROL 0x02
#define UAC_EP_CS_ATTR_FILL_MAX 0x80 #define UAC_EP_CS_ATTR_FILL_MAX 0x80
/* Audio class v2.0: CLOCK_SOURCE descriptor */
struct uac_clock_source_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubtype;
__u8 bClockID;
__u8 bmAttributes;
__u8 bmControls;
__u8 bAssocTerminal;
__u8 iClockSource;
} __attribute__((packed));
/* A.10.2 Feature Unit Control Selectors */ /* A.10.2 Feature Unit Control Selectors */
struct uac_feature_unit_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubtype;
__u8 bUnitID;
__u8 bSourceID;
__u8 bControlSize;
__u8 controls[0]; /* variable length */
} __attribute__((packed));
#define UAC_FU_CONTROL_UNDEFINED 0x00 #define UAC_FU_CONTROL_UNDEFINED 0x00
#define UAC_MUTE_CONTROL 0x01 #define UAC_MUTE_CONTROL 0x01
#define UAC_VOLUME_CONTROL 0x02 #define UAC_VOLUME_CONTROL 0x02
......
...@@ -22,8 +22,7 @@ config SND_USB_AUDIO ...@@ -22,8 +22,7 @@ config SND_USB_AUDIO
will be called snd-usb-audio. will be called snd-usb-audio.
config SND_USB_UA101 config SND_USB_UA101
tristate "Edirol UA-101/UA-1000 driver (EXPERIMENTAL)" tristate "Edirol UA-101/UA-1000 driver"
depends on EXPERIMENTAL
select SND_PCM select SND_PCM
select SND_RAWMIDI select SND_RAWMIDI
help help
...@@ -65,6 +64,7 @@ config SND_USB_CAIAQ ...@@ -65,6 +64,7 @@ config SND_USB_CAIAQ
* Native Instruments Audio 8 DJ * Native Instruments Audio 8 DJ
* Native Instruments Guitar Rig Session I/O * Native Instruments Guitar Rig Session I/O
* Native Instruments Guitar Rig mobile * Native Instruments Guitar Rig mobile
* Native Instruments Traktor Kontrol X1
To compile this driver as a module, choose M here: the module To compile this driver as a module, choose M here: the module
will be called snd-usb-caiaq. will be called snd-usb-caiaq.
......
...@@ -2,14 +2,24 @@ ...@@ -2,14 +2,24 @@
# Makefile for ALSA # Makefile for ALSA
# #
snd-usb-audio-objs := usbaudio.o usbmixer.o snd-usb-audio-objs := card.o \
snd-usb-lib-objs := usbmidi.o mixer.o \
snd-ua101-objs := ua101.o mixer_quirks.o \
proc.o \
quirks.o \
format.o \
endpoint.o \
urb.o \
pcm.o \
helper.o
snd-usbmidi-lib-objs := midi.o
# Toplevel Module Dependency # Toplevel Module Dependency
obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-audio.o snd-usb-lib.o obj-$(CONFIG_SND_USB_AUDIO) += snd-usb-audio.o snd-usbmidi-lib.o
obj-$(CONFIG_SND_USB_UA101) += snd-ua101.o snd-usb-lib.o
obj-$(CONFIG_SND_USB_USX2Y) += snd-usb-lib.o obj-$(CONFIG_SND_USB_UA101) += snd-usbmidi-lib.o
obj-$(CONFIG_SND_USB_US122L) += snd-usb-lib.o obj-$(CONFIG_SND_USB_USX2Y) += snd-usbmidi-lib.o
obj-$(CONFIG_SND_USB_US122L) += snd-usbmidi-lib.o
obj-$(CONFIG_SND) += usx2y/ caiaq/ obj-$(CONFIG_SND) += misc/ usx2y/ caiaq/
...@@ -35,33 +35,41 @@ static int control_info(struct snd_kcontrol *kcontrol, ...@@ -35,33 +35,41 @@ static int control_info(struct snd_kcontrol *kcontrol,
struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
int pos = kcontrol->private_value; int pos = kcontrol->private_value;
int is_intval = pos & CNT_INTVAL; int is_intval = pos & CNT_INTVAL;
unsigned int id = dev->chip.usb_id; int maxval = 63;
uinfo->count = 1; uinfo->count = 1;
pos &= ~CNT_INTVAL; pos &= ~CNT_INTVAL;
if (id == USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ) switch (dev->chip.usb_id) {
&& (pos == 0)) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO8DJ):
/* current input mode of A8DJ */ if (pos == 0) {
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; /* current input mode of A8DJ */
uinfo->value.integer.min = 0; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->value.integer.max = 2; uinfo->value.integer.min = 0;
return 0; uinfo->value.integer.max = 2;
} return 0;
}
break;
if (id == USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ) case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
&& (pos == 0)) { if (pos == 0) {
/* current input mode of A4DJ */ /* current input mode of A4DJ */
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->value.integer.min = 0; uinfo->value.integer.min = 0;
uinfo->value.integer.max = 1; uinfo->value.integer.max = 1;
return 0; return 0;
}
break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
maxval = 127;
break;
} }
if (is_intval) { if (is_intval) {
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
uinfo->value.integer.min = 0; uinfo->value.integer.min = 0;
uinfo->value.integer.max = 64; uinfo->value.integer.max = maxval;
} else { } else {
uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN; uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
uinfo->value.integer.min = 0; uinfo->value.integer.min = 0;
...@@ -102,9 +110,10 @@ static int control_put(struct snd_kcontrol *kcontrol, ...@@ -102,9 +110,10 @@ static int control_put(struct snd_kcontrol *kcontrol,
struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol); struct snd_usb_audio *chip = snd_kcontrol_chip(kcontrol);
struct snd_usb_caiaqdev *dev = caiaqdev(chip->card); struct snd_usb_caiaqdev *dev = caiaqdev(chip->card);
int pos = kcontrol->private_value; int pos = kcontrol->private_value;
unsigned char cmd = EP1_CMD_WRITE_IO;
if (dev->chip.usb_id == switch (dev->chip.usb_id) {
USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ)) { case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ): {
/* A4DJ has only one control */ /* A4DJ has only one control */
/* do not expose hardware input mode 0 */ /* do not expose hardware input mode 0 */
dev->control_state[0] = ucontrol->value.integer.value[0] + 1; dev->control_state[0] = ucontrol->value.integer.value[0] + 1;
...@@ -113,10 +122,15 @@ static int control_put(struct snd_kcontrol *kcontrol, ...@@ -113,10 +122,15 @@ static int control_put(struct snd_kcontrol *kcontrol,
return 1; return 1;
} }
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
cmd = EP1_CMD_DIMM_LEDS;
break;
}
if (pos & CNT_INTVAL) { if (pos & CNT_INTVAL) {
dev->control_state[pos & ~CNT_INTVAL] dev->control_state[pos & ~CNT_INTVAL]
= ucontrol->value.integer.value[0]; = ucontrol->value.integer.value[0];
snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, snd_usb_caiaq_send_command(dev, cmd,
dev->control_state, sizeof(dev->control_state)); dev->control_state, sizeof(dev->control_state));
} else { } else {
if (ucontrol->value.integer.value[0]) if (ucontrol->value.integer.value[0])
...@@ -124,7 +138,7 @@ static int control_put(struct snd_kcontrol *kcontrol, ...@@ -124,7 +138,7 @@ static int control_put(struct snd_kcontrol *kcontrol,
else else
dev->control_state[pos / 8] &= ~(1 << (pos % 8)); dev->control_state[pos / 8] &= ~(1 << (pos % 8));
snd_usb_caiaq_send_command(dev, EP1_CMD_WRITE_IO, snd_usb_caiaq_send_command(dev, cmd,
dev->control_state, sizeof(dev->control_state)); dev->control_state, sizeof(dev->control_state));
} }
...@@ -273,6 +287,43 @@ static struct caiaq_controller a4dj_controller[] = { ...@@ -273,6 +287,43 @@ static struct caiaq_controller a4dj_controller[] = {
{ "Current input mode", 0 | CNT_INTVAL } { "Current input mode", 0 | CNT_INTVAL }
}; };
static struct caiaq_controller kontrolx1_controller[] = {
{ "LED FX A: ON", 7 | CNT_INTVAL },
{ "LED FX A: 1", 6 | CNT_INTVAL },
{ "LED FX A: 2", 5 | CNT_INTVAL },
{ "LED FX A: 3", 4 | CNT_INTVAL },
{ "LED FX B: ON", 3 | CNT_INTVAL },
{ "LED FX B: 1", 2 | CNT_INTVAL },
{ "LED FX B: 2", 1 | CNT_INTVAL },
{ "LED FX B: 3", 0 | CNT_INTVAL },
{ "LED Hotcue", 28 | CNT_INTVAL },
{ "LED Shift (white)", 29 | CNT_INTVAL },
{ "LED Shift (green)", 30 | CNT_INTVAL },
{ "LED Deck A: FX1", 24 | CNT_INTVAL },
{ "LED Deck A: FX2", 25 | CNT_INTVAL },
{ "LED Deck A: IN", 17 | CNT_INTVAL },
{ "LED Deck A: OUT", 16 | CNT_INTVAL },
{ "LED Deck A: < BEAT", 19 | CNT_INTVAL },
{ "LED Deck A: BEAT >", 18 | CNT_INTVAL },
{ "LED Deck A: CUE/ABS", 21 | CNT_INTVAL },
{ "LED Deck A: CUP/REL", 20 | CNT_INTVAL },
{ "LED Deck A: PLAY", 23 | CNT_INTVAL },
{ "LED Deck A: SYNC", 22 | CNT_INTVAL },
{ "LED Deck B: FX1", 26 | CNT_INTVAL },
{ "LED Deck B: FX2", 27 | CNT_INTVAL },
{ "LED Deck B: IN", 15 | CNT_INTVAL },
{ "LED Deck B: OUT", 14 | CNT_INTVAL },
{ "LED Deck B: < BEAT", 13 | CNT_INTVAL },
{ "LED Deck B: BEAT >", 12 | CNT_INTVAL },
{ "LED Deck B: CUE/ABS", 11 | CNT_INTVAL },
{ "LED Deck B: CUP/REL", 10 | CNT_INTVAL },
{ "LED Deck B: PLAY", 9 | CNT_INTVAL },
{ "LED Deck B: SYNC", 8 | CNT_INTVAL },
};
static int __devinit add_controls(struct caiaq_controller *c, int num, static int __devinit add_controls(struct caiaq_controller *c, int num,
struct snd_usb_caiaqdev *dev) struct snd_usb_caiaqdev *dev)
{ {
...@@ -321,10 +372,16 @@ int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev) ...@@ -321,10 +372,16 @@ int __devinit snd_usb_caiaq_control_init(struct snd_usb_caiaqdev *dev)
ret = add_controls(a8dj_controller, ret = add_controls(a8dj_controller,
ARRAY_SIZE(a8dj_controller), dev); ARRAY_SIZE(a8dj_controller), dev);
break; break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ): case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_AUDIO4DJ):
ret = add_controls(a4dj_controller, ret = add_controls(a4dj_controller,
ARRAY_SIZE(a4dj_controller), dev); ARRAY_SIZE(a4dj_controller), dev);
break; break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
ret = add_controls(kontrolx1_controller,
ARRAY_SIZE(kontrolx1_controller), dev);
break;
} }
return ret; return ret;
......
...@@ -47,7 +47,8 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2}," ...@@ -47,7 +47,8 @@ MODULE_SUPPORTED_DEVICE("{{Native Instruments, RigKontrol2},"
"{Native Instruments, Audio 4 DJ}," "{Native Instruments, Audio 4 DJ},"
"{Native Instruments, Audio 8 DJ}," "{Native Instruments, Audio 8 DJ},"
"{Native Instruments, Session I/O}," "{Native Instruments, Session I/O},"
"{Native Instruments, GuitarRig mobile}"); "{Native Instruments, GuitarRig mobile}"
"{Native Instruments, Traktor Kontrol X1}");
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */ static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-max */
static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */ static char* id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* Id for this card */
...@@ -128,6 +129,11 @@ static struct usb_device_id snd_usb_id_table[] = { ...@@ -128,6 +129,11 @@ static struct usb_device_id snd_usb_id_table[] = {
.idVendor = USB_VID_NATIVEINSTRUMENTS, .idVendor = USB_VID_NATIVEINSTRUMENTS,
.idProduct = USB_PID_AUDIO2DJ .idProduct = USB_PID_AUDIO2DJ
}, },
{
.match_flags = USB_DEVICE_ID_MATCH_DEVICE,
.idVendor = USB_VID_NATIVEINSTRUMENTS,
.idProduct = USB_PID_TRAKTORKONTROLX1
},
{ /* terminator */ } { /* terminator */ }
}; };
......
...@@ -5,18 +5,20 @@ ...@@ -5,18 +5,20 @@
#define USB_VID_NATIVEINSTRUMENTS 0x17cc #define USB_VID_NATIVEINSTRUMENTS 0x17cc
#define USB_PID_RIGKONTROL2 0x1969 #define USB_PID_RIGKONTROL2 0x1969
#define USB_PID_RIGKONTROL3 0x1940 #define USB_PID_RIGKONTROL3 0x1940
#define USB_PID_KORECONTROLLER 0x4711 #define USB_PID_KORECONTROLLER 0x4711
#define USB_PID_KORECONTROLLER2 0x4712 #define USB_PID_KORECONTROLLER2 0x4712
#define USB_PID_AK1 0x0815 #define USB_PID_AK1 0x0815
#define USB_PID_AUDIO2DJ 0x041c #define USB_PID_AUDIO2DJ 0x041c
#define USB_PID_AUDIO4DJ 0x0839 #define USB_PID_AUDIO4DJ 0x0839
#define USB_PID_AUDIO8DJ 0x1978 #define USB_PID_AUDIO8DJ 0x1978
#define USB_PID_SESSIONIO 0x1915 #define USB_PID_SESSIONIO 0x1915
#define USB_PID_GUITARRIGMOBILE 0x0d8d #define USB_PID_GUITARRIGMOBILE 0x0d8d
#define USB_PID_TRAKTORKONTROLX1 0x2305
#define EP1_BUFSIZE 64 #define EP1_BUFSIZE 64
#define EP4_BUFSIZE 512
#define CAIAQ_USB_STR_LEN 0xff #define CAIAQ_USB_STR_LEN 0xff
#define MAX_STREAMS 32 #define MAX_STREAMS 32
...@@ -104,6 +106,8 @@ struct snd_usb_caiaqdev { ...@@ -104,6 +106,8 @@ struct snd_usb_caiaqdev {
struct input_dev *input_dev; struct input_dev *input_dev;
char phys[64]; /* physical device path */ char phys[64]; /* physical device path */
unsigned short keycode[64]; unsigned short keycode[64];
struct urb *ep4_in_urb;
unsigned char ep4_in_buf[EP4_BUFSIZE];
#endif #endif
/* ALSA */ /* ALSA */
......
...@@ -16,9 +16,11 @@ ...@@ -16,9 +16,11 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include <linux/gfp.h>
#include <linux/init.h> #include <linux/init.h>
#include <linux/usb.h> #include <linux/usb.h>
#include <linux/usb/input.h> #include <linux/usb/input.h>
#include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#include "device.h" #include "device.h"
...@@ -65,6 +67,8 @@ static unsigned short keycode_kore[] = { ...@@ -65,6 +67,8 @@ static unsigned short keycode_kore[] = {
KEY_BRL_DOT5 KEY_BRL_DOT5
}; };
#define KONTROLX1_INPUTS 40
#define DEG90 (range / 2) #define DEG90 (range / 2)
#define DEG180 (range) #define DEG180 (range)
#define DEG270 (DEG90 + DEG180) #define DEG270 (DEG90 + DEG180)
...@@ -162,6 +166,17 @@ static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev, ...@@ -162,6 +166,17 @@ static void snd_caiaq_input_read_analog(struct snd_usb_caiaqdev *dev,
input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]); input_report_abs(input_dev, ABS_Z, (buf[4] << 8) | buf[5]);
input_sync(input_dev); input_sync(input_dev);
break; break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
input_report_abs(input_dev, ABS_HAT0X, (buf[8] << 8) | buf[9]);
input_report_abs(input_dev, ABS_HAT0Y, (buf[4] << 8) | buf[5]);
input_report_abs(input_dev, ABS_HAT1X, (buf[12] << 8) | buf[13]);
input_report_abs(input_dev, ABS_HAT1Y, (buf[2] << 8) | buf[3]);
input_report_abs(input_dev, ABS_HAT2X, (buf[15] << 8) | buf[15]);
input_report_abs(input_dev, ABS_HAT2Y, (buf[0] << 8) | buf[1]);
input_report_abs(input_dev, ABS_HAT3X, (buf[10] << 8) | buf[11]);
input_report_abs(input_dev, ABS_HAT3Y, (buf[6] << 8) | buf[7]);
input_sync(input_dev);
break;
} }
} }
...@@ -201,7 +216,7 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev, ...@@ -201,7 +216,7 @@ static void snd_caiaq_input_read_erp(struct snd_usb_caiaqdev *dev,
} }
static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev, static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev,
char *buf, unsigned int len) unsigned char *buf, unsigned int len)
{ {
struct input_dev *input_dev = dev->input_dev; struct input_dev *input_dev = dev->input_dev;
unsigned short *keycode = input_dev->keycode; unsigned short *keycode = input_dev->keycode;
...@@ -218,15 +233,84 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev, ...@@ -218,15 +233,84 @@ static void snd_caiaq_input_read_io(struct snd_usb_caiaqdev *dev,
input_report_key(input_dev, keycode[i], input_report_key(input_dev, keycode[i],
buf[i / 8] & (1 << (i % 8))); buf[i / 8] & (1 << (i % 8)));
if (dev->chip.usb_id == switch (dev->chip.usb_id) {
USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER) || case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER):
dev->chip.usb_id == case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2):
USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_KORECONTROLLER2))
input_report_abs(dev->input_dev, ABS_MISC, 255 - buf[4]); input_report_abs(dev->input_dev, ABS_MISC, 255 - buf[4]);
break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
/* rotary encoders */
input_report_abs(dev->input_dev, ABS_X, buf[5] & 0xf);
input_report_abs(dev->input_dev, ABS_Y, buf[5] >> 4);
input_report_abs(dev->input_dev, ABS_Z, buf[6] & 0xf);
input_report_abs(dev->input_dev, ABS_MISC, buf[6] >> 4);
break;
}
input_sync(input_dev); input_sync(input_dev);
} }
static void snd_usb_caiaq_ep4_reply_dispatch(struct urb *urb)
{
struct snd_usb_caiaqdev *dev = urb->context;
unsigned char *buf = urb->transfer_buffer;
int ret;
if (urb->status || !dev || urb != dev->ep4_in_urb)
return;
if (urb->actual_length < 24)
goto requeue;
switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
if (buf[0] & 0x3)
snd_caiaq_input_read_io(dev, buf + 1, 7);
if (buf[0] & 0x4)
snd_caiaq_input_read_analog(dev, buf + 8, 16);
break;
}
requeue:
dev->ep4_in_urb->actual_length = 0;
ret = usb_submit_urb(dev->ep4_in_urb, GFP_ATOMIC);
if (ret < 0)
log("unable to submit urb. OOM!?\n");
}
static int snd_usb_caiaq_input_open(struct input_dev *idev)
{
struct snd_usb_caiaqdev *dev = input_get_drvdata(idev);
if (!dev)
return -EINVAL;
switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
if (usb_submit_urb(dev->ep4_in_urb, GFP_KERNEL) != 0)
return -EIO;
break;
}
return 0;
}
static void snd_usb_caiaq_input_close(struct input_dev *idev)
{
struct snd_usb_caiaqdev *dev = input_get_drvdata(idev);
if (!dev)
return;
switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
usb_kill_urb(dev->ep4_in_urb);
break;
}
}
void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev, void snd_usb_caiaq_input_dispatch(struct snd_usb_caiaqdev *dev,
char *buf, char *buf,
unsigned int len) unsigned int len)
...@@ -251,7 +335,7 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) ...@@ -251,7 +335,7 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
{ {
struct usb_device *usb_dev = dev->chip.dev; struct usb_device *usb_dev = dev->chip.dev;
struct input_dev *input; struct input_dev *input;
int i, ret; int i, ret = 0;
input = input_allocate_device(); input = input_allocate_device();
if (!input) if (!input)
...@@ -265,7 +349,9 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) ...@@ -265,7 +349,9 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
usb_to_input_id(usb_dev, &input->id); usb_to_input_id(usb_dev, &input->id);
input->dev.parent = &usb_dev->dev; input->dev.parent = &usb_dev->dev;
switch (dev->chip.usb_id) { input_set_drvdata(input, dev);
switch (dev->chip.usb_id) {
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2): case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_RIGKONTROL2):
input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) | input->absbit[0] = BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
...@@ -325,26 +411,73 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev) ...@@ -325,26 +411,73 @@ int snd_usb_caiaq_input_init(struct snd_usb_caiaqdev *dev)
input_set_abs_params(input, ABS_Z, 0, 4096, 0, 10); input_set_abs_params(input, ABS_Z, 0, 4096, 0, 10);
input_set_abs_params(input, ABS_MISC, 0, 255, 0, 1); input_set_abs_params(input, ABS_MISC, 0, 255, 0, 1);
snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5); snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
break;
case USB_ID(USB_VID_NATIVEINSTRUMENTS, USB_PID_TRAKTORKONTROLX1):
input->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS);
input->absbit[0] = BIT_MASK(ABS_HAT0X) | BIT_MASK(ABS_HAT0Y) |
BIT_MASK(ABS_HAT1X) | BIT_MASK(ABS_HAT1Y) |
BIT_MASK(ABS_HAT2X) | BIT_MASK(ABS_HAT2Y) |
BIT_MASK(ABS_HAT3X) | BIT_MASK(ABS_HAT3Y) |
BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) |
BIT_MASK(ABS_Z);
input->absbit[BIT_WORD(ABS_MISC)] |= BIT_MASK(ABS_MISC);
BUILD_BUG_ON(sizeof(dev->keycode) < KONTROLX1_INPUTS);
for (i = 0; i < KONTROLX1_INPUTS; i++)
dev->keycode[i] = BTN_MISC + i;
input->keycodemax = KONTROLX1_INPUTS;
/* analog potentiometers */
input_set_abs_params(input, ABS_HAT0X, 0, 4096, 0, 10);
input_set_abs_params(input, ABS_HAT0Y, 0, 4096, 0, 10);
input_set_abs_params(input, ABS_HAT1X, 0, 4096, 0, 10);
input_set_abs_params(input, ABS_HAT1Y, 0, 4096, 0, 10);
input_set_abs_params(input, ABS_HAT2X, 0, 4096, 0, 10);
input_set_abs_params(input, ABS_HAT2Y, 0, 4096, 0, 10);
input_set_abs_params(input, ABS_HAT3X, 0, 4096, 0, 10);
input_set_abs_params(input, ABS_HAT3Y, 0, 4096, 0, 10);
/* rotary encoders */
input_set_abs_params(input, ABS_X, 0, 0xf, 0, 1);
input_set_abs_params(input, ABS_Y, 0, 0xf, 0, 1);
input_set_abs_params(input, ABS_Z, 0, 0xf, 0, 1);
input_set_abs_params(input, ABS_MISC, 0, 0xf, 0, 1);
dev->ep4_in_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->ep4_in_urb) {
ret = -ENOMEM;
goto exit_free_idev;
}
usb_fill_bulk_urb(dev->ep4_in_urb, usb_dev,
usb_rcvbulkpipe(usb_dev, 0x4),
dev->ep4_in_buf, EP4_BUFSIZE,
snd_usb_caiaq_ep4_reply_dispatch, dev);
snd_usb_caiaq_set_auto_msg(dev, 1, 10, 5);
break; break;
default: default:
/* no input methods supported on this device */ /* no input methods supported on this device */
input_free_device(input); goto exit_free_idev;
return 0;
} }
input->open = snd_usb_caiaq_input_open;
input->close = snd_usb_caiaq_input_close;
input->keycode = dev->keycode; input->keycode = dev->keycode;
input->keycodesize = sizeof(unsigned short); input->keycodesize = sizeof(unsigned short);
for (i = 0; i < input->keycodemax; i++) for (i = 0; i < input->keycodemax; i++)
__set_bit(dev->keycode[i], input->keybit); __set_bit(dev->keycode[i], input->keybit);
ret = input_register_device(input); ret = input_register_device(input);
if (ret < 0) { if (ret < 0)
input_free_device(input); goto exit_free_idev;
return ret;
}
dev->input_dev = input; dev->input_dev = input;
return 0; return 0;
exit_free_idev:
input_free_device(input);
return ret;
} }
void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev) void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev)
...@@ -352,6 +485,10 @@ void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev) ...@@ -352,6 +485,10 @@ void snd_usb_caiaq_input_free(struct snd_usb_caiaqdev *dev)
if (!dev || !dev->input_dev) if (!dev || !dev->input_dev)
return; return;
usb_kill_urb(dev->ep4_in_urb);
usb_free_urb(dev->ep4_in_urb);
dev->ep4_in_urb = NULL;
input_unregister_device(dev->input_dev); input_unregister_device(dev->input_dev);
dev->input_dev = NULL; dev->input_dev = NULL;
} }
......
This diff is collapsed.
#ifndef __USBAUDIO_CARD_H
#define __USBAUDIO_CARD_H
#define MAX_PACKS 20
#define MAX_PACKS_HS (MAX_PACKS * 8) /* in high speed mode */
#define MAX_URBS 8
#define SYNC_URBS 4 /* always four urbs for sync */
#define MAX_QUEUE 24 /* try not to exceed this queue length, in ms */
struct audioformat {
struct list_head list;
u64 formats; /* ALSA format bits */
unsigned int channels; /* # channels */
unsigned int fmt_type; /* USB audio format type (1-3) */
unsigned int frame_size; /* samples per frame for non-audio */
int iface; /* interface number */
unsigned char altsetting; /* corresponding alternate setting */
unsigned char altset_idx; /* array index of altenate setting */
unsigned char attributes; /* corresponding attributes of cs endpoint */
unsigned char endpoint; /* endpoint */
unsigned char ep_attr; /* endpoint attributes */
unsigned char datainterval; /* log_2 of data packet interval */
unsigned int maxpacksize; /* max. packet size */
unsigned int rates; /* rate bitmasks */
unsigned int rate_min, rate_max; /* min/max rates */
unsigned int nr_rates; /* number of rate table entries */
unsigned int *rate_table; /* rate table */
};
struct snd_usb_substream;
struct snd_urb_ctx {
struct urb *urb;
unsigned int buffer_size; /* size of data buffer, if data URB */
struct snd_usb_substream *subs;
int index; /* index for urb array */
int packets; /* number of packets per urb */
};
struct snd_urb_ops {
int (*prepare)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
int (*retire)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
int (*prepare_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
int (*retire_sync)(struct snd_usb_substream *subs, struct snd_pcm_runtime *runtime, struct urb *u);
};
struct snd_usb_substream {
struct snd_usb_stream *stream;
struct usb_device *dev;
struct snd_pcm_substream *pcm_substream;
int direction; /* playback or capture */
int interface; /* current interface */
int endpoint; /* assigned endpoint */
struct audioformat *cur_audiofmt; /* current audioformat pointer (for hw_params callback) */
unsigned int cur_rate; /* current rate (for hw_params callback) */
unsigned int period_bytes; /* current period bytes (for hw_params callback) */
unsigned int altset_idx; /* USB data format: index of alternate setting */
unsigned int datapipe; /* the data i/o pipe */
unsigned int syncpipe; /* 1 - async out or adaptive in */
unsigned int datainterval; /* log_2 of data packet interval */
unsigned int syncinterval; /* P for adaptive mode, 0 otherwise */
unsigned int freqn; /* nominal sampling rate in fs/fps in Q16.16 format */
unsigned int freqm; /* momentary sampling rate in fs/fps in Q16.16 format */
unsigned int freqmax; /* maximum sampling rate, used for buffer management */
unsigned int phase; /* phase accumulator */
unsigned int maxpacksize; /* max packet size in bytes */
unsigned int maxframesize; /* max packet size in frames */
unsigned int curpacksize; /* current packet size in bytes (for capture) */
unsigned int curframesize; /* current packet size in frames (for capture) */
unsigned int fill_max: 1; /* fill max packet size always */
unsigned int txfr_quirk:1; /* allow sub-frame alignment */
unsigned int fmt_type; /* USB audio format type (1-3) */
unsigned int running: 1; /* running status */
unsigned int hwptr_done; /* processed byte position in the buffer */
unsigned int transfer_done; /* processed frames since last period update */
unsigned long active_mask; /* bitmask of active urbs */
unsigned long unlink_mask; /* bitmask of unlinked urbs */
unsigned int nurbs; /* # urbs */
struct snd_urb_ctx dataurb[MAX_URBS]; /* data urb table */
struct snd_urb_ctx syncurb[SYNC_URBS]; /* sync urb table */
char *syncbuf; /* sync buffer for all sync URBs */
dma_addr_t sync_dma; /* DMA address of syncbuf */
u64 formats; /* format bitmasks (all or'ed) */
unsigned int num_formats; /* number of supported audio formats (list) */
struct list_head fmt_list; /* format list */
struct snd_pcm_hw_constraint_list rate_list; /* limited rates */
spinlock_t lock;
struct snd_urb_ops ops; /* callbacks (must be filled at init) */
};
struct snd_usb_stream {
struct snd_usb_audio *chip;
struct snd_pcm *pcm;
int pcm_index;
unsigned int fmt_type; /* USB audio format type (1-3) */
struct snd_usb_substream substream[2];
struct list_head list;
};
#endif /* __USBAUDIO_CARD_H */
#ifndef __USBAUDIO_DEBUG_H
#define __USBAUDIO_DEBUG_H
/*
* h/w constraints
*/
#ifdef HW_CONST_DEBUG
#define hwc_debug(fmt, args...) printk(KERN_DEBUG fmt, ##args)
#else
#define hwc_debug(fmt, args...) /**/
#endif
#endif /* __USBAUDIO_DEBUG_H */
This diff is collapsed.
#ifndef __USBAUDIO_ENDPOINT_H
#define __USBAUDIO_ENDPOINT_H
int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip,
int iface_no);
int snd_usb_add_audio_endpoint(struct snd_usb_audio *chip,
int stream,
struct audioformat *fp);
#endif /* __USBAUDIO_ENDPOINT_H */
This diff is collapsed.
#ifndef __USBAUDIO_FORMAT_H
#define __USBAUDIO_FORMAT_H
int snd_usb_parse_audio_format(struct snd_usb_audio *chip, struct audioformat *fp,
int format, unsigned char *fmt, int stream,
struct usb_host_interface *iface);
#endif /* __USBAUDIO_FORMAT_H */
/*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include "usbaudio.h"
#include "helper.h"
/*
* combine bytes and get an integer value
*/
unsigned int snd_usb_combine_bytes(unsigned char *bytes, int size)
{
switch (size) {
case 1: return *bytes;
case 2: return combine_word(bytes);
case 3: return combine_triple(bytes);
case 4: return combine_quad(bytes);
default: return 0;
}
}
/*
* parse descriptor buffer and return the pointer starting the given
* descriptor type.
*/
void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype)
{
u8 *p, *end, *next;
p = descstart;
end = p + desclen;
for (; p < end;) {
if (p[0] < 2)
return NULL;
next = p + p[0];
if (next > end)
return NULL;
if (p[1] == dtype && (!after || (void *)p > after)) {
return p;
}
p = next;
}
return NULL;
}
/*
* find a class-specified interface descriptor with the given subtype.
*/
void *snd_usb_find_csint_desc(void *buffer, int buflen, void *after, u8 dsubtype)
{
unsigned char *p = after;
while ((p = snd_usb_find_desc(buffer, buflen, p,
USB_DT_CS_INTERFACE)) != NULL) {
if (p[0] >= 3 && p[2] == dsubtype)
return p;
}
return NULL;
}
/*
* Wrapper for usb_control_msg().
* Allocates a temp buffer to prevent dmaing from/to the stack.
*/
int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request,
__u8 requesttype, __u16 value, __u16 index, void *data,
__u16 size, int timeout)
{
int err;
void *buf = NULL;
if (size > 0) {
buf = kmemdup(data, size, GFP_KERNEL);
if (!buf)
return -ENOMEM;
}
err = usb_control_msg(dev, pipe, request, requesttype,
value, index, buf, size, timeout);
if (size > 0) {
memcpy(data, buf, size);
kfree(buf);
}
return err;
}
unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip,
struct usb_host_interface *alts)
{
if (snd_usb_get_speed(chip->dev) == USB_SPEED_HIGH &&
get_endpoint(alts, 0)->bInterval >= 1 &&
get_endpoint(alts, 0)->bInterval <= 4)
return get_endpoint(alts, 0)->bInterval - 1;
else
return 0;
}
#ifndef __USBAUDIO_HELPER_H
#define __USBAUDIO_HELPER_H
unsigned int snd_usb_combine_bytes(unsigned char *bytes, int size);
void *snd_usb_find_desc(void *descstart, int desclen, void *after, u8 dtype);
void *snd_usb_find_csint_desc(void *descstart, int desclen, void *after, u8 dsubtype);
int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe,
__u8 request, __u8 requesttype, __u16 value, __u16 index,
void *data, __u16 size, int timeout);
unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip,
struct usb_host_interface *alts);
/*
* retrieve usb_interface descriptor from the host interface
* (conditional for compatibility with the older API)
*/
#ifndef get_iface_desc
#define get_iface_desc(iface) (&(iface)->desc)
#define get_endpoint(alt,ep) (&(alt)->endpoint[ep].desc)
#define get_ep_desc(ep) (&(ep)->desc)
#define get_cfg_desc(cfg) (&(cfg)->desc)
#endif
#ifndef snd_usb_get_speed
#define snd_usb_get_speed(dev) ((dev)->speed)
#endif
#endif /* __USBAUDIO_HELPER_H */
...@@ -53,7 +53,8 @@ ...@@ -53,7 +53,8 @@
#include <sound/rawmidi.h> #include <sound/rawmidi.h>
#include <sound/asequencer.h> #include <sound/asequencer.h>
#include "usbaudio.h" #include "usbaudio.h"
#include "midi.h"
#include "helper.h"
/* /*
* define this to log all USB packets * define this to log all USB packets
...@@ -986,6 +987,8 @@ static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream) ...@@ -986,6 +987,8 @@ static void snd_usbmidi_output_drain(struct snd_rawmidi_substream *substream)
DEFINE_WAIT(wait); DEFINE_WAIT(wait);
long timeout = msecs_to_jiffies(50); long timeout = msecs_to_jiffies(50);
if (ep->umidi->disconnected)
return;
/* /*
* The substream buffer is empty, but some data might still be in the * The substream buffer is empty, but some data might still be in the
* currently active URBs, so we have to wait for those to complete. * currently active URBs, so we have to wait for those to complete.
...@@ -1123,14 +1126,21 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi, ...@@ -1123,14 +1126,21 @@ static int snd_usbmidi_in_endpoint_create(struct snd_usb_midi* umidi,
* Frees an output endpoint. * Frees an output endpoint.
* May be called when ep hasn't been initialized completely. * May be called when ep hasn't been initialized completely.
*/ */
static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint* ep) static void snd_usbmidi_out_endpoint_clear(struct snd_usb_midi_out_endpoint *ep)
{ {
unsigned int i; unsigned int i;
for (i = 0; i < OUTPUT_URBS; ++i) for (i = 0; i < OUTPUT_URBS; ++i)
if (ep->urbs[i].urb) if (ep->urbs[i].urb) {
free_urb_and_buffer(ep->umidi, ep->urbs[i].urb, free_urb_and_buffer(ep->umidi, ep->urbs[i].urb,
ep->max_transfer); ep->max_transfer);
ep->urbs[i].urb = NULL;
}
}
static void snd_usbmidi_out_endpoint_delete(struct snd_usb_midi_out_endpoint *ep)
{
snd_usbmidi_out_endpoint_clear(ep);
kfree(ep); kfree(ep);
} }
...@@ -1262,15 +1272,18 @@ void snd_usbmidi_disconnect(struct list_head* p) ...@@ -1262,15 +1272,18 @@ void snd_usbmidi_disconnect(struct list_head* p)
usb_kill_urb(ep->out->urbs[j].urb); usb_kill_urb(ep->out->urbs[j].urb);
if (umidi->usb_protocol_ops->finish_out_endpoint) if (umidi->usb_protocol_ops->finish_out_endpoint)
umidi->usb_protocol_ops->finish_out_endpoint(ep->out); umidi->usb_protocol_ops->finish_out_endpoint(ep->out);
ep->out->active_urbs = 0;
if (ep->out->drain_urbs) {
ep->out->drain_urbs = 0;
wake_up(&ep->out->drain_wait);
}
} }
if (ep->in) if (ep->in)
for (j = 0; j < INPUT_URBS; ++j) for (j = 0; j < INPUT_URBS; ++j)
usb_kill_urb(ep->in->urbs[j]); usb_kill_urb(ep->in->urbs[j]);
/* free endpoints here; later call can result in Oops */ /* free endpoints here; later call can result in Oops */
if (ep->out) { if (ep->out)
snd_usbmidi_out_endpoint_delete(ep->out); snd_usbmidi_out_endpoint_clear(ep->out);
ep->out = NULL;
}
if (ep->in) { if (ep->in) {
snd_usbmidi_in_endpoint_delete(ep->in); snd_usbmidi_in_endpoint_delete(ep->in);
ep->in = NULL; ep->in = NULL;
......
#ifndef __USBMIDI_H
#define __USBMIDI_H
/* maximum number of endpoints per interface */
#define MIDI_MAX_ENDPOINTS 2
/* data for QUIRK_MIDI_FIXED_ENDPOINT */
struct snd_usb_midi_endpoint_info {
int8_t out_ep; /* ep number, 0 autodetect */
uint8_t out_interval; /* interval for interrupt endpoints */
int8_t in_ep;
uint8_t in_interval;
uint16_t out_cables; /* bitmask */
uint16_t in_cables; /* bitmask */
};
/* for QUIRK_MIDI_YAMAHA, data is NULL */
/* for QUIRK_MIDI_MIDIMAN, data points to a snd_usb_midi_endpoint_info
* structure (out_cables and in_cables only) */
/* for QUIRK_COMPOSITE, data points to an array of snd_usb_audio_quirk
* structures, terminated with .ifnum = -1 */
/* for QUIRK_AUDIO_FIXED_ENDPOINT, data points to an audioformat structure */
/* for QUIRK_AUDIO/MIDI_STANDARD_INTERFACE, data is NULL */
/* for QUIRK_AUDIO_EDIROL_UA700_UA25/UA1000, data is NULL */
/* for QUIRK_IGNORE_INTERFACE, data is NULL */
/* for QUIRK_MIDI_NOVATION and _RAW, data is NULL */
/* for QUIRK_MIDI_EMAGIC, data points to a snd_usb_midi_endpoint_info
* structure (out_cables and in_cables only) */
/* for QUIRK_MIDI_CME, data is NULL */
int snd_usbmidi_create(struct snd_card *card,
struct usb_interface *iface,
struct list_head *midi_list,
const struct snd_usb_audio_quirk *quirk);
void snd_usbmidi_input_stop(struct list_head* p);
void snd_usbmidi_input_start(struct list_head* p);
void snd_usbmidi_disconnect(struct list_head *p);
#endif /* __USBMIDI_H */
snd-ua101-objs := ua101.o
obj-$(CONFIG_SND_USB_UA101) += snd-ua101.o
...@@ -23,7 +23,8 @@ ...@@ -23,7 +23,8 @@
#include <sound/initval.h> #include <sound/initval.h>
#include <sound/pcm.h> #include <sound/pcm.h>
#include <sound/pcm_params.h> #include <sound/pcm_params.h>
#include "usbaudio.h" #include "../usbaudio.h"
#include "../midi.h"
MODULE_DESCRIPTION("Edirol UA-101/1000 driver"); MODULE_DESCRIPTION("Edirol UA-101/1000 driver");
MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>"); MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
......
This diff is collapsed.
#ifndef __USBMIXER_H
#define __USBMIXER_H
struct usb_mixer_interface {
struct snd_usb_audio *chip;
unsigned int ctrlif;
struct list_head list;
unsigned int ignore_ctl_error;
struct urb *urb;
/* array[MAX_ID_ELEMS], indexed by unit id */
struct usb_mixer_elem_info **id_elems;
/* the usb audio specification version this interface complies to */
int protocol;
/* Sound Blaster remote control stuff */
const struct rc_config *rc_cfg;
u32 rc_code;
wait_queue_head_t rc_waitq;
struct urb *rc_urb;
struct usb_ctrlrequest *rc_setup_packet;
u8 rc_buffer[6];
u8 audigy2nx_leds[3];
u8 xonar_u1_status;
};
#define MAX_CHANNELS 10 /* max logical channels */
struct usb_mixer_elem_info {
struct usb_mixer_interface *mixer;
struct usb_mixer_elem_info *next_id_elem; /* list of controls with same id */
struct snd_ctl_elem_id *elem_id;
unsigned int id;
unsigned int control; /* CS or ICN (high byte) */
unsigned int cmask; /* channel mask bitmap: 0 = master */
int channels;
int val_type;
int min, max, res;
int dBmin, dBmax;
int cached;
int cache_val[MAX_CHANNELS];
u8 initialized;
};
int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
int ignore_error);
void snd_usb_mixer_disconnect(struct list_head *p);
void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid);
int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
int request, int validx, int value_set);
#endif /* __USBMIXER_H */
...@@ -85,8 +85,8 @@ static struct usbmix_name_map extigy_map[] = { ...@@ -85,8 +85,8 @@ static struct usbmix_name_map extigy_map[] = {
/* 16: MU (w/o controls) */ /* 16: MU (w/o controls) */
{ 17, NULL, 1 }, /* DISABLED: PU-switch (any effect?) */ { 17, NULL, 1 }, /* DISABLED: PU-switch (any effect?) */
{ 17, "Channel Routing", 2 }, /* PU: mode select */ { 17, "Channel Routing", 2 }, /* PU: mode select */
{ 18, "Tone Control - Bass", USB_FEATURE_BASS }, /* FU */ { 18, "Tone Control - Bass", UAC_BASS_CONTROL }, /* FU */
{ 18, "Tone Control - Treble", USB_FEATURE_TREBLE }, /* FU */ { 18, "Tone Control - Treble", UAC_TREBLE_CONTROL }, /* FU */
{ 18, "Master Playback" }, /* FU; others */ { 18, "Master Playback" }, /* FU; others */
/* 19: OT speaker */ /* 19: OT speaker */
/* 20: OT headphone */ /* 20: OT headphone */
......
This diff is collapsed.
#ifndef SND_USB_MIXER_QUIRKS_H
#define SND_USB_MIXER_QUIRKS_H
int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer);
void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
unsigned char samplerate_id);
void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer,
int unitid);
#endif /* SND_USB_MIXER_QUIRKS_H */
This diff is collapsed.
#ifndef __USBAUDIO_PCM_H
#define __USBAUDIO_PCM_H
void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream);
int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
struct usb_host_interface *alts,
struct audioformat *fmt);
int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
struct usb_host_interface *alts,
struct audioformat *fmt, int rate);
#endif /* __USBAUDIO_PCM_H */
/*
* 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; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
#include <linux/init.h>
#include <linux/usb.h>
#include <sound/core.h>
#include <sound/info.h>
#include <sound/pcm.h>
#include "usbaudio.h"
#include "helper.h"
#include "card.h"
#include "proc.h"
/* convert our full speed USB rate into sampling rate in Hz */
static inline unsigned get_full_speed_hz(unsigned int usb_rate)
{
return (usb_rate * 125 + (1 << 12)) >> 13;
}
/* convert our high speed USB rate into sampling rate in Hz */
static inline unsigned get_high_speed_hz(unsigned int usb_rate)
{
return (usb_rate * 125 + (1 << 9)) >> 10;
}
/*
* common proc files to show the usb device info
*/
static void proc_audio_usbbus_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
{
struct snd_usb_audio *chip = entry->private_data;
if (!chip->shutdown)
snd_iprintf(buffer, "%03d/%03d\n", chip->dev->bus->busnum, chip->dev->devnum);
}
static void proc_audio_usbid_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
{
struct snd_usb_audio *chip = entry->private_data;
if (!chip->shutdown)
snd_iprintf(buffer, "%04x:%04x\n",
USB_ID_VENDOR(chip->usb_id),
USB_ID_PRODUCT(chip->usb_id));
}
void snd_usb_audio_create_proc(struct snd_usb_audio *chip)
{
struct snd_info_entry *entry;
if (!snd_card_proc_new(chip->card, "usbbus", &entry))
snd_info_set_text_ops(entry, chip, proc_audio_usbbus_read);
if (!snd_card_proc_new(chip->card, "usbid", &entry))
snd_info_set_text_ops(entry, chip, proc_audio_usbid_read);
}
/*
* proc interface for list the supported pcm formats
*/
static void proc_dump_substream_formats(struct snd_usb_substream *subs, struct snd_info_buffer *buffer)
{
struct list_head *p;
static char *sync_types[4] = {
"NONE", "ASYNC", "ADAPTIVE", "SYNC"
};
list_for_each(p, &subs->fmt_list) {
struct audioformat *fp;
snd_pcm_format_t fmt;
fp = list_entry(p, struct audioformat, list);
snd_iprintf(buffer, " Interface %d\n", fp->iface);
snd_iprintf(buffer, " Altset %d\n", fp->altsetting);
snd_iprintf(buffer, " Format:");
for (fmt = 0; fmt <= SNDRV_PCM_FORMAT_LAST; ++fmt)
if (fp->formats & (1uLL << fmt))
snd_iprintf(buffer, " %s",
snd_pcm_format_name(fmt));
snd_iprintf(buffer, "\n");
snd_iprintf(buffer, " Channels: %d\n", fp->channels);
snd_iprintf(buffer, " Endpoint: %d %s (%s)\n",
fp->endpoint & USB_ENDPOINT_NUMBER_MASK,
fp->endpoint & USB_DIR_IN ? "IN" : "OUT",
sync_types[(fp->ep_attr & USB_ENDPOINT_SYNCTYPE) >> 2]);
if (fp->rates & SNDRV_PCM_RATE_CONTINUOUS) {
snd_iprintf(buffer, " Rates: %d - %d (continuous)\n",
fp->rate_min, fp->rate_max);
} else {
unsigned int i;
snd_iprintf(buffer, " Rates: ");
for (i = 0; i < fp->nr_rates; i++) {
if (i > 0)
snd_iprintf(buffer, ", ");
snd_iprintf(buffer, "%d", fp->rate_table[i]);
}
snd_iprintf(buffer, "\n");
}
if (snd_usb_get_speed(subs->dev) == USB_SPEED_HIGH)
snd_iprintf(buffer, " Data packet interval: %d us\n",
125 * (1 << fp->datainterval));
// snd_iprintf(buffer, " Max Packet Size = %d\n", fp->maxpacksize);
// snd_iprintf(buffer, " EP Attribute = %#x\n", fp->attributes);
}
}
static void proc_dump_substream_status(struct snd_usb_substream *subs, struct snd_info_buffer *buffer)
{
if (subs->running) {
unsigned int i;
snd_iprintf(buffer, " Status: Running\n");
snd_iprintf(buffer, " Interface = %d\n", subs->interface);
snd_iprintf(buffer, " Altset = %d\n", subs->altset_idx);
snd_iprintf(buffer, " URBs = %d [ ", subs->nurbs);
for (i = 0; i < subs->nurbs; i++)
snd_iprintf(buffer, "%d ", subs->dataurb[i].packets);
snd_iprintf(buffer, "]\n");
snd_iprintf(buffer, " Packet Size = %d\n", subs->curpacksize);
snd_iprintf(buffer, " Momentary freq = %u Hz (%#x.%04x)\n",
snd_usb_get_speed(subs->dev) == USB_SPEED_FULL
? get_full_speed_hz(subs->freqm)
: get_high_speed_hz(subs->freqm),
subs->freqm >> 16, subs->freqm & 0xffff);
} else {
snd_iprintf(buffer, " Status: Stop\n");
}
}
static void proc_pcm_format_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer)
{
struct snd_usb_stream *stream = entry->private_data;
snd_iprintf(buffer, "%s : %s\n", stream->chip->card->longname, stream->pcm->name);
if (stream->substream[SNDRV_PCM_STREAM_PLAYBACK].num_formats) {
snd_iprintf(buffer, "\nPlayback:\n");
proc_dump_substream_status(&stream->substream[SNDRV_PCM_STREAM_PLAYBACK], buffer);
proc_dump_substream_formats(&stream->substream[SNDRV_PCM_STREAM_PLAYBACK], buffer);
}
if (stream->substream[SNDRV_PCM_STREAM_CAPTURE].num_formats) {
snd_iprintf(buffer, "\nCapture:\n");
proc_dump_substream_status(&stream->substream[SNDRV_PCM_STREAM_CAPTURE], buffer);
proc_dump_substream_formats(&stream->substream[SNDRV_PCM_STREAM_CAPTURE], buffer);
}
}
void snd_usb_proc_pcm_format_add(struct snd_usb_stream *stream)
{
struct snd_info_entry *entry;
char name[32];
struct snd_card *card = stream->chip->card;
sprintf(name, "stream%d", stream->pcm_index);
if (!snd_card_proc_new(card, name, &entry))
snd_info_set_text_ops(entry, stream, proc_pcm_format_read);
}
#ifndef __USBAUDIO_PROC_H
#define __USBAUDIO_PROC_H
void snd_usb_audio_create_proc(struct snd_usb_audio *chip);
void snd_usb_proc_pcm_format_add(struct snd_usb_stream *stream);
#endif /* __USBAUDIO_PROC_H */
This diff is collapsed.
#ifndef __USBAUDIO_QUIRKS_H
#define __USBAUDIO_QUIRKS_H
int snd_usb_create_quirk(struct snd_usb_audio *chip,
struct usb_interface *iface,
struct usb_driver *driver,
const struct snd_usb_audio_quirk *quirk);
int snd_usb_apply_interface_quirk(struct snd_usb_audio *chip,
int iface,
int altno);
int snd_usb_apply_boot_quirk(struct usb_device *dev,
struct usb_interface *intf,
const struct snd_usb_audio_quirk *quirk);
void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
struct audioformat *fmt);
int snd_usb_is_big_endian_format(struct snd_usb_audio *chip,
struct audioformat *fp);
#endif /* __USBAUDIO_QUIRKS_H */
This diff is collapsed.
#ifndef __USBAUDIO_URB_H
#define __USBAUDIO_URB_H
void snd_usb_init_substream(struct snd_usb_stream *as,
int stream,
struct audioformat *fp);
int snd_usb_init_substream_urbs(struct snd_usb_substream *subs,
unsigned int period_bytes,
unsigned int rate,
unsigned int frame_bits);
void snd_usb_release_substream_urbs(struct snd_usb_substream *subs, int force);
int snd_usb_substream_prepare(struct snd_usb_substream *subs,
struct snd_pcm_runtime *runtime);
int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, int cmd);
int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream, int cmd);
#endif /* __USBAUDIO_URB_H */
This diff is collapsed.
This diff is collapsed.
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#define MODNAME "US122L" #define MODNAME "US122L"
#include "usb_stream.c" #include "usb_stream.c"
#include "../usbaudio.h" #include "../usbaudio.h"
#include "../midi.h"
#include "us122l.h" #include "us122l.h"
MODULE_AUTHOR("Karsten Wiese <fzu@wemgehoertderstaat.de>"); MODULE_AUTHOR("Karsten Wiese <fzu@wemgehoertderstaat.de>");
......
#ifndef USBUSX2Y_H #ifndef USBUSX2Y_H
#define USBUSX2Y_H #define USBUSX2Y_H
#include "../usbaudio.h" #include "../usbaudio.h"
#include "../midi.h"
#include "usbus428ctldefs.h" #include "usbus428ctldefs.h"
#define NRURBS 2 #define NRURBS 2
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment