From: Clemens Ladisch <clemens@ladisch.de>
To: Smeefer <smeefer@gmail.com>
Cc: alsa-devel@alsa-project.org
Subject: Re: Trouble about Roland UA-55 and snd-usb-audio module
Date: Thu, 07 Feb 2013 21:35:09 +0100 [thread overview]
Message-ID: <51140FFD.3060907@ladisch.de> (raw)
In-Reply-To: <loom.20130131T042847-100@post.gmane.org>
Smeefer wrote:
> The latest AV Linux kernel version is 3.0.47-avl-10. I will find out if this
> is close to bleeding edge like i hope it is!
In theory, implicit feedback support was added in kernel 3.5, but there
have been lots of important bugfixes since then, so I've just based it
on 3.8-rc6:
--8<---------------------------------------------------------------->8--
The following changes since commit 88b62b915b0b7e25870eb0604ed9a92ba4bfc9f7:
Linux 3.8-rc6 (2013-02-01 12:08:14 +1100)
are available in the git repository at:
git://git.alsa-project.org/alsa-kprivate.git full-roland-support
for you to fetch changes up to 59f42365d5e06ec5f0660e3062ab14eaa03bdc31:
ALSA: usb-audio: detect PCM streams on all recent Roland devices (2013-02-07 21:09:01 +0100)
----------------------------------------------------------------
Clemens Ladisch (4):
ALSA: usb-audio: store protocol version in struct audioformat
ALSA: usb-audio: detect implicit feedback on Roland devices
ALSA: usb-audio: detect MIDI ports on all recent Roland devices
ALSA: usb-audio: detect PCM streams on all recent Roland devices
sound/usb/card.h | 1 +
sound/usb/clock.c | 4 +---
sound/usb/format.c | 34 +++++++++---------------------
sound/usb/format.h | 2 +-
sound/usb/midi.c | 41 ++++++++++++++++++++++++++++++++++++
sound/usb/pcm.c | 43 ++++++++++++++++++++++++++++++++++---
sound/usb/quirks-table.h | 25 ++++++++++++++++++++++
sound/usb/quirks.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++++
sound/usb/stream.c | 13 +++++++++++-
sound/usb/usbaudio.h | 2 ++
10 files changed, 188 insertions(+), 32 deletions(-)
diff --git a/sound/usb/card.h b/sound/usb/card.h
index 8a751b4..76907e2 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -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 */
diff --git a/sound/usb/clock.c b/sound/usb/clock.c
index 5e634a2..787f097 100644
--- a/sound/usb/clock.c
+++ b/sound/usb/clock.c
@@ -301,9 +301,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);
diff --git a/sound/usb/format.c b/sound/usb/format.c
index e831ee4..ae1198b 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -43,13 +43,12 @@
*/
static u64 parse_audio_format_i_type(struct snd_usb_audio *chip,
struct audioformat *fp,
- int format, void *_fmt,
- int protocol)
+ int format, void *_fmt)
{
int sample_width, sample_bytes;
u64 pcm_formats;
- switch (protocol) {
+ switch (fp->protocol) {
case UAC_VERSION_1:
default: {
struct uac_format_type_i_discrete_descriptor *fmt = _fmt;
@@ -354,11 +353,8 @@ err:
*/
static int parse_audio_format_i(struct snd_usb_audio *chip,
struct audioformat *fp, 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;
int pcm_format, ret;
if (fmt->bFormatType == UAC_FORMAT_TYPE_III) {
@@ -380,8 +376,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
}
fp->formats = 1uLL << 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;
}
@@ -391,11 +386,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);
@@ -420,12 +412,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:
@@ -445,11 +434,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);
@@ -475,17 +461,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,
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",
diff --git a/sound/usb/format.h b/sound/usb/format.h
index 387924f..60b6682 100644
--- a/sound/usb/format.h
+++ b/sound/usb/format.h
@@ -4,6 +4,6 @@
int snd_usb_parse_audio_format(struct snd_usb_audio *chip,
struct audioformat *fp, int format,
struct uac_format_type_i_continuous_descriptor *fmt,
- int stream, struct usb_host_interface *iface);
+ int stream);
#endif /* __USBAUDIO_FORMAT_H */
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index 34b9bb7..3508360 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -1959,6 +1959,44 @@ static int snd_usbmidi_detect_yamaha(struct snd_usb_midi* umidi,
}
/*
+ * 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.
*/
static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi* umidi,
@@ -2171,6 +2209,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,
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index d82e378..3c2f9f5 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -199,13 +199,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);
@@ -297,6 +295,33 @@ static int deactivate_endpoints(struct snd_usb_substream *subs)
return 0;
}
+static int search_roland_implicit_fb(struct usb_device *dev, int ifnum,
+ 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 < 2)
+ return -ENOENT;
+ *alts = &iface->altsetting[1];
+ altsd = get_iface_desc(*alts);
+ if (altsd->bInterfaceClass != USB_CLASS_VENDOR_SPEC ||
+ altsd->bInterfaceSubClass != 2 ||
+ altsd->bInterfaceProtocol != 1 ||
+ 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
*/
@@ -389,6 +414,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->bInterfaceSubClass == 2 &&
+ altsd->bInterfaceProtocol == 2 &&
+ altsd->bNumEndpoints == 1 &&
+ USB_ID_VENDOR(subs->stream->chip->usb_id) == 0x0582 /* Roland */ &&
+ search_roland_implicit_fb(dev, altsd->bInterfaceNumber + 1,
+ &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)) &&
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 64d25a7..4bf53d5 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -1953,6 +1953,31 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
}
},
+/* this catches most recent vendor-specific Roland devices */
+{
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
+ USB_DEVICE_ID_MATCH_INT_CLASS |
+ USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+ .idVendor = 0x0582,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOSTREAMING,
+ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_AUDIO_ROLAND
+ }
+},
+{
+ .match_flags = USB_DEVICE_ID_MATCH_VENDOR |
+ USB_DEVICE_ID_MATCH_INT_CLASS |
+ USB_DEVICE_ID_MATCH_INT_SUBCLASS,
+ .idVendor = 0x0582,
+ .bInterfaceClass = USB_CLASS_VENDOR_SPEC,
+ .bInterfaceSubClass = USB_SUBCLASS_MIDISTREAMING,
+ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_MIDI_ROLAND
+ }
+},
/* Guillemot devices */
{
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 2c97185..9209d4d 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -173,6 +173,59 @@ static int create_fixed_stream_quirk(struct snd_usb_audio *chip,
return 0;
}
+static int create_roland_audio_quirk(struct snd_usb_audio *chip,
+ struct usb_interface *iface,
+ struct usb_driver *driver,
+ const struct snd_usb_audio_quirk *quirk)
+{
+ struct usb_host_interface *alts;
+ struct usb_interface_descriptor *altsd;
+ struct usb_endpoint_descriptor *epd;
+
+ /*
+ * Most Roland 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 be correctly marked as input/output */
+ switch (altsd->bInterfaceProtocol) {
+ case 0:
+ break;
+ case 1:
+ if (!usb_endpoint_dir_in(epd))
+ return -ENODEV;
+ break;
+ case 2:
+ if (!usb_endpoint_dir_out(epd))
+ return -ENODEV;
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ /* must have format descriptors */
+ if (!snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL,
+ UAC_FORMAT_TYPE))
+ return -ENODEV;
+
+ return create_standard_audio_quirk(chip, iface, driver, NULL);
+}
+
/*
* 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.
@@ -304,6 +357,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
[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,
@@ -313,6 +367,7 @@ int snd_usb_create_quirk(struct snd_usb_audio *chip,
[QUIRK_MIDI_FTDI] = create_any_midi_quirk,
[QUIRK_AUDIO_STANDARD_INTERFACE] = create_standard_audio_quirk,
[QUIRK_AUDIO_FIXED_ENDPOINT] = create_fixed_stream_quirk,
+ [QUIRK_AUDIO_ROLAND] = create_roland_audio_quirk,
[QUIRK_AUDIO_EDIROL_UAXX] = create_uaxx_quirk,
[QUIRK_AUDIO_ALIGN_TRANSFER] = create_align_transfer_quirk,
[QUIRK_AUDIO_STANDARD_MIXER] = create_standard_mixer_quirk,
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index ad181d5..6e837b7 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -507,6 +507,16 @@ 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 &&
+ altsd->bInterfaceSubClass == USB_SUBCLASS_AUDIOSTREAMING &&
+ protocol <= 2)
+ protocol = UAC_VERSION_1;
+
chconfig = 0;
/* get audio formats */
switch (protocol) {
@@ -630,6 +640,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)
@@ -671,7 +682,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);
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index 1ac3fd9..4313747 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -74,6 +74,7 @@ enum quirk_type {
QUIRK_MIDI_STANDARD_INTERFACE,
QUIRK_MIDI_FIXED_ENDPOINT,
QUIRK_MIDI_YAMAHA,
+ QUIRK_MIDI_ROLAND,
QUIRK_MIDI_MIDIMAN,
QUIRK_MIDI_NOVATION,
QUIRK_MIDI_RAW_BYTES,
@@ -84,6 +85,7 @@ enum quirk_type {
QUIRK_MIDI_FTDI,
QUIRK_AUDIO_STANDARD_INTERFACE,
QUIRK_AUDIO_FIXED_ENDPOINT,
+ QUIRK_AUDIO_ROLAND,
QUIRK_AUDIO_EDIROL_UAXX,
QUIRK_AUDIO_ALIGN_TRANSFER,
QUIRK_AUDIO_STANDARD_MIXER,
next prev parent reply other threads:[~2013-02-07 20:36 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-11-14 7:35 Trouble about Roland UA-11 UA-33 UA-55 and snd-usb-audio module FirebUntU
2012-11-14 7:45 ` Clemens Ladisch
2012-11-15 22:40 ` FirebUntU
2012-11-15 22:42 ` FirebUntU
2013-01-09 11:58 ` Trouble about Roland " Smeefer Carbone
2013-01-10 11:02 ` Roland UA-55 Smeefer Carbone
2013-01-20 17:57 ` Trouble about Roland UA-55 and snd-usb-audio module Clemens Ladisch
2013-01-25 19:24 ` Smeefer
2013-01-28 21:21 ` Smeefer
2013-01-28 21:43 ` Clemens Ladisch
2013-01-31 3:40 ` Smeefer
2013-02-07 20:35 ` Clemens Ladisch [this message]
2013-02-08 12:55 ` Clemens Ladisch
2013-03-03 12:25 ` LH
2016-02-29 10:07 ` Jeroen Kransen
2016-03-03 13:11 ` Clemens Ladisch
2016-03-06 23:03 ` JB Fonder
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=51140FFD.3060907@ladisch.de \
--to=clemens@ladisch.de \
--cc=alsa-devel@alsa-project.org \
--cc=smeefer@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.