ALSA: usb: handle descriptor with SYNC_NONE illegal value
[firefly-linux-kernel-4.4.55.git] / sound / usb / pcm.c
index b4ef410e5a982b31adc933153773b34f9ccbbc2b..30797269d5aade31fb44d781a6c36d3f9f5a4f1f 100644 (file)
@@ -391,6 +391,20 @@ static int set_sync_endpoint(struct snd_usb_substream *subs,
         */
        attr = fmt->ep_attr & USB_ENDPOINT_SYNCTYPE;
 
+       if ((is_playback && (attr != USB_ENDPOINT_SYNC_ASYNC)) ||
+               (!is_playback && (attr != USB_ENDPOINT_SYNC_ADAPTIVE))) {
+
+               /*
+                * In these modes the notion of sync_endpoint is irrelevant.
+                * Reset pointers to avoid using stale data from previously
+                * used settings, e.g. when configuration and endpoints were
+                * changed
+                */
+
+               subs->sync_endpoint = NULL;
+               subs->data_endpoint->sync_master = NULL;
+       }
+
        err = set_sync_ep_implicit_fb_quirk(subs, dev, altsd, attr);
        if (err < 0)
                return err;
@@ -398,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
@@ -415,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;
@@ -425,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;
        }
 
@@ -436,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;