ALSA: usb-audio: Add keep_iface flag
authorTakashi Iwai <tiwai@suse.de>
Wed, 2 May 2018 08:04:27 +0000 (10:04 +0200)
committerTakashi Iwai <tiwai@suse.de>
Wed, 2 May 2018 14:02:33 +0000 (16:02 +0200)
Introduce a new flag to struct snd_usb_audio for allowing the device
to skip usb_set_interface() calls at changing or closing the stream.
As of this patch, the flag is nowhere set, so it's just a place
holder.  The dynamic switching will be added in the following patch.

A background information for this change:

Dell WD15 dock with Realtek chip gives a very long pause at each time
the driver changes the altset, which eventually happens at every PCM
stream open/close and parameter change.  As the long pause happens in
each usb_set_interface() call, there is nothing we can do as long as
it's called.  The workaround is to reduce calling it as much as
possible, and this flag indicates that behavior.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/usb/pcm.c
sound/usb/usbaudio.h

index ae7d8a0a0a0a32bae4100c48bccd024ca88f3d09..dc2dfec9effd5bad11fe07abcaed8821b8529814 100644 (file)
@@ -509,12 +509,14 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
 
        /* close the old interface */
        if (subs->interface >= 0 && subs->interface != fmt->iface) {
-               err = usb_set_interface(subs->dev, subs->interface, 0);
-               if (err < 0) {
-                       dev_err(&dev->dev,
-                               "%d:%d: return to setting 0 failed (%d)\n",
-                               fmt->iface, fmt->altsetting, err);
-                       return -EIO;
+               if (!subs->stream->chip->keep_iface) {
+                       err = usb_set_interface(subs->dev, subs->interface, 0);
+                       if (err < 0) {
+                               dev_err(&dev->dev,
+                                       "%d:%d: return to setting 0 failed (%d)\n",
+                                       fmt->iface, fmt->altsetting, err);
+                               return -EIO;
+                       }
                }
                subs->interface = -1;
                subs->altset_idx = 0;
@@ -1253,7 +1255,8 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction)
 
        stop_endpoints(subs, true);
 
-       if (subs->interface >= 0 &&
+       if (!as->chip->keep_iface &&
+           subs->interface >= 0 &&
            !snd_usb_lock_shutdown(subs->stream->chip)) {
                usb_set_interface(subs->dev, subs->interface, 0);
                subs->interface = -1;
index 4d5c89a7ba2b5b97b62a1464ead6743710e34ed8..32f4a54255361d31db8ca81dda885f6dc28844ad 100644 (file)
@@ -59,6 +59,9 @@ struct snd_usb_audio {
 
        int setup;                      /* from the 'device_setup' module param */
        bool autoclock;                 /* from the 'autoclock' module param */
+       bool keep_iface;                /* keep interface/altset after closing
+                                        * or parameter change
+                                        */
 
        struct usb_host_interface *ctrl_intf;   /* the audio control interface */
 };