Merge "hal: Add support for parsing hdmi edid information"
diff --git a/hal/Android.mk b/hal/Android.mk
index 1af245a..ec47740 100644
--- a/hal/Android.mk
+++ b/hal/Android.mk
@@ -46,6 +46,10 @@
LOCAL_C_INCLUDES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include
LOCAL_ADDITIONAL_DEPENDENCIES += $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr
+ifneq ($(filter msm8994 ,$(TARGET_BOARD_PLATFORM)),)
+ LOCAL_SRC_FILES += edid.c
+endif
+
ifeq ($(strip $(AUDIO_FEATURE_ENABLED_PCM_OFFLOAD)),true)
LOCAL_CFLAGS += -DPCM_OFFLOAD_ENABLED
endif
diff --git a/hal/audio_extn/audio_extn.c b/hal/audio_extn/audio_extn.c
index 5ab7018..3cb18f5 100644
--- a/hal/audio_extn/audio_extn.c
+++ b/hal/audio_extn/audio_extn.c
@@ -30,6 +30,7 @@
#include "audio_extn.h"
#include "platform.h"
#include "platform_api.h"
+#include "edid.h"
#define MAX_SLEEP_RETRY 100
#define WIFI_INIT_WAIT_SLEEP 50
@@ -235,30 +236,6 @@
#define audio_extn_set_afe_proxy_parameters(adev, parms) (0)
#define audio_extn_get_afe_proxy_parameters(query, reply) (0)
#else
-/* Front left channel. */
-#define PCM_CHANNEL_FL 1
-
-/* Front right channel. */
-#define PCM_CHANNEL_FR 2
-
-/* Front center channel. */
-#define PCM_CHANNEL_FC 3
-
-/* Left surround channel.*/
-#define PCM_CHANNEL_LS 4
-
-/* Right surround channel.*/
-#define PCM_CHANNEL_RS 5
-
-/* Low frequency effect channel. */
-#define PCM_CHANNEL_LFE 6
-
-/* Left back channel; Rear left channel. */
-#define PCM_CHANNEL_LB 8
-
-/* Right back channel; Rear right channel. */
-#define PCM_CHANNEL_RB 9
-
static int32_t afe_proxy_set_channel_mapping(struct audio_device *adev,
int channel_count)
{
diff --git a/hal/audio_extn/audio_extn.h b/hal/audio_extn/audio_extn.h
index 02add40..05c5e84 100644
--- a/hal/audio_extn/audio_extn.h
+++ b/hal/audio_extn/audio_extn.h
@@ -354,7 +354,7 @@
typedef enum {
DAP_STATE_ON = 0,
DAP_STATE_BYPASS,
-};
+} dap_state;
#ifndef AUDIO_FORMAT_E_AC3_JOC
#define AUDIO_FORMAT_E_AC3_JOC 0x19000000UL
#endif
diff --git a/hal/audio_hw.c b/hal/audio_hw.c
index 4e33dfb..3dea397 100644
--- a/hal/audio_hw.c
+++ b/hal/audio_hw.c
@@ -206,7 +206,11 @@
static const struct string_to_enum out_channels_name_to_enum_table[] = {
STRING_TO_ENUM(AUDIO_CHANNEL_OUT_STEREO),
- STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1),
+ STRING_TO_ENUM(AUDIO_CHANNEL_OUT_QUAD),/* QUAD_BACK is same as QUAD */
+ STRING_TO_ENUM(AUDIO_CHANNEL_OUT_QUAD_SIDE),
+ STRING_TO_ENUM(AUDIO_CHANNEL_OUT_PENTA),
+ STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1), /* 5POINT1_BACK is same as 5POINT1 */
+ STRING_TO_ENUM(AUDIO_CHANNEL_OUT_5POINT1_SIDE),
STRING_TO_ENUM(AUDIO_CHANNEL_OUT_7POINT1),
};
@@ -677,7 +681,7 @@
/* must be called with hw device mutex locked */
static int read_hdmi_channel_masks(struct stream_out *out)
{
- int ret = 0;
+ int ret = 0, i = 0;
int channels = platform_edid_get_max_channels(out->dev->platform);
switch (channels) {
@@ -686,13 +690,21 @@
* Stereo case is handled in normal playback path
*/
case 6:
- ALOGV("%s: HDMI supports 5.1", __func__);
- out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1;
+ ALOGV("%s: HDMI supports Quad and 5.1", __func__);
+ out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_QUAD;
+ out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_QUAD_SIDE;
+ out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_PENTA;
+ out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_5POINT1;
+ out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_5POINT1_SIDE;
break;
case 8:
- ALOGV("%s: HDMI supports 5.1 and 7.1 channels", __func__);
- out->supported_channel_masks[0] = AUDIO_CHANNEL_OUT_5POINT1;
- out->supported_channel_masks[1] = AUDIO_CHANNEL_OUT_7POINT1;
+ ALOGV("%s: HDMI supports Quad, 5.1 and 7.1 channels", __func__);
+ out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_QUAD;
+ out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_QUAD_SIDE;
+ out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_PENTA;
+ out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_5POINT1;
+ out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_5POINT1_SIDE;
+ out->supported_channel_masks[i++] = AUDIO_CHANNEL_OUT_7POINT1;
break;
default:
ALOGE("HDMI does not support multi channel playback");
@@ -1278,16 +1290,24 @@
struct listnode *node;
struct audio_usecase *usecase;
+ unsigned int supported_channels = platform_edid_get_max_channels(
+ adev->platform);
+ ALOGV("supported_channels %d, channels %d", supported_channels, channels);
/* Check if change in HDMI channel config is allowed */
if (!allow_hdmi_channel_config(adev))
return 0;
+ if (channels > supported_channels)
+ channels = supported_channels;
+
if (channels == adev->cur_hdmi_channels) {
- ALOGD("%s: Requested channels are same as current channels(%d)", __func__, channels);
+ ALOGD("%s: Requested channels are same as current channels(%d)",
+ __func__, channels);
return 0;
}
platform_set_hdmi_channels(adev->platform, channels);
+ platform_set_edid_channels_configuration(adev->platform, channels);
adev->cur_hdmi_channels = channels;
/*
@@ -1408,7 +1428,8 @@
property_get("audio.use.hdmi.sink.cap", prop_value, NULL);
if (!strncmp("true", prop_value, 4)) {
sink_channels = platform_edid_get_max_channels(out->dev->platform);
- ALOGD("%s: set HDMI channel count[%d] based on sink capability", __func__, sink_channels);
+ ALOGD("%s: set HDMI channel count[%d] based on sink capability",
+ __func__, sink_channels);
check_and_set_hdmi_channels(adev, sink_channels);
} else {
if (is_offload_usecase(out->usecase))
@@ -1451,7 +1472,11 @@
}
break;
}
+ platform_set_stream_channel_map(adev->platform, out->channel_mask,
+ out->pcm_device_id);
} else {
+ platform_set_stream_channel_map(adev->platform, out->channel_mask,
+ out->pcm_device_id);
out->pcm = NULL;
out->compr = compress_open(adev->snd_card,
out->pcm_device_id,
@@ -2960,6 +2985,24 @@
adev->bt_wb_speech_enabled = false;
}
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_CONNECT, value, sizeof(value));
+ if (ret >= 0) {
+ val = atoi(value);
+ if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+ ALOGV("cache new edid");
+ platform_cache_edid(adev->platform);
+ }
+ }
+
+ ret = str_parms_get_str(parms, AUDIO_PARAMETER_DEVICE_DISCONNECT, value, sizeof(value));
+ if (ret >= 0) {
+ val = atoi(value);
+ if (val & AUDIO_DEVICE_OUT_AUX_DIGITAL) {
+ ALOGV("invalidate cached edid");
+ platform_invalidate_edid(adev->platform);
+ }
+ }
+
audio_extn_set_parameters(adev, parms);
done:
diff --git a/hal/audio_hw.h b/hal/audio_hw.h
index d05f743..77f1d37 100644
--- a/hal/audio_hw.h
+++ b/hal/audio_hw.h
@@ -47,7 +47,7 @@
#define ACDB_DEV_TYPE_OUT 1
#define ACDB_DEV_TYPE_IN 2
-#define MAX_SUPPORTED_CHANNEL_MASKS 2
+#define MAX_SUPPORTED_CHANNEL_MASKS 8
#define DEFAULT_HDMI_OUT_CHANNELS 2
#define SND_CARD_STATE_OFFLINE 0
diff --git a/hal/edid.c b/hal/edid.c
new file mode 100644
index 0000000..9b05950
--- /dev/null
+++ b/hal/edid.c
@@ -0,0 +1,687 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "audio_hw_edid"
+/*#define LOG_NDEBUG 0*/
+/*#define LOG_NDDEBUG 0*/
+
+#include <errno.h>
+#include <cutils/properties.h>
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <cutils/str_parms.h>
+#include <cutils/log.h>
+
+#include "audio_hw.h"
+#include "platform.h"
+#include "platform_api.h"
+#include "edid.h"
+
+static const char * edid_format_to_str(unsigned char format)
+{
+ char * format_str = "??";
+
+ switch (format) {
+ case LPCM:
+ format_str = "Format:LPCM";
+ break;
+ case AC3:
+ format_str = "Format:AC-3";
+ break;
+ case MPEG1:
+ format_str = "Format:MPEG1 (Layers 1 & 2)";
+ break;
+ case MP3:
+ format_str = "Format:MP3 (MPEG1 Layer 3)";
+ break;
+ case MPEG2_MULTI_CHANNEL:
+ format_str = "Format:MPEG2 (multichannel)";
+ break;
+ case AAC:
+ format_str = "Format:AAC";
+ break;
+ case DTS:
+ format_str = "Format:DTS";
+ break;
+ case ATRAC:
+ format_str = "Format:ATRAC";
+ break;
+ case SACD:
+ format_str = "Format:One-bit audio aka SACD";
+ break;
+ case DOLBY_DIGITAL_PLUS:
+ format_str = "Format:Dolby Digital +";
+ break;
+ case DTS_HD:
+ format_str = "Format:DTS-HD";
+ break;
+ case MAT:
+ format_str = "Format:MAT (MLP)";
+ break;
+ case DST:
+ format_str = "Format:DST";
+ break;
+ case WMA_PRO:
+ format_str = "Format:WMA Pro";
+ break;
+ default:
+ break;
+ }
+ return format_str;
+}
+
+static int get_edid_sf(unsigned char byte)
+{
+ int nfreq = 0;
+
+ if (byte & BIT(6)) {
+ ALOGV("192kHz");
+ nfreq = 192000;
+ } else if (byte & BIT(5)) {
+ ALOGV("176kHz");
+ nfreq = 176000;
+ } else if (byte & BIT(4)) {
+ ALOGV("96kHz");
+ nfreq = 96000;
+ } else if (byte & BIT(3)) {
+ ALOGV("88.2kHz");
+ nfreq = 88200;
+ } else if (byte & BIT(2)) {
+ ALOGV("48kHz");
+ nfreq = 48000;
+ } else if (byte & BIT(1)) {
+ ALOGV("44.1kHz");
+ nfreq = 44100;
+ } else if (byte & BIT(0)) {
+ ALOGV("32kHz");
+ nfreq = 32000;
+ }
+ return nfreq;
+}
+
+static int get_edid_bps(unsigned char byte,
+ unsigned char format)
+{
+ int bits_per_sample = 0;
+ if (format == 1) {
+ if (byte & BIT(2)) {
+ ALOGV("24bit");
+ bits_per_sample = 24;
+ } else if (byte & BIT(1)) {
+ ALOGV("20bit");
+ bits_per_sample = 20;
+ } else if (byte & BIT(0)) {
+ ALOGV("16bit");
+ bits_per_sample = 16;
+ }
+ } else {
+ ALOGV("not lpcm format, return 0");
+ return 0;
+ }
+ return bits_per_sample;
+}
+
+static void update_channel_map(edid_audio_info* info)
+{
+ /* HDMI Cable follows CEA standard so SAD is received in CEA
+ * Input source file channel map is fed to ASM in WAV standard(audio.h)
+ * so upto 7.1 SAD bits are:
+ * in CEA convention: RLC/RRC,FLC/FRC,RC,RL/RR,FC,LFE,FL/FR
+ * in WAV convention: BL/BR,FLC/FRC,BC,SL/SR,FC,LFE,FL/FR
+ * Corresponding ADSP IDs (apr-audio_v2.h):
+ * PCM_CHANNEL_FL/PCM_CHANNEL_FR,
+ * PCM_CHANNEL_LFE,
+ * PCM_CHANNEL_FC,
+ * PCM_CHANNEL_LS/PCM_CHANNEL_RS,
+ * PCM_CHANNEL_CS,
+ * PCM_CHANNEL_FLC/PCM_CHANNEL_FRC
+ * PCM_CHANNEL_LB/PCM_CHANNEL_RB
+ */
+ if (!info)
+ return;
+ memset(info->channel_map, 0, MAX_CHANNELS_SUPPORTED);
+ if(info->speaker_allocation[0] & BIT(0)) {
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ }
+ if(info->speaker_allocation[0] & BIT(1)) {
+ info->channel_map[2] = PCM_CHANNEL_LFE;
+ }
+ if(info->speaker_allocation[0] & BIT(2)) {
+ info->channel_map[3] = PCM_CHANNEL_FC;
+ }
+ if(info->speaker_allocation[0] & BIT(3)) {
+ /*
+ * As per CEA(HDMI Cable) standard Bit 3 is equivalent
+ * to SideLeft/SideRight of WAV standard
+ */
+ info->channel_map[4] = PCM_CHANNEL_LS;
+ info->channel_map[5] = PCM_CHANNEL_RS;
+ }
+ if(info->speaker_allocation[0] & BIT(4)) {
+ if(info->speaker_allocation[0] & BIT(3)) {
+ info->channel_map[6] = PCM_CHANNEL_CS;
+ info->channel_map[7] = 0;
+ } else if (info->speaker_allocation[1] & BIT(1)) {
+ info->channel_map[6] = PCM_CHANNEL_CS;
+ info->channel_map[7] = PCM_CHANNEL_TS;
+ } else if (info->speaker_allocation[1] & BIT(2)) {
+ info->channel_map[6] = PCM_CHANNEL_CS;
+ info->channel_map[7] = PCM_CHANNEL_CVH;
+ } else {
+ info->channel_map[4] = PCM_CHANNEL_CS;
+ info->channel_map[5] = 0;
+ }
+ }
+ if(info->speaker_allocation[0] & BIT(5)) {
+ info->channel_map[6] = PCM_CHANNEL_FLC;
+ info->channel_map[7] = PCM_CHANNEL_FRC;
+ }
+ if(info->speaker_allocation[0] & BIT(6)) {
+ // If RLC/RRC is present, RC is invalid as per specification
+ info->speaker_allocation[0] &= 0xef;
+ /*
+ * As per CEA(HDMI Cable) standard Bit 6 is equivalent
+ * to BackLeft/BackRight of WAV standard
+ */
+ info->channel_map[6] = PCM_CHANNEL_LB;
+ info->channel_map[7] = PCM_CHANNEL_RB;
+ }
+ // higher channel are not defined by LPASS
+ //info->nSpeakerAllocation[0] &= 0x3f;
+ if(info->speaker_allocation[0] & BIT(7)) {
+ info->channel_map[6] = 0; // PCM_CHANNEL_FLW; but not defined by LPASS
+ info->channel_map[7] = 0; // PCM_CHANNEL_FRW; but not defined by LPASS
+ }
+ if(info->speaker_allocation[1] & BIT(0)) {
+ info->channel_map[6] = 0; // PCM_CHANNEL_FLH; but not defined by LPASS
+ info->channel_map[7] = 0; // PCM_CHANNEL_FRH; but not defined by LPASS
+ }
+
+ ALOGI("%s channel map updated to [%d %d %d %d %d %d %d %d ] [%x %x %x]", __func__
+ , info->channel_map[0], info->channel_map[1], info->channel_map[2]
+ , info->channel_map[3], info->channel_map[4], info->channel_map[5]
+ , info->channel_map[6], info->channel_map[7]
+ , info->speaker_allocation[0], info->speaker_allocation[1]
+ , info->speaker_allocation[2]);
+}
+
+static void dump_speaker_allocation(edid_audio_info* info)
+{
+ if (!info)
+ return;
+
+ if (info->speaker_allocation[0] & BIT(7))
+ ALOGV("FLW/FRW");
+ if (info->speaker_allocation[0] & BIT(6))
+ ALOGV("RLC/RRC");
+ if (info->speaker_allocation[0] & BIT(5))
+ ALOGV("FLC/FRC");
+ if (info->speaker_allocation[0] & BIT(4))
+ ALOGV("RC");
+ if (info->speaker_allocation[0] & BIT(3))
+ ALOGV("RL/RR");
+ if (info->speaker_allocation[0] & BIT(2))
+ ALOGV("FC");
+ if (info->speaker_allocation[0] & BIT(1))
+ ALOGV("LFE");
+ if (info->speaker_allocation[0] & BIT(0))
+ ALOGV("FL/FR");
+ if (info->speaker_allocation[1] & BIT(2))
+ ALOGV("FCH");
+ if (info->speaker_allocation[1] & BIT(1))
+ ALOGV("TC");
+ if (info->speaker_allocation[1] & BIT(0))
+ ALOGV("FLH/FRH");
+}
+
+static void update_channel_allocation(edid_audio_info* info)
+{
+ int16_t ca;
+ int16_t spkr_alloc;
+
+ if (!info)
+ return;
+
+ /* Most common 5.1 SAD is 0xF, ca 0x0b
+ * and 7.1 SAD is 0x4F, ca 0x13 */
+ spkr_alloc = ((info->speaker_allocation[1]) << 8) |
+ (info->speaker_allocation[0]);
+ ALOGV("info->nSpeakerAllocation %x %x\n", info->speaker_allocation[0],
+ info->speaker_allocation[1]);
+ ALOGV("spkr_alloc: %x", spkr_alloc);
+
+ /* The below switch case calculates channel allocation values
+ as defined in CEA-861 section 6.6.2 */
+ switch (spkr_alloc) {
+ case BIT(0): ca = 0x00; break;
+ case BIT(0)|BIT(1): ca = 0x01; break;
+ case BIT(0)|BIT(2): ca = 0x02; break;
+ case BIT(0)|BIT(1)|BIT(2): ca = 0x03; break;
+ case BIT(0)|BIT(4): ca = 0x04; break;
+ case BIT(0)|BIT(1)|BIT(4): ca = 0x05; break;
+ case BIT(0)|BIT(2)|BIT(4): ca = 0x06; break;
+ case BIT(0)|BIT(1)|BIT(2)|BIT(4): ca = 0x07; break;
+ case BIT(0)|BIT(3): ca = 0x08; break;
+ case BIT(0)|BIT(1)|BIT(3): ca = 0x09; break;
+ case BIT(0)|BIT(2)|BIT(3): ca = 0x0A; break;
+ case BIT(0)|BIT(1)|BIT(2)|BIT(3): ca = 0x0B; break;
+ case BIT(0)|BIT(3)|BIT(4): ca = 0x0C; break;
+ case BIT(0)|BIT(1)|BIT(3)|BIT(4): ca = 0x0D; break;
+ case BIT(0)|BIT(2)|BIT(3)|BIT(4): ca = 0x0E; break;
+ case BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(4): ca = 0x0F; break;
+ case BIT(0)|BIT(3)|BIT(6): ca = 0x10; break;
+ case BIT(0)|BIT(1)|BIT(3)|BIT(6): ca = 0x11; break;
+ case BIT(0)|BIT(2)|BIT(3)|BIT(6): ca = 0x12; break;
+ case BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(6): ca = 0x13; break;
+ case BIT(0)|BIT(5): ca = 0x14; break;
+ case BIT(0)|BIT(1)|BIT(5): ca = 0x15; break;
+ case BIT(0)|BIT(2)|BIT(5): ca = 0x16; break;
+ case BIT(0)|BIT(1)|BIT(2)|BIT(5): ca = 0x17; break;
+ case BIT(0)|BIT(4)|BIT(5): ca = 0x18; break;
+ case BIT(0)|BIT(1)|BIT(4)|BIT(5): ca = 0x19; break;
+ case BIT(0)|BIT(2)|BIT(4)|BIT(5): ca = 0x1A; break;
+ case BIT(0)|BIT(1)|BIT(2)|BIT(4)|BIT(5): ca = 0x1B; break;
+ case BIT(0)|BIT(3)|BIT(5): ca = 0x1C; break;
+ case BIT(0)|BIT(1)|BIT(3)|BIT(5): ca = 0x1D; break;
+ case BIT(0)|BIT(2)|BIT(3)|BIT(5): ca = 0x1E; break;
+ case BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(5): ca = 0x1F; break;
+ case BIT(0)|BIT(2)|BIT(3)|BIT(10): ca = 0x20; break;
+ case BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(10): ca = 0x21; break;
+ case BIT(0)|BIT(2)|BIT(3)|BIT(9): ca = 0x22; break;
+ case BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(9): ca = 0x23; break;
+ case BIT(0)|BIT(3)|BIT(8): ca = 0x24; break;
+ case BIT(0)|BIT(1)|BIT(3)|BIT(8): ca = 0x25; break;
+ case BIT(0)|BIT(3)|BIT(7): ca = 0x26; break;
+ case BIT(0)|BIT(1)|BIT(3)|BIT(7): ca = 0x27; break;
+ case BIT(0)|BIT(2)|BIT(3)|BIT(4)|BIT(9): ca = 0x28; break;
+ case BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(4)|BIT(9): ca = 0x29; break;
+ case BIT(0)|BIT(2)|BIT(3)|BIT(4)|BIT(10): ca = 0x2A; break;
+ case BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(4)|BIT(10): ca = 0x2B; break;
+ case BIT(0)|BIT(2)|BIT(3)|BIT(9)|BIT(10): ca = 0x2C; break;
+ case BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(9)|BIT(10): ca = 0x2D; break;
+ case BIT(0)|BIT(2)|BIT(3)|BIT(8): ca = 0x2E; break;
+ case BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(8): ca = 0x2F; break;
+ case BIT(0)|BIT(2)|BIT(3)|BIT(7): ca = 0x30; break;
+ case BIT(0)|BIT(1)|BIT(2)|BIT(3)|BIT(7): ca = 0x31; break;
+ default: ca = 0x0; break;
+ }
+ ALOGD("%s channel allocation: %x", __func__, ca);
+ info->channel_allocation = ca;
+}
+
+static void update_channel_map_lpass(edid_audio_info* info)
+{
+ if (!info)
+ return;
+ if (info->channel_allocation < 0 || info->channel_allocation > 0x1f) {
+ ALOGE("Channel allocation out of supported range");
+ return;
+ }
+ ALOGV("channel_allocation 0x%x", info->channel_allocation);
+ memset(info->channel_map, 0, MAX_CHANNELS_SUPPORTED);
+ switch(info->channel_allocation) {
+ case 0x0:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ break;
+ case 0x1:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_LFE;
+ break;
+ case 0x2:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_FC;
+ break;
+ case 0x3:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_LFE;
+ info->channel_map[3] = PCM_CHANNEL_FC;
+ break;
+ case 0x4:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_CS;
+ break;
+ case 0x5:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_LFE;
+ info->channel_map[3] = PCM_CHANNEL_CS;
+ break;
+ case 0x6:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_FC;
+ info->channel_map[3] = PCM_CHANNEL_CS;
+ break;
+ case 0x7:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_LFE;
+ info->channel_map[3] = PCM_CHANNEL_FC;
+ info->channel_map[4] = PCM_CHANNEL_CS;
+ break;
+ case 0x8:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_LS;
+ info->channel_map[3] = PCM_CHANNEL_RS;
+ break;
+ case 0x9:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_LFE;
+ info->channel_map[3] = PCM_CHANNEL_LS;
+ info->channel_map[4] = PCM_CHANNEL_RS;
+ break;
+ case 0xa:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_FC;
+ info->channel_map[3] = PCM_CHANNEL_LS;
+ info->channel_map[4] = PCM_CHANNEL_RS;
+ break;
+ case 0xb:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_LFE;
+ info->channel_map[3] = PCM_CHANNEL_FC;
+ info->channel_map[4] = PCM_CHANNEL_LS;
+ info->channel_map[5] = PCM_CHANNEL_RS;
+ break;
+ case 0xc:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_LS;
+ info->channel_map[3] = PCM_CHANNEL_RS;
+ info->channel_map[4] = PCM_CHANNEL_CS;
+ break;
+ case 0xd:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_LFE;
+ info->channel_map[3] = PCM_CHANNEL_LS;
+ info->channel_map[4] = PCM_CHANNEL_RS;
+ info->channel_map[5] = PCM_CHANNEL_CS;
+ break;
+ case 0xe:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_FC;
+ info->channel_map[3] = PCM_CHANNEL_LS;
+ info->channel_map[4] = PCM_CHANNEL_RS;
+ info->channel_map[5] = PCM_CHANNEL_CS;
+ break;
+ case 0xf:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_LFE;
+ info->channel_map[3] = PCM_CHANNEL_FC;
+ info->channel_map[4] = PCM_CHANNEL_LS;
+ info->channel_map[5] = PCM_CHANNEL_RS;
+ info->channel_map[6] = PCM_CHANNEL_CS;
+ break;
+ case 0x10:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_LS;
+ info->channel_map[3] = PCM_CHANNEL_RS;
+ info->channel_map[4] = PCM_CHANNEL_LB;
+ info->channel_map[5] = PCM_CHANNEL_RB;
+ break;
+ case 0x11:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_LFE;
+ info->channel_map[3] = PCM_CHANNEL_LS;
+ info->channel_map[4] = PCM_CHANNEL_RS;
+ info->channel_map[5] = PCM_CHANNEL_LB;
+ info->channel_map[6] = PCM_CHANNEL_RB;
+ break;
+ case 0x12:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_FC;
+ info->channel_map[3] = PCM_CHANNEL_LS;
+ info->channel_map[4] = PCM_CHANNEL_RS;
+ info->channel_map[5] = PCM_CHANNEL_LB;
+ info->channel_map[6] = PCM_CHANNEL_RB;
+ break;
+ case 0x13:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_LFE;
+ info->channel_map[3] = PCM_CHANNEL_FC;
+ info->channel_map[4] = PCM_CHANNEL_LS;
+ info->channel_map[5] = PCM_CHANNEL_RS;
+ info->channel_map[6] = PCM_CHANNEL_LB;
+ info->channel_map[7] = PCM_CHANNEL_RB;
+ break;
+ case 0x14:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_FLC;
+ info->channel_map[3] = PCM_CHANNEL_FRC;
+ break;
+ case 0x15:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_LFE;
+ info->channel_map[3] = PCM_CHANNEL_FLC;
+ info->channel_map[4] = PCM_CHANNEL_FRC;
+ break;
+ case 0x16:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_FC;
+ info->channel_map[3] = PCM_CHANNEL_FLC;
+ info->channel_map[4] = PCM_CHANNEL_FRC;
+ break;
+ case 0x17:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_LFE;
+ info->channel_map[3] = PCM_CHANNEL_FC;
+ info->channel_map[4] = PCM_CHANNEL_FLC;
+ info->channel_map[5] = PCM_CHANNEL_FRC;
+ break;
+ case 0x18:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_CS;
+ info->channel_map[3] = PCM_CHANNEL_FLC;
+ info->channel_map[4] = PCM_CHANNEL_FRC;
+ break;
+ case 0x19:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_LFE;
+ info->channel_map[3] = PCM_CHANNEL_CS;
+ info->channel_map[4] = PCM_CHANNEL_FLC;
+ info->channel_map[5] = PCM_CHANNEL_FRC;
+ break;
+ case 0x1a:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_FC;
+ info->channel_map[3] = PCM_CHANNEL_CS;
+ info->channel_map[4] = PCM_CHANNEL_FLC;
+ info->channel_map[5] = PCM_CHANNEL_FRC;
+ break;
+ case 0x1b:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_LFE;
+ info->channel_map[3] = PCM_CHANNEL_FC;
+ info->channel_map[4] = PCM_CHANNEL_CS;
+ info->channel_map[5] = PCM_CHANNEL_FLC;
+ info->channel_map[6] = PCM_CHANNEL_FRC;
+ break;
+ case 0x1c:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_LS;
+ info->channel_map[3] = PCM_CHANNEL_RS;
+ info->channel_map[4] = PCM_CHANNEL_FLC;
+ info->channel_map[5] = PCM_CHANNEL_FRC;
+ break;
+ case 0x1d:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_LFE;
+ info->channel_map[3] = PCM_CHANNEL_LS;
+ info->channel_map[4] = PCM_CHANNEL_RS;
+ info->channel_map[5] = PCM_CHANNEL_FLC;
+ info->channel_map[6] = PCM_CHANNEL_FRC;
+ break;
+ case 0x1e:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_FC;
+ info->channel_map[3] = PCM_CHANNEL_LS;
+ info->channel_map[4] = PCM_CHANNEL_RS;
+ info->channel_map[5] = PCM_CHANNEL_FLC;
+ info->channel_map[6] = PCM_CHANNEL_FRC;
+ break;
+ case 0x1f:
+ info->channel_map[0] = PCM_CHANNEL_FL;
+ info->channel_map[1] = PCM_CHANNEL_FR;
+ info->channel_map[2] = PCM_CHANNEL_LFE;
+ info->channel_map[3] = PCM_CHANNEL_FC;
+ info->channel_map[4] = PCM_CHANNEL_LS;
+ info->channel_map[5] = PCM_CHANNEL_RS;
+ info->channel_map[6] = PCM_CHANNEL_FLC;
+ info->channel_map[7] = PCM_CHANNEL_FRC;
+ break;
+ default:
+ break;
+ }
+ ALOGD("%s channel map updated to [%d %d %d %d %d %d %d %d ]", __func__
+ , info->channel_map[0], info->channel_map[1], info->channel_map[2]
+ , info->channel_map[3], info->channel_map[4], info->channel_map[5]
+ , info->channel_map[6], info->channel_map[7]);
+}
+
+static void dump_edid_data(edid_audio_info *info)
+{
+
+ int i;
+ for (i = 0; i < info->audio_blocks && i < MAX_EDID_BLOCKS; i++) {
+ ALOGV("%s:FormatId:%d rate:%d bps:%d channels:%d", __func__,
+ info->audio_blocks_array[i].format_id,
+ info->audio_blocks_array[i].sampling_freq,
+ info->audio_blocks_array[i].bits_per_sample,
+ info->audio_blocks_array[i].channels);
+ }
+ ALOGV("%s:no of audio blocks:%d", __func__, info->audio_blocks);
+ ALOGV("%s:speaker allocation:[%x %x %x]", __func__,
+ info->speaker_allocation[0], info->speaker_allocation[1],
+ info->speaker_allocation[2]);
+ ALOGV("%s:channel map:[%x %x %x %x %x %x %x %x]", __func__,
+ info->channel_map[0], info->channel_map[1],
+ info->channel_map[2], info->channel_map[3],
+ info->channel_map[4], info->channel_map[5],
+ info->channel_map[6], info->channel_map[7]);
+ ALOGV("%s:channel allocation:%d", __func__, info->channel_allocation);
+ ALOGV("%s:[%d %d %d %d %d %d %d %d ]", __func__,
+ info->channel_map[0], info->channel_map[1],
+ info->channel_map[2], info->channel_map[3],
+ info->channel_map[4], info->channel_map[5],
+ info->channel_map[6], info->channel_map[7]);
+}
+
+bool edid_get_sink_caps(edid_audio_info* info, char *edid_data)
+{
+ unsigned char channels[MAX_EDID_BLOCKS];
+ unsigned char formats[MAX_EDID_BLOCKS];
+ unsigned char frequency[MAX_EDID_BLOCKS];
+ unsigned char bitrate[MAX_EDID_BLOCKS];
+ int i = 0;
+ int length, count_desc;
+
+ if (!info || !edid_data) {
+ ALOGE("No valid EDID");
+ return false;
+ }
+
+ length = (int) *edid_data++;
+ ALOGV("Total length is %d",length);
+
+ count_desc = length/MIN_AUDIO_DESC_LENGTH;
+
+ if (!count_desc) {
+ ALOGE("insufficient descriptors");
+ return false;
+ }
+
+ memset(info, 0, sizeof(edid_audio_info));
+
+ info->audio_blocks = count_desc-1;
+ if (info->audio_blocks > MAX_EDID_BLOCKS) {
+ info->audio_blocks = MAX_EDID_BLOCKS;
+ }
+
+ ALOGV("Total # of audio descriptors %d",count_desc);
+
+ for (i=0; i<info->audio_blocks; i++) {
+ // last block for speaker allocation;
+ channels [i] = (*edid_data & 0x7) + 1;
+ formats [i] = (*edid_data++) >> 3;
+ frequency[i] = *edid_data++;
+ bitrate [i] = *edid_data++;
+ }
+ info->speaker_allocation[0] = *edid_data++;
+ info->speaker_allocation[1] = *edid_data++;
+ info->speaker_allocation[2] = *edid_data++;
+
+ update_channel_map(info);
+ update_channel_allocation(info);
+ update_channel_map_lpass(info);
+
+ for (i=0; i<info->audio_blocks; i++) {
+ ALOGV("AUDIO DESC BLOCK # %d\n",i);
+
+ info->audio_blocks_array[i].channels = channels[i];
+ ALOGV("info->audio_blocks_array[i].channels %d\n",
+ info->audio_blocks_array[i].channels);
+
+ ALOGV("Format Byte %d\n", formats[i]);
+ info->audio_blocks_array[i].format_id = (edid_audio_format_id)formats[i];
+ ALOGV("info->audio_blocks_array[i].format_id %s",
+ edid_format_to_str(formats[i]));
+
+ ALOGV("Frequency Byte %d\n", frequency[i]);
+ info->audio_blocks_array[i].sampling_freq = get_edid_sf(frequency[i]);
+ ALOGV("info->audio_blocks_array[i].sampling_freq %d",
+ info->audio_blocks_array[i].sampling_freq);
+
+ ALOGV("BitsPerSample Byte %d\n", bitrate[i]);
+ info->audio_blocks_array[i].bits_per_sample =
+ get_edid_bps(bitrate[i],formats[i]);
+ ALOGV("info->audio_blocks_array[i].bits_per_sample %d",
+ info->audio_blocks_array[i].bits_per_sample);
+ }
+ dump_speaker_allocation(info);
+ dump_edid_data(info);
+ return true;
+}
diff --git a/hal/edid.h b/hal/edid.h
new file mode 100644
index 0000000..ec83ec8
--- /dev/null
+++ b/hal/edid.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef EDID_H
+#define EDID_H
+
+/* HDMI EDID Information */
+#define BIT(nr) (1UL << (nr))
+#define MAX_EDID_BLOCKS 10
+#define MAX_SHORT_AUDIO_DESC_CNT 30
+#define MIN_AUDIO_DESC_LENGTH 3
+#define MIN_SPKR_ALLOCATION_DATA_LENGTH 3
+#define MAX_CHANNELS_SUPPORTED 8
+#define MAX_DISPLAY_DEVICES 3
+#define MAX_FRAME_BUFFER_NAME_SIZE 80
+#define MAX_CHAR_PER_INT 13
+
+#define PCM_CHANNEL_FL 1 /* Front left channel. */
+#define PCM_CHANNEL_FR 2 /* Front right channel. */
+#define PCM_CHANNEL_FC 3 /* Front center channel. */
+#define PCM_CHANNEL_LS 4 /* Left surround channel. */
+#define PCM_CHANNEL_RS 5 /* Right surround channel. */
+#define PCM_CHANNEL_LFE 6 /* Low frequency effect channel. */
+#define PCM_CHANNEL_CS 7 /* Center surround channel; Rear center channel. */
+#define PCM_CHANNEL_LB 8 /* Left back channel; Rear left channel. */
+#define PCM_CHANNEL_RB 9 /* Right back channel; Rear right channel. */
+#define PCM_CHANNEL_TS 10 /* Top surround channel. */
+#define PCM_CHANNEL_CVH 11 /* Center vertical height channel. */
+#define PCM_CHANNEL_MS 12 /* Mono surround channel. */
+#define PCM_CHANNEL_FLC 13 /* Front left of center. */
+#define PCM_CHANNEL_FRC 14 /* Front right of center. */
+#define PCM_CHANNEL_RLC 15 /* Rear left of center. */
+#define PCM_CHANNEL_RRC 16 /* Rear right of center. */
+
+#define MAX_HDMI_CHANNEL_CNT 8
+
+typedef enum edid_audio_format_id {
+ LPCM = 1,
+ AC3,
+ MPEG1,
+ MP3,
+ MPEG2_MULTI_CHANNEL,
+ AAC,
+ DTS,
+ ATRAC,
+ SACD,
+ DOLBY_DIGITAL_PLUS,
+ DTS_HD,
+ MAT,
+ DST,
+ WMA_PRO
+} edid_audio_format_id;
+
+typedef struct edid_audio_block_info {
+ edid_audio_format_id format_id;
+ int sampling_freq;
+ int bits_per_sample;
+ int channels;
+} edid_audio_block_info;
+
+typedef struct edid_audio_info {
+ int audio_blocks;
+ unsigned char speaker_allocation[MIN_SPKR_ALLOCATION_DATA_LENGTH];
+ edid_audio_block_info audio_blocks_array[MAX_EDID_BLOCKS];
+ char channel_map[MAX_CHANNELS_SUPPORTED];
+ int channel_allocation;
+} edid_audio_info;
+
+bool edid_get_sink_caps(edid_audio_info* info, char *edid_data);
+#endif /* EDID_H */
diff --git a/hal/msm8916/platform.c b/hal/msm8916/platform.c
index 43cc00a..a192f5c 100644
--- a/hal/msm8916/platform.c
+++ b/hal/msm8916/platform.c
@@ -1051,7 +1051,7 @@
else
get_cvd_version(cvd_version, adev);
- my_data->acdb_init(snd_card_name, cvd_version);
+ my_data->acdb_init((char *)snd_card_name, cvd_version);
if (cvd_version)
free(cvd_version);
}
@@ -1268,13 +1268,14 @@
return acdb_device_table[snd_device];
}
-int platform_set_snd_device_bit_width(snd_device_t snd_device, unsigned int bit_width)
+int platform_set_snd_device_bit_width(snd_device_t snd_device __unused,
+ unsigned int bit_width __unused)
{
ALOGE("%s: Not implemented", __func__);
return -ENOSYS;
}
-int platform_get_snd_device_bit_width(snd_device_t snd_device)
+int platform_get_snd_device_bit_width(snd_device_t snd_device __unused)
{
ALOGE("%s: Not implemented", __func__);
return -ENOSYS;
@@ -2608,3 +2609,34 @@
return -ENOSYS;
}
+int platform_get_edid_info(void *platform __unused)
+{
+ return -ENOSYS;
+}
+
+int platform_set_channel_map(void *platform __unused, int ch_count __unused,
+ char *ch_map __unused, int snd_id __unused)
+{
+ return -ENOSYS;
+}
+
+int platform_set_stream_channel_map(void *platform __unused,
+ audio_channel_mask_t channel_mask __unused,
+ int snd_id __unused)
+{
+ return -ENOSYS;
+}
+
+int platform_set_edid_channels_configuration(void *platform __unused,
+ int channels __unused)
+{
+ return 0;
+}
+
+void platform_cache_edid(void * platform __unused)
+{
+}
+
+void platform_invalidate_edid(void * platform __unused)
+{
+}
diff --git a/hal/msm8960/platform.c b/hal/msm8960/platform.c
index 941d39f..458593c 100644
--- a/hal/msm8960/platform.c
+++ b/hal/msm8960/platform.c
@@ -28,6 +28,7 @@
#include <audio_hw.h>
#include <platform_api.h>
#include "platform.h"
+#include "audio_extn.h"
#define LIB_ACDB_LOADER "libacdbloader.so"
#define LIB_CSD_CLIENT "libcsd-client.so"
@@ -421,13 +422,14 @@
return -ENOSYS;
}
-int platform_set_snd_device_bit_width(snd_device_t snd_device, unsigned int bit_width)
+int platform_set_snd_device_bit_width(snd_device_t snd_device __unused,
+ unsigned int bit_width __unused)
{
ALOGE("%s: Not implemented", __func__);
return -ENOSYS;
}
-int platform_get_snd_device_bit_width(snd_device_t snd_device)
+int platform_get_snd_device_bit_width(snd_device_t snd_device __unused)
{
ALOGE("%s: Not implemented", __func__);
return -ENOSYS;
@@ -1087,3 +1089,47 @@
{
return 0;
}
+
+int platform_get_edid_info(void *platform __unused)
+{
+ return -ENOSYS;
+}
+
+int platform_set_channel_map(void *platform __unused, int ch_count __unused,
+ char *ch_map __unused, int snd_id __unused)
+{
+ return -ENOSYS;
+}
+
+int platform_set_stream_channel_map(void *platform __unused,
+ audio_channel_mask_t channel_mask __unused,
+ int snd_id __unused)
+{
+ return -ENOSYS;
+}
+
+int platform_set_edid_channels_configuration(void *platform __unused,
+ int channels __unused)
+{
+ return 0;
+}
+
+unsigned char platform_map_to_edid_format(int format __unused)
+{
+ return 0;
+}
+bool platform_is_edid_supported_format(void *platform __unused,
+ int format __unused)
+{
+ return false;
+}
+
+void platform_cache_edid(void * platform __unused)
+{
+
+}
+
+void platform_invalidate_edid(void * platform __unused)
+{
+
+}
diff --git a/hal/msm8960/platform.h b/hal/msm8960/platform.h
index 950ea84..4b4d14e 100644
--- a/hal/msm8960/platform.h
+++ b/hal/msm8960/platform.h
@@ -145,4 +145,6 @@
#define AFE_PROXY_PLAYBACK_PCM_DEVICE 7
#define AFE_PROXY_RECORD_PCM_DEVICE 8
+#define DEVICE_NAME_MAX_SIZE 128
+
#endif // QCOM_AUDIO_PLATFORM_H
diff --git a/hal/msm8974/platform.c b/hal/msm8974/platform.c
index 6184e5e..1683d0a 100644
--- a/hal/msm8974/platform.c
+++ b/hal/msm8974/platform.c
@@ -20,6 +20,12 @@
#define LOG_TAG "msm8974_platform"
/*#define LOG_NDEBUG 0*/
#define LOG_NDDEBUG 0
+/*#define VERY_VERY_VERBOSE_LOGGING*/
+#ifdef VERY_VERY_VERBOSE_LOGGING
+#define ALOGVV ALOGV
+#else
+#define ALOGVV(a...) do { } while(0)
+#endif
#include <stdlib.h>
#include <dlfcn.h>
@@ -33,6 +39,7 @@
#include "platform.h"
#include "audio_extn.h"
#include "voice_extn.h"
+#include "edid.h"
#include "sound/compress_params.h"
#include "sound/msmcal-hwdep.h"
@@ -158,6 +165,8 @@
void *hw_info;
struct csd_data *csd;
+ void *edid_info;
+ bool edid_valid;
};
static int pcm_device_table[AUDIO_USECASE_MAX][2] = {
@@ -1013,6 +1022,7 @@
my_data->fluence_mode = FLUENCE_ENDFIRE;
my_data->slowtalk = false;
my_data->hd_voice = false;
+ my_data->edid_info = NULL;
property_get("ro.qc.sdk.audio.fluencetype", my_data->fluence_cap, "");
if (!strncmp("fluencepro", my_data->fluence_cap, sizeof("fluencepro"))) {
@@ -1167,6 +1177,11 @@
/* deinit audio device arbitration */
audio_extn_dev_arbi_deinit();
+ if (my_data->edid_info) {
+ free(my_data->edid_info);
+ my_data->edid_info = NULL;
+ }
+
free(platform);
/* deinit usb */
audio_extn_usb_deinit();
@@ -2149,56 +2164,28 @@
int platform_edid_get_max_channels(void *platform)
{
+ int channel_count;
+ int max_channels = 2;
+ int i = 0, ret = 0;
struct platform_data *my_data = (struct platform_data *)platform;
struct audio_device *adev = my_data->adev;
- char block[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE];
- char *sad = block;
- int num_audio_blocks;
- int channel_count;
- int max_channels = 0;
- int i, ret, count;
+ edid_audio_info *info = NULL;
+ ret = platform_get_edid_info(platform);
+ info = (edid_audio_info *)my_data->edid_info;
- struct mixer_ctl *ctl;
-
- ctl = mixer_get_ctl_by_name(adev->mixer, AUDIO_DATA_BLOCK_MIXER_CTL);
- if (!ctl) {
- ALOGE("%s: Could not get ctl for mixer cmd - %s",
- __func__, AUDIO_DATA_BLOCK_MIXER_CTL);
- return 0;
- }
-
- mixer_ctl_update(ctl);
-
- count = mixer_ctl_get_num_values(ctl);
-
- /* Read SAD blocks, clamping the maximum size for safety */
- if (count > (int)sizeof(block))
- count = (int)sizeof(block);
-
- ret = mixer_ctl_get_array(ctl, block, count);
- if (ret != 0) {
- ALOGE("%s: mixer_ctl_get_array() failed to get EDID info", __func__);
- return 0;
- }
-
- /* Calculate the number of SAD blocks */
- num_audio_blocks = count / SAD_BLOCK_SIZE;
-
- for (i = 0; i < num_audio_blocks; i++) {
- /* Only consider LPCM blocks */
- if ((sad[0] >> 3) != EDID_FORMAT_LPCM) {
- sad += 3;
- continue;
+ if(ret == 0 && info != NULL) {
+ for (i = 0; i < info->audio_blocks && i < MAX_EDID_BLOCKS; i++) {
+ ALOGV("%s:format %d channel %d", __func__,
+ info->audio_blocks_array[i].format_id,
+ info->audio_blocks_array[i].channels);
+ if (info->audio_blocks_array[i].format_id == LPCM) {
+ channel_count = info->audio_blocks_array[i].channels;
+ if (channel_count > max_channels) {
+ max_channels = channel_count;
+ }
+ }
}
-
- channel_count = (sad[0] & 0x7) + 1;
- if (channel_count > max_channels)
- max_channels = channel_count;
-
- /* Advance to next block */
- sad += 3;
}
-
return max_channels;
}
@@ -2855,3 +2842,335 @@
*device_to_be_id = msm_device_to_be_id;
*length = msm_be_id_array_len;
}
+
+int platform_set_stream_channel_map(void *platform, audio_channel_mask_t channel_mask, int snd_id)
+{
+ int ret = 0;
+ int channels = audio_channel_count_from_out_mask(channel_mask);
+
+ char channel_map[8];
+ memset(channel_map, 0, sizeof(channel_map));
+ /* Following are all most common standard WAV channel layouts
+ overridden by channel mask if its allowed and different */
+ switch (channels) {
+ case 1:
+ /* AUDIO_CHANNEL_OUT_MONO */
+ channel_map[0] = PCM_CHANNEL_FC;
+ case 2:
+ /* AUDIO_CHANNEL_OUT_STEREO */
+ channel_map[0] = PCM_CHANNEL_FL;
+ channel_map[1] = PCM_CHANNEL_FR;
+ case 3:
+ /* AUDIO_CHANNEL_OUT_2POINT1 */
+ channel_map[0] = PCM_CHANNEL_FL;
+ channel_map[1] = PCM_CHANNEL_FR;
+ channel_map[2] = PCM_CHANNEL_FC;
+ break;
+ case 4:
+ /* AUDIO_CHANNEL_OUT_QUAD_SIDE */
+ channel_map[0] = PCM_CHANNEL_FL;
+ channel_map[1] = PCM_CHANNEL_FR;
+ channel_map[2] = PCM_CHANNEL_LS;
+ channel_map[3] = PCM_CHANNEL_RS;
+ if (channel_mask == AUDIO_CHANNEL_OUT_QUAD_BACK)
+ {
+ channel_map[2] = PCM_CHANNEL_LB;
+ channel_map[3] = PCM_CHANNEL_RB;
+ }
+ if (channel_mask == AUDIO_CHANNEL_OUT_SURROUND)
+ {
+ channel_map[2] = PCM_CHANNEL_FC;
+ channel_map[3] = PCM_CHANNEL_CS;
+ }
+ break;
+ case 5:
+ /* AUDIO_CHANNEL_OUT_PENTA */
+ channel_map[0] = PCM_CHANNEL_FL;
+ channel_map[1] = PCM_CHANNEL_FR;
+ channel_map[2] = PCM_CHANNEL_FC;
+ channel_map[3] = PCM_CHANNEL_LB;
+ channel_map[4] = PCM_CHANNEL_RB;
+ break;
+ case 6:
+ /* AUDIO_CHANNEL_OUT_5POINT1 */
+ channel_map[0] = PCM_CHANNEL_FL;
+ channel_map[1] = PCM_CHANNEL_FR;
+ channel_map[2] = PCM_CHANNEL_FC;
+ channel_map[3] = PCM_CHANNEL_LFE;
+ channel_map[4] = PCM_CHANNEL_LB;
+ channel_map[5] = PCM_CHANNEL_RB;
+ if (channel_mask == AUDIO_CHANNEL_OUT_5POINT1_SIDE)
+ {
+ channel_map[4] = PCM_CHANNEL_LS;
+ channel_map[5] = PCM_CHANNEL_RS;
+ }
+ break;
+ case 7:
+ /* AUDIO_CHANNEL_OUT_6POINT1 */
+ channel_map[0] = PCM_CHANNEL_FL;
+ channel_map[1] = PCM_CHANNEL_FR;
+ channel_map[2] = PCM_CHANNEL_FC;
+ channel_map[3] = PCM_CHANNEL_LFE;
+ channel_map[4] = PCM_CHANNEL_LB;
+ channel_map[5] = PCM_CHANNEL_RB;
+ channel_map[6] = PCM_CHANNEL_CS;
+ case 8:
+ /* AUDIO_CHANNEL_OUT_7POINT1 */
+ channel_map[0] = PCM_CHANNEL_FL;
+ channel_map[1] = PCM_CHANNEL_FR;
+ channel_map[2] = PCM_CHANNEL_FC;
+ channel_map[3] = PCM_CHANNEL_LFE;
+ channel_map[4] = PCM_CHANNEL_LB;
+ channel_map[5] = PCM_CHANNEL_RB;
+ channel_map[6] = PCM_CHANNEL_LS;
+ channel_map[7] = PCM_CHANNEL_RS;
+ break;
+ default:
+ ALOGE("unsupported channels %d for setting channel map", channels);
+ return -1;
+ }
+ ret = platform_set_channel_map(platform, channels, channel_map, snd_id);
+ return ret;
+}
+
+int platform_get_edid_info(void *platform)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ char block[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE];
+ char *sad = block;
+ int num_audio_blocks;
+ int channel_count = 2;
+ int i, ret, count;
+
+ struct mixer_ctl *ctl;
+ char edid_data[MAX_SAD_BLOCKS * SAD_BLOCK_SIZE + 1] = {0};
+ edid_audio_info *info;
+
+ if (my_data->edid_valid) {
+ /* use cached edid */
+ return 0;
+ }
+
+ if (my_data->edid_info == NULL) {
+ my_data->edid_info =
+ (struct edid_audio_info *)calloc(1, sizeof(struct edid_audio_info));
+ }
+
+ info = my_data->edid_info;
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, AUDIO_DATA_BLOCK_MIXER_CTL);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, AUDIO_DATA_BLOCK_MIXER_CTL);
+ goto fail;
+ }
+
+ mixer_ctl_update(ctl);
+
+ count = mixer_ctl_get_num_values(ctl);
+
+ /* Read SAD blocks, clamping the maximum size for safety */
+ if (count > (int)sizeof(block))
+ count = (int)sizeof(block);
+
+ ret = mixer_ctl_get_array(ctl, block, count);
+ if (ret != 0) {
+ ALOGE("%s: mixer_ctl_get_array() failed to get EDID info", __func__);
+ goto fail;
+ }
+ edid_data[0] = count;
+ memcpy(&edid_data[1], block, count);
+
+ if (!edid_get_sink_caps(info, edid_data)) {
+ ALOGE("%s: Failed to get HDMI sink capabilities", __func__);
+ goto fail;
+ }
+ my_data->edid_valid = true;
+ return 0;
+fail:
+ if (my_data->edid_info) {
+ free(my_data->edid_info);
+ my_data->edid_info = NULL;
+ my_data->edid_valid = false;
+ }
+ ALOGE("%s: return -EINVAL", __func__);
+ return -EINVAL;
+}
+
+
+int platform_set_channel_allocation(void *platform, int channel_alloc)
+{
+ struct mixer_ctl *ctl;
+ const char *mixer_ctl_name = "HDMI RX CA";
+ int ret;
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ ret = EINVAL;
+ }
+ ALOGD(":%s channel allocation = 0x%x", __func__, channel_alloc);
+ ret = mixer_ctl_set_value(ctl, 0, channel_alloc);
+
+ if (ret < 0) {
+ ALOGE("%s: Could not set ctl, error:%d ", __func__, ret);
+ }
+
+ return ret;
+}
+
+int platform_set_channel_map(void *platform, int ch_count, char *ch_map, int snd_id)
+{
+ struct mixer_ctl *ctl;
+ char mixer_ctl_name[44]; // max length of name is 44 as defined
+ int ret;
+ unsigned int i;
+ int set_values[8] = {0};
+ char device_num[13]; // device number up to 2 digit
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ ALOGV("%s channel_count:%d",__func__, ch_count);
+ if (NULL == ch_map) {
+ ALOGE("%s: Invalid channel mapping used", __func__);
+ return -EINVAL;
+ }
+ strlcpy(mixer_ctl_name, "Playback Channel Map", sizeof(mixer_ctl_name));
+ if (snd_id >= 0) {
+ snprintf(device_num, sizeof(device_num), "%d", snd_id);
+ strncat(mixer_ctl_name, device_num, 13);
+ }
+
+ ALOGD("%s mixer_ctl_name:%s", __func__, mixer_ctl_name);
+
+ ctl = mixer_get_ctl_by_name(adev->mixer, mixer_ctl_name);
+ if (!ctl) {
+ ALOGE("%s: Could not get ctl for mixer cmd - %s",
+ __func__, mixer_ctl_name);
+ return -EINVAL;
+ }
+ for (i = 0; i< ARRAY_SIZE(set_values); i++) {
+ set_values[i] = ch_map[i];
+ }
+
+ ALOGD("%s: set mapping(%d %d %d %d %d %d %d %d) for channel:%d", __func__,
+ set_values[0], set_values[1], set_values[2], set_values[3], set_values[4],
+ set_values[5], set_values[6], set_values[7], ch_count);
+
+ ret = mixer_ctl_set_array(ctl, set_values, ch_count);
+ if (ret < 0) {
+ ALOGE("%s: Could not set ctl, error:%d ch_count:%d",
+ __func__, ret, ch_count);
+ }
+ return ret;
+}
+
+unsigned char platform_map_to_edid_format(int audio_format)
+{
+
+ unsigned char format;
+ switch (audio_format & AUDIO_FORMAT_MAIN_MASK) {
+ case AUDIO_FORMAT_AC3:
+ ALOGV("%s: AC3", __func__);
+ format = AC3;
+ break;
+ case AUDIO_FORMAT_AAC:
+ ALOGV("%s:AAC", __func__);
+ format = AAC;
+ break;
+ case AUDIO_FORMAT_E_AC3:
+ ALOGV("%s:E_AC3", __func__);
+ format = DOLBY_DIGITAL_PLUS;
+ break;
+ case AUDIO_FORMAT_PCM_16_BIT:
+ default:
+ ALOGV("%s:PCM", __func__);
+ format = LPCM;
+ break;
+ }
+ return format;
+}
+
+bool platform_is_edid_supported_format(void *platform, int format)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ edid_audio_info *info = NULL;
+ int num_audio_blocks;
+ int i, ret, count;
+ unsigned char format_id = platform_map_to_edid_format(format);
+
+ ret = platform_get_edid_info(platform);
+ info = (edid_audio_info *)my_data->edid_info;
+ if (ret == 0 && info != NULL) {
+ for (i = 0; i < info->audio_blocks && i < MAX_EDID_BLOCKS; i++) {
+ if (info->audio_blocks_array[i].format_id == format_id)
+ ALOGV("%s:platform_is_edid_supported_format true %x",
+ __func__, format);
+ return true;
+ }
+ }
+ ALOGV("%s:platform_is_edid_supported_format false %x",
+ __func__, format);
+ return false;
+}
+
+int platform_set_edid_channels_configuration(void *platform, int channels) {
+
+ struct platform_data *my_data = (struct platform_data *)platform;
+ struct audio_device *adev = my_data->adev;
+ edid_audio_info *info = NULL;
+ int num_audio_blocks;
+ int channel_count = 2;
+ int i, ret, count;
+ char default_channelMap[MAX_CHANNELS_SUPPORTED] = {0};
+
+ ret = platform_get_edid_info(platform);
+ info = (edid_audio_info *)my_data->edid_info;
+ if(ret == 0 && info != NULL) {
+ if (channels > 2) {
+
+ ALOGV("%s:able to get HDMI sink capabilities multi channel playback",
+ __func__);
+ for (i = 0; i < info->audio_blocks && i < MAX_EDID_BLOCKS; i++) {
+ if (info->audio_blocks_array[i].format_id == LPCM &&
+ info->audio_blocks_array[i].channels > channel_count &&
+ info->audio_blocks_array[i].channels <= MAX_HDMI_CHANNEL_CNT) {
+ channel_count = info->audio_blocks_array[i].channels;
+ }
+ }
+ ALOGVV("%s:channel_count:%d", __func__, channel_count);
+ /*
+ * Channel map is set for supported hdmi max channel count even
+ * though the input channel count set on adm is less than or equal to
+ * max supported channel count
+ */
+ platform_set_channel_map(platform, channel_count, info->channel_map, -1);
+ platform_set_channel_allocation(platform, info->channel_allocation);
+ } else {
+ default_channelMap[0] = PCM_CHANNEL_FL;
+ default_channelMap[1] = PCM_CHANNEL_FR;
+ platform_set_channel_map(platform,2,default_channelMap,-1);
+ platform_set_channel_allocation(platform,0);
+ }
+ }
+
+ return 0;
+}
+
+void platform_cache_edid(void * platform)
+{
+ platform_get_edid_info(platform);
+}
+
+void platform_invalidate_edid(void * platform)
+{
+ struct platform_data *my_data = (struct platform_data *)platform;
+ my_data->edid_valid = false;
+ if (my_data->edid_info) {
+ memset(my_data->edid_info, 0, sizeof(struct edid_audio_info));
+ }
+}
diff --git a/hal/platform_api.h b/hal/platform_api.h
index 368677b..381901c 100644
--- a/hal/platform_api.h
+++ b/hal/platform_api.h
@@ -96,4 +96,15 @@
void platform_set_echo_reference(void *platform, bool enable);
void platform_get_device_to_be_id_map(int **be_id_map, int *length);
+int platform_set_channel_allocation(void *platform, int channel_alloc);
+int platform_get_edid_info(void *platform);
+int platform_set_channel_map(void *platform, int ch_count, char *ch_map,
+ int snd_id);
+int platform_set_stream_channel_map(void *platform, audio_channel_mask_t channel_mask, int snd_id);
+int platform_set_edid_channels_configuration(void *platform, int channels);
+unsigned char platform_map_to_edid_format(int format);
+bool platform_is_edid_supported_format(void *platform, int format);
+void platform_cache_edid(void * platform);
+void platform_invalidate_edid(void * platform);
+
#endif // AUDIO_PLATFORM_API_H