summaryrefslogtreecommitdiffstats
path: root/exynos5/hal/libhdmi/libsForhdmi
diff options
context:
space:
mode:
Diffstat (limited to 'exynos5/hal/libhdmi/libsForhdmi')
-rw-r--r--exynos5/hal/libhdmi/libsForhdmi/Android.mk17
-rw-r--r--exynos5/hal/libhdmi/libsForhdmi/libcec/Android.mk33
-rw-r--r--exynos5/hal/libhdmi/libsForhdmi/libcec/cec.h11
-rw-r--r--exynos5/hal/libhdmi/libsForhdmi/libcec/libcec.c386
-rw-r--r--exynos5/hal/libhdmi/libsForhdmi/libcec/libcec.h209
-rw-r--r--exynos5/hal/libhdmi/libsForhdmi/libddc/Android.mk49
-rw-r--r--exynos5/hal/libhdmi/libsForhdmi/libddc/libddc.c289
-rw-r--r--exynos5/hal/libhdmi/libsForhdmi/libddc/libddc.h35
-rw-r--r--exynos5/hal/libhdmi/libsForhdmi/libedid/Android.mk34
-rw-r--r--exynos5/hal/libhdmi/libsForhdmi/libedid/edid.h181
-rw-r--r--exynos5/hal/libhdmi/libsForhdmi/libedid/libedid.c1265
-rw-r--r--exynos5/hal/libhdmi/libsForhdmi/libedid/libedid.h42
12 files changed, 2551 insertions, 0 deletions
diff --git a/exynos5/hal/libhdmi/libsForhdmi/Android.mk b/exynos5/hal/libhdmi/libsForhdmi/Android.mk
new file mode 100644
index 0000000..9acbc52
--- /dev/null
+++ b/exynos5/hal/libhdmi/libsForhdmi/Android.mk
@@ -0,0 +1,17 @@
+# Copyright (C) 2008 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.
+
+ifeq ($(filter-out exynos5,$(TARGET_BOARD_PLATFORM)),)
+include $(all-subdir-makefiles)
+endif
diff --git a/exynos5/hal/libhdmi/libsForhdmi/libcec/Android.mk b/exynos5/hal/libhdmi/libsForhdmi/libcec/Android.mk
new file mode 100644
index 0000000..9a4b721
--- /dev/null
+++ b/exynos5/hal/libhdmi/libsForhdmi/libcec/Android.mk
@@ -0,0 +1,33 @@
+# Copyright (C) 2008 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.
+
+ifeq ($(BOARD_USES_HDMI),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := eng
+
+LOCAL_PRELINK_MODULE := false
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SRC_FILES := libcec.c
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH) \
+ $(LOCAL_PATH)/../../../include
+
+LOCAL_MODULE := libcec
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/exynos5/hal/libhdmi/libsForhdmi/libcec/cec.h b/exynos5/hal/libhdmi/libsForhdmi/libcec/cec.h
new file mode 100644
index 0000000..4b0d3af
--- /dev/null
+++ b/exynos5/hal/libhdmi/libsForhdmi/libcec/cec.h
@@ -0,0 +1,11 @@
+#ifndef _LINUX_CEC_H_
+#define _LINUX_CEC_H_
+
+#define CEC_IOC_MAGIC 'c'
+
+/**
+ * CEC device request code to set logical address.
+ */
+#define CEC_IOC_SETLADDR _IOW(CEC_IOC_MAGIC, 0, unsigned int)
+
+#endif /* _LINUX_CEC_H_ */
diff --git a/exynos5/hal/libhdmi/libsForhdmi/libcec/libcec.c b/exynos5/hal/libhdmi/libsForhdmi/libcec/libcec.c
new file mode 100644
index 0000000..e688051
--- /dev/null
+++ b/exynos5/hal/libhdmi/libsForhdmi/libcec/libcec.c
@@ -0,0 +1,386 @@
+/*
+* Copyright@ Samsung Electronics Co. LTD
+*
+* 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.
+*/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <cutils/log.h>
+
+/* drv. header */
+#include "cec.h"
+
+#include "libcec.h"
+
+#define CEC_DEBUG 0
+
+/**
+ * @def CEC_DEVICE_NAME
+ * Defines simbolic name of the CEC device.
+ */
+#define CEC_DEVICE_NAME "/dev/CEC"
+
+static struct {
+ enum CECDeviceType devtype;
+ unsigned char laddr;
+} laddresses[] = {
+ { CEC_DEVICE_RECODER, 1 },
+ { CEC_DEVICE_RECODER, 2 },
+ { CEC_DEVICE_TUNER, 3 },
+ { CEC_DEVICE_PLAYER, 4 },
+ { CEC_DEVICE_AUDIO, 5 },
+ { CEC_DEVICE_TUNER, 6 },
+ { CEC_DEVICE_TUNER, 7 },
+ { CEC_DEVICE_PLAYER, 8 },
+ { CEC_DEVICE_RECODER, 9 },
+ { CEC_DEVICE_TUNER, 10 },
+ { CEC_DEVICE_PLAYER, 11 },
+};
+
+static int CECSetLogicalAddr(unsigned int laddr);
+
+#ifdef CEC_DEBUG
+inline static void CECPrintFrame(unsigned char *buffer, unsigned int size);
+#endif
+
+static int fd = -1;
+
+/**
+ * Open device driver and assign CEC file descriptor.
+ *
+ * @return If success to assign CEC file descriptor, return 1; otherwise, return 0.
+ */
+int CECOpen()
+{
+ int res = 1;
+
+ if (fd != -1)
+ CECClose();
+
+ if ((fd = open(CEC_DEVICE_NAME, O_RDWR)) < 0) {
+ LOGE("Can't open %s!\n", CEC_DEVICE_NAME);
+ res = 0;
+ }
+
+ return res;
+}
+
+/**
+ * Close CEC file descriptor.
+ *
+ * @return If success to close CEC file descriptor, return 1; otherwise, return 0.
+ */
+int CECClose()
+{
+ int res = 1;
+
+ if (fd != -1) {
+ if (close(fd) != 0) {
+ LOGE("close() failed!\n");
+ res = 0;
+ }
+ fd = -1;
+ }
+
+ return res;
+}
+
+/**
+ * Allocate logical address.
+ *
+ * @param paddr [in] CEC device physical address.
+ * @param devtype [in] CEC device type.
+ *
+ * @return new logical address, or 0 if an arror occured.
+ */
+int CECAllocLogicalAddress(int paddr, enum CECDeviceType devtype)
+{
+ unsigned char laddr = CEC_LADDR_UNREGISTERED;
+ int i = 0;
+
+ if (fd == -1) {
+ LOGE("open device first!\n");
+ return 0;
+ }
+
+ if (CECSetLogicalAddr(laddr) < 0) {
+ LOGE("CECSetLogicalAddr() failed!\n");
+ return 0;
+ }
+
+ if (paddr == CEC_NOT_VALID_PHYSICAL_ADDRESS)
+ return CEC_LADDR_UNREGISTERED;
+
+ /* send "Polling Message" */
+ while (i < sizeof(laddresses)/sizeof(laddresses[0])) {
+ if (laddresses[i].devtype == devtype) {
+ unsigned char _laddr = laddresses[i].laddr;
+ unsigned char message = ((_laddr << 4) | _laddr);
+ if (CECSendMessage(&message, 1) != 1) {
+ laddr = _laddr;
+ break;
+ }
+ }
+ i++;
+ }
+
+ if (laddr == CEC_LADDR_UNREGISTERED) {
+ LOGE("All LA addresses in use!!!\n");
+ return CEC_LADDR_UNREGISTERED;
+ }
+
+ if (CECSetLogicalAddr(laddr) < 0) {
+ LOGE("CECSetLogicalAddr() failed!\n");
+ return 0;
+ }
+
+ /* broadcast "Report Physical Address" */
+ unsigned char buffer[5];
+ buffer[0] = (laddr << 4) | CEC_MSG_BROADCAST;
+ buffer[1] = CEC_OPCODE_REPORT_PHYSICAL_ADDRESS;
+ buffer[2] = (paddr >> 8) & 0xFF;
+ buffer[3] = paddr & 0xFF;
+ buffer[4] = devtype;
+
+ if (CECSendMessage(buffer, 5) != 5) {
+ LOGE("CECSendMessage() failed!\n");
+ return 0;
+ }
+
+ return laddr;
+}
+
+/**
+ * Send CEC message.
+ *
+ * @param *buffer [in] pointer to buffer address where message located.
+ * @param size [in] message size.
+ *
+ * @return number of bytes written, or 0 if an arror occured.
+ */
+int CECSendMessage(unsigned char *buffer, int size)
+{
+ if (fd == -1) {
+ LOGE("open device first!\n");
+ return 0;
+ }
+
+ if (size > CEC_MAX_FRAME_SIZE) {
+ LOGE("size should not exceed %d\n", CEC_MAX_FRAME_SIZE);
+ return 0;
+ }
+
+#if CEC_DEBUG
+ LOGI("CECSendMessage() : ");
+ CECPrintFrame(buffer, size);
+#endif
+
+ return write(fd, buffer, size);
+}
+
+/**
+ * Receive CEC message.
+ *
+ * @param *buffer [in] pointer to buffer address where message will be stored.
+ * @param size [in] buffer size.
+ * @param timeout [in] timeout in microseconds.
+ *
+ * @return number of bytes received, or 0 if an arror occured.
+ */
+int CECReceiveMessage(unsigned char *buffer, int size, long timeout)
+{
+ int bytes = 0;
+ fd_set rfds;
+ struct timeval tv;
+ int retval;
+
+ if (fd == -1) {
+ LOGE("open device first!\n");
+ return 0;
+ }
+
+ tv.tv_sec = 0;
+ tv.tv_usec = timeout;
+
+ FD_ZERO(&rfds);
+ FD_SET(fd, &rfds);
+
+ retval = select(fd + 1, &rfds, NULL, NULL, &tv);
+
+ if (retval == -1) {
+ return 0;
+ } else if (retval) {
+ bytes = read(fd, buffer, size);
+#if CEC_DEBUG
+ LOGI("CECReceiveMessage() : size(%d)", bytes);
+ if(bytes > 0)
+ CECPrintFrame(buffer, bytes);
+#endif
+ }
+
+ return bytes;
+}
+
+/**
+ * Set CEC logical address.
+ *
+ * @return 1 if success, otherwise, return 0.
+ */
+int CECSetLogicalAddr(unsigned int laddr)
+{
+ if (ioctl(fd, CEC_IOC_SETLADDR, &laddr)) {
+ LOGE("ioctl(CEC_IOC_SETLA) failed!\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+#if CEC_DEBUG
+/**
+ * Print CEC frame.
+ */
+void CECPrintFrame(unsigned char *buffer, unsigned int size)
+{
+ if (size > 0) {
+ int i;
+ LOGI("fsize: %d ", size);
+ LOGI("frame: ");
+ for (i = 0; i < size; i++)
+ LOGI("0x%02x ", buffer[i]);
+
+ LOGI("\n");
+ }
+}
+#endif
+
+/**
+ * Check CEC message.
+ *
+ * @param opcode [in] pointer to buffer address where message will be stored.
+ * @param lsrc [in] buffer size.
+ *
+ * @return 1 if message should be ignored, otherwise, return 0.
+ */
+//TODO: not finished
+int CECIgnoreMessage(unsigned char opcode, unsigned char lsrc)
+{
+ int retval = 0;
+
+ /* if a message coming from address 15 (unregistered) */
+ if (lsrc == CEC_LADDR_UNREGISTERED) {
+ switch (opcode) {
+ case CEC_OPCODE_DECK_CONTROL:
+ case CEC_OPCODE_PLAY:
+ retval = 1;
+ default:
+ break;
+ }
+ }
+
+ return retval;
+}
+
+/**
+ * Check CEC message.
+ *
+ * @param opcode [in] pointer to buffer address where message will be stored.
+ * @param size [in] message size.
+ *
+ * @return 0 if message should be ignored, otherwise, return 1.
+ */
+//TODO: not finished
+int CECCheckMessageSize(unsigned char opcode, int size)
+{
+ int retval = 1;
+
+ switch (opcode) {
+ case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
+ if (size != 1)
+ retval = 0;
+ break;
+ case CEC_OPCODE_SET_SYSTEM_AUDIO_MODE:
+ if (size != 2)
+ retval = 0;
+ break;
+ case CEC_OPCODE_PLAY:
+ case CEC_OPCODE_DECK_CONTROL:
+ case CEC_OPCODE_SET_MENU_LANGUAGE:
+ case CEC_OPCODE_ACTIVE_SOURCE:
+ case CEC_OPCODE_ROUTING_INFORMATION:
+ case CEC_OPCODE_SET_STREAM_PATH:
+ if (size != 3)
+ retval = 0;
+ break;
+ case CEC_OPCODE_FEATURE_ABORT:
+ case CEC_OPCODE_DEVICE_VENDOR_ID:
+ case CEC_OPCODE_REPORT_PHYSICAL_ADDRESS:
+ if (size != 4)
+ retval = 0;
+ break;
+ case CEC_OPCODE_ROUTING_CHANGE:
+ if (size != 5)
+ retval = 0;
+ break;
+ /* CDC - 1.4 */
+ case 0xf8:
+ if (!(size > 5 && size <= 16))
+ retval = 0;
+ break;
+ default:
+ break;
+ }
+
+ return retval;
+}
+
+/**
+ * Check CEC message.
+ *
+ * @param opcode [in] pointer to buffer address where message will be stored.
+ * @param broadcast [in] broadcast/direct message.
+ *
+ * @return 0 if message should be ignored, otherwise, return 1.
+ */
+//TODO: not finished
+int CECCheckMessageMode(unsigned char opcode, int broadcast)
+{
+ int retval = 1;
+
+ switch (opcode) {
+ case CEC_OPCODE_REQUEST_ACTIVE_SOURCE:
+ case CEC_OPCODE_SET_MENU_LANGUAGE:
+ case CEC_OPCODE_ACTIVE_SOURCE:
+ if (!broadcast)
+ retval = 0;
+ break;
+ case CEC_OPCODE_GIVE_PHYSICAL_ADDRESS:
+ case CEC_OPCODE_DECK_CONTROL:
+ case CEC_OPCODE_PLAY:
+ case CEC_OPCODE_FEATURE_ABORT:
+ case CEC_OPCODE_ABORT:
+ if (broadcast)
+ retval = 0;
+ break;
+ default:
+ break;
+ }
+
+ return retval;
+}
diff --git a/exynos5/hal/libhdmi/libsForhdmi/libcec/libcec.h b/exynos5/hal/libhdmi/libsForhdmi/libcec/libcec.h
new file mode 100644
index 0000000..5bbfc15
--- /dev/null
+++ b/exynos5/hal/libhdmi/libsForhdmi/libcec/libcec.h
@@ -0,0 +1,209 @@
+/*
+ * Copyright@ Samsung Electronics Co. LTD
+ *
+ * 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.
+ */
+
+#ifndef _LIBCEC_H_
+#define _LIBCEC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Maximum CEC frame size */
+#define CEC_MAX_FRAME_SIZE 16
+/** Not valid CEC physical address */
+#define CEC_NOT_VALID_PHYSICAL_ADDRESS 0xFFFF
+
+/** CEC broadcast address (as destination address) */
+#define CEC_MSG_BROADCAST 0x0F
+/** CEC unregistered address (as initiator address) */
+#define CEC_LADDR_UNREGISTERED 0x0F
+
+/*
+ * CEC Messages
+ */
+
+//@{
+/** @name Messages for the One Touch Play Feature */
+#define CEC_OPCODE_ACTIVE_SOURCE 0x82
+#define CEC_OPCODE_IMAGE_VIEW_ON 0x04
+#define CEC_OPCODE_TEXT_VIEW_ON 0x0D
+//@}
+
+//@{
+/** @name Messages for the Routing Control Feature */
+#define CEC_OPCODE_INACTIVE_SOURCE 0x9D
+#define CEC_OPCODE_REQUEST_ACTIVE_SOURCE 0x85
+#define CEC_OPCODE_ROUTING_CHANGE 0x80
+#define CEC_OPCODE_ROUTING_INFORMATION 0x81
+#define CEC_OPCODE_SET_STREAM_PATH 0x86
+//@}
+
+//@{
+/** @name Messages for the Standby Feature */
+#define CEC_OPCODE_STANDBY 0x36
+//@}
+
+//@{
+/** @name Messages for the One Touch Record Feature */
+#define CEC_OPCODE_RECORD_OFF 0x0B
+#define CEC_OPCODE_RECORD_ON 0x09
+#define CEC_OPCODE_RECORD_STATUS 0x0A
+#define CEC_OPCODE_RECORD_TV_SCREEN 0x0F
+//@}
+
+//@{
+/** @name Messages for the Timer Programming Feature */
+#define CEC_OPCODE_CLEAR_ANALOGUE_TIMER 0x33
+#define CEC_OPCODE_CLEAR_DIGITAL_TIMER 0x99
+#define CEC_OPCODE_CLEAR_EXTERNAL_TIMER 0xA1
+#define CEC_OPCODE_SET_ANALOGUE_TIMER 0x34
+#define CEC_OPCODE_SET_DIGITAL_TIMER 0x97
+#define CEC_OPCODE_SET_EXTERNAL_TIMER 0xA2
+#define CEC_OPCODE_SET_TIMER_PROGRAM_TITLE 0x67
+#define CEC_OPCODE_TIMER_CLEARED_STATUS 0x43
+#define CEC_OPCODE_TIMER_STATUS 0x35
+//@}
+
+//@{
+/** @name Messages for the System Information Feature */
+#define CEC_OPCODE_CEC_VERSION 0x9E
+#define CEC_OPCODE_GET_CEC_VERSION 0x9F
+#define CEC_OPCODE_GIVE_PHYSICAL_ADDRESS 0x83
+#define CEC_OPCODE_GET_MENU_LANGUAGE 0x91
+//#define CEC_OPCODE_POLLING_MESSAGE
+#define CEC_OPCODE_REPORT_PHYSICAL_ADDRESS 0x84
+#define CEC_OPCODE_SET_MENU_LANGUAGE 0x32
+//@}
+
+//@{
+/** @name Messages for the Deck Control Feature */
+#define CEC_OPCODE_DECK_CONTROL 0x42
+#define CEC_OPCODE_DECK_STATUS 0x1B
+#define CEC_OPCODE_GIVE_DECK_STATUS 0x1A
+#define CEC_OPCODE_PLAY 0x41
+//@}
+
+//@{
+/** @name Messages for the Tuner Control Feature */
+#define CEC_OPCODE_GIVE_TUNER_DEVICE_STATUS 0x08
+#define CEC_OPCODE_SELECT_ANALOGUE_SERVICE 0x92
+#define CEC_OPCODE_SELECT_DIGITAL_SERVICE 0x93
+#define CEC_OPCODE_TUNER_DEVICE_STATUS 0x07
+#define CEC_OPCODE_TUNER_STEP_DECREMENT 0x06
+#define CEC_OPCODE_TUNER_STEP_INCREMENT 0x05
+//@}
+
+//@{
+/** @name Messages for the Vendor Specific Commands Feature */
+#define CEC_OPCODE_DEVICE_VENDOR_ID 0x87
+#define CEC_OPCODE_GET_DEVICE_VENDOR_ID 0x8C
+#define CEC_OPCODE_VENDOR_COMMAND 0x89
+#define CEC_OPCODE_VENDOR_COMMAND_WITH_ID 0xA0
+#define CEC_OPCODE_VENDOR_REMOTE_BUTTON_DOWN 0x8A
+#define CEC_OPCODE_VENDOR_REMOVE_BUTTON_UP 0x8B
+//@}
+
+//@{
+/** @name Messages for the OSD Display Feature */
+#define CEC_OPCODE_SET_OSD_STRING 0x64
+//@}
+
+//@{
+/** @name Messages for the Device OSD Transfer Feature */
+#define CEC_OPCODE_GIVE_OSD_NAME 0x46
+#define CEC_OPCODE_SET_OSD_NAME 0x47
+//@}
+
+//@{
+/** @name Messages for the Device Menu Control Feature */
+#define CEC_OPCODE_MENU_REQUEST 0x8D
+#define CEC_OPCODE_MENU_STATUS 0x8E
+#define CEC_OPCODE_USER_CONTROL_PRESSED 0x44
+#define CEC_OPCODE_USER_CONTROL_RELEASED 0x45
+//@}
+
+//@{
+/** @name Messages for the Remote Control Passthrough Feature */
+//@}
+
+//@{
+/** @name Messages for the Power Status Feature */
+#define CEC_OPCODE_GIVE_DEVICE_POWER_STATUS 0x8F
+#define CEC_OPCODE_REPORT_POWER_STATUS 0x90
+//@}
+
+//@{
+/** @name Messages for General Protocol messages */
+#define CEC_OPCODE_FEATURE_ABORT 0x00
+#define CEC_OPCODE_ABORT 0xFF
+//@}
+
+//@{
+/** @name Messages for the System Audio Control Feature */
+#define CEC_OPCODE_GIVE_AUDIO_STATUS 0x71
+#define CEC_OPCODE_GIVE_SYSTEM_AUDIO_MODE_STATUS 0x7D
+#define CEC_OPCODE_REPORT_AUDIO_STATUS 0x7A
+#define CEC_OPCODE_SET_SYSTEM_AUDIO_MODE 0x72
+#define CEC_OPCODE_SYSTEM_AUDIO_MODE_REQUEST 0x70
+#define CEC_OPCODE_SYSTEM_AUDIO_MODE_STATUS 0x7E
+//@}
+
+//@{
+/** @name Messages for the Audio Rate Control Feature */
+#define CEC_OPCODE_SET_AUDIO_RATE 0x9A
+//@}
+
+//@{
+/** @name CEC Operands */
+
+//TODO: not finished
+
+#define CEC_DECK_CONTROL_MODE_STOP 0x03
+#define CEC_PLAY_MODE_PLAY_FORWARD 0x24
+//@}
+
+/**
+ * @enum CECDeviceType
+ * Type of CEC device
+ */
+enum CECDeviceType {
+ /** TV */
+ CEC_DEVICE_TV,
+ /** Recording Device */
+ CEC_DEVICE_RECODER,
+ /** Tuner */
+ CEC_DEVICE_TUNER,
+ /** Playback Device */
+ CEC_DEVICE_PLAYER,
+ /** Audio System */
+ CEC_DEVICE_AUDIO,
+};
+
+int CECOpen();
+int CECClose();
+int CECAllocLogicalAddress(int paddr, enum CECDeviceType devtype);
+int CECSendMessage(unsigned char *buffer, int size);
+int CECReceiveMessage(unsigned char *buffer, int size, long timeout);
+
+int CECIgnoreMessage(unsigned char opcode, unsigned char lsrc);
+int CECCheckMessageSize(unsigned char opcode, int size);
+int CECCheckMessageMode(unsigned char opcode, int broadcast);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBCEC_H_ */
diff --git a/exynos5/hal/libhdmi/libsForhdmi/libddc/Android.mk b/exynos5/hal/libhdmi/libsForhdmi/libddc/Android.mk
new file mode 100644
index 0000000..99af09b
--- /dev/null
+++ b/exynos5/hal/libhdmi/libsForhdmi/libddc/Android.mk
@@ -0,0 +1,49 @@
+# Copyright (C) 2008 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.
+
+ifeq ($(BOARD_USES_HDMI),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := eng
+
+LOCAL_PRELINK_MODULE := false
+LOCAL_SHARED_LIBRARIES := liblog
+LOCAL_SRC_FILES := libddc.c
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH) \
+ $(LOCAL_PATH)/../../../include
+
+ifeq ($(BOARD_HDMI_DDC_CH), DDC_CH_I2C_7)
+LOCAL_CFLAGS += -DDDC_CH_I2C_7
+endif
+
+ifeq ($(BOARD_HDMI_DDC_CH), DDC_CH_I2C_1)
+LOCAL_CFLAGS += -DDDC_CH_I2C_1
+endif
+
+ifeq ($(BOARD_HDMI_DDC_CH), DDC_CH_I2C_2)
+LOCAL_CFLAGS += -DDDC_CH_I2C_2
+endif
+
+ifeq ($(BOARD_HDMI_DDC_CH), DDC_CH_I2C_8)
+LOCAL_CFLAGS += -DDDC_CH_I2C_8
+endif
+
+LOCAL_MODULE := libddc
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/exynos5/hal/libhdmi/libsForhdmi/libddc/libddc.c b/exynos5/hal/libhdmi/libsForhdmi/libddc/libddc.c
new file mode 100644
index 0000000..4e6e374
--- /dev/null
+++ b/exynos5/hal/libhdmi/libsForhdmi/libddc/libddc.c
@@ -0,0 +1,289 @@
+/*
+* Copyright@ Samsung Electronics Co. LTD
+*
+* 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.
+*/
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <linux/i2c.h>
+#include <cutils/log.h>
+#include "i2c-dev.h"
+
+#include "libddc.h"
+
+#define DDC_DEBUG 0
+
+/**
+ * @brief DDC device name.
+ * User should change this.
+ */
+#ifdef DDC_CH_I2C_1
+#define DEV_NAME "/dev/i2c-1"
+#endif
+
+#ifdef DDC_CH_I2C_2
+#define DEV_NAME "/dev/i2c-2"
+#endif
+
+#ifdef DDC_CH_I2C_7
+#define DEV_NAME "/dev/i2c-7"
+#endif
+
+#ifdef DDC_CH_I2C_8
+#define DEV_NAME "/dev/i2c-8"
+#endif
+
+/**
+ * DDC file descriptor
+ */
+static int ddc_fd = -1;
+
+/**
+ * Reference count of DDC file descriptor
+ */
+static unsigned int ref_cnt = 0;
+
+/**
+ * Check if DDC file is already opened or not
+ * @return If DDC file is already opened, return 1; Otherwise, return 0.
+ */
+static int DDCFileAvailable()
+{
+ return (ddc_fd < 0) ? 0 : 1;
+}
+
+/**
+ * Initialze DDC library. Open DDC device
+ * @return If succeed in opening DDC device or it is already opened, return 1;@n
+ * Otherwise, return 0.
+ */
+int DDCOpen()
+{
+ int ret = 1;
+
+ // check already open??
+ if (ref_cnt > 0) {
+ ref_cnt++;
+ return 1;
+ }
+
+ // open
+ if ((ddc_fd = open(DEV_NAME,O_RDWR)) < 0) {
+ LOGE("%s: Cannot open I2C_DDC : %s",__func__, DEV_NAME);
+ ret = 0;
+ }
+
+ ref_cnt++;
+ return ret;
+}
+
+/**
+ * Finalize DDC library. Close DDC device
+ * @return If succeed in closing DDC device or it is being used yet, return 1;@n
+ * Otherwise, return 0.
+ */
+int DDCClose()
+{
+ int ret = 1;
+ // check if fd is available
+ if (ref_cnt == 0) {
+#if DDC_DEBUG
+ LOGE("%s: I2C_DDC is not available!!!!", __func__);
+#endif
+ return 1;
+ }
+
+ // close
+ if (ref_cnt > 1) {
+ ref_cnt--;
+ return 1;
+ }
+
+ if (close(ddc_fd) < 0) {
+#if DDC_DEBUG
+ LOGE("%s: Cannot close I2C_DDC : %s",__func__,DEV_NAME);
+#endif
+ ret = 0;
+ }
+
+ ref_cnt--;
+ ddc_fd = -1;
+
+ return ret;
+}
+
+/**
+ * Read data though DDC. For more information of DDC, refer DDC Spec.
+ * @param addr [in] Device address
+ * @param offset [in] Byte offset
+ * @param size [in] Sizes of data
+ * @param buffer [out] Pointer to buffer to store data
+ * @return If succeed in reading, return 1; Otherwise, return 0.
+ */
+int DDCRead(unsigned char addr, unsigned char offset,
+ unsigned int size, unsigned char* buffer)
+{
+ struct i2c_rdwr_ioctl_data msgset;
+ struct i2c_msg msgs[2];
+ int ret = 1;
+
+ if (!DDCFileAvailable()) {
+#if DDC_DEBUG
+ LOGE("%s: I2C_DDC is not available!!!!", __func__);
+#endif
+ return 0;
+ }
+
+ // set offset
+ msgs[0].addr = addr>>1;
+ msgs[0].flags = 0;
+ msgs[0].len = 1;
+ msgs[0].buf = &offset;
+
+ // read data
+ msgs[1].addr = addr>>1;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = size;
+ msgs[1].buf = buffer;
+
+ // set rdwr ioctl data
+ msgset.nmsgs = 2;
+ msgset.msgs = msgs;
+
+ // i2c fast read
+ if ((ret = ioctl(ddc_fd, I2C_RDWR, &msgset)) < 0) {
+ perror("ddc error:");
+ ret = 0;
+ }
+
+ return ret;
+}
+
+/**
+ * Read data though E-DDC. For more information of E-DDC, refer E-DDC Spec.
+ * @param segpointer [in] Segment pointer
+ * @param segment [in] Segment number
+ * @param addr [in] Device address
+ * @param offset [in] Byte offset
+ * @param size [in] Sizes of data
+ * @param buffer [out] Pointer to buffer to store data
+ * @return If succeed in reading, return 1; Otherwise, return 0.
+ */
+
+int EDDCRead(unsigned char segpointer, unsigned char segment, unsigned char addr,
+ unsigned char offset, unsigned int size, unsigned char* buffer)
+{
+ struct i2c_rdwr_ioctl_data msgset;
+ struct i2c_msg msgs[3];
+ int ret = 1;
+
+ if (!DDCFileAvailable()) {
+#if DDC_DEBUG
+ LOGE("%s: I2C_DDC is not available!!!!", __func__);
+#endif
+ return 0;
+ }
+
+ // set segment pointer
+ msgs[0].addr = segpointer>>1;
+ // ignore ack only if segment is "0"
+ if (segment == 0)
+ msgs[0].flags = I2C_M_IGNORE_NAK;
+ else
+ msgs[0].flags = 0;
+
+ msgs[0].len = 1;
+ msgs[0].buf = &segment;
+
+ // set offset
+ msgs[1].addr = addr>>1;
+ msgs[1].flags = 0;
+ msgs[1].len = 1;
+ msgs[1].buf = &offset;
+
+ // read data
+ msgs[2].addr = addr>>1;
+ msgs[2].flags = I2C_M_RD;
+ msgs[2].len = size;
+ msgs[2].buf = buffer;
+
+ msgset.nmsgs = 3;
+ msgset.msgs = msgs;
+
+ // eddc read
+ if (ioctl(ddc_fd, I2C_RDWR, &msgset) < 0) {
+#if DDC_DEBUG
+ LOGE("%s: ioctl(I2C_RDWR) failed!!!", __func__);
+#endif
+ ret = 0;
+ }
+ return ret;
+}
+
+/**
+ * Write data though DDC. For more information of DDC, refer DDC Spec.
+ * @param addr [in] Device address
+ * @param offset [in] Byte offset
+ * @param size [in] Sizes of data
+ * @param buffer [out] Pointer to buffer to write
+ * @return If succeed in writing, return 1; Otherwise, return 0.
+ */
+int DDCWrite(unsigned char addr, unsigned char offset, unsigned int size, unsigned char* buffer)
+{
+ unsigned char* temp;
+ int bytes;
+ int retval = 0;
+
+ // allocate temporary buffer
+ temp = (unsigned char*) malloc((size+1)*sizeof(unsigned char));
+ if (!temp) {
+ LOGE("%s: not enough resources at %s", __FUNCTION__);
+ goto exit;
+ }
+
+ temp[0] = offset;
+ memcpy(temp+1,buffer,size);
+
+ if (!DDCFileAvailable()) {
+ LOGE("%s: I2C_DDC is not available!!!!", __func__);
+ goto exit;
+ }
+
+ if (ioctl(ddc_fd, I2C_SLAVE, addr>>1) < 0) {
+ LOGE("%s: cannot set slave address 0x%02x", __func__,addr);
+ goto exit;
+ }
+
+ // write temp buffer
+ if ((bytes = write(ddc_fd,temp,size+1)) != (size+1)) {
+ LOGE("%s: fail to write %d bytes, only write %d bytes",__func__, size, bytes);
+ goto exit;
+ }
+
+ retval = 1;
+
+exit:
+ // free temp buffer
+ if (temp)
+ free(temp);
+
+ return retval;
+}
diff --git a/exynos5/hal/libhdmi/libsForhdmi/libddc/libddc.h b/exynos5/hal/libhdmi/libsForhdmi/libddc/libddc.h
new file mode 100644
index 0000000..368855b
--- /dev/null
+++ b/exynos5/hal/libhdmi/libsForhdmi/libddc/libddc.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright@ Samsung Electronics Co. LTD
+ *
+ * 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.
+ */
+
+#ifndef _LIBDDC_H_
+#define _LIBDDC_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int DDCOpen();
+int DDCRead(unsigned char addr, unsigned char offset, unsigned int size, unsigned char* buffer);
+int DDCWrite(unsigned char addr, unsigned char offset, unsigned int size, unsigned char* buffer);
+int EDDCRead(unsigned char segpointer, unsigned char segment, unsigned char addr,
+ unsigned char offset, unsigned int size, unsigned char* buffer);
+int DDCClose();
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _LIBDDC_H_ */
diff --git a/exynos5/hal/libhdmi/libsForhdmi/libedid/Android.mk b/exynos5/hal/libhdmi/libsForhdmi/libedid/Android.mk
new file mode 100644
index 0000000..602ae4d
--- /dev/null
+++ b/exynos5/hal/libhdmi/libsForhdmi/libedid/Android.mk
@@ -0,0 +1,34 @@
+# Copyright (C) 2008 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.
+
+ifeq ($(BOARD_USES_HDMI),true)
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := eng
+
+LOCAL_PRELINK_MODULE := false
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)
+LOCAL_SHARED_LIBRARIES := liblog libddc
+LOCAL_SRC_FILES := libedid.c
+
+LOCAL_C_INCLUDES := \
+ $(LOCAL_PATH) \
+ $(LOCAL_PATH)/../../../include
+
+LOCAL_MODULE := libedid
+include $(BUILD_SHARED_LIBRARY)
+
+endif
diff --git a/exynos5/hal/libhdmi/libsForhdmi/libedid/edid.h b/exynos5/hal/libhdmi/libsForhdmi/libedid/edid.h
new file mode 100644
index 0000000..aea1309
--- /dev/null
+++ b/exynos5/hal/libhdmi/libsForhdmi/libedid/edid.h
@@ -0,0 +1,181 @@
+/*
+ * Copyright@ Samsung Electronics Co. LTD
+ *
+ * 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.
+ */
+
+#ifndef _EDID_H_
+#define _EDID_H_
+
+//@{
+/**
+ * @name EDID Addresses
+ */
+#define EDID_ADDR (0xA0)
+#define EDID_SEGMENT_POINTER (0x60)
+//@}
+
+//@{
+/**
+ * @name EDID offset and bit values
+ */
+#define SIZEOFBYTE (8)
+#define SIZEOFEDIDBLOCK (0x80)
+#define EDID_EXTENSION_NUMBER_POS (0x7E)
+
+#define EDID_TIMING_EXT_TAG_ADDR_POS (0)
+#define EDID_TIMING_EXT_REV_NUMBER_POS (1)
+#define EDID_DETAILED_TIMING_OFFSET_POS (2)
+#define EDID_DATA_BLOCK_START_POS (4)
+
+// for Extension Data Block
+#define EDID_TIMING_EXT_TAG_VAL (0x02)
+#define EDID_BLOCK_MAP_EXT_TAG_VAL (0xF0)
+
+#define EDID_SHORT_AUD_DEC_TAG_VAL (1<<5)
+#define EDID_SHORT_VID_DEC_TAG_VAL (2<<5)
+#define EDID_VSDB_TAG_VAL (3<<5)
+#define EDID_SPEAKER_ALLOCATION_TAG_VAL (4<<5)
+#define EDID_VESA_DTC_TAG_VAL (5<<5)
+#define EDID_RESERVED_TAG_VAL (6<<5)
+
+#define EDID_EXTENDED_TAG_VAL (7<<5)
+#define EDID_EXTENDED_COLORIMETRY_VAL (5)
+#define EDID_EXTENDED_COLORIMETRY_BLOCK_LEN (3)
+
+#define EDID_TAG_CODE_MASK (1<<7 | 1<<6 | 1<<5)
+#define EDID_DATA_BLOCK_SIZE_MASK (1<<4 | 1<<3 | 1<<2 | 1<<1 | 1<<0)
+
+#define EDID_VSDB_MIN_LENGTH_VAL (5)
+
+// for Established Timings
+#define EDID_ET_POS (0x23)
+#define EDID_ET_640x480p_VAL (0x20)
+
+// for DTD
+#define EDID_DTD_START_ADDR (0x36)
+#define EDID_DTD_BYTE_LENGTH (18)
+#define EDID_DTD_TOTAL_LENGTH (EDID_DTD_BYTE_LENGTH*4)
+
+#define EDID_DTD_PIXELCLOCK_POS1 (0)
+#define EDID_DTD_PIXELCLOCK_POS2 (1)
+
+#define EDID_DTD_HBLANK_POS1 (3)
+#define EDID_DTD_HBLANK_POS2 (4)
+#define EDID_DTD_HBLANK_POS2_MASK (0xF)
+
+#define EDID_DTD_HACTIVE_POS1 (2)
+#define EDID_DTD_HACTIVE_POS2 (4)
+#define EDID_DTD_HACTIVE_POS2_MASK (0xF0)
+
+#define EDID_DTD_VBLANK_POS1 (6)
+#define EDID_DTD_VBLANK_POS2 (7)
+#define EDID_DTD_VBLANK_POS2_MASK (0x0F)
+
+#define EDID_DTD_VACTIVE_POS1 (5)
+#define EDID_DTD_VACTIVE_POS2 (7)
+#define EDID_DTD_VACTIVE_POS2_MASK (0xF0)
+
+#define EDID_DTD_INTERLACE_POS (17)
+#define EDID_DTD_INTERLACE_MASK (1<<7)
+
+// for SVD
+#define EDID_SVD_VIC_MASK (0x7F)
+
+// for CS
+#define EDID_COLOR_SPACE_POS (3)
+#define EDID_YCBCR444_CS_MASK (1<<5)
+#define EDID_YCBCR422_CS_MASK (1<<4)
+
+// for Color Depth
+#define EDID_DC_48_VAL (1<<6)
+#define EDID_DC_36_VAL (1<<5)
+#define EDID_DC_30_VAL (1<<4)
+#define EDID_DC_YCBCR_VAL (1<<3)
+
+#define EDID_DC_POS (6)
+#define EDID_DC_MASK (EDID_DC_48_VAL | EDID_DC_36_VAL| EDID_DC_30_VAL | EDID_DC_YCBCR_VAL)
+
+// for colorimetry
+#define EDID_XVYCC601_MASK (1<<0)
+#define EDID_XVYCC709_MASK (1<<1)
+#define EDID_EXTENDED_MASK (1<<0|1<<1|1<<2)
+
+// for SAD
+#define SHORT_AUD_DESCRIPTOR_LPCM (1<<0)
+#define SHORT_AUD_DESCRIPTOR_AC3 (1<<1)
+#define SHORT_AUD_DESCRIPTOR_MPEG1 (1<<2)
+#define SHORT_AUD_DESCRIPTOR_MP3 (1<<3)
+#define SHORT_AUD_DESCRIPTOR_MPEG2 (1<<4)
+#define SHORT_AUD_DESCRIPTOR_AAC (1<<5)
+#define SHORT_AUD_DESCRIPTOR_DTS (1<<6)
+#define SHORT_AUD_DESCRIPTOR_ATRAC (1<<7)
+
+#define EDID_SAD_CODE_MASK (1<<6 | 1<<5 | 1<<4 | 1<<3)
+#define EDID_SAD_CHANNEL_MASK (1<<2 | 1<<1 | 1<<0)
+#define EDID_SAD_192KHZ_MASK (1<<6)
+#define EDID_SAD_176KHZ_MASK (1<<5)
+#define EDID_SAD_96KHZ_MASK (1<<4)
+#define EDID_SAD_88KHZ_MASK (1<<3)
+#define EDID_SAD_48KHZ_MASK (1<<2)
+#define EDID_SAD_44KHZ_MASK (1<<1)
+#define EDID_SAD_32KHZ_MASK (1<<0)
+
+#define EDID_SAD_WORD_24_MASK (1<<2)
+#define EDID_SAD_WORD_20_MASK (1<<1)
+#define EDID_SAD_WORD_16_MASK (1<<0)
+
+// for CEC
+#define EDID_CEC_PHYICAL_ADDR (4)
+
+// for 3D
+#define EDID_HDMI_EXT_POS (8)
+#define EDID_HDMI_VIDEO_PRESENT_MASK (1<<5)
+
+// latency
+#define EDID_HDMI_LATENCY_MASK (1<<7|1<<6)
+#define EDID_HDMI_LATENCY_POS (6)
+
+#define EDID_HDMI_3D_PRESENT_POS (13)
+#define EDID_HDMI_3D_PRESENT_MASK (1<<7)
+#define EDID_HDMI_3D_MULTI_PRESENT_MASK (1<<6 | 1<<5)
+#define EDID_HDMI_3D_MULTI_PRESENT_BIT 5
+
+#define EDID_3D_STRUCTURE_ONLY_EXIST (1<<5)
+#define EDID_3D_STRUCTURE_MASK_EXIST (1<<6)
+
+#define EDID_3D_STRUCTURE_FP (0)
+#define EDID_3D_STRUCTURE_FA (1)
+#define EDID_3D_STRUCTURE_LA (2)
+#define EDID_3D_STRUCTURE_SSF (3)
+#define EDID_3D_STRUCTURE_LD (4)
+#define EDID_3D_STRUCTURE_LDGFX (5)
+#define EDID_3D_STRUCTURE_TB (6)
+#define EDID_3D_STRUCTURE_SSH (8)
+
+#define EDID_HDMI_EXT_LENGTH_POS (14)
+#define EDID_HDMI_VSDB_VIC_LEN_BIT (5)
+#define EDID_HDMI_VSDB_VIC_LEN_MASK (1<<7|1<<6|1<<5)
+#define EDID_HDMI_VSDB_3D_LEN_MASK (1<<4|1<<3|1<<2|1<<1|1<<0)
+
+#define EDID_HDMI_2D_VIC_ORDER_MASK (1<<7|1<<6|1<<5|1<<4)
+#define EDID_HDMI_3D_STRUCTURE_MASK (1<<3|1<<2|1<<1|1<<0)
+
+// for MAX TMDS
+#define EDID_MAX_TMDS_POS (7)
+
+// for 3D Structure
+#define NUM_OF_VIC_FOR_3D 16
+//@}
+
+#endif /* _EDID_H_ */
diff --git a/exynos5/hal/libhdmi/libsForhdmi/libedid/libedid.c b/exynos5/hal/libhdmi/libsForhdmi/libedid/libedid.c
new file mode 100644
index 0000000..c6bed50
--- /dev/null
+++ b/exynos5/hal/libhdmi/libsForhdmi/libedid/libedid.c
@@ -0,0 +1,1265 @@
+/*
+* Copyright@ Samsung Electronics Co. LTD
+*
+* 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.
+*/
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <cutils/log.h>
+
+#include "edid.h"
+#include "libedid.h"
+#include "../libddc/libddc.h"
+
+//#define EDID_DEBUG 1
+
+#ifdef EDID_DEBUG
+#define DPRINTF(args...) LOGI(args)
+#else
+#define DPRINTF(args...)
+#endif
+
+#define NUM_OF_VIC_FOR_3D 16
+
+/**
+ * @var gEdidData
+ * Pointer to EDID data
+ */
+static unsigned char* gEdidData;
+
+/**
+ * @var gExtensions
+ * Number of EDID extensions
+ */
+static int gExtensions;
+
+
+/**
+ * @var aVIC
+ * This contains first 16 VIC in EDID
+ */
+static unsigned char aVIC[NUM_OF_VIC_FOR_3D];
+
+//! Structure for parsing video timing parameter in EDID
+static const struct edid_params {
+ /** H Total */
+ unsigned int HTotal;
+
+ /** H Blank */
+ unsigned int HBlank;
+
+ /** V Total */
+ unsigned int VTotal;
+
+ /** V Blank */
+ unsigned int VBlank;
+
+ /** CEA VIC */
+ unsigned char VIC;
+
+ /** CEA VIC for 16:9 aspect ratio */
+ unsigned char VIC16_9;
+
+ /** 0 if progressive, 1 if interlaced */
+ unsigned char interlaced;
+
+ /** Pixel frequency */
+ enum PixelFreq PixelClock;
+} aVideoParams[] =
+{
+ { 800 , 160 , 525 , 45, 1 , 1 , 0, PIXEL_FREQ_25_200 ,}, // v640x480p_60Hz
+ { 858 , 138 , 525 , 45, 2 , 3 , 0, PIXEL_FREQ_27_027 ,}, // v720x480p_60Hz
+ { 1650, 370 , 750 , 30, 4 , 4 , 0, PIXEL_FREQ_74_250 ,}, // v1280x720p_60Hz
+ { 2200, 280 , 1125, 22, 5 , 5 , 1, PIXEL_FREQ_74_250 ,}, // v1920x1080i_60H
+ { 1716, 276 , 525 , 22, 6 , 7 , 1, PIXEL_FREQ_74_250 ,}, // v720x480i_60Hz
+ { 1716, 276 , 262 , 22, 8 , 9 , 0, PIXEL_FREQ_27_027 ,}, // v720x240p_60Hz
+ //{ 1716, 276 , 263 , 23, 8 , 9 , 0, PIXEL_FREQ_27_027 , }, // v720x240p_60Hz(mode 2)
+ { 3432, 552 , 525 , 22, 10, 11, 1, PIXEL_FREQ_54_054 , }, // v2880x480i_60Hz
+ { 3432, 552 , 262 , 22, 12, 13, 0, PIXEL_FREQ_54_054 , }, // v2880x240p_60Hz
+ //{ 3432, 552 , 263 , 23, 12, 13, 0, PIXEL_FREQ_54_054 , }, // v2880x240p_60Hz(mode 2)
+ { 1716, 276 , 525 , 45, 14, 15, 0, PIXEL_FREQ_54_054 , }, // v1440x480p_60Hz
+ { 2200, 280 , 1125, 45, 16, 16, 0, PIXEL_FREQ_148_500, }, // v1920x1080p_60H
+ { 864 , 144 , 625 , 49, 17, 18, 0, PIXEL_FREQ_27 , }, // v720x576p_50Hz
+ { 1980, 700 , 750 , 30, 19, 19, 0, PIXEL_FREQ_74_250 , }, // v1280x720p_50Hz
+ { 2640, 720 , 1125, 22, 20, 20, 1, PIXEL_FREQ_74_250 , }, // v1920x1080i_50H
+ { 1728, 288 , 625 , 24, 21, 22, 1, PIXEL_FREQ_27 , }, // v720x576i_50Hz
+ { 1728, 288 , 312 , 24, 23, 24, 0, PIXEL_FREQ_27 , }, // v720x288p_50Hz
+ //{ 1728, 288 , 313 , 25, 23, 24, 0, PIXEL_FREQ_27 , }, // v720x288p_50Hz(mode 2)
+ //{ 1728, 288 , 314 , 26, 23, 24, 0, PIXEL_FREQ_27 , }, // v720x288p_50Hz(mode 3)
+ { 3456, 576 , 625 , 24, 25, 26, 1, PIXEL_FREQ_54 , }, // v2880x576i_50Hz
+ { 3456, 576 , 312 , 24, 27, 28, 0, PIXEL_FREQ_54 , }, // v2880x288p_50Hz
+ //{ 3456, 576 , 313 , 25, 27, 28, 0, PIXEL_FREQ_54 , }, // v2880x288p_50Hz(mode 2)
+ //{ 3456, 576 , 314 , 26, 27, 28, 0, PIXEL_FREQ_54 , }, // v2880x288p_50Hz(mode 3)
+ { 1728, 288 , 625 , 49, 29, 30, 0, PIXEL_FREQ_54 , }, // v1440x576p_50Hz
+ { 2640, 720 , 1125, 45, 31, 31, 0, PIXEL_FREQ_148_500,}, // v1920x1080p_50Hz
+ { 2750, 830 , 1125, 45, 32, 32, 0, PIXEL_FREQ_74_250 ,}, // v1920x1080p_24Hz
+ { 2640, 720 , 1125, 45, 33, 33, 0, PIXEL_FREQ_74_250 ,}, // v1920x1080p_25Hz
+ { 2200, 280 , 1125, 45, 34, 34, 0, PIXEL_FREQ_74_250 ,}, // v1920x1080p_30Hz
+ { 3432, 552 , 525 , 45, 35, 36, 0, PIXEL_FREQ_108_108,}, // v2880x480p_60Hz
+ { 3456, 576 , 625 , 49, 37, 38, 0, PIXEL_FREQ_108 ,}, // v2880x576p_50Hz
+ { 2304, 384 , 1250, 85, 39, 39, 1, PIXEL_FREQ_72 ,}, // v1920x1080i_50Hz(1250)
+ { 2640, 720 , 1125, 22, 40, 40, 1, PIXEL_FREQ_148_500, }, // v1920x1080i_100Hz
+ { 1980, 700 , 750 , 30, 41, 41, 0, PIXEL_FREQ_148_500, }, // v1280x720p_100Hz
+ { 864 , 144 , 625 , 49, 42, 43, 0, PIXEL_FREQ_54 , }, // v720x576p_100Hz
+ { 1728, 288 , 625 , 24, 44, 45, 1, PIXEL_FREQ_54 , }, // v720x576i_100Hz
+ { 2200, 280 , 1125, 22, 46, 46, 1, PIXEL_FREQ_148_500, }, // v1920x1080i_120Hz
+ { 1650, 370 , 750 , 30, 47, 47, 0, PIXEL_FREQ_148_500, }, // v1280x720p_120Hz
+ { 858 , 138 , 525 , 54, 48, 49, 0, PIXEL_FREQ_54_054 , }, // v720x480p_120Hz
+ { 1716, 276 , 525 , 22, 50, 51, 1, PIXEL_FREQ_54_054 , }, // v720x480i_120Hz
+ { 864 , 144 , 625 , 49, 52, 53, 0, PIXEL_FREQ_108 , }, // v720x576p_200Hz
+ { 1728, 288 , 625 , 24, 54, 55, 1, PIXEL_FREQ_108 , }, // v720x576i_200Hz
+ { 858 , 138 , 525 , 45, 56, 57, 0, PIXEL_FREQ_108_108, }, // v720x480p_240Hz
+ { 1716, 276 , 525 , 22, 58, 59, 1, PIXEL_FREQ_108_108, }, // v720x480i_240Hz
+ // PHY Freq is not available yet
+ //{ 3300, 2020, 750 , 30, 60, 60, 0, PIXEL_FREQ_59_400 ,}, // v1280x720p24Hz
+ { 3960, 2680, 750 , 30, 61, 61, 0, PIXEL_FREQ_74_250 , }, // v1280x720p25Hz
+ { 3300, 2020, 750 , 30, 62, 62, 0, PIXEL_FREQ_74_250 ,}, // v1280x720p30Hz
+ // PHY Freq is not available yet
+ //{ 2200, 280 , 1125, 45, 63, 63, 0, PIXEL_FREQ_297, }, // v1920x1080p120Hz
+ //{ 2640, 720 , 1125, 45, 64, 64, 0, PIXEL_FREQ_297, }, // v1920x1080p100Hz
+ //{ 4400, 560 , 2250, 90, 1, 1, 0, 0, PIXEL_FREQ_297, }, // v4Kx2K30Hz
+};
+
+//! Structure for Checking 3D Mandatory Format in EDID
+static const struct edid_3d_mandatory {
+ /** video Format */
+ enum VideoFormat resolution;
+
+ /** 3D Structure */
+ enum HDMI3DVideoStructure hdmi_3d_format;
+} edid_3d [] =
+{
+ { v1920x1080p_24Hz, HDMI_3D_FP_FORMAT }, // 1920x1080p @ 23.98/24Hz
+ { v1280x720p_60Hz, HDMI_3D_FP_FORMAT }, // 1280x720p @ 59.94/60Hz
+ { v1920x1080i_60Hz, HDMI_3D_SSH_FORMAT }, // 1920x1080i @ 59.94/60Hz
+ { v1920x1080p_24Hz, HDMI_3D_TB_FORMAT }, // 1920x1080p @ 23.98/24Hz
+ { v1280x720p_60Hz, HDMI_3D_TB_FORMAT }, // 1280x720p @ 59.94/60Hz
+ { v1280x720p_50Hz, HDMI_3D_FP_FORMAT }, // 1280x720p @ 50Hz
+ { v1920x1080i_50Hz, HDMI_3D_SSH_FORMAT }, // 1920x1080i @ 50Hz
+ { v1280x720p_50Hz, HDMI_3D_TB_FORMAT }, // 1280x720p @ 50Hz
+};
+
+/**
+ * Calculate a checksum.
+ *
+ * @param buffer [in] Pointer to data to calculate a checksum
+ * @param size [in] Sizes of data
+ *
+ * @return If checksum result is 0, return 1; Otherwise, return 0.
+ */
+static int CalcChecksum(const unsigned char* const buffer, const int size)
+{
+ unsigned char i,sum;
+ int ret = 1;
+
+ // check parameter
+ if (buffer == NULL ) {
+ DPRINTF("invalid parameter : buffer\n");
+ return 0;
+ }
+ for (sum = 0, i = 0 ; i < size; i++)
+ sum += buffer[i];
+
+ // check checksum
+ if (sum != 0)
+ ret = 0;
+
+ return ret;
+}
+
+/**
+ * Read EDID Block(128 bytes)
+ *
+ * @param blockNum [in] Number of block to read @n
+ * For example, EDID block = 0, EDID first Extension = 1, and so on.
+ * @param outBuffer [out] Pointer to buffer to store EDID data
+ *
+ * @return If fail to read, return 0; Otherwise, return 1.
+ */
+static int ReadEDIDBlock(const unsigned int blockNum, unsigned char* const outBuffer)
+{
+ int segNum, offset, dataPtr;
+
+ // check parameter
+ if (outBuffer == NULL) {
+ DPRINTF("invalid parameter : outBuffer\n");
+ return 0;
+ }
+
+ // calculate
+ segNum = blockNum / 2;
+ offset = (blockNum % 2) * SIZEOFEDIDBLOCK;
+ dataPtr = (blockNum) * SIZEOFEDIDBLOCK;
+
+ // read block
+ if (!EDDCRead(EDID_SEGMENT_POINTER, segNum, EDID_ADDR, offset, SIZEOFEDIDBLOCK, outBuffer)) {
+ DPRINTF("Fail to Read %dth EDID Block\n", blockNum);
+ return 0;
+ }
+
+ if (!CalcChecksum(outBuffer, SIZEOFEDIDBLOCK)) {
+ DPRINTF("CheckSum fail : %dth EDID Block\n", blockNum);
+ return 0;
+ }
+
+ // print data
+#ifdef EDID_DEBUG
+ offset = 0;
+ do {
+ LOGI("0x%02X", outBuffer[offset++]);
+ if (offset % 16)
+ LOGI(" ");
+ else
+ LOGI("\n");
+ } while (SIZEOFEDIDBLOCK > offset);
+#endif // EDID_DEBUG
+ return 1;
+}
+
+/**
+ * Check if EDID data is valid or not.
+ *
+ * @return if EDID data is valid, return 1; Otherwise, return 0.
+ */
+static inline int EDIDValid(void)
+{
+ return (gEdidData == NULL) ? 0 : 1;
+}
+
+/**
+ * Search HDMI Vender Specific Data Block(VSDB) in EDID extension block.
+ *
+ * @param extension [in] the number of EDID extension block to check
+ *
+ * @return if there is a HDMI VSDB, return the offset from start of @n
+ * EDID extension block. if there is no VSDB, return 0.
+ */
+static int GetVSDBOffset(const int extension)
+{
+ unsigned int BlockOffset = extension*SIZEOFEDIDBLOCK;
+ unsigned int offset = BlockOffset + EDID_DATA_BLOCK_START_POS;
+ unsigned int tag,blockLen,DTDOffset;
+
+ if (!EDIDValid() || (extension > gExtensions)) {
+ DPRINTF("EDID Data is not available\n");
+ return 0;
+ }
+
+ DTDOffset = gEdidData[BlockOffset + EDID_DETAILED_TIMING_OFFSET_POS];
+
+ // check if there is HDMI VSDB
+ while (offset < BlockOffset + DTDOffset) {
+ // find the block tag and length
+ // tag
+ tag = gEdidData[offset] & EDID_TAG_CODE_MASK;
+ // block len
+ blockLen = (gEdidData[offset] & EDID_DATA_BLOCK_SIZE_MASK) + 1;
+
+ // check if it is HDMI VSDB
+ // if so, check identifier value, if it's hdmi vsbd - return offset
+ if (tag == EDID_VSDB_TAG_VAL &&
+ gEdidData[offset+1] == 0x03 &&
+ gEdidData[offset+2] == 0x0C &&
+ gEdidData[offset+3] == 0x0 &&
+ blockLen > EDID_VSDB_MIN_LENGTH_VAL )
+ return offset;
+
+ // else find next block
+ offset += blockLen;
+ }
+
+ // return error
+ return 0;
+}
+
+/**
+ * Check if Sink supports the HDMI mode.
+ * @return If Sink supports HDMI mode, return 1; Otherwise, return 0.
+ */
+static int CheckHDMIMode(void)
+{
+ int i;
+
+ // read EDID
+ if (!EDIDRead())
+ return 0;
+
+ // find VSDB
+ for (i = 1; i <= gExtensions; i++)
+ if (GetVSDBOffset(i) > 0) // if there is a VSDB, it means RX support HDMI mode
+ return 1;
+
+ return 0;
+}
+
+/**
+ * Check if EDID extension block is timing extension block or not.
+ * @param extension [in] The number of EDID extension block to check
+ * @return If the block is timing extension, return 1; Otherwise, return 0.
+ */
+static int IsTimingExtension(const int extension)
+{
+ int ret = 0;
+ if (!EDIDValid() || (extension > gExtensions)) {
+ DPRINTF("EDID Data is not available\n");
+ return ret;
+ }
+
+ if (gEdidData[extension*SIZEOFEDIDBLOCK] == EDID_TIMING_EXT_TAG_VAL) {
+ // check extension revsion number
+ // revision num == 3
+ if (gEdidData[extension*SIZEOFEDIDBLOCK + EDID_TIMING_EXT_REV_NUMBER_POS] == 3)
+ ret = 1;
+ // revison num != 3 && DVI mode
+ else if (!CheckHDMIMode() &&
+ gEdidData[extension*SIZEOFEDIDBLOCK + EDID_TIMING_EXT_REV_NUMBER_POS] != 2)
+ ret = 1;
+ }
+ return ret;
+}
+
+/**
+ * Check if the video format is contained in - @n
+ * Detailed Timing Descriptor(DTD) of EDID extension block.
+ * @param extension [in] Number of EDID extension block to check
+ * @param videoFormat [in] Video format to check
+ * @return If the video format is contained in DTD of EDID extension block, -@n
+ * return 1; Otherwise, return 0.
+ */
+static int IsContainVideoDTD(const int extension,const enum VideoFormat videoFormat)
+{
+ int i, StartOffset, EndOffset;
+
+ if (!EDIDValid() || (extension > gExtensions)) {
+ DPRINTF("EDID Data is not available\n");
+ return 0;
+ }
+
+ // if edid block( 0th block )
+ if (extension == 0) {
+ StartOffset = EDID_DTD_START_ADDR;
+ EndOffset = StartOffset + EDID_DTD_TOTAL_LENGTH;
+ } else { // if edid extension block
+ StartOffset = extension*SIZEOFEDIDBLOCK + gEdidData[extension*SIZEOFEDIDBLOCK + EDID_DETAILED_TIMING_OFFSET_POS];
+ EndOffset = (extension+1)*SIZEOFEDIDBLOCK;
+ }
+
+ // check DTD(Detailed Timing Description)
+ for (i = StartOffset; i < EndOffset; i+= EDID_DTD_BYTE_LENGTH) {
+ unsigned int hblank = 0, hactive = 0, vblank = 0, vactive = 0, interlaced = 0, pixelclock = 0;
+ unsigned int vHActive = 0, vVActive = 0, vVBlank = 0;
+
+ // get pixel clock
+ pixelclock = (gEdidData[i+EDID_DTD_PIXELCLOCK_POS2] << SIZEOFBYTE);
+ pixelclock |= gEdidData[i+EDID_DTD_PIXELCLOCK_POS1];
+
+ if (!pixelclock)
+ continue;
+
+ // get HBLANK value in pixels
+ hblank = gEdidData[i+EDID_DTD_HBLANK_POS2] & EDID_DTD_HBLANK_POS2_MASK;
+ hblank <<= SIZEOFBYTE; // lower 4 bits
+ hblank |= gEdidData[i+EDID_DTD_HBLANK_POS1];
+
+ // get HACTIVE value in pixels
+ hactive = gEdidData[i+EDID_DTD_HACTIVE_POS2] & EDID_DTD_HACTIVE_POS2_MASK;
+ hactive <<= (SIZEOFBYTE/2); // upper 4 bits
+ hactive |= gEdidData[i+EDID_DTD_HACTIVE_POS1];
+
+ // get VBLANK value in pixels
+ vblank = gEdidData[i+EDID_DTD_VBLANK_POS2] & EDID_DTD_VBLANK_POS2_MASK;
+ vblank <<= SIZEOFBYTE; // lower 4 bits
+ vblank |= gEdidData[i+EDID_DTD_VBLANK_POS1];
+
+ // get VACTIVE value in pixels
+ vactive = gEdidData[i+EDID_DTD_VACTIVE_POS2] & EDID_DTD_VACTIVE_POS2_MASK;
+ vactive <<= (SIZEOFBYTE/2); // upper 4 bits
+ vactive |= gEdidData[i+EDID_DTD_VACTIVE_POS1];
+
+ vHActive = aVideoParams[videoFormat].HTotal - aVideoParams[videoFormat].HBlank;
+ if (aVideoParams[videoFormat].interlaced == 1) {
+ if (aVideoParams[videoFormat].VIC == v1920x1080i_50Hz_1250) { // VTOP and VBOT are same
+ vVActive = (aVideoParams[videoFormat].VTotal - aVideoParams[videoFormat].VBlank*2)/2;
+ vVBlank = aVideoParams[videoFormat].VBlank;
+ } else {
+ vVActive = (aVideoParams[videoFormat].VTotal - aVideoParams[videoFormat].VBlank*2 - 1)/2;
+ vVBlank = aVideoParams[videoFormat].VBlank;
+ }
+ } else {
+ vVActive = aVideoParams[videoFormat].VTotal - aVideoParams[videoFormat].VBlank;
+ vVBlank = aVideoParams[videoFormat].VBlank;
+ }
+
+ // get Interlaced Mode Value
+ interlaced = (int)(gEdidData[i+EDID_DTD_INTERLACE_POS] & EDID_DTD_INTERLACE_MASK);
+ if (interlaced)
+ interlaced = 1;
+
+ DPRINTF("EDID: hblank = %d,vblank = %d, hactive = %d, vactive = %d\n"
+ ,hblank,vblank,hactive,vactive);
+ DPRINTF("REQ: hblank = %d,vblank = %d, hactive = %d, vactive = %d\n"
+ ,aVideoParams[videoFormat].HBlank
+ ,vVBlank,vHActive,vVActive);
+
+ if (hblank == aVideoParams[videoFormat].HBlank && vblank == vVBlank // blank
+ && hactive == vHActive && vactive == vVActive) { //line
+ unsigned int EDIDpixelclock = aVideoParams[videoFormat].PixelClock;
+ EDIDpixelclock /= 100; pixelclock /= 100;
+
+ if (pixelclock == EDIDpixelclock) {
+ DPRINTF("Sink Support the Video mode\n");
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * Check if a VIC(Video Identification Code) is contained in -@n
+ * EDID extension block.
+ * @param extension [in] Number of EDID extension block to check
+ * @param VIC [in] VIC to check
+ * @return If the VIC is contained in contained in EDID extension block, -@n
+ * return 1; Otherwise, return 0.
+ */
+static int IsContainVIC(const int extension, const int VIC)
+{
+ unsigned int StartAddr = extension*SIZEOFEDIDBLOCK;
+ unsigned int ExtAddr = StartAddr + EDID_DATA_BLOCK_START_POS;
+ unsigned int tag,blockLen;
+ unsigned int DTDStartAddr = gEdidData[StartAddr + EDID_DETAILED_TIMING_OFFSET_POS];
+
+ if (!EDIDValid() || (extension > gExtensions)) {
+ DPRINTF("EDID Data is not available\n");
+ return 0;
+ }
+
+ // while
+ while (ExtAddr < StartAddr + DTDStartAddr) {
+ // find the block tag and length
+ // tag
+ tag = gEdidData[ExtAddr] & EDID_TAG_CODE_MASK;
+ // block len
+ blockLen = (gEdidData[ExtAddr] & EDID_DATA_BLOCK_SIZE_MASK) + 1;
+ DPRINTF("tag = %d\n",tag);
+ DPRINTF("blockLen = %d\n",blockLen-1);
+
+ // check if it is short video description
+ if (tag == EDID_SHORT_VID_DEC_TAG_VAL) {
+ // if so, check SVD
+ unsigned int i;
+ for (i = 1; i < blockLen; i++) {
+ DPRINTF("EDIDVIC = %d\n",gEdidData[ExtAddr+i] & EDID_SVD_VIC_MASK);
+ DPRINTF("VIC = %d\n",VIC);
+
+ // check VIC with SVDB
+ if (VIC == (gEdidData[ExtAddr+i] & EDID_SVD_VIC_MASK)) {
+ DPRINTF("Sink Device supports requested video mode\n");
+ return 1;
+ }
+ }
+ }
+ // else find next block
+ ExtAddr += blockLen;
+ }
+
+ return 0;
+}
+
+/**
+ * Check if EDID contains the video format.
+ * @param videoFormat [in] Video format to check
+ * @param pixelRatio [in] Pixel aspect ratio of video format to check
+ * @return if EDID contains the video format, return 1; Otherwise, return 0.
+ */
+static int CheckResolution(const enum VideoFormat videoFormat,
+ const enum PixelAspectRatio pixelRatio)
+{
+ int i, vic;
+
+ // read EDID
+ if (!EDIDRead())
+ return 0;
+
+ // check ET(Established Timings) for 640x480p@60Hz
+ if (videoFormat == v640x480p_60Hz // if it's 640x480p@60Hz
+ && (gEdidData[EDID_ET_POS] & EDID_ET_640x480p_VAL)) // it support
+ return 1;
+
+ // check STI(Standard Timing Identification)
+ // do not need
+
+ // check DTD(Detailed Timing Description) of EDID block(0th)
+ if (IsContainVideoDTD(0,videoFormat))
+ return 1;
+
+ // check EDID Extension
+ vic = (pixelRatio == HDMI_PIXEL_RATIO_16_9) ?
+ aVideoParams[videoFormat].VIC16_9 : aVideoParams[videoFormat].VIC;
+
+ // find VSDB
+ for (i = 1; i <= gExtensions; i++) {
+ if (IsTimingExtension(i)) // if it's timing block
+ if (IsContainVIC(i, vic) || IsContainVideoDTD(i, videoFormat))
+ return 1;
+ }
+
+ return 0;
+}
+
+/**
+ * Check if EDID supports the color depth.
+ * @param depth [in] Color depth
+ * @param space [in] Color space
+ * @return If EDID supports the color depth, return 1; Otherwise, return 0.
+ */
+static int CheckColorDepth(const enum ColorDepth depth,const enum ColorSpace space)
+{
+ int i;
+ unsigned int StartAddr;
+
+ // if color depth == 24 bit, no need to check
+ if (depth == HDMI_CD_24)
+ return 1;
+
+ // check EDID data is valid or not
+ // read EDID
+ if (!EDIDRead())
+ return 0;
+
+ // find VSDB
+ for (i = 1; i <= gExtensions; i++) {
+ if (IsTimingExtension(i) // if it's timing block
+ && ((StartAddr = GetVSDBOffset(i)) > 0)) { // check block
+ int blockLength = gEdidData[StartAddr] & EDID_DATA_BLOCK_SIZE_MASK;
+ if (blockLength >= EDID_DC_POS) {
+ // get supported DC value
+ int deepColor = gEdidData[StartAddr + EDID_DC_POS] & EDID_DC_MASK;
+ DPRINTF("EDID deepColor = %x\n",deepColor);
+ // check supported DeepColor
+ // if YCBCR444
+ if (space == HDMI_CS_YCBCR444) {
+ if ( !(deepColor & EDID_DC_YCBCR_VAL))
+ return 0;
+ }
+
+ // check colorDepth
+ switch (depth) {
+ case HDMI_CD_36:
+ deepColor &= EDID_DC_36_VAL;
+ break;
+ case HDMI_CD_30:
+ deepColor &= EDID_DC_30_VAL;
+ break;
+ case HDMI_CD_24:
+ deepColor = 1;
+ break;
+ default :
+ deepColor = 0;
+ }
+ if (deepColor)
+ return 1;
+ else
+ return 0;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Check if EDID supports the color space.
+ * @param space [in] Color space
+ * @return If EDID supports the color space, return 1; Otherwise, return 0.
+ */
+static int CheckColorSpace(const enum ColorSpace space)
+{
+ int i;
+
+ // RGB is default
+ if (space == HDMI_CS_RGB)
+ return 1;
+
+ // check EDID data is valid or not
+ // read EDID
+ if (!EDIDRead())
+ return 0;
+
+ // find VSDB
+ for (i = 1; i <= gExtensions; i++) {
+ if (IsTimingExtension(i)) { // if it's timing block
+ // read Color Space
+ int CS = gEdidData[i*SIZEOFEDIDBLOCK + EDID_COLOR_SPACE_POS];
+
+ if ((space == HDMI_CS_YCBCR444 && (CS & EDID_YCBCR444_CS_MASK)) || // YCBCR444
+ (space == HDMI_CS_YCBCR422 && (CS & EDID_YCBCR422_CS_MASK))) // YCBCR422
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Check if EDID supports the colorimetry.
+ * @param color [in] Colorimetry
+ * @return If EDID supports the colorimetry, return 1; Otherwise, return 0.
+ */
+static int CheckColorimetry(const enum HDMIColorimetry color)
+{
+ int i;
+
+ // do not need to parse if not extended colorimetry
+ if (color == HDMI_COLORIMETRY_NO_DATA ||
+ color == HDMI_COLORIMETRY_ITU601 ||
+ color == HDMI_COLORIMETRY_ITU709)
+ return 1;
+
+ // read EDID
+ if (!EDIDRead())
+ return 0;
+
+ // find VSDB
+ for (i = 1; i <= gExtensions; i++) {
+ if (IsTimingExtension(i)) { // if it's timing block
+ // check address
+ unsigned int ExtAddr = i*SIZEOFEDIDBLOCK + EDID_DATA_BLOCK_START_POS;
+ unsigned int EndAddr = i*SIZEOFEDIDBLOCK + gEdidData[i*SIZEOFEDIDBLOCK + EDID_DETAILED_TIMING_OFFSET_POS];
+ unsigned int tag,blockLen;
+
+ while (ExtAddr < EndAddr) {
+ // find the block tag and length
+ // tag
+ tag = gEdidData[ExtAddr] & EDID_TAG_CODE_MASK;
+ // block len
+ blockLen = (gEdidData[ExtAddr] & EDID_DATA_BLOCK_SIZE_MASK) + 1;
+
+ // check if it is colorimetry block
+ if (tag == EDID_EXTENDED_TAG_VAL && // extended tag
+ gEdidData[ExtAddr+1] == EDID_EXTENDED_COLORIMETRY_VAL && // colorimetry block
+ (blockLen-1) == EDID_EXTENDED_COLORIMETRY_BLOCK_LEN) { // check length
+ // get supported DC value
+ int colorimetry = (gEdidData[ExtAddr + 2]);
+ int metadata = (gEdidData[ExtAddr + 3]);
+
+ DPRINTF("EDID extened colorimetry = %x\n",colorimetry);
+ DPRINTF("EDID gamut metadata profile = %x\n",metadata);
+
+ // check colorDepth
+ switch (color) {
+ case HDMI_COLORIMETRY_EXTENDED_xvYCC601:
+ if (colorimetry & EDID_XVYCC601_MASK && metadata)
+ return 1;
+ break;
+ case HDMI_COLORIMETRY_EXTENDED_xvYCC709:
+ if (colorimetry & EDID_XVYCC709_MASK && metadata)
+ return 1;
+ break;
+ default:
+ break;
+ }
+ return 0;
+ }
+ // else find next block
+ ExtAddr += blockLen;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Get Max TMDS clock that HDMI Rx can receive.
+ * @return If available, return MaxTMDS clock; Otherwise, return 0.
+ */
+static unsigned int GetMaxTMDS(void)
+{
+ int i;
+ unsigned int StartAddr;
+
+ // find VSDB
+ for (i = 1; i <= gExtensions; i++) {
+ if (IsTimingExtension(i) // if it's timing block
+ && ((StartAddr = GetVSDBOffset(i)) > 0)) { // check block
+ int blockLength = gEdidData[StartAddr] & EDID_DATA_BLOCK_SIZE_MASK;
+ if (blockLength >= EDID_MAX_TMDS_POS) {
+ // get supported DC value
+ return gEdidData[StartAddr + EDID_MAX_TMDS_POS];
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Save first 16 VIC of EDID
+ */
+static void SaveVIC(void)
+{
+ int extension;
+ int vic_count = 0;
+ for (extension = 1; extension <= gExtensions && vic_count < NUM_OF_VIC_FOR_3D; extension++) {
+ unsigned int StartAddr = extension*SIZEOFEDIDBLOCK;
+ unsigned int ExtAddr = StartAddr + EDID_DATA_BLOCK_START_POS;
+ unsigned int tag,blockLen;
+ unsigned int DTDStartAddr = gEdidData[StartAddr + EDID_DETAILED_TIMING_OFFSET_POS];
+
+ while (ExtAddr < StartAddr + DTDStartAddr) {
+ // find the block tag and length
+ // tag
+ tag = gEdidData[ExtAddr] & EDID_TAG_CODE_MASK;
+ // block len
+ blockLen = (gEdidData[ExtAddr] & EDID_DATA_BLOCK_SIZE_MASK) + 1;
+
+ // check if it is short video description
+ if (tag == EDID_SHORT_VID_DEC_TAG_VAL) {
+ // if so, check SVD
+ unsigned int edid_index;
+ for (edid_index = 1; edid_index < blockLen && vic_count < NUM_OF_VIC_FOR_3D; edid_index++) {
+ DPRINTF("EDIDVIC = %d\r\n", gEdidData[ExtAddr+edid_index] & EDID_SVD_VIC_MASK);
+
+ // check VIC with SVDB
+ aVIC[vic_count++] = (gEdidData[ExtAddr+edid_index] & EDID_SVD_VIC_MASK);
+ }
+ }
+ // else find next block
+ ExtAddr += blockLen;
+ }
+ }
+}
+
+/**
+ * Check if Rx supports requested 3D format.
+ * @param pVideo [in] HDMI Video Parameter
+ * @return If Rx supports requested 3D format, return 1; Otherwise, return 0.
+ */
+static int EDID3DFormatSupport(const struct HDMIVideoParameter * const pVideo)
+{
+ int edid_index;
+ unsigned int StartAddr;
+ unsigned int vic;
+ vic = (pVideo->pixelAspectRatio == HDMI_PIXEL_RATIO_16_9) ?
+ aVideoParams[pVideo->resolution].VIC16_9 : aVideoParams[pVideo->resolution].VIC;
+
+ // if format == 2D, no need to check
+ if (pVideo->hdmi_3d_format == HDMI_2D_VIDEO_FORMAT)
+ return 1;
+
+ // check EDID data is valid or not
+ if (!EDIDRead())
+ return 0;
+
+ // save first 16 VIC to check
+ SaveVIC();
+
+ // find VSDB
+ for (edid_index = 1; edid_index <= gExtensions; edid_index++) {
+ if (IsTimingExtension(edid_index) // if it's timing block
+ && ((StartAddr = GetVSDBOffset(edid_index)) > 0)) { // check block
+ unsigned int blockLength = gEdidData[StartAddr] & EDID_DATA_BLOCK_SIZE_MASK;
+ unsigned int VSDBHdmiVideoPre = 0;
+ unsigned int VSDB3DPresent = 0;
+ unsigned int VSDB3DMultiPresent = 0;
+ unsigned int HDMIVICLen;
+ unsigned int HDMI3DLen;
+ int Hdmi3DStructure = 0;
+ unsigned int Hdmi3DMask = 0xFFFF;
+ unsigned int latency_offset = 0;
+
+ DPRINTF("VSDB Block length[0x%x] = 0x%x\r\n",StartAddr,blockLength);
+
+ // get HDMI Video Present value
+ if (blockLength >= EDID_HDMI_EXT_POS) {
+ VSDBHdmiVideoPre = gEdidData[StartAddr + EDID_HDMI_EXT_POS]
+ & EDID_HDMI_VIDEO_PRESENT_MASK;
+ DPRINTF("EDID HDMI Video Present = 0x%x\n",VSDBHdmiVideoPre);
+ } else { // data related to 3D format is not available
+ return 0;
+ }
+
+ // check if latency field is available
+ latency_offset = (gEdidData[StartAddr + EDID_HDMI_EXT_POS]
+ & EDID_HDMI_LATENCY_MASK) >> EDID_HDMI_LATENCY_POS;
+ if (latency_offset == 0)
+ latency_offset = 4;
+ else if (latency_offset == 3)
+ latency_offset = 0;
+ else
+ latency_offset = 2;
+
+ StartAddr -= latency_offset;
+
+ // HDMI_VIC_LEN
+ HDMIVICLen = (gEdidData[StartAddr + EDID_HDMI_EXT_LENGTH_POS]
+ & EDID_HDMI_VSDB_VIC_LEN_MASK) >> EDID_HDMI_VSDB_VIC_LEN_BIT;
+
+ if (pVideo->hdmi_3d_format == HDMI_VIC_FORMAT) {
+ if (HDMIVICLen) {
+ for (edid_index = 0; edid_index < (int)HDMIVICLen; edid_index++) {
+ if (vic == gEdidData[StartAddr + EDID_HDMI_EXT_LENGTH_POS + edid_index])
+ return 1;
+ }
+ return 0;
+ } else {
+ return 0;
+ }
+ }
+
+ // HDMI_3D_LEN
+ HDMI3DLen = gEdidData[StartAddr + EDID_HDMI_EXT_LENGTH_POS]
+ & EDID_HDMI_VSDB_3D_LEN_MASK;
+
+ DPRINTF("HDMI VIC LENGTH[%x] = %x\r\n",
+ StartAddr + EDID_HDMI_EXT_LENGTH_POS, HDMIVICLen);
+ DPRINTF("HDMI 3D LENGTH[%x] = %x\r\n",
+ StartAddr + EDID_HDMI_EXT_LENGTH_POS, HDMI3DLen);
+
+ // check 3D_Present bit
+ if (blockLength >= (EDID_HDMI_3D_PRESENT_POS - latency_offset)) {
+ VSDB3DPresent = gEdidData[StartAddr + EDID_HDMI_3D_PRESENT_POS]
+ & EDID_HDMI_3D_PRESENT_MASK;
+ VSDB3DMultiPresent = gEdidData[StartAddr + EDID_HDMI_3D_PRESENT_POS]
+ & EDID_HDMI_3D_MULTI_PRESENT_MASK;
+ }
+
+ if (VSDB3DPresent) {
+ DPRINTF("VSDB 3D Present!!!\r\n");
+ // check with 3D madatory format
+ if (CheckResolution(pVideo->resolution, pVideo->pixelAspectRatio)) {
+ int size = sizeof(edid_3d)/sizeof(struct edid_3d_mandatory);
+ for (edid_index = 0; edid_index < size; edid_index++) {
+ if (edid_3d[edid_index].resolution == pVideo->resolution &&
+ edid_3d[edid_index].hdmi_3d_format == pVideo->hdmi_3d_format )
+ return 1;
+ }
+ }
+ }
+
+ // check 3D_Multi_Present bit
+ if (VSDB3DMultiPresent) {
+ DPRINTF("VSDB 3D Multi Present!!! = 0x%02x\r\n",VSDB3DMultiPresent);
+ // 3D Structure only
+ if (VSDB3DMultiPresent == EDID_3D_STRUCTURE_ONLY_EXIST) {
+ // 3D Structure All
+ Hdmi3DStructure = (gEdidData[StartAddr + EDID_HDMI_EXT_LENGTH_POS + HDMIVICLen + 1] << 8);
+ Hdmi3DStructure |= gEdidData[StartAddr + EDID_HDMI_EXT_LENGTH_POS + HDMIVICLen + 2];
+ DPRINTF("VSDB 3D Structure!!! = [0x%02x]\r\n",Hdmi3DStructure);
+ }
+
+ // 3D Structure and Mask
+ if (VSDB3DMultiPresent == EDID_3D_STRUCTURE_MASK_EXIST) {
+ // 3D Structure All
+ Hdmi3DStructure = (gEdidData[StartAddr + EDID_HDMI_EXT_LENGTH_POS + HDMIVICLen + 1] << 8);
+ Hdmi3DStructure |= gEdidData[StartAddr + EDID_HDMI_EXT_LENGTH_POS + HDMIVICLen + 2];
+ // 3D Structure Mask
+ Hdmi3DMask |= (gEdidData[StartAddr + EDID_HDMI_EXT_LENGTH_POS + HDMIVICLen + 3] << 8);
+ Hdmi3DMask |= gEdidData[StartAddr + EDID_HDMI_EXT_LENGTH_POS + HDMIVICLen + 4];
+ DPRINTF("VSDB 3D Structure!!! = [0x%02x]\r\n",Hdmi3DStructure);
+ DPRINTF("VSDB 3D Mask!!! = [0x%02x]\r\n",Hdmi3DMask);
+ DPRINTF("Current 3D Video format!!! = [%d]\r\n",pVideo->hdmi_3d_format);
+ DPRINTF("Current 3D Video format!!! = [0x%02x]\r\n",1<<pVideo->hdmi_3d_format);
+ }
+
+ // check 3D Structure and Mask
+ if (Hdmi3DStructure & (1<<pVideo->hdmi_3d_format)) {
+ DPRINTF("VSDB 3D Structure Contains Current Video Structure!!!\r\n");
+ // check first 16 EDID
+ for (edid_index = 0; edid_index < NUM_OF_VIC_FOR_3D; edid_index++) {
+ DPRINTF("VIC = %d, EDID Vic = %d!!!\r\n",vic,aVIC[edid_index]);
+ if (Hdmi3DMask & (1<<edid_index)) {
+ if (vic == aVIC[edid_index]) {
+ DPRINTF("VSDB 3D Mask Contains Current Video format!!!\r\n");
+ return 1;
+ }
+ }
+ }
+ }
+ }
+
+ // check block length if HDMI_VIC or HDMI Multi available
+ if (blockLength >= (EDID_HDMI_EXT_LENGTH_POS - latency_offset)) {
+ unsigned int HDMI3DExtLen = HDMI3DLen - (VSDB3DMultiPresent>>EDID_HDMI_3D_MULTI_PRESENT_BIT)*2;
+ unsigned int VICOrder;
+
+ // check if there is 3D extra data ?
+ //TODO: check 3D_Detail in case of SSH
+ if (HDMI3DExtLen) {
+ // check HDMI 3D Extra Data
+ for (edid_index = 0; edid_index < (int)(HDMI3DExtLen / 2); edid_index++) {
+ VICOrder = gEdidData[StartAddr + EDID_HDMI_EXT_LENGTH_POS + HDMIVICLen +
+ (VSDB3DMultiPresent>>EDID_HDMI_3D_MULTI_PRESENT_BIT) * 2 + edid_index * 2]
+ & EDID_HDMI_2D_VIC_ORDER_MASK;
+ VICOrder = (1<<VICOrder);
+ Hdmi3DStructure = gEdidData[StartAddr + EDID_HDMI_EXT_LENGTH_POS + HDMIVICLen +
+ (VSDB3DMultiPresent>>EDID_HDMI_3D_MULTI_PRESENT_BIT) * 2 + edid_index * 2]
+ & EDID_HDMI_3D_STRUCTURE_MASK;
+ Hdmi3DStructure = (1<<Hdmi3DStructure);
+ if (Hdmi3DStructure == pVideo->hdmi_3d_format && vic == aVIC[VICOrder])
+ return 1;
+ }
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Initialize EDID library. This will intialize DDC library.
+ * @return If success, return 1; Otherwise, return 0.
+ */
+int EDIDOpen(void)
+{
+ // init DDC
+ return DDCOpen();
+}
+
+/**
+ * Finalize EDID library. This will finalize DDC library.
+ * @return If success, return 1; Otherwise, return 0.
+ */
+int EDIDClose(void)
+{
+ // reset EDID
+ EDIDReset();
+
+ // close EDDC
+ return DDCClose();
+}
+
+/**
+ * Read EDID data of Rx.
+ * @return If success, return 1; Otherwise, return 0;
+ */
+int EDIDRead(void)
+{
+ int block,dataPtr;
+ unsigned char temp[SIZEOFEDIDBLOCK];
+
+ // if already read??
+ if (EDIDValid())
+ return 1;
+
+ // read EDID Extension Number
+ // read EDID
+ if (!ReadEDIDBlock(0,temp))
+ return 0;
+
+ // get extension
+ gExtensions = temp[EDID_EXTENSION_NUMBER_POS];
+
+ // prepare buffer
+ gEdidData = (unsigned char*)malloc((gExtensions+1)*SIZEOFEDIDBLOCK);
+ if (!gEdidData)
+ return 0;
+
+ // copy EDID Block 0
+ memcpy(gEdidData,temp,SIZEOFEDIDBLOCK);
+
+ // read EDID Extension
+ for (block = 1,dataPtr = SIZEOFEDIDBLOCK; block <= gExtensions; block++,dataPtr+=SIZEOFEDIDBLOCK) {
+ // read extension 1~gExtensions
+ if (!ReadEDIDBlock(block, gEdidData+dataPtr)) {
+ // reset buffer
+ EDIDReset();
+ return 0;
+ }
+ }
+
+ // check if extension is more than 1, and first extension block is not block map.
+ if (gExtensions > 1 && gEdidData[SIZEOFEDIDBLOCK] != EDID_BLOCK_MAP_EXT_TAG_VAL) {
+ // reset buffer
+ DPRINTF("EDID has more than 1 extension but, first extension block is not block map\n");
+ EDIDReset();
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * Reset stored EDID data.
+ */
+void EDIDReset(void)
+{
+ if (gEdidData) {
+ free(gEdidData);
+ gEdidData = NULL;
+ DPRINTF("\t\t\t\tEDID is reset!!!\n");
+ }
+}
+
+/**
+ * Get CEC physical address.
+ * @param outAddr [out] CEC physical address. LSB 2 bytes is available. [0:0:AB:CD]
+ * @return If success, return 1; Otherwise, return 0.
+ */
+int EDIDGetCECPhysicalAddress(int* const outAddr)
+{
+ int i;
+ unsigned int StartAddr;
+
+ // check EDID data is valid or not
+ // read EDID
+ if (!EDIDRead())
+ return 0;
+
+ // find VSDB
+ for (i = 1; i <= gExtensions; i++) {
+ if (IsTimingExtension(i) // if it's timing block
+ && (StartAddr = GetVSDBOffset(i)) > 0) { // check block
+ // get supported DC value
+ // int tempDC1 = (int)(gEdidData[tempAddr+EDID_DC_POS]);
+ int phyAddr = gEdidData[StartAddr + EDID_CEC_PHYICAL_ADDR] << 8;
+ phyAddr |= gEdidData[StartAddr + EDID_CEC_PHYICAL_ADDR+1];
+
+ DPRINTF("phyAddr = %x\n",phyAddr);
+
+ *outAddr = phyAddr;
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * Check if Rx supports HDMI/DVI mode or not.
+ * @param video [in] HDMI or DVI mode to check
+ * @return If Rx supports requested mode, return 1; Otherwise, return 0.
+ */
+int EDIDHDMIModeSupport(struct HDMIVideoParameter * const video)
+{
+ // check if read edid?
+ if (!EDIDRead()) {
+ DPRINTF("EDID Read Fail!!!\n");
+ return 0;
+ }
+
+ // check hdmi mode
+ if (video->mode == HDMI) {
+ if (!CheckHDMIMode()) {
+ DPRINTF("HDMI mode Not Supported\n");
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/**
+ * Check if Rx supports requested video resoultion or not.
+ * @param video [in] Video parameters to check
+ * @return If Rx supports video parameters, return 1; Otherwise, return 0.
+ */
+int EDIDVideoResolutionSupport(struct HDMIVideoParameter * const video)
+{
+ unsigned int TMDSClock;
+ unsigned int MaxTMDS = 0;
+
+ // check if read edid?
+ if (!EDIDRead()) {
+ DPRINTF("EDID Read Fail!!!\n");
+ return 0;
+ }
+
+ // get max tmds
+ MaxTMDS = GetMaxTMDS()*5;
+
+ // Check MAX TMDS
+ TMDSClock = aVideoParams[video->resolution].PixelClock/100;
+ if (video->colorDepth == HDMI_CD_36)
+ TMDSClock *= 1.5;
+ else if (video->colorDepth == HDMI_CD_30)
+ TMDSClock *=1.25;
+
+ DPRINTF("MAX TMDS = %d, Current TMDS = %d\n",MaxTMDS, TMDSClock);
+ if (MaxTMDS != 0 && MaxTMDS < TMDSClock) {
+ DPRINTF("Pixel clock is beyond Maximun TMDS in EDID\n");
+ return 0;
+ }
+
+ // check resolution
+ if (!CheckResolution(video->resolution,video->pixelAspectRatio)) {
+ DPRINTF("Video Resolution Not Supported\n");
+ return 0;
+ }
+
+ // check 3D format
+ if (!EDID3DFormatSupport(video)) {
+ DPRINTF("3D Format Not Supported\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * Check if Rx supports requested color depth or not.
+ * @param video [in] Video parameters to check
+ * @return If Rx supports video parameters, return 1; Otherwise, return 0.
+ */
+int EDIDColorDepthSupport(struct HDMIVideoParameter * const video)
+{
+ // check if read edid?
+ if (!EDIDRead()) {
+ DPRINTF("EDID Read Fail!!!\n");
+ return 0;
+ }
+
+ // check resolution
+ if (!CheckColorDepth(video->colorDepth,video->colorSpace)) {
+ DPRINTF("Color Depth Not Supported\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * Check if Rx supports requested color space or not.
+ * @param video [in] Video parameters to check
+ * @return If Rx supports video parameters, return 1; Otherwise, return 0.
+ */
+int EDIDColorSpaceSupport(struct HDMIVideoParameter * const video)
+{
+ // check if read edid?
+ if (!EDIDRead()) {
+ DPRINTF("EDID Read Fail!!!\n");
+ return 0;
+ }
+ // check color space
+ if (!CheckColorSpace(video->colorSpace)) {
+ DPRINTF("Color Space Not Supported\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * Check if Rx supports requested colorimetry or not.
+ * @param video [in] Video parameters to check
+ * @return If Rx supports video parameters, return 1; Otherwise, return 0.
+ */
+int EDIDColorimetrySupport(struct HDMIVideoParameter * const video)
+{
+ // check if read edid?
+ if (!EDIDRead()) {
+ DPRINTF("EDID Read Fail!!!\n");
+ return 0;
+ }
+
+ // check colorimetry
+ if (!CheckColorimetry(video->colorimetry)) {
+ DPRINTF("Colorimetry Not Supported\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+/**
+ * Check if Rx supports requested audio parameters or not.
+ * @param audio [in] Audio parameters to check
+ * @return If Rx supports audio parameters, return 1; Otherwise, return 0.
+ */
+int EDIDAudioModeSupport(struct HDMIAudioParameter * const audio)
+{
+ int i;
+
+ // read EDID
+ if (!EDIDRead()) {
+ DPRINTF("EDID Read Fail!!!\n");
+ return 0;
+ }
+
+ // check EDID Extension
+ // find timing block
+ for (i = 1; i <= gExtensions; i++) {
+ if (IsTimingExtension(i)) { // if it's timing block
+ // find Short Audio Description
+ unsigned int StartAddr = i*SIZEOFEDIDBLOCK;
+ unsigned int ExtAddr = StartAddr + EDID_DATA_BLOCK_START_POS;
+ unsigned int tag,blockLen;
+ unsigned int DTDStartAddr = gEdidData[StartAddr + EDID_DETAILED_TIMING_OFFSET_POS];
+
+ while (ExtAddr < StartAddr + DTDStartAddr) {
+ // find the block tag and length
+ // tag
+ tag = gEdidData[ExtAddr] & EDID_TAG_CODE_MASK;
+ // block len
+ blockLen = (gEdidData[ExtAddr] & EDID_DATA_BLOCK_SIZE_MASK) + 1;
+
+ DPRINTF("tag = %d\n",tag);
+ DPRINTF("blockLen = %d\n",blockLen-1);
+
+ // check if it is short video description
+ if (tag == EDID_SHORT_AUD_DEC_TAG_VAL) {
+ // if so, check SAD
+ unsigned int j, channelNum;
+ int audioFormat,sampleFreq,wordLen;
+ for (j = 1; j < blockLen; j += 3) {
+ audioFormat = gEdidData[ExtAddr+j] & EDID_SAD_CODE_MASK;
+ channelNum = gEdidData[ExtAddr+j] & EDID_SAD_CHANNEL_MASK;
+ sampleFreq = gEdidData[ExtAddr+j+1];
+ wordLen = gEdidData[ExtAddr+j+2];
+
+ DPRINTF("request = %d, EDIDAudioFormatCode = %d\n",(audio->formatCode)<<3, audioFormat);
+ DPRINTF("request = %d, EDIDChannelNumber= %d\n",(audio->channelNum)-1, channelNum);
+ DPRINTF("request = %d, EDIDSampleFreq= %d\n",1<<(audio->sampleFreq), sampleFreq);
+ DPRINTF("request = %d, EDIDWordLeng= %d\n",1<<(audio->wordLength), wordLen);
+
+ // check parameter
+ // check audioFormat
+ if (audioFormat & ( (audio->formatCode) << 3) && // format code
+ channelNum >= ( (audio->channelNum) -1) && // channel number
+ (sampleFreq & (1<<(audio->sampleFreq)))) { // sample frequency
+ if (audioFormat == LPCM_FORMAT) { // check wordLen
+ int ret = 0;
+ switch (audio->wordLength) {
+ case WORD_16:
+ case WORD_17:
+ case WORD_18:
+ case WORD_19:
+ case WORD_20:
+ ret = wordLen & (1<<1);
+ break;
+ case WORD_21:
+ case WORD_22:
+ case WORD_23:
+ case WORD_24:
+ ret = wordLen & (1<<2);
+ break;
+ }
+ return ret;
+ }
+ return 1; // if not LPCM
+ }
+ }
+ }
+ // else find next block
+ ExtAddr += blockLen;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/exynos5/hal/libhdmi/libsForhdmi/libedid/libedid.h b/exynos5/hal/libhdmi/libsForhdmi/libedid/libedid.h
new file mode 100644
index 0000000..dfd3096
--- /dev/null
+++ b/exynos5/hal/libhdmi/libsForhdmi/libedid/libedid.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright@ Samsung Electronics Co. LTD
+ *
+ * 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.
+ */
+
+#ifndef _LIBEDID_H_
+#define _LIBEDID_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "video.h"
+#include "audio.h"
+
+int EDIDOpen(void);
+int EDIDRead(void);
+void EDIDReset(void);
+int EDIDHDMIModeSupport(struct HDMIVideoParameter *video);
+int EDIDVideoResolutionSupport(struct HDMIVideoParameter *video);
+int EDIDColorDepthSupport(struct HDMIVideoParameter *video);
+int EDIDColorSpaceSupport(struct HDMIVideoParameter *video);
+int EDIDColorimetrySupport(struct HDMIVideoParameter *video);
+int EDIDAudioModeSupport(struct HDMIAudioParameter *audio);
+int EDIDGetCECPhysicalAddress(int* outAddr);
+int EDIDClose(void);
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* _LIBEDID_H_ */