hal: Add support for parsing hdmi edid information
Add support for parsing hdmi edid data and setting channel map
to asm
Parse edid data on hdmi connection and invalidat on disconnection.
Fix audio playback errors on HDMI when source channel count is
greater than sink channel count for offload playback.
Change-Id: I1e0a8335611a87974cb273431659938a0b345e68
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;
+}