The commit 
289ca025ee1d ("ALSA: Use priority list for managing device
list") changed the way to register/disconnect/free devices via a
single priority list.  This helped to make behavior consistent, but it
also changed a slight behavior change: namely, the control device is
registered earlier than others, while it was supposed to be the very
last one.
I've put SNDRV_DEV_CONTROL in the current position as the release of
ctl elements often conflict with the private ctl elements some PCM or
other components may create, which often leads to a double-free.
But, the order of register and disconnect should be indeed fixed as
expected in the early days: the control device gets registered at
last, and disconnected at first.
This patch changes the priority list order to move SNDRV_DEV_CONTROL
as the last guy to assure the register / disconnect order.  Meanwhile,
for keeping the messy resource release order, manually treat the
control and lowlevel devices as last freed one.
Additional note:
The lowlevel device is the device where a card driver creates at
probe.  And, we still keep the release order control -> lowlevel, as
there might  be link from a control element back to a lowlevel object.
Fixes: 289ca025ee1d ("ALSA: Use priority list for managing device list")
Reported-by: Tzung-Bi Shih <tzungbi@google.com>
Tested-by: Tzung-Bi Shih <tzungbi@google.com>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
  */
 enum snd_device_type {
        SNDRV_DEV_LOWLEVEL,
-       SNDRV_DEV_CONTROL,
        SNDRV_DEV_INFO,
        SNDRV_DEV_BUS,
        SNDRV_DEV_CODEC,
        SNDRV_DEV_SEQUENCER,
        SNDRV_DEV_HWDEP,
        SNDRV_DEV_JACK,
+       SNDRV_DEV_CONTROL,      /* NOTE: this must be the last one */
 };
 
 enum snd_device_state {
 
 
        if (snd_BUG_ON(!card))
                return;
+       list_for_each_entry_safe_reverse(dev, next, &card->devices, list) {
+               /* exception: free ctl and lowlevel stuff later */
+               if (dev->type == SNDRV_DEV_CONTROL ||
+                   dev->type == SNDRV_DEV_LOWLEVEL)
+                       continue;
+               __snd_device_free(dev);
+       }
+
+       /* free all */
        list_for_each_entry_safe_reverse(dev, next, &card->devices, list)
                __snd_device_free(dev);
 }