Merge branch 'full-roland-support' of git://git.alsa-project.org/alsa-kprivate into for-next
For adding support for many Roland and Yamaha devices: * 'full-roland-support' of git://git.alsa-project.org/alsa-kprivate: ALSA: usb-audio: add quirks for Roland QUAD/OCTO-CAPTURE ALSA: usb-audio: claim autodetected PCM interfaces all at once ALSA: usb-audio: remove superfluous Roland quirks ALSA: usb-audio: add MIDI port names for some Roland devices ALSA: usb-audio: add support for many Roland/Yamaha devices ALSA: usb-audio: detect implicit feedback on Roland devices ALSA: usb-audio: store protocol version in struct audioformat
This commit is contained in:
commit
ea70ee057c
@ -21,6 +21,7 @@ struct audioformat {
|
||||
unsigned char endpoint; /* endpoint */
|
||||
unsigned char ep_attr; /* endpoint attributes */
|
||||
unsigned char datainterval; /* log_2 of data packet interval */
|
||||
unsigned char protocol; /* UAC_VERSION_1/2 */
|
||||
unsigned int maxpacksize; /* max. packet size */
|
||||
unsigned int rates; /* rate bitmasks */
|
||||
unsigned int rate_min, rate_max; /* min/max rates */
|
||||
|
@ -407,9 +407,7 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface,
|
||||
struct usb_host_interface *alts,
|
||||
struct audioformat *fmt, int rate)
|
||||
{
|
||||
struct usb_interface_descriptor *altsd = get_iface_desc(alts);
|
||||
|
||||
switch (altsd->bInterfaceProtocol) {
|
||||
switch (fmt->protocol) {
|
||||
case UAC_VERSION_1:
|
||||
default:
|
||||
return set_sample_rate_v1(chip, iface, alts, fmt, rate);
|
||||
|
@ -43,13 +43,12 @@
|
||||
*/
|
||||
static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
|
||||
struct audioformat *fp,
|
||||
unsigned int format, void *_fmt,
|
||||
int protocol)
|
||||
unsigned int format, void *_fmt)
|
||||
{
|
||||
int sample_width, sample_bytes;
|
||||
u64 pcm_formats = 0;
|
||||
|
||||
switch (protocol) {
|
||||
switch (fp->protocol) {
|
||||
case UAC_VERSION_1:
|
||||
default: {
|
||||
struct uac_format_type_i_discrete_descriptor *fmt = _fmt;
|
||||
@ -360,11 +359,8 @@ err:
|
||||
*/
|
||||
static int parse_audio_format_i(struct snd_usb_audio *chip,
|
||||
struct audioformat *fp, unsigned int format,
|
||||
struct uac_format_type_i_continuous_descriptor *fmt,
|
||||
struct usb_host_interface *iface)
|
||||
struct uac_format_type_i_continuous_descriptor *fmt)
|
||||
{
|
||||
struct usb_interface_descriptor *altsd = get_iface_desc(iface);
|
||||
int protocol = altsd->bInterfaceProtocol;
|
||||
snd_pcm_format_t pcm_format;
|
||||
int ret;
|
||||
|
||||
@ -387,8 +383,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
|
||||
}
|
||||
fp->formats = pcm_format_to_bits(pcm_format);
|
||||
} else {
|
||||
fp->formats = parse_audio_format_i_type(chip, fp, format,
|
||||
fmt, protocol);
|
||||
fp->formats = parse_audio_format_i_type(chip, fp, format, fmt);
|
||||
if (!fp->formats)
|
||||
return -EINVAL;
|
||||
}
|
||||
@ -398,11 +393,8 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
|
||||
* proprietary class specific descriptor.
|
||||
* audio class v2 uses class specific EP0 range requests for that.
|
||||
*/
|
||||
switch (protocol) {
|
||||
switch (fp->protocol) {
|
||||
default:
|
||||
snd_printdd(KERN_WARNING "%d:%u:%d : invalid protocol version %d, assuming v1\n",
|
||||
chip->dev->devnum, fp->iface, fp->altsetting, protocol);
|
||||
/* fall through */
|
||||
case UAC_VERSION_1:
|
||||
fp->channels = fmt->bNrChannels;
|
||||
ret = parse_audio_format_rates_v1(chip, fp, (unsigned char *) fmt, 7);
|
||||
@ -427,12 +419,9 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
|
||||
*/
|
||||
static int parse_audio_format_ii(struct snd_usb_audio *chip,
|
||||
struct audioformat *fp,
|
||||
int format, void *_fmt,
|
||||
struct usb_host_interface *iface)
|
||||
int format, void *_fmt)
|
||||
{
|
||||
int brate, framesize, ret;
|
||||
struct usb_interface_descriptor *altsd = get_iface_desc(iface);
|
||||
int protocol = altsd->bInterfaceProtocol;
|
||||
|
||||
switch (format) {
|
||||
case UAC_FORMAT_TYPE_II_AC3:
|
||||
@ -452,11 +441,8 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
|
||||
|
||||
fp->channels = 1;
|
||||
|
||||
switch (protocol) {
|
||||
switch (fp->protocol) {
|
||||
default:
|
||||
snd_printdd(KERN_WARNING "%d:%u:%d : invalid protocol version %d, assuming v1\n",
|
||||
chip->dev->devnum, fp->iface, fp->altsetting, protocol);
|
||||
/* fall through */
|
||||
case UAC_VERSION_1: {
|
||||
struct uac_format_type_ii_discrete_descriptor *fmt = _fmt;
|
||||
brate = le16_to_cpu(fmt->wMaxBitRate);
|
||||
@ -483,17 +469,17 @@ static int parse_audio_format_ii(struct snd_usb_audio *chip,
|
||||
int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
|
||||
struct audioformat *fp, unsigned int format,
|
||||
struct uac_format_type_i_continuous_descriptor *fmt,
|
||||
int stream, struct usb_host_interface *iface)
|
||||
int stream)
|
||||
{
|
||||
int err;
|
||||
|
||||
switch (fmt->bFormatType) {
|
||||
case UAC_FORMAT_TYPE_I:
|
||||
case UAC_FORMAT_TYPE_III:
|
||||
err = parse_audio_format_i(chip, fp, format, fmt, iface);
|
||||
err = parse_audio_format_i(chip, fp, format, fmt);
|
||||
break;
|
||||
case UAC_FORMAT_TYPE_II:
|
||||
err = parse_audio_format_ii(chip, fp, format, fmt, iface);
|
||||
err = parse_audio_format_ii(chip, fp, format, fmt);
|
||||
break;
|
||||
default:
|
||||
snd_printd(KERN_INFO "%d:%u:%d : format type %d is not supported yet\n",
|
||||
|
@ -4,6 +4,6 @@
|
||||
int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
|
||||
struct audioformat *fp, unsigned int format,
|
||||
struct uac_format_type_i_continuous_descriptor *fmt,
|
||||
int stream, struct usb_host_interface *iface);
|
||||
int stream);
|
||||
|
||||
#endif /* __USBAUDIO_FORMAT_H */
|
||||
|
@ -1575,8 +1575,41 @@ static struct port_info {
|
||||
EXTERNAL_PORT(0x0582, 0x004d, 0, "%s MIDI"),
|
||||
EXTERNAL_PORT(0x0582, 0x004d, 1, "%s 1"),
|
||||
EXTERNAL_PORT(0x0582, 0x004d, 2, "%s 2"),
|
||||
/* BOSS GT-PRO */
|
||||
CONTROL_PORT(0x0582, 0x0089, 0, "%s Control"),
|
||||
/* Edirol UM-3EX */
|
||||
CONTROL_PORT(0x0582, 0x009a, 3, "%s Control"),
|
||||
/* Roland VG-99 */
|
||||
CONTROL_PORT(0x0582, 0x00b2, 0, "%s Control"),
|
||||
EXTERNAL_PORT(0x0582, 0x00b2, 1, "%s MIDI"),
|
||||
/* Cakewalk Sonar V-Studio 100 */
|
||||
EXTERNAL_PORT(0x0582, 0x00eb, 0, "%s MIDI"),
|
||||
CONTROL_PORT(0x0582, 0x00eb, 1, "%s Control"),
|
||||
/* Roland VB-99 */
|
||||
CONTROL_PORT(0x0582, 0x0102, 0, "%s Control"),
|
||||
EXTERNAL_PORT(0x0582, 0x0102, 1, "%s MIDI"),
|
||||
/* Roland A-PRO */
|
||||
EXTERNAL_PORT(0x0582, 0x010f, 0, "%s MIDI"),
|
||||
CONTROL_PORT(0x0582, 0x010f, 1, "%s 1"),
|
||||
CONTROL_PORT(0x0582, 0x010f, 2, "%s 2"),
|
||||
/* Roland SD-50 */
|
||||
ROLAND_SYNTH_PORT(0x0582, 0x0114, 0, "%s Synth", 128),
|
||||
EXTERNAL_PORT(0x0582, 0x0114, 1, "%s MIDI"),
|
||||
CONTROL_PORT(0x0582, 0x0114, 2, "%s Control"),
|
||||
/* Roland OCTA-CAPTURE */
|
||||
EXTERNAL_PORT(0x0582, 0x0120, 0, "%s MIDI"),
|
||||
CONTROL_PORT(0x0582, 0x0120, 1, "%s Control"),
|
||||
EXTERNAL_PORT(0x0582, 0x0121, 0, "%s MIDI"),
|
||||
CONTROL_PORT(0x0582, 0x0121, 1, "%s Control"),
|
||||
/* Roland SPD-SX */
|
||||
CONTROL_PORT(0x0582, 0x0145, 0, "%s Control"),
|
||||
EXTERNAL_PORT(0x0582, 0x0145, 1, "%s MIDI"),
|
||||
/* Roland A-Series */
|
||||
CONTROL_PORT(0x0582, 0x0156, 0, "%s Keyboard"),
|
||||
EXTERNAL_PORT(0x0582, 0x0156, 1, "%s MIDI"),
|
||||
/* Roland INTEGRA-7 */
|
||||
ROLAND_SYNTH_PORT(0x0582, 0x015b, 0, "%s Synth", 128),
|
||||
CONTROL_PORT(0x0582, 0x015b, 1, "%s Control"),
|
||||
/* M-Audio MidiSport 8x8 */
|
||||
CONTROL_PORT(0x0763, 0x1031, 8, "%s Control"),
|
||||
CONTROL_PORT(0x0763, 0x1033, 8, "%s Control"),
|
||||
@ -1947,6 +1980,44 @@ static int snd_usbmidi_detect_yamaha(struct snd_usb_midi* umidi,
|
||||
return snd_usbmidi_detect_endpoints(umidi, endpoint, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Detects the endpoints and ports of Roland devices.
|
||||
*/
|
||||
static int snd_usbmidi_detect_roland(struct snd_usb_midi* umidi,
|
||||
struct snd_usb_midi_endpoint_info* endpoint)
|
||||
{
|
||||
struct usb_interface* intf;
|
||||
struct usb_host_interface *hostif;
|
||||
u8* cs_desc;
|
||||
|
||||
intf = umidi->iface;
|
||||
if (!intf)
|
||||
return -ENOENT;
|
||||
hostif = intf->altsetting;
|
||||
/*
|
||||
* Some devices have a descriptor <06 24 F1 02 <inputs> <outputs>>,
|
||||
* some have standard class descriptors, or both kinds, or neither.
|
||||
*/
|
||||
for (cs_desc = hostif->extra;
|
||||
cs_desc < hostif->extra + hostif->extralen && cs_desc[0] >= 2;
|
||||
cs_desc += cs_desc[0]) {
|
||||
if (cs_desc[0] >= 6 &&
|
||||
cs_desc[1] == USB_DT_CS_INTERFACE &&
|
||||
cs_desc[2] == 0xf1 &&
|
||||
cs_desc[3] == 0x02) {
|
||||
endpoint->in_cables = (1 << cs_desc[4]) - 1;
|
||||
endpoint->out_cables = (1 << cs_desc[5]) - 1;
|
||||
return snd_usbmidi_detect_endpoints(umidi, endpoint, 1);
|
||||
} else if (cs_desc[0] >= 7 &&
|
||||
cs_desc[1] == USB_DT_CS_INTERFACE &&
|
||||
cs_desc[2] == UAC_HEADER) {
|
||||
return snd_usbmidi_get_ms_info(umidi, endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
/*
|
||||
* Creates the endpoints and their ports for Midiman devices.
|
||||
*/
|
||||
@ -2162,6 +2233,9 @@ int snd_usbmidi_create(struct snd_card *card,
|
||||
case QUIRK_MIDI_YAMAHA:
|
||||
err = snd_usbmidi_detect_yamaha(umidi, &endpoints[0]);
|
||||
break;
|
||||
case QUIRK_MIDI_ROLAND:
|
||||
err = snd_usbmidi_detect_roland(umidi, &endpoints[0]);
|
||||
break;
|
||||
case QUIRK_MIDI_MIDIMAN:
|
||||
umidi->usb_protocol_ops = &snd_usbmidi_midiman_ops;
|
||||
memcpy(&endpoints[0], quirk->data,
|
||||
|
@ -202,13 +202,11 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
|
||||
struct usb_host_interface *alts,
|
||||
struct audioformat *fmt)
|
||||
{
|
||||
struct usb_interface_descriptor *altsd = get_iface_desc(alts);
|
||||
|
||||
/* if endpoint doesn't have pitch control, bail out */
|
||||
if (!(fmt->attributes & UAC_EP_CS_ATTR_PITCH_CONTROL))
|
||||
return 0;
|
||||
|
||||
switch (altsd->bInterfaceProtocol) {
|
||||
switch (fmt->protocol) {
|
||||
case UAC_VERSION_1:
|
||||
default:
|
||||
return init_pitch_v1(chip, iface, alts, fmt);
|
||||
@ -300,6 +298,35 @@ static int deactivate_endpoints(struct snd_usb_substream *subs)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int search_roland_implicit_fb(struct usb_device *dev, int ifnum,
|
||||
unsigned int altsetting,
|
||||
struct usb_host_interface **alts,
|
||||
unsigned int *ep)
|
||||
{
|
||||
struct usb_interface *iface;
|
||||
struct usb_interface_descriptor *altsd;
|
||||
struct usb_endpoint_descriptor *epd;
|
||||
|
||||
iface = usb_ifnum_to_if(dev, ifnum);
|
||||
if (!iface || iface->num_altsetting < altsetting + 1)
|
||||
return -ENOENT;
|
||||
*alts = &iface->altsetting[altsetting];
|
||||
altsd = get_iface_desc(*alts);
|
||||
if (altsd->bAlternateSetting != altsetting ||
|
||||
altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC ||
|
||||
(altsd->bInterfaceSubClass != 2 &&
|
||||
altsd->bInterfaceProtocol != 2 ) ||
|
||||
altsd->bNumEndpoints < 1)
|
||||
return -ENOENT;
|
||||
epd = get_endpoint(*alts, 0);
|
||||
if (!usb_endpoint_is_isoc_in(epd) ||
|
||||
(epd->bmAttributes & USB_ENDPOINT_USAGE_MASK) !=
|
||||
USB_ENDPOINT_USAGE_IMPLICIT_FB)
|
||||
return -ENOENT;
|
||||
*ep = epd->bEndpointAddress;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* find a matching format and set up the interface
|
||||
*/
|
||||
@ -395,6 +422,18 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
|
||||
goto add_sync_ep;
|
||||
}
|
||||
}
|
||||
if (is_playback &&
|
||||
attr == USB_ENDPOINT_SYNC_ASYNC &&
|
||||
altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
|
||||
altsd->bInterfaceProtocol == 2 &&
|
||||
altsd->bNumEndpoints == 1 &&
|
||||
USB_ID_VENDOR(subs->stream->chip->usb_id) == 0x0582 /* Roland */ &&
|
||||
search_roland_implicit_fb(dev, altsd->bInterfaceNumber + 1,
|
||||
altsd->bAlternateSetting,
|
||||
&alts, &ep) >= 0) {
|
||||
implicit_fb = 1;
|
||||
goto add_sync_ep;
|
||||
}
|
||||
|
||||
if (((is_playback && attr == USB_ENDPOINT_SYNC_ASYNC) ||
|
||||
(!is_playback && attr == USB_ENDPOINT_SYNC_ADAPTIVE)) &&
|
||||
|
@ -461,6 +461,17 @@ YAMAHA_DEVICE(0x7000, "DTX"),
|
||||
YAMAHA_DEVICE(0x7010, "UB99"),
|
||||
#undef YAMAHA_DEVICE
|
||||
#undef YAMAHA_INTERFACE
|
||||
/* this catches most recent vendor-specific Yamaha devices */
|
||||
{
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_CLASS,
|
||||
.idVendor = 0x0499,
|
||||
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
|
||||
.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_AUTODETECT
|
||||
}
|
||||
},
|
||||
|
||||
/*
|
||||
* Roland/RolandED/Edirol/BOSS devices
|
||||
@ -1136,7 +1147,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
||||
}
|
||||
}
|
||||
},
|
||||
/* TODO: add Roland M-1000 support */
|
||||
{
|
||||
/*
|
||||
* Has ID 0x0038 when not in "Advanced Driver" mode;
|
||||
@ -1251,7 +1261,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
||||
}
|
||||
}
|
||||
},
|
||||
/* TODO: add Edirol M-100FX support */
|
||||
{
|
||||
/* has ID 0x004e when not in "Advanced Driver" mode */
|
||||
USB_DEVICE(0x0582, 0x004c),
|
||||
@ -1370,20 +1379,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
/* has ID 0x006b when not in "Advanced Driver" mode */
|
||||
USB_DEVICE_VENDOR_SPEC(0x0582, 0x006a),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
.vendor_name = "Roland",
|
||||
.product_name = "SP-606",
|
||||
.ifnum = 3,
|
||||
.type = QUIRK_MIDI_FIXED_ENDPOINT,
|
||||
.data = & (const struct snd_usb_midi_endpoint_info) {
|
||||
.out_cables = 0x0001,
|
||||
.in_cables = 0x0001
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
/* has ID 0x006e when not in "Advanced Driver" mode */
|
||||
USB_DEVICE(0x0582, 0x006d),
|
||||
@ -1471,8 +1466,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
||||
}
|
||||
}
|
||||
},
|
||||
/* TODO: add Roland V-SYNTH XT support */
|
||||
/* TODO: add BOSS GT-PRO support */
|
||||
{
|
||||
/* has ID 0x008c when not in "Advanced Driver" mode */
|
||||
USB_DEVICE(0x0582, 0x008b),
|
||||
@ -1486,42 +1479,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
||||
.in_cables = 0x0001
|
||||
}
|
||||
}
|
||||
},
|
||||
/* TODO: add Edirol PC-80 support */
|
||||
{
|
||||
USB_DEVICE(0x0582, 0x0096),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
.vendor_name = "EDIROL",
|
||||
.product_name = "UA-1EX",
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_COMPOSITE,
|
||||
.data = (const struct snd_usb_audio_quirk[]) {
|
||||
{
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 1,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
USB_DEVICE(0x0582, 0x009a),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
.vendor_name = "EDIROL",
|
||||
.product_name = "UM-3EX",
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_MIDI_FIXED_ENDPOINT,
|
||||
.data = & (const struct snd_usb_midi_endpoint_info) {
|
||||
.out_cables = 0x000f,
|
||||
.in_cables = 0x000f
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
/*
|
||||
@ -1552,125 +1509,9 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
/* TODO: add Edirol MD-P1 support */
|
||||
{
|
||||
USB_DEVICE(0x582, 0x00a6),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
.vendor_name = "Roland",
|
||||
.product_name = "Juno-G",
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_MIDI_FIXED_ENDPOINT,
|
||||
.data = & (const struct snd_usb_midi_endpoint_info) {
|
||||
.out_cables = 0x0001,
|
||||
.in_cables = 0x0001
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
/* Roland SH-201 */
|
||||
USB_DEVICE(0x0582, 0x00ad),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
.vendor_name = "Roland",
|
||||
.product_name = "SH-201",
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_COMPOSITE,
|
||||
.data = (const struct snd_usb_audio_quirk[]) {
|
||||
{
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 1,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 2,
|
||||
.type = QUIRK_MIDI_FIXED_ENDPOINT,
|
||||
.data = & (const struct snd_usb_midi_endpoint_info) {
|
||||
.out_cables = 0x0001,
|
||||
.in_cables = 0x0001
|
||||
}
|
||||
},
|
||||
{
|
||||
.ifnum = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
/* Advanced mode of the Roland VG-99, with MIDI and 24-bit PCM at 44.1
|
||||
* kHz. In standard mode, the device has ID 0582:00b3, and offers
|
||||
* 16-bit PCM at 44.1 kHz with no MIDI.
|
||||
*/
|
||||
USB_DEVICE(0x0582, 0x00b2),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
.vendor_name = "Roland",
|
||||
.product_name = "VG-99",
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_COMPOSITE,
|
||||
.data = (const struct snd_usb_audio_quirk[]) {
|
||||
{
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 1,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 2,
|
||||
.type = QUIRK_MIDI_FIXED_ENDPOINT,
|
||||
.data = & (const struct snd_usb_midi_endpoint_info) {
|
||||
.out_cables = 0x0003,
|
||||
.in_cables = 0x0003
|
||||
}
|
||||
},
|
||||
{
|
||||
.ifnum = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
/* Roland SonicCell */
|
||||
USB_DEVICE(0x0582, 0x00c2),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
.vendor_name = "Roland",
|
||||
.product_name = "SonicCell",
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_COMPOSITE,
|
||||
.data = (const struct snd_usb_audio_quirk[]) {
|
||||
{
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 1,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 2,
|
||||
.type = QUIRK_MIDI_FIXED_ENDPOINT,
|
||||
.data = & (const struct snd_usb_midi_endpoint_info) {
|
||||
.out_cables = 0x0001,
|
||||
.in_cables = 0x0001
|
||||
}
|
||||
},
|
||||
{
|
||||
.ifnum = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
/* Edirol M-16DX */
|
||||
/* FIXME: This quirk gives a good-working capture stream but the
|
||||
* playback seems problematic because of lacking of sync
|
||||
* with capture stream. It needs to sync with the capture
|
||||
* clock. As now, you'll get frequent sound distortions
|
||||
* via the playback.
|
||||
*/
|
||||
USB_DEVICE(0x0582, 0x00c4),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
@ -1698,35 +1539,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
/* BOSS GT-10 */
|
||||
USB_DEVICE(0x0582, 0x00da),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_COMPOSITE,
|
||||
.data = (const struct snd_usb_audio_quirk[]) {
|
||||
{
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 1,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 2,
|
||||
.type = QUIRK_MIDI_FIXED_ENDPOINT,
|
||||
.data = & (const struct snd_usb_midi_endpoint_info) {
|
||||
.out_cables = 0x0001,
|
||||
.in_cables = 0x0001
|
||||
}
|
||||
},
|
||||
{
|
||||
.ifnum = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
/* Advanced modes of the Edirol UA-25EX.
|
||||
* For the standard mode, UA-25EX has ID 0582:00e7, which
|
||||
@ -1757,42 +1569,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
/* has ID 0x00ea when not in Advanced Driver mode */
|
||||
USB_DEVICE_VENDOR_SPEC(0x0582, 0x00e9),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
/* .vendor_name = "Roland", */
|
||||
/* .product_name = "UA-1G", */
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_COMPOSITE,
|
||||
.data = (const struct snd_usb_audio_quirk[]) {
|
||||
{
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 1,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
USB_DEVICE_VENDOR_SPEC(0x0582, 0x0104),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
/* .vendor_name = "Roland", */
|
||||
/* .product_name = "UM-1G", */
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_MIDI_FIXED_ENDPOINT,
|
||||
.data = & (const struct snd_usb_midi_endpoint_info) {
|
||||
.out_cables = 0x0001,
|
||||
.in_cables = 0x0001
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
/* Edirol UM-3G */
|
||||
USB_DEVICE_VENDOR_SPEC(0x0582, 0x0108),
|
||||
@ -1806,92 +1582,49 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
||||
}
|
||||
},
|
||||
{
|
||||
/* Boss JS-8 Jam Station */
|
||||
USB_DEVICE(0x0582, 0x0109),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
/* .vendor_name = "BOSS", */
|
||||
/* .product_name = "JS-8", */
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_COMPOSITE,
|
||||
.data = (const struct snd_usb_audio_quirk[]) {
|
||||
{
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 1,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 2,
|
||||
.type = QUIRK_MIDI_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
/* has ID 0x0110 when not in Advanced Driver mode */
|
||||
USB_DEVICE_VENDOR_SPEC(0x0582, 0x010f),
|
||||
/* only 44.1 kHz works at the moment */
|
||||
USB_DEVICE(0x0582, 0x0120),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
/* .vendor_name = "Roland", */
|
||||
/* .product_name = "A-PRO", */
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_MIDI_FIXED_ENDPOINT,
|
||||
.data = & (const struct snd_usb_midi_endpoint_info) {
|
||||
.out_cables = 0x0003,
|
||||
.in_cables = 0x0007
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
/* Roland GAIA SH-01 */
|
||||
USB_DEVICE(0x0582, 0x0111),
|
||||
.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
|
||||
.vendor_name = "Roland",
|
||||
.product_name = "GAIA",
|
||||
/* .product_name = "OCTO-CAPTURE", */
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_COMPOSITE,
|
||||
.data = (const struct snd_usb_audio_quirk[]) {
|
||||
{
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 1,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 2,
|
||||
.type = QUIRK_MIDI_FIXED_ENDPOINT,
|
||||
.data = &(const struct snd_usb_midi_endpoint_info) {
|
||||
.out_cables = 0x0003,
|
||||
.in_cables = 0x0003
|
||||
.type = QUIRK_AUDIO_FIXED_ENDPOINT,
|
||||
.data = & (const struct audioformat) {
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.channels = 10,
|
||||
.iface = 0,
|
||||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.endpoint = 0x05,
|
||||
.ep_attr = 0x05,
|
||||
.rates = SNDRV_PCM_RATE_44100,
|
||||
.rate_min = 44100,
|
||||
.rate_max = 44100,
|
||||
.nr_rates = 1,
|
||||
.rate_table = (unsigned int[]) { 44100 }
|
||||
}
|
||||
},
|
||||
{
|
||||
.ifnum = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
USB_DEVICE(0x0582, 0x0113),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
/* .vendor_name = "BOSS", */
|
||||
/* .product_name = "ME-25", */
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_COMPOSITE,
|
||||
.data = (const struct snd_usb_audio_quirk[]) {
|
||||
{
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 1,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
.type = QUIRK_AUDIO_FIXED_ENDPOINT,
|
||||
.data = & (const struct audioformat) {
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.channels = 12,
|
||||
.iface = 1,
|
||||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.endpoint = 0x85,
|
||||
.ep_attr = 0x25,
|
||||
.rates = SNDRV_PCM_RATE_44100,
|
||||
.rate_min = 44100,
|
||||
.rate_max = 44100,
|
||||
.nr_rates = 1,
|
||||
.rate_table = (unsigned int[]) { 44100 }
|
||||
}
|
||||
},
|
||||
{
|
||||
.ifnum = 2,
|
||||
@ -1902,108 +1635,12 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
||||
}
|
||||
},
|
||||
{
|
||||
.ifnum = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
USB_DEVICE(0x0582, 0x0127),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
/* .vendor_name = "Roland", */
|
||||
/* .product_name = "GR-55", */
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_COMPOSITE,
|
||||
.data = (const struct snd_usb_audio_quirk[]) {
|
||||
{
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 1,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 2,
|
||||
.type = QUIRK_MIDI_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
/* Added support for Roland UM-ONE which differs from UM-1 */
|
||||
USB_DEVICE(0x0582, 0x012a),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
/* .vendor_name = "ROLAND", */
|
||||
/* .product_name = "UM-ONE", */
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_MIDI_FIXED_ENDPOINT,
|
||||
.data = & (const struct snd_usb_midi_endpoint_info) {
|
||||
.out_cables = 0x0001,
|
||||
.in_cables = 0x0003
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
USB_DEVICE(0x0582, 0x011e),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
/* .vendor_name = "BOSS", */
|
||||
/* .product_name = "BR-800", */
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_COMPOSITE,
|
||||
.data = (const struct snd_usb_audio_quirk[]) {
|
||||
{
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 1,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 2,
|
||||
.type = QUIRK_MIDI_FIXED_ENDPOINT,
|
||||
.data = & (const struct snd_usb_midi_endpoint_info) {
|
||||
.out_cables = 0x0001,
|
||||
.in_cables = 0x0001
|
||||
}
|
||||
},
|
||||
{
|
||||
.ifnum = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
USB_DEVICE(0x0582, 0x0130),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
/* .vendor_name = "BOSS", */
|
||||
/* .product_name = "MICRO BR-80", */
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_COMPOSITE,
|
||||
.data = (const struct snd_usb_audio_quirk[]) {
|
||||
{
|
||||
.ifnum = 0,
|
||||
.ifnum = 3,
|
||||
.type = QUIRK_IGNORE_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 1,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 2,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 3,
|
||||
.type = QUIRK_MIDI_FIXED_ENDPOINT,
|
||||
.data = & (const struct snd_usb_midi_endpoint_info) {
|
||||
.out_cables = 0x0001,
|
||||
.in_cables = 0x0001
|
||||
}
|
||||
.ifnum = 4,
|
||||
.type = QUIRK_IGNORE_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = -1
|
||||
@ -2012,35 +1649,83 @@ YAMAHA_DEVICE(0x7010, "UB99"),
|
||||
}
|
||||
},
|
||||
{
|
||||
USB_DEVICE(0x0582, 0x014d),
|
||||
/* only 44.1 kHz works at the moment */
|
||||
USB_DEVICE(0x0582, 0x012f),
|
||||
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
|
||||
/* .vendor_name = "BOSS", */
|
||||
/* .product_name = "GT-100", */
|
||||
/* .vendor_name = "Roland", */
|
||||
/* .product_name = "QUAD-CAPTURE", */
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_COMPOSITE,
|
||||
.data = (const struct snd_usb_audio_quirk[]) {
|
||||
{
|
||||
.ifnum = 0,
|
||||
.type = QUIRK_AUDIO_FIXED_ENDPOINT,
|
||||
.data = & (const struct audioformat) {
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.channels = 4,
|
||||
.iface = 0,
|
||||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.endpoint = 0x05,
|
||||
.ep_attr = 0x05,
|
||||
.rates = SNDRV_PCM_RATE_44100,
|
||||
.rate_min = 44100,
|
||||
.rate_max = 44100,
|
||||
.nr_rates = 1,
|
||||
.rate_table = (unsigned int[]) { 44100 }
|
||||
}
|
||||
},
|
||||
{
|
||||
.ifnum = 1,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
.type = QUIRK_AUDIO_FIXED_ENDPOINT,
|
||||
.data = & (const struct audioformat) {
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
.channels = 6,
|
||||
.iface = 1,
|
||||
.altsetting = 1,
|
||||
.altset_idx = 1,
|
||||
.endpoint = 0x85,
|
||||
.ep_attr = 0x25,
|
||||
.rates = SNDRV_PCM_RATE_44100,
|
||||
.rate_min = 44100,
|
||||
.rate_max = 44100,
|
||||
.nr_rates = 1,
|
||||
.rate_table = (unsigned int[]) { 44100 }
|
||||
}
|
||||
},
|
||||
{
|
||||
.ifnum = 2,
|
||||
.type = QUIRK_AUDIO_STANDARD_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 3,
|
||||
.type = QUIRK_MIDI_FIXED_ENDPOINT,
|
||||
.data = & (const struct snd_usb_midi_endpoint_info) {
|
||||
.out_cables = 0x0001,
|
||||
.in_cables = 0x0001
|
||||
}
|
||||
},
|
||||
{
|
||||
.ifnum = 3,
|
||||
.type = QUIRK_IGNORE_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = 4,
|
||||
.type = QUIRK_IGNORE_INTERFACE
|
||||
},
|
||||
{
|
||||
.ifnum = -1
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
/* this catches most recent vendor-specific Roland devices */
|
||||
{
|
||||
.match_flags = USB_DEVICE_ID_MATCH_VENDOR |
|
||||
USB_DEVICE_ID_MATCH_INT_CLASS,
|
||||
.idVendor = 0x0582,
|
||||
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
|
||||
.driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
|
||||
.ifnum = QUIRK_ANY_INTERFACE,
|
||||
.type = QUIRK_AUTODETECT
|
||||
}
|
||||
},
|
||||
|
||||
/* Guillemot devices */
|
||||
{
|
||||
|
@ -18,6 +18,7 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/usb/audio.h>
|
||||
#include <linux/usb/midi.h>
|
||||
|
||||
#include <sound/control.h>
|
||||
#include <sound/core.h>
|
||||
@ -175,6 +176,212 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int create_auto_pcm_quirk(struct snd_usb_audio *chip,
|
||||
struct usb_interface *iface,
|
||||
struct usb_driver *driver)
|
||||
{
|
||||
struct usb_host_interface *alts;
|
||||
struct usb_interface_descriptor *altsd;
|
||||
struct usb_endpoint_descriptor *epd;
|
||||
struct uac1_as_header_descriptor *ashd;
|
||||
struct uac_format_type_i_discrete_descriptor *fmtd;
|
||||
|
||||
/*
|
||||
* Most Roland/Yamaha audio streaming interfaces have more or less
|
||||
* standard descriptors, but older devices might lack descriptors, and
|
||||
* future ones might change, so ensure that we fail silently if the
|
||||
* interface doesn't look exactly right.
|
||||
*/
|
||||
|
||||
/* must have a non-zero altsetting for streaming */
|
||||
if (iface->num_altsetting < 2)
|
||||
return -ENODEV;
|
||||
alts = &iface->altsetting[1];
|
||||
altsd = get_iface_desc(alts);
|
||||
|
||||
/* must have an isochronous endpoint for streaming */
|
||||
if (altsd->bNumEndpoints < 1)
|
||||
return -ENODEV;
|
||||
epd = get_endpoint(alts, 0);
|
||||
if (!usb_endpoint_xfer_isoc(epd))
|
||||
return -ENODEV;
|
||||
|
||||
/* must have format descriptors */
|
||||
ashd = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL,
|
||||
UAC_AS_GENERAL);
|
||||
fmtd = snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL,
|
||||
UAC_FORMAT_TYPE);
|
||||
if (!ashd || ashd->bLength < 7 ||
|
||||
!fmtd || fmtd->bLength < 8)
|
||||
return -ENODEV;
|
||||
|
||||
return create_standard_audio_quirk(chip, iface, driver, NULL);
|
||||
}
|
||||
|
||||
static int create_yamaha_midi_quirk(struct snd_usb_audio *chip,
|
||||
struct usb_interface *iface,
|
||||
struct usb_driver *driver,
|
||||
struct usb_host_interface *alts)
|
||||
{
|
||||
static const struct snd_usb_audio_quirk yamaha_midi_quirk = {
|
||||
.type = QUIRK_MIDI_YAMAHA
|
||||
};
|
||||
struct usb_midi_in_jack_descriptor *injd;
|
||||
struct usb_midi_out_jack_descriptor *outjd;
|
||||
|
||||
/* must have some valid jack descriptors */
|
||||
injd = snd_usb_find_csint_desc(alts->extra, alts->extralen,
|
||||
NULL, USB_MS_MIDI_IN_JACK);
|
||||
outjd = snd_usb_find_csint_desc(alts->extra, alts->extralen,
|
||||
NULL, USB_MS_MIDI_OUT_JACK);
|
||||
if (!injd && !outjd)
|
||||
return -ENODEV;
|
||||
if (injd && (injd->bLength < 5 ||
|
||||
(injd->bJackType != USB_MS_EMBEDDED &&
|
||||
injd->bJackType != USB_MS_EXTERNAL)))
|
||||
return -ENODEV;
|
||||
if (outjd && (outjd->bLength < 6 ||
|
||||
(outjd->bJackType != USB_MS_EMBEDDED &&
|
||||
outjd->bJackType != USB_MS_EXTERNAL)))
|
||||
return -ENODEV;
|
||||
return create_any_midi_quirk(chip, iface, driver, &yamaha_midi_quirk);
|
||||
}
|
||||
|
||||
static int create_roland_midi_quirk(struct snd_usb_audio *chip,
|
||||
struct usb_interface *iface,
|
||||
struct usb_driver *driver,
|
||||
struct usb_host_interface *alts)
|
||||
{
|
||||
static const struct snd_usb_audio_quirk roland_midi_quirk = {
|
||||
.type = QUIRK_MIDI_ROLAND
|
||||
};
|
||||
u8 *roland_desc = NULL;
|
||||
|
||||
/* might have a vendor-specific descriptor <06 24 F1 02 ...> */
|
||||
for (;;) {
|
||||
roland_desc = snd_usb_find_csint_desc(alts->extra,
|
||||
alts->extralen,
|
||||
roland_desc, 0xf1);
|
||||
if (!roland_desc)
|
||||
return -ENODEV;
|
||||
if (roland_desc[0] < 6 || roland_desc[3] != 2)
|
||||
continue;
|
||||
return create_any_midi_quirk(chip, iface, driver,
|
||||
&roland_midi_quirk);
|
||||
}
|
||||
}
|
||||
|
||||
static int create_std_midi_quirk(struct snd_usb_audio *chip,
|
||||
struct usb_interface *iface,
|
||||
struct usb_driver *driver,
|
||||
struct usb_host_interface *alts)
|
||||
{
|
||||
struct usb_ms_header_descriptor *mshd;
|
||||
struct usb_ms_endpoint_descriptor *msepd;
|
||||
|
||||
/* must have the MIDIStreaming interface header descriptor*/
|
||||
mshd = (struct usb_ms_header_descriptor *)alts->extra;
|
||||
if (alts->extralen < 7 ||
|
||||
mshd->bLength < 7 ||
|
||||
mshd->bDescriptorType != USB_DT_CS_INTERFACE ||
|
||||
mshd->bDescriptorSubtype != USB_MS_HEADER)
|
||||
return -ENODEV;
|
||||
/* must have the MIDIStreaming endpoint descriptor*/
|
||||
msepd = (struct usb_ms_endpoint_descriptor *)alts->endpoint[0].extra;
|
||||
if (alts->endpoint[0].extralen < 4 ||
|
||||
msepd->bLength < 4 ||
|
||||
msepd->bDescriptorType != USB_DT_CS_ENDPOINT ||
|
||||
msepd->bDescriptorSubtype != UAC_MS_GENERAL ||
|
||||
msepd->bNumEmbMIDIJack < 1 ||
|
||||
msepd->bNumEmbMIDIJack > 16)
|
||||
return -ENODEV;
|
||||
|
||||
return create_any_midi_quirk(chip, iface, driver, NULL);
|
||||
}
|
||||
|
||||
static int create_auto_midi_quirk(struct snd_usb_audio *chip,
|
||||
struct usb_interface *iface,
|
||||
struct usb_driver *driver)
|
||||
{
|
||||
struct usb_host_interface *alts;
|
||||
struct usb_interface_descriptor *altsd;
|
||||
struct usb_endpoint_descriptor *epd;
|
||||
int err;
|
||||
|
||||
alts = &iface->altsetting[0];
|
||||
altsd = get_iface_desc(alts);
|
||||
|
||||
/* must have at least one bulk/interrupt endpoint for streaming */
|
||||
if (altsd->bNumEndpoints < 1)
|
||||
return -ENODEV;
|
||||
epd = get_endpoint(alts, 0);
|
||||
if (!usb_endpoint_xfer_bulk(epd) ||
|
||||
!usb_endpoint_xfer_int(epd))
|
||||
return -ENODEV;
|
||||
|
||||
switch (USB_ID_VENDOR(chip->usb_id)) {
|
||||
case 0x0499: /* Yamaha */
|
||||
err = create_yamaha_midi_quirk(chip, iface, driver, alts);
|
||||
if (err < 0 && err != -ENODEV)
|
||||
return err;
|
||||
break;
|
||||
case 0x0582: /* Roland */
|
||||
err = create_roland_midi_quirk(chip, iface, driver, alts);
|
||||
if (err < 0 && err != -ENODEV)
|
||||
return err;
|
||||
break;
|
||||
}
|
||||
|
||||
return create_std_midi_quirk(chip, iface, driver, alts);
|
||||
}
|
||||
|
||||
static int create_autodetect_quirk(struct snd_usb_audio *chip,
|
||||
struct usb_interface *iface,
|
||||
struct usb_driver *driver)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = create_auto_pcm_quirk(chip, iface, driver);
|
||||
if (err == -ENODEV)
|
||||
err = create_auto_midi_quirk(chip, iface, driver);
|
||||
return err;
|
||||
}
|
||||
|
||||
static int create_autodetect_quirks(struct snd_usb_audio *chip,
|
||||
struct usb_interface *iface,
|
||||
struct usb_driver *driver,
|
||||
const struct snd_usb_audio_quirk *quirk)
|
||||
{
|
||||
int probed_ifnum = get_iface_desc(iface->altsetting)->bInterfaceNumber;
|
||||
int ifcount, ifnum, err;
|
||||
|
||||
err = create_autodetect_quirk(chip, iface, driver);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
/*
|
||||
* ALSA PCM playback/capture devices cannot be registered in two steps,
|
||||
* so we have to claim the other corresponding interface here.
|
||||
*/
|
||||
ifcount = chip->dev->actconfig->desc.bNumInterfaces;
|
||||
for (ifnum = 0; ifnum < ifcount; ifnum++) {
|
||||
if (ifnum == probed_ifnum || quirk->ifnum >= 0)
|
||||
continue;
|
||||
iface = usb_ifnum_to_if(chip->dev, ifnum);
|
||||
if (!iface ||
|
||||
usb_interface_claimed(iface) ||
|
||||
get_iface_desc(iface->altsetting)->bInterfaceClass !=
|
||||
USB_CLASS_VENDOR_SPEC)
|
||||
continue;
|
||||
|
||||
err = create_autodetect_quirk(chip, iface, driver);
|
||||
if (err >= 0)
|
||||
usb_driver_claim_interface(driver, iface, (void *)-1L);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a stream for an Edirol UA-700/UA-25/UA-4FX interface.
|
||||
* The only way to detect the sample rate is by looking at wMaxPacketSize.
|
||||
@ -303,9 +510,11 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
|
||||
static const quirk_func_t quirk_funcs[] = {
|
||||
[QUIRK_IGNORE_INTERFACE] = ignore_interface_quirk,
|
||||
[QUIRK_COMPOSITE] = create_composite_quirk,
|
||||
[QUIRK_AUTODETECT] = create_autodetect_quirks,
|
||||
[QUIRK_MIDI_STANDARD_INTERFACE] = create_any_midi_quirk,
|
||||
[QUIRK_MIDI_FIXED_ENDPOINT] = create_any_midi_quirk,
|
||||
[QUIRK_MIDI_YAMAHA] = create_any_midi_quirk,
|
||||
[QUIRK_MIDI_ROLAND] = create_any_midi_quirk,
|
||||
[QUIRK_MIDI_MIDIMAN] = create_any_midi_quirk,
|
||||
[QUIRK_MIDI_NOVATION] = create_any_midi_quirk,
|
||||
[QUIRK_MIDI_RAW_BYTES] = create_any_midi_quirk,
|
||||
|
@ -493,10 +493,10 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
|
||||
altsd = get_iface_desc(alts);
|
||||
protocol = altsd->bInterfaceProtocol;
|
||||
/* skip invalid one */
|
||||
if ((altsd->bInterfaceClass != USB_CLASS_AUDIO &&
|
||||
if (((altsd->bInterfaceClass != USB_CLASS_AUDIO ||
|
||||
(altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING &&
|
||||
altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC)) &&
|
||||
altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC) ||
|
||||
(altsd->bInterfaceSubClass != USB_SUBCLASS_AUDIOSTREAMING &&
|
||||
altsd->bInterfaceSubClass != USB_SUBCLASS_VENDOR_SPEC) ||
|
||||
altsd->bNumEndpoints < 1 ||
|
||||
le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == 0)
|
||||
continue;
|
||||
@ -512,6 +512,15 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
|
||||
if (snd_usb_apply_interface_quirk(chip, iface_no, altno))
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Roland audio streaming interfaces are marked with protocols
|
||||
* 0/1/2, but are UAC 1 compatible.
|
||||
*/
|
||||
if (USB_ID_VENDOR(chip->usb_id) == 0x0582 &&
|
||||
altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC &&
|
||||
protocol <= 2)
|
||||
protocol = UAC_VERSION_1;
|
||||
|
||||
chconfig = 0;
|
||||
/* get audio formats */
|
||||
switch (protocol) {
|
||||
@ -635,6 +644,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
|
||||
fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress;
|
||||
fp->ep_attr = get_endpoint(alts, 0)->bmAttributes;
|
||||
fp->datainterval = snd_usb_parse_datainterval(chip, alts);
|
||||
fp->protocol = protocol;
|
||||
fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize);
|
||||
fp->channels = num_channels;
|
||||
if (snd_usb_get_speed(dev) == USB_SPEED_HIGH)
|
||||
@ -676,7 +686,7 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no)
|
||||
}
|
||||
|
||||
/* ok, let's parse further... */
|
||||
if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream, alts) < 0) {
|
||||
if (snd_usb_parse_audio_format(chip, fp, format, fmt, stream) < 0) {
|
||||
kfree(fp->rate_table);
|
||||
kfree(fp->chmap);
|
||||
kfree(fp);
|
||||
|
@ -72,9 +72,11 @@ struct snd_usb_audio {
|
||||
enum quirk_type {
|
||||
QUIRK_IGNORE_INTERFACE,
|
||||
QUIRK_COMPOSITE,
|
||||
QUIRK_AUTODETECT,
|
||||
QUIRK_MIDI_STANDARD_INTERFACE,
|
||||
QUIRK_MIDI_FIXED_ENDPOINT,
|
||||
QUIRK_MIDI_YAMAHA,
|
||||
QUIRK_MIDI_ROLAND,
|
||||
QUIRK_MIDI_MIDIMAN,
|
||||
QUIRK_MIDI_NOVATION,
|
||||
QUIRK_MIDI_RAW_BYTES,
|
||||
|
Loading…
Reference in New Issue
Block a user