hal: Fix combo device issue with routing change

- If one of the split backends match with derived sound
  device, we are disabling only the backends that do not
  match with derived sound device. This was introduced
  with Change-Id: I171fbead85746a2a34632f7580f56ef40505665c
- However, the change does not clean up the combo device
  which is being disabled.
- We need to decrement reference count of combo device and
  send some updates for combo device along with the change
  mentioned above. Not doing this can lead to combo device
  not getting enabled on subsequent tries.
  This change fixes the above issue.
- Also, if one of the split backends matches with derived
  sound device, do not re-enable the device.

Change-Id: Id1bd00bfa5f0236400529e5771851749421ac84c
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index d3e7a5f..a3b374c 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -681,6 +681,7 @@
 int audio_extn_utils_get_bit_width_from_string(const char *);
 int audio_extn_utils_get_sample_rate_from_string(const char *);
 int audio_extn_utils_get_channels_from_string(const char *);
+void audio_extn_utils_release_snd_device(snd_device_t snd_device);
 
 #ifdef DS2_DOLBY_DAP_ENABLED
 #define LIB_DS2_DAP_HAL "vendor/lib/libhwdaphal.so"
diff --git a/hal/audio_extn/utils.c b/hal/audio_extn/utils.c
index 0a48953..433743e 100644
--- a/hal/audio_extn/utils.c
+++ b/hal/audio_extn/utils.c
@@ -2518,3 +2518,12 @@
 
     return -EINVAL;
 }
+
+void audio_extn_utils_release_snd_device(snd_device_t snd_device)
+{
+    audio_extn_dev_arbi_release(snd_device);
+    audio_extn_sound_trigger_update_device_status(snd_device,
+                                    ST_EVENT_SND_DEVICE_FREE);
+    audio_extn_listen_update_device_status(snd_device,
+                                    LISTEN_EVENT_SND_DEVICE_FREE);
+}
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 3e3f72f..34f27e4 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -1183,11 +1183,7 @@
             ALOGD("%s: deinit ec ref loopback", __func__);
             audio_extn_ffv_deinit_ec_ref_loopback(adev, snd_device);
         }
-        audio_extn_dev_arbi_release(snd_device);
-        audio_extn_sound_trigger_update_device_status(snd_device,
-                                        ST_EVENT_SND_DEVICE_FREE);
-        audio_extn_listen_update_device_status(snd_device,
-                                        LISTEN_EVENT_SND_DEVICE_FREE);
+        audio_extn_utils_release_snd_device(snd_device);
     }
 
     return 0;
@@ -1413,16 +1409,19 @@
         list_for_each(node, &adev->usecase_list) {
             usecase = node_to_item(node, struct audio_usecase, list);
             if (switch_device[usecase->id]) {
-                /* Check if sound device to be switched can be split and if any
+                /* Check if output sound device to be switched can be split and if any
                    of the split devices match with derived sound device */
-                platform_split_snd_device(adev->platform, usecase->out_snd_device,
-                                          &num_devices, split_snd_devices);
-                if (num_devices > 1) {
-                    for (i = 0; i < num_devices; i++) {
-                        /* Disable devices that do not match with derived sound device */
-                        if (split_snd_devices[i] != derive_snd_device[usecase->id]) {
-                            disable_snd_device(adev, split_snd_devices[i]);
+                if (platform_split_snd_device(adev->platform, usecase->out_snd_device,
+                                               &num_devices, split_snd_devices) == 0) {
+                    adev->snd_dev_ref_cnt[usecase->out_snd_device]--;
+                    if (adev->snd_dev_ref_cnt[usecase->out_snd_device] == 0) {
+                        ALOGD("%s: disabling snd_device(%d)", __func__, usecase->out_snd_device);
+                        for (i = 0; i < num_devices; i++) {
+                            /* Disable devices that do not match with derived sound device */
+                            if (split_snd_devices[i] != derive_snd_device[usecase->id])
+                                disable_snd_device(adev, split_snd_devices[i]);
                         }
+                        audio_extn_utils_release_snd_device(usecase->out_snd_device);
                     }
                 } else {
                     disable_snd_device(adev, usecase->out_snd_device);
@@ -1433,7 +1432,23 @@
         list_for_each(node, &adev->usecase_list) {
             usecase = node_to_item(node, struct audio_usecase, list);
             if (switch_device[usecase->id]) {
-                enable_snd_device(adev, derive_snd_device[usecase->id]);
+                if (platform_split_snd_device(adev->platform, usecase->out_snd_device,
+                                               &num_devices, split_snd_devices) == 0) {
+                        /* Enable derived sound device only if it does not match with
+                           one of the split sound devices. This is because the matching
+                           sound device was not disabled */
+                        bool should_enable = true;
+                        for (i = 0; i < num_devices; i++) {
+                            if (derive_snd_device[usecase->id] == split_snd_devices[i]) {
+                                 should_enable = false;
+                                 break;
+                            }
+                        }
+                        if (should_enable)
+                            enable_snd_device(adev, derive_snd_device[usecase->id]);
+                } else {
+                    enable_snd_device(adev, derive_snd_device[usecase->id]);
+                }
             }
         }