am c750b06b: Merge "audio: add bluetooth sco support" into jb-mr1-dev

* commit 'c750b06b27d22a70658ef681f86db0a202f8a832':
  audio: add bluetooth sco support
diff --git a/audio/audio_hw.c b/audio/audio_hw.c
index 926741a..b7656af 100644
--- a/audio/audio_hw.c
+++ b/audio/audio_hw.c
@@ -43,6 +43,8 @@
 #define PCM_TOTAL 2
 
 #define PCM_DEVICE 0
+#define PCM_DEVICE_VOICE 2
+#define PCM_DEVICE_SCO 3
 
 /* duration in ms of volume ramp applied when starting capture to remove plop */
 #define CAPTURE_START_RAMP_MS 100
@@ -55,6 +57,14 @@
     .format = PCM_FORMAT_S16_LE,
 };
 
+struct pcm_config pcm_config_sco = {
+    .channels = 1,
+    .rate = 8000,
+    .period_size = 128,
+    .period_count = 2,
+    .format = PCM_FORMAT_S16_LE,
+};
+
 struct audio_device {
     struct audio_hw_device hw_device;
 
@@ -65,6 +75,10 @@
     audio_source_t input_source;
     int cur_route_id;     /* current route ID: combination of input source
                            * and output device IDs */
+    struct pcm *pcm_voice_out;
+    struct pcm *pcm_sco_out;
+    struct pcm *pcm_voice_in;
+    struct pcm *pcm_sco_in;
 };
 
 struct stream_out {
@@ -336,7 +350,8 @@
     if (out->device & (AUDIO_DEVICE_OUT_SPEAKER |
                        AUDIO_DEVICE_OUT_WIRED_HEADSET |
                        AUDIO_DEVICE_OUT_WIRED_HEADPHONE |
-                       AUDIO_DEVICE_OUT_AUX_DIGITAL)) {
+                       AUDIO_DEVICE_OUT_AUX_DIGITAL |
+                       AUDIO_DEVICE_OUT_ALL_SCO)) {
         out->pcm[PCM_CARD] = pcm_open(PCM_CARD, PCM_DEVICE,
                                       PCM_OUT, &pcm_config);
 
@@ -396,6 +411,62 @@
     return 0;
 }
 
+/* must be called with the hw device mutex locked, OK to hold other mutexes */
+static void start_bt_sco(struct audio_device *adev) {
+    adev->pcm_voice_out = pcm_open(PCM_CARD, PCM_DEVICE_VOICE, PCM_OUT,
+                              &pcm_config_sco);
+    if (adev->pcm_voice_out && !pcm_is_ready(adev->pcm_voice_out)) {
+        ALOGE("pcm_open(VOICE_OUT) failed: %s", pcm_get_error(adev->pcm_voice_out));
+        goto err_voice_out;
+    }
+    adev->pcm_sco_out = pcm_open(PCM_CARD, PCM_DEVICE_SCO, PCM_OUT,
+                            &pcm_config_sco);
+    if (adev->pcm_sco_out && !pcm_is_ready(adev->pcm_sco_out)) {
+        ALOGE("pcm_open(SCO_OUT) failed: %s", pcm_get_error(adev->pcm_sco_out));
+        goto err_sco_out;
+    }
+    adev->pcm_voice_in = pcm_open(PCM_CARD, PCM_DEVICE_VOICE, PCM_IN,
+                                 &pcm_config_sco);
+    if (adev->pcm_voice_in && !pcm_is_ready(adev->pcm_voice_in)) {
+        ALOGE("pcm_open(VOICE_IN) failed: %s", pcm_get_error(adev->pcm_voice_in));
+        goto err_voice_in;
+    }
+    adev->pcm_sco_in = pcm_open(PCM_CARD, PCM_DEVICE_SCO, PCM_IN,
+                               &pcm_config_sco);
+    if (adev->pcm_sco_in && !pcm_is_ready(adev->pcm_sco_in)) {
+        ALOGE("pcm_open(SCO_IN) failed: %s", pcm_get_error(adev->pcm_sco_in));
+        goto err_sco_in;
+    }
+
+    pcm_start(adev->pcm_voice_out);
+    pcm_start(adev->pcm_sco_out);
+    pcm_start(adev->pcm_voice_in);
+    pcm_start(adev->pcm_sco_in);
+
+    return;
+
+err_sco_in:
+    pcm_close(adev->pcm_sco_in);
+err_voice_in:
+    pcm_close(adev->pcm_voice_in);
+err_sco_out:
+    pcm_close(adev->pcm_sco_out);
+err_voice_out:
+    pcm_close(adev->pcm_voice_out);
+}
+
+/* must be called with the hw device mutex locked, OK to hold other mutexes */
+static void stop_bt_sco(struct audio_device *adev) {
+    pcm_stop(adev->pcm_voice_out);
+    pcm_stop(adev->pcm_sco_out);
+    pcm_stop(adev->pcm_voice_in);
+    pcm_stop(adev->pcm_sco_in);
+
+    pcm_close(adev->pcm_voice_out);
+    pcm_close(adev->pcm_sco_out);
+    pcm_close(adev->pcm_voice_in);
+    pcm_close(adev->pcm_sco_in);
+}
 
 static size_t get_input_buffer_size(unsigned int sample_rate,
                                     audio_format_t format,
@@ -613,6 +684,15 @@
                 do_out_standby(out);
             }
 
+            /* Start/stop the BT SCO stream */
+            if ((val & AUDIO_DEVICE_OUT_ALL_SCO) ^
+                (adev->out_device & AUDIO_DEVICE_OUT_ALL_SCO)) {
+                if (val & AUDIO_DEVICE_OUT_ALL_SCO)
+                    start_bt_sco(adev);
+                else
+                    stop_bt_sco(adev);
+            }
+
             out->device = val;
             if (!out->standby) {
                 adev->out_device = out->device;
diff --git a/mixer_paths.xml b/mixer_paths.xml
index c7c16fd..57da918 100644
--- a/mixer_paths.xml
+++ b/mixer_paths.xml
@@ -3,6 +3,7 @@
   <ctl name="DAC1R Mixer AIF1.1 Switch" value="0" />
   <ctl name="DAC1L Mixer AIF1.1 Switch" value="0" />
   <ctl name="DAC1 Switch" value="0" />
+  <ctl name="DAC2 Switch" value="0" />
   <ctl name="AIF1DRC1 Mode" value="Default" />
   <ctl name="AIF1DAC1 DRC Switch" value="0" />
 
@@ -39,8 +40,15 @@
 
   <ctl name="AIF2DACL Mux" value="AIF3" />
   <ctl name="AIF2DACR Mux" value="AIF3" />
-  <ctl name="AIF3ADC Mux" value="Mono PCM" />
-  <ctl name="Mono PCM Out Mux" value="AIF2ADCL" />
+  <ctl name="AIF2DAC Mux" value="AIF3DACDAT" />
+  <ctl name="AIF3ADC Mux" value="AIF2ADCDAT" />
+
+  <ctl name="AIF1ADC1L Mixer AIF2 Switch" value="0" />
+  <ctl name="AIF1ADC1R Mixer AIF2 Switch" value="0" />
+  <ctl name="AIF1ADC2L Mixer AIF2 Switch" value="0" />
+  <ctl name="AIF1ADC2R Mixer AIF2 Switch" value="0" />
+  <ctl name="AIF1ADC1L Mixer ADC/DMIC Switch" value="0" />
+  <ctl name="AIF1ADC1R Mixer ADC/DMIC Switch" value="0" />
 
   <!-- These are commonly used control sequences -->
   <path name="dac1">
@@ -49,6 +57,12 @@
     <ctl name="DAC1 Switch" value="1" />
   </path>
 
+  <path name="dac2">
+    <ctl name="AIF2DAC2L Mixer AIF1.1 Switch" value="1" />
+    <ctl name="AIF2DAC2R Mixer AIF1.1 Switch" value="1" />
+    <ctl name="DAC2 Switch" value="1" />
+  </path>
+
   <path name="eq-speaker">
     <ctl name="AIF1DAC1 EQ Switch" value="1" />
     <ctl name="AIF1DAC1 EQ1 Volume" value="3" />
@@ -87,15 +101,13 @@
   <path name="adc-to-aif1adc">
     <ctl name="AIF1ADC1L Mixer ADC/DMIC Switch" value="1" />
     <ctl name="AIF1ADC1R Mixer ADC/DMIC Switch" value="1" />
-    <ctl name="AIF1ADC1L Mixer AIF2 Switch" value="0" />
-    <ctl name="AIF1ADC1R Mixer AIF2 Switch" value="0" />
   </path>
 
   <path name="aif2-to-aif1adc">
-    <ctl name="AIF1ADC1L Mixer ADC/DMIC Switch" value="0" />
-    <ctl name="AIF1ADC1R Mixer ADC/DMIC Switch" value="0" />
     <ctl name="AIF1ADC1L Mixer AIF2 Switch" value="1" />
     <ctl name="AIF1ADC1R Mixer AIF2 Switch" value="1" />
+    <ctl name="AIF1ADC2L Mixer AIF2 Switch" value="1" />
+    <ctl name="AIF1ADC2R Mixer AIF2 Switch" value="1" />
   </path>
 
   <path name="main-mic">
@@ -189,8 +201,7 @@
   </path>
 
   <path name="bt-sco-headset">
-    <ctl name="AIF2DAC2L Mixer AIF1.1 Switch" value="1" />
-    <ctl name="AIF2DAC2R Mixer AIF1.1 Switch" value="1" />
+    <path name="dac2" />
   </path>
 
   <!-- Capture paths -->
@@ -233,6 +244,10 @@
     <ctl name="AIF1ADC1 HPF Mode" value="HiFi" />
   </path>
 
+  <path name="bt-sco-mic">
+    <path name="aif2-to-aif1adc" />
+  </path>
+
   <!-- TODO headset paths not properly configured yet -->
   <path name="voice-rec-headset-mic">
     <path name="headset-mic" />
@@ -246,8 +261,4 @@
     <ctl name="AIF1ADC1 HPF Mode" value="Voice 1" />
   </path>
 
-  <path name="bt-sco-mic">
-    <path name="aif2-to-aif1adc" />
-  </path>
-
 </mixer>