hal : Test to receive events from kernel

 - Test app to wait for events of Hdmi-in connection state, audio present state,
   sample rate changes.
 - Added code to send edid data by using sysfs exposed by kernel.

Change-Id: Ia68df476397e8aed2aba299337377fe948ff9434
diff --git a/Makefile.am b/Makefile.am
index ebde009..bd08211 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
 SUBDIRS = hal post_proc
 
 if QAHW_SUPPORT
-SUBDIRS += qahw_api qahw_api/test
+SUBDIRS += qahw_api qahw_api/test hdmi_in_test
 endif
 
 ACLOCAL_AMFLAGS = -I m4
diff --git a/configure.ac b/configure.ac
index ffa5f8c..da39527 100644
--- a/configure.ac
+++ b/configure.ac
@@ -120,7 +120,8 @@
         hal/Makefile \
         post_proc/Makefile \
         qahw_api/Makefile \
-        qahw_api/test/Makefile
+        qahw_api/test/Makefile \
+        hdmi_in_test/Makefile
         ])
 
 AC_OUTPUT
diff --git a/hdmi_in_test/Makefile.am b/hdmi_in_test/Makefile.am
new file mode 100644
index 0000000..34e4ff5
--- /dev/null
+++ b/hdmi_in_test/Makefile.am
@@ -0,0 +1,9 @@
+
+ACLOCAL_AMFLAGS = -I m4
+bin_PROGRAMS = hdmi_in_test
+pkgconfigdir = $(libdir)/pkgconfig
+
+hdmi_in_test_SOURCES = src/hdmi_in_event_test.c
+hdmi_in_test_CFLAGS  = $(CFLAGS) -Wno-sign-compare -Werror
+hdmi_in_test_LDADD = -llog -lpthread
+
diff --git a/hdmi_in_test/src/edid.h b/hdmi_in_test/src/edid.h
new file mode 100644
index 0000000..8dc6b84
--- /dev/null
+++ b/hdmi_in_test/src/edid.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of The Linux Foundation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+uint8_t default_edid[] = {
+/* Block 0 (EDID Base Block) */
+0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+/* Vendor Identification */
+0x45, 0x23, 0xDD, 0xDD, 0x01, 0x01, 0x01, 0x01, 0x01, 0x16,
+/* EDID Structure Version and Revision */
+0x01, 0x03,
+/* Display Parameters */
+0x80, 0x90, 0x51, 0x78, 0x0A,
+/* Color characteristics */
+0x0D, 0xC9, 0xA0, 0x57, 0x47, 0x98, 0x27, 0x12, 0x48, 0x4C,
+/* Established Timings */
+0x21, 0x08, 0x00,
+/* Standard Timings */
+0x81, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+/* Detailed Descriptors */
+0x02, 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40,
+0x58, 0x2C,
+0x45, 0x00, 0xA0, 0x2A, 0x53, 0x00, 0x00, 0x1E,
+/* Detailed Descriptors */
+0x01, 0x1D, 0x00, 0x72, 0x51, 0xD0, 0x1E, 0x20,
+0x6E, 0x28, 0x55, 0x00, 0xA0, 0x2A, 0x53, 0x00,
+0x00, 0x1E,
+/* Monitor Descriptor */
+0x00, 0x00, 0x00, 0xFD, 0x00, 0x3A, 0x3E, 0x0F,
+0x46, 0x0F, 0x00, 0x0A, 0x20, 0x20, 0x20, 0x20,
+0x20, 0x20,
+/* Monitor Descriptor */
+0x00, 0x00, 0x00, 0xFC, 0x00, 0x54, 0x56, 0x0A,
+0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+0x20, 0x20,
+/* Extension Flag */
+0x01,
+/*checksum */
+0x9A,
+
+/* Block 1 (Extension Block) */
+/* Extension Header */
+0x02, 0x03, 0x37,
+/* Display supports */
+0xF0,
+/* Video Data Bock */
+0x4A, 0x10, 0x04, 0x05, 0x03, 0x02, 0x07, 0x06,
+0x20, 0x01, 0x3C,
+/* Audio Data Block */
+0x29,
+0x09, 0x07, 0x07, /* LPCM, max 2 ch, 48k, 44.1k, 32k */
+0x15, 0x07, 0x50, /* AC-3, max 6 ch, 48k, 44.1k, 32k, max bitrate 640*/
+0x3D, 0x07, 0x50, /* DTS, max 6ch, 48,44.1,32k, max br 640*/
+/* Speaker Allocation Data Block */
+0x83, 0x01, 0x00, 0x00,
+/* HDMI VSDB */
+/* no deep color, Max_TMDS_Clock = 165 MHz*/
+0x76, 0x03, 0x0C, 0x00, 0x30, 0x00, 0x80, 0x21,
+/* hdmi_video_present=1, 3d_present=1, 3d_multi_present=0,
+hdmi_vic_len=0, hdmi_3d_len=0xC*/
+0x2F, 0x88, 0x0C, 0x20, 0x90, 0x08, 0x10, 0x18,
+0x10, 0x28, 0x10, 0x78, 0x10, 0x06, 0x26,
+/* VCDB */
+0xE2, 0x00, 0x7B,
+/* Detailed Descriptor */
+0x01, 0x1D, 0x80, 0x18, 0x71, 0x1C, 0x16, 0x20,
+0x58, 0x2C, 0x25, 0x00, 0xA0, 0x2A, 0x53, 0x00,
+0x00, 0x9E,
+/* Detailed Descriptor */
+0x8C, 0x0A, 0xD0, 0x8A, 0x20, 0xE0, 0x2D, 0x10,
+0x10, 0x3E, 0x96, 0x00, 0xA0, 0x2A, 0x53, 0x00,
+0x00, 0x18,
+/* Detailed Descriptor */
+0x8C, 0x0A, 0xD0, 0x8A, 0x20, 0xE0, 0x2D, 0x10,
+0x10, 0x3E, 0x96, 0x00, 0x38, 0x2A, 0x43, 0x00,
+0x00, 0x18,
+/* Detailed Descriptor */
+0x8C, 0x0A, 0xA0, 0x14, 0x51, 0xF0, 0x16, 0x00,
+0x26, 0x7C, 0x43, 0x00, 0x38, 0x2A, 0x43, 0x00,
+0x00, 0x98,
+/* checksum */
+0x38
+};
+
+uint8_t edid_with_addtnl_snd_formats[] = {
+/* Block 0 (EDID Base Block) */
+0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00,
+/* Vendor Identification */
+0x1E, 0x6D, 0x01, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x17,
+/* EDID Structure Version and Revision */
+0x01, 0x03,
+/* Display Parameters */
+0x80, 0xa0, 0x5A, 0x78, 0x0A,
+/* Color characteristics */
+0xEE, 0x91, 0xa3, 0x54, 0x4c, 0x99, 0x26, 0x0f, 0x50, 0x54,
+/* Established Timings */
+0xa1, 0x08, 0x00,
+
+0x31, 0x40, 0x45, 0x40, 0x61, 0x40, 0x71, 0x40,
+0x81, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+
+0x02, 0x3a, 0x80, 0x18, 0x71, 0x38, 0x2d, 0x40,
+0x58, 0x2c,
+0x45, 0x00, 0xa0, 0x5a, 0x00, 0x00, 0x00, 0x1e,
+
+0x66, 0x21, 0x50, 0xb0, 0x51, 0x00, 0x1b, 0x30,
+0x40, 0x70, 0x36, 0x00, 0xa0, 0x5a, 0x00, 0x00,
+0x00, 0x1e,
+
+0x00, 0x00, 0x00, 0xfd, 0x00, 0x3a, 0x3e, 0x1e,
+0x53, 0x10, 0x00, 0x0a, 0x20, 0x20, 0x20, 0x20,
+0x20, 0x20,
+
+0x00, 0x00, 0x00, 0xfc, 0x00, 0x4c, 0x47, 0x20,
+0x54, 0x56, 0x0a, 0x20, 0x20, 0x20, 0x20, 0x20,
+0x20, 0x20,
+
+/* Extension Flag */
+0x01,
+/*checksum */
+0x42,
+
+/* Block 1 (Extension Block) */
+/* Extension Header */
+0x02, 0x03, 0x37,
+/* Display supports */
+0xF0,
+/* Video Data Bock */
+0x4E, 0x10, 0x9F, 0x04, 0x13, 0x05, 0x14, 0x03, 0x02, 0x12, 0x20, 0x21,
+0x22, 0x15, 0x01,
+
+/* Audio Data Block */
+0x2F,
+0x3D, 0x06, 0xC0,
+0x15, 0x07, 0x50,
+0x0F, 0x57, 0x07,
+0x57, 0x06, 0x00,
+0x5F, 0x7E, 0x01,
+
+/* Speaker Allocation Data Block */
+0x67, 0x03, 0x0C, 0x00,
+
+0x30, 0x00, 0x80, 0x1E, 0xE3, 0x05, 0x00, 0x00, 0x01,
+
+0x1D, 0x80, 0x18, 0x71, 0x1C, 0x16, 0x20, 0x58, 0x2C, 0x25, 0x00,
+0xA0, 0x5A, 0x00, 0x00, 0x00,
+0x9E, 0x01, 0x1D, 0x00, 0x80, 0x51, 0xD0, 0x1A, 0x20, 0x6E, 0x88,
+0x55, 0x00, 0xA0, 0x5A, 0x00,
+0x00, 0x00, 0x1A, 0x02, 0x3A, 0x80, 0x18, 0x71, 0x38, 0x2D, 0x40,
+0x58, 0x2C, 0x45, 0x00, 0xA0,
+0x5A, 0x00, 0x00, 0x00, 0x1E, 0x66, 0x21, 0x50, 0xB0, 0x51, 0x00,
+0x1B, 0x30, 0x40, 0x70, 0x36,
+0x00, 0xA0, 0x5A, 0x00, 0x00, 0x00, 0x1E, 0x00, 0x00, 0x00, 0x00,
+0x00, 0x00, 0x00, 0x00,
+/* checksum */
+0xFB
+};
diff --git a/hdmi_in_test/src/hdmi_in_event_test.c b/hdmi_in_test/src/hdmi_in_event_test.c
new file mode 100644
index 0000000..4dd7568
--- /dev/null
+++ b/hdmi_in_test/src/hdmi_in_event_test.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2017, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *    * Redistributions of source code must retain the above copyright
+ *      notice, this list of conditions and the following disclaimer.
+ *    * Redistributions in binary form must reproduce the above
+ *      copyright notice, this list of conditions and the following
+ *      disclaimer in the documentation and/or other materials provided
+ *      with the distribution.
+ *    * Neither the name of The Linux Foundation nor the names of its
+ *      contributors may be used to endorse or promote products derived
+ *      from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/* Test app to capture event updates from kernel */
+/*#define LOG_NDEBUG 0*/
+#include <fcntl.h>
+#include <linux/netlink.h>
+#include <pthread.h>
+#include <poll.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/prctl.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <utils/Log.h>
+#include "edid.h"
+
+static int sock_event_fd = -1;
+
+int hdmi_conn_state = 0;
+int hdmi_audio_state = 0;
+int hdmi_audio_format = 0;
+int hdmi_sample_rate = 0;
+int hdmi_num_channels = 0;
+
+const char hdmi_in_audio_sys_path[] =
+                               "/sys/devices/virtual/switch/hpd_state/state";
+const char hdmi_in_audio_dev_path[] = "/devices/virtual/switch/hpd_state";
+const char hdmi_in_audio_state_sys_path[] =
+                               "/sys/devices/virtual/switch/audio_state/state";
+const char hdmi_in_audio_state_dev_path[] =
+                               "/devices/virtual/switch/audio_state";
+const char hdmi_in_audio_format_sys_path[] =
+                               "/sys/devices/virtual/switch/audio_format/state";
+const char hdmi_in_audio_format_dev_path[] =
+                               "/devices/virtual/switch/audio_format";
+const char hdmi_in_audio_sample_rate_sys_path[] =
+                               "/sys/devices/virtual/switch/sample_rate/state";
+const char hdmi_in_audio_sample_rate_dev_path[] =
+                               "/devices/virtual/switch/sample_rate";
+const char hdmi_in_audio_channel_sys_path[] =
+                               "/sys/devices/virtual/switch/channels/state";
+const char hdmi_in_audio_channel_dev_path[] =
+                               "/devices/virtual/switch/channels";
+
+pthread_t poll_event_th;
+pthread_attr_t poll_event_attr;
+
+void send_edid_data()
+{
+    int fd = -1;
+    int ret;
+    char path[] =
+"/sys/devices/soc/ca0c000.qcom,cci/ca0c000.qcom,cci:toshiba,tc358840@0/tc358840_audio_data";
+
+    fd = open(path, O_WRONLY, 0);
+    if (fd < 0) {
+        ALOGE("Unable open fd for file %s", path);
+        return;
+    }
+
+    ret = write(fd, default_edid, sizeof(default_edid));
+
+    close(fd);
+}
+
+void read_data_from_fd(const char* path, int *value)
+{
+    int fd = -1;
+    char buf[16];
+    int ret;
+
+    fd = open(path, O_RDONLY, 0);
+    if (fd < 0) {
+        ALOGE("Unable open fd for file %s", path);
+        return;
+    }
+
+    ret = read(fd, buf, 15);
+    if (ret < 0) {
+        ALOGE("File %s Data is empty", path);
+        close(fd);
+        return;
+    }
+
+    buf[ret] = '\0';
+    *value = atoi(buf);
+    close(fd);
+}
+
+void get_hdmi_status()
+{
+    read_data_from_fd(hdmi_in_audio_sys_path, &hdmi_conn_state);
+    read_data_from_fd(hdmi_in_audio_state_sys_path, &hdmi_audio_state);
+    read_data_from_fd(hdmi_in_audio_format_sys_path, &hdmi_audio_format);
+    read_data_from_fd(hdmi_in_audio_sample_rate_sys_path, &hdmi_sample_rate);
+    read_data_from_fd(hdmi_in_audio_channel_sys_path, &hdmi_num_channels);
+
+    ALOGI("HDMI In state: %d, audio_state: %d, audio_format: %d,",
+		hdmi_conn_state, hdmi_audio_state, hdmi_audio_format);
+    ALOGI(" hdmi_sample_rate: %d, hdmi_num_channels: %d\n",
+		hdmi_sample_rate, hdmi_num_channels);
+}
+
+int poll_event_init()
+{
+    struct sockaddr_nl sock_addr;
+    int sz = (64*1024);
+    int soc;
+
+    memset(&sock_addr, 0, sizeof(sock_addr));
+    sock_addr.nl_family = AF_NETLINK;
+    sock_addr.nl_pid = getpid();
+    sock_addr.nl_groups = 0xffffffff;
+
+    soc = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_KOBJECT_UEVENT);
+    if (soc < 0) {
+        return 0;
+    }
+
+    setsockopt(soc, SOL_SOCKET, SO_RCVBUFFORCE, &sz, sizeof(sz));
+
+    if (bind(soc, (struct sockaddr*) &sock_addr, sizeof(sock_addr)) < 0) {
+        close(soc);
+        return 0;
+    }
+
+    sock_event_fd = soc;
+
+    return (soc > 0);
+}
+
+void listen_uevent(void *ptr)
+{
+    char buffer[64*1024];
+    struct pollfd fds;
+    int i, count;
+    int j;
+    char *dev_path = NULL;
+    char *switch_state = NULL;
+    char *switch_name = NULL;
+
+    while(1) {
+
+        fds.fd = sock_event_fd;
+        fds.events = POLLIN;
+        fds.revents = 0;
+        i = poll(&fds, 1, -1);
+
+        if (i > 0 && (fds.revents & POLLIN)) {
+            count = recv(sock_event_fd, buffer, (64*1024), 0 );
+            if (count > 0) {
+                buffer[count] = '\0';
+                j = 0;
+                while(j < count) {
+                    if (strncmp(&buffer[j], "DEVPATH=", 8) == 0) {
+                        dev_path = &buffer[j+8];
+                        j += 8;
+                        continue;
+                    } else if (strncmp(&buffer[j], "SWITCH_NAME=", 12) == 0) {
+                        switch_name = &buffer[j+12];
+                        j += 12;
+                        continue;
+                    } else if (strncmp(&buffer[j], "SWITCH_STATE=", 13) == 0) {
+                        switch_state = &buffer[j+13];
+                        j += 13;
+                        continue;
+                    }
+                    j++;
+                }
+                ALOGI("devpath = %s, switch_name = %s \n",
+                                         dev_path, switch_name);
+
+                if (strncmp(hdmi_in_audio_dev_path, dev_path,
+                                strlen(hdmi_in_audio_dev_path)) == 0) {
+                    get_hdmi_status();
+                } else if (strncmp(hdmi_in_audio_sample_rate_dev_path, dev_path,
+                                strlen(hdmi_in_audio_sample_rate_dev_path)) == 0) {
+                    get_hdmi_status();
+                } else if (strncmp(hdmi_in_audio_state_dev_path, dev_path,
+                                strlen(hdmi_in_audio_state_dev_path)) == 0) {
+                    get_hdmi_status();
+                } else if (strncmp(hdmi_in_audio_channel_dev_path, dev_path,
+                                strlen(hdmi_in_audio_channel_dev_path)) == 0) {
+                    get_hdmi_status();
+                }
+            }
+        } else {
+            ALOGD("NO Data\n");
+        }
+    }
+}
+
+int main()
+{
+    ALOGI("hdmi-in event test\n");
+
+    pthread_attr_init(&poll_event_attr);
+    pthread_attr_setdetachstate(&poll_event_attr, PTHREAD_CREATE_JOINABLE);
+    poll_event_init();
+    pthread_create(&poll_event_th, &poll_event_attr,
+                       (void *) listen_uevent, NULL);
+    get_hdmi_status();
+
+    /* Enable once kernel side write is proper
+    send_edid_data();*/
+    pthread_join(poll_event_th, NULL);
+    ALOGI("hdmi-in event test exit\n");
+    return 0;
+}