The M-Audio Transit exposes an interface with a SYNC_NONE attribute. This is not a valid value according to the USB audio classspec. However there is a sync endpoint associated to this record. Changing the logic to try to use this sync endpoint allows for seamless transitions between altset 2 and altset 3. If any errors happen, the behavior remains the same.
$ more /proc/asound/card1/stream0 M-Audio Transit USB at usb-0000:00:14.0-2, full speed : USB Audio
Playback: Status: Stop Interface 1 Altset 1 Format: S24_3LE Channels: 2 Endpoint: 3 OUT (ADAPTIVE) Rates: 48001 - 96000 (continuous) Interface 1 Altset 2 Format: S24_3LE Channels: 2 Endpoint: 3 OUT (NONE) Rates: 8000 - 48000 (continuous) Interface 1 Altset 3 Format: S16_LE Channels: 2 Endpoint: 3 OUT (ASYNC) Rates: 8000 - 48000 (continuous)
Signed-off-by: Pierre-Louis Bossart pierre-louis.bossart@linux.intel.com --- sound/usb/pcm.c | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-)
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 7fb17c8..3079726 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -412,10 +412,17 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, if (altsd->bNumEndpoints < 2) return 0;
- if ((is_playback && attr != USB_ENDPOINT_SYNC_ASYNC) || + if ((is_playback && (attr == USB_ENDPOINT_SYNC_SYNC || + attr == USB_ENDPOINT_SYNC_ADAPTIVE)) || (!is_playback && attr != USB_ENDPOINT_SYNC_ADAPTIVE)) return 0;
+ /* + * In case of illegal SYNC_NONE for OUT endpoint, we keep going to see + * if we don't find a sync endpoint, as on M-Audio Transit. In case of + * error fall back to SYNC mode and don't create sync endpoint + */ + /* check sync-pipe endpoint */ /* ... and check descriptor size before accessing bSynchAddress because there is a version of the SB Audigy 2 NX firmware lacking @@ -429,6 +436,8 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, get_endpoint(alts, 1)->bmAttributes, get_endpoint(alts, 1)->bLength, get_endpoint(alts, 1)->bSynchAddress); + if (is_playback && attr == USB_ENDPOINT_SYNC_NONE) + return 0; return -EINVAL; } ep = get_endpoint(alts, 1)->bEndpointAddress; @@ -439,6 +448,8 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, "%d:%d : invalid sync pipe. is_playback %d, ep %02x, bSynchAddress %02x\n", fmt->iface, fmt->altsetting, is_playback, ep, get_endpoint(alts, 0)->bSynchAddress); + if (is_playback && attr == USB_ENDPOINT_SYNC_NONE) + return 0; return -EINVAL; }
@@ -450,8 +461,11 @@ static int set_sync_endpoint(struct snd_usb_substream *subs, implicit_fb ? SND_USB_ENDPOINT_TYPE_DATA : SND_USB_ENDPOINT_TYPE_SYNC); - if (!subs->sync_endpoint) + if (!subs->sync_endpoint) { + if (is_playback && attr == USB_ENDPOINT_SYNC_NONE) + return 0; return -EINVAL; + }
subs->data_endpoint->sync_master = subs->sync_endpoint;