12ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel/* 22ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* Copyright (c) 2014, 2016, The Linux Foundation. All rights reserved. 32ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* 42ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* Redistribution and use in source and binary forms, with or without 52ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* modification, are permitted provided that the following conditions are 62ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* met: 72ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* * Redistributions of source code must retain the above copyright 82ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* notice, this list of conditions and the following disclaimer. 92ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* * Redistributions in binary form must reproduce the above 102ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* copyright notice, this list of conditions and the following 112ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* disclaimer in the documentation and/or other materials provided 122ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* with the distribution. 132ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* * Neither the name of The Linux Foundation. nor the names of its 142ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* contributors may be used to endorse or promote products derived 152ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* from this software without specific prior written permission. 162ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* 172ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED 182ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 192ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT 202ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS 212ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 222ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 232ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 242ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 252ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 262ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN 272ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 282ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel*/ 292ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 302ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel#define DEBUG 0 312ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel#define ATRACE_TAG (ATRACE_TAG_GRAPHICS | ATRACE_TAG_HAL) 322ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel#include <cstdlib> 332ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel#include <cutils/log.h> 342ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel#include <errno.h> 352ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel#include <fcntl.h> 362ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel#include <hardware/hdmi_cec.h> 372ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel#include <utils/Trace.h> 382ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel#include "qhdmi_cec.h" 392ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel#include "QHDMIClient.h" 402ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 412ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelnamespace qhdmicec { 422ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 432ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelconst int NUM_HDMI_PORTS = 1; 442ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelconst int MAX_SYSFS_DATA = 128; 452ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelconst int MAX_CEC_FRAME_SIZE = 20; 462ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelconst int MAX_SEND_MESSAGE_RETRIES = 1; 472ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 482ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelenum { 492ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel LOGICAL_ADDRESS_SET = 1, 502ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel LOGICAL_ADDRESS_UNSET = -1, 512ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel}; 522ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 532ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel// Offsets of members of struct hdmi_cec_msg 542ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel// drivers/video/msm/mdss/mdss_hdmi_cec.c 552ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel// XXX: Get this from a driver header 562ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelenum { 572ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel CEC_OFFSET_SENDER_ID, 582ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel CEC_OFFSET_RECEIVER_ID, 592ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel CEC_OFFSET_OPCODE, 602ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel CEC_OFFSET_OPERAND, 612ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel CEC_OFFSET_FRAME_LENGTH = 17, 622ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel CEC_OFFSET_RETRANSMIT, 632ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel}; 642ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 652ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel//Forward declarations 662ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic void cec_close_context(cec_context_t* ctx __unused); 672ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic int cec_enable(cec_context_t *ctx, int enable); 682ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic int cec_is_connected(const struct hdmi_cec_device* dev, int port_id); 692ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 702ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic ssize_t read_node(const char *path, char *data) 712ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 722ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ssize_t err = 0; 732ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel FILE *fp = NULL; 742ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel err = access(path, R_OK); 752ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if (!err) { 762ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel fp = fopen(path, "r"); 772ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if (fp) { 782ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel err = fread(data, sizeof(char), MAX_SYSFS_DATA ,fp); 792ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel fclose(fp); 802ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 812ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 822ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return err; 832ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 842ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 852ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic ssize_t write_node(const char *path, const char *data, size_t len) 862ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 872ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ssize_t err = 0; 882ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel int fd = -1; 892ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel err = access(path, W_OK); 902ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if (!err) { 912ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel fd = open(path, O_WRONLY); 922ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel errno = 0; 932ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel err = write(fd, data, len); 942ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if (err < 0) { 952ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel err = -errno; 962ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 972ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel close(fd); 982ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } else { 992ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGE("%s: Failed to access path: %s error: %s", 1002ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel __FUNCTION__, path, strerror(errno)); 1012ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel err = -errno; 1022ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 1032ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return err; 1042ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 1052ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 1062ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel// Helper function to write integer values to the full sysfs path 1072ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic ssize_t write_int_to_node(cec_context_t *ctx, 1082ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel const char *path_postfix, 1092ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel const int value) 1102ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 1112ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel char sysfs_full_path[MAX_PATH_LENGTH]; 1122ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel char sysfs_data[MAX_SYSFS_DATA]; 1132ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel snprintf(sysfs_data, sizeof(sysfs_data), "%d",value); 1142ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel snprintf(sysfs_full_path,sizeof(sysfs_full_path), "%s/%s", 1152ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->fb_sysfs_path, path_postfix); 1162ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ssize_t err = write_node(sysfs_full_path, sysfs_data, strlen(sysfs_data)); 1172ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return err; 1182ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 1192ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 1202ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic void hex_to_string(const char *msg, ssize_t len, char *str) 1212ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 1222ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel //Functions assumes sufficient memory in str 1232ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel char *ptr = str; 1242ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel for(int i=0; i < len ; i++) { 1252ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ptr += snprintf(ptr, 3, "%02X", msg[i]); 1262ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel // Overwrite null termination of snprintf in all except the last byte 1272ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if (i < len - 1) 1282ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel *ptr = ':'; 1292ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ptr++; 1302ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 1312ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 1322ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 1332ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic ssize_t cec_get_fb_node_number(cec_context_t *ctx) 1342ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 1352ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel //XXX: Do this from a common utility library across the display HALs 1362ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel const int MAX_FB_DEVICES = 2; 1372ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ssize_t len = 0; 1382ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel char fb_type_path[MAX_PATH_LENGTH]; 1392ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel char fb_type[MAX_SYSFS_DATA]; 1402ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel const char *dtv_panel_str = "dtv panel"; 1412ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 1422ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel for(int num = 0; num < MAX_FB_DEVICES; num++) { 1432ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel snprintf(fb_type_path, sizeof(fb_type_path),"%s%d/msm_fb_type", 1442ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel SYSFS_BASE,num); 1452ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: num: %d fb_type_path: %s", __FUNCTION__, num, fb_type_path); 1462ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel len = read_node(fb_type_path, fb_type); 1472ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: fb_type:%s", __FUNCTION__, fb_type); 1482ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if(len > 0 && (strncmp(fb_type, dtv_panel_str, strlen(dtv_panel_str)) == 0)){ 1492ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: Found DTV panel at fb%d", __FUNCTION__, num); 1502ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->fb_num = num; 1512ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel snprintf(ctx->fb_sysfs_path, sizeof(ctx->fb_sysfs_path), 1522ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel "%s%d", SYSFS_BASE, num); 1532ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel break; 1542ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 1552ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 1562ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if (len < 0) 1572ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return len; 1582ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel else 1592ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return 0; 1602ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 1612ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 1622ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic int cec_add_logical_address(const struct hdmi_cec_device* dev, 1632ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel cec_logical_address_t addr) 1642ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 1652ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if (addr < CEC_ADDR_TV || addr > CEC_ADDR_BROADCAST) { 1662ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGE("%s: Received invalid address: %d ", __FUNCTION__, addr); 1672ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return -EINVAL; 1682ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 1692ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel cec_context_t* ctx = (cec_context_t*)(dev); 1702ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->logical_address[addr] = LOGICAL_ADDRESS_SET; 1712ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 1722ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel //XXX: We can get multiple logical addresses here but we can only send one 1732ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel //to the driver. Store locally for now 1742ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ssize_t err = write_int_to_node(ctx, "cec/logical_addr", addr); 1752ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGI("%s: Allocated logical address: %d ", __FUNCTION__, addr); 1762ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return (int) err; 1772ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 1782ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 1792ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic void cec_clear_logical_address(const struct hdmi_cec_device* dev) 1802ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 1812ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel cec_context_t* ctx = (cec_context_t*)(dev); 1822ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel memset(ctx->logical_address, LOGICAL_ADDRESS_UNSET, 1832ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel sizeof(ctx->logical_address)); 1842ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel //XXX: Find logical_addr that needs to be reset 1852ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel write_int_to_node(ctx, "cec/logical_addr", 15); 1862ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: Cleared logical addresses", __FUNCTION__); 1872ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 1882ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 1892ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic int cec_get_physical_address(const struct hdmi_cec_device* dev, 1902ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel uint16_t* addr) 1912ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 1922ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel cec_context_t* ctx = (cec_context_t*)(dev); 1932ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel char pa_path[MAX_PATH_LENGTH]; 1942ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel char pa_data[MAX_SYSFS_DATA]; 1952ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel snprintf (pa_path, sizeof(pa_path),"%s/pa", 1962ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->fb_sysfs_path); 1972ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel int err = (int) read_node(pa_path, pa_data); 1982ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel *addr = (uint16_t) atoi(pa_data); 1992ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: Physical Address: 0x%x", __FUNCTION__, *addr); 2002ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if (err < 0) 2012ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return err; 2022ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel else 2032ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return 0; 2042ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 2052ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 2062ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic int cec_send_message(const struct hdmi_cec_device* dev, 2072ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel const cec_message_t* msg) 2082ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 2092ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ATRACE_CALL(); 2102ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if(cec_is_connected(dev, 0) <= 0) 2112ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return HDMI_RESULT_FAIL; 2122ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 2132ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel cec_context_t* ctx = (cec_context_t*)(dev); 2142ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: initiator: %d destination: %d length: %u", 2152ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel __FUNCTION__, msg->initiator, msg->destination, 2162ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel (uint32_t) msg->length); 2172ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 2182ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel // Dump message received from framework 2192ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel char dump[128]; 2202ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if(msg->length > 0) { 2212ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel hex_to_string((char*)msg->body, msg->length, dump); 2222ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: message from framework: %s", __FUNCTION__, dump); 2232ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 2242ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 2252ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel char write_msg_path[MAX_PATH_LENGTH]; 2262ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel char write_msg[MAX_CEC_FRAME_SIZE]; 2272ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel memset(write_msg, 0, sizeof(write_msg)); 2282ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel // See definition of struct hdmi_cec_msg in driver code 2292ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel // drivers/video/msm/mdss/mdss_hdmi_cec.c 2302ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel // Write header block 2312ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel // XXX: Include this from header in kernel 2322ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel write_msg[CEC_OFFSET_SENDER_ID] = msg->initiator; 2332ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel write_msg[CEC_OFFSET_RECEIVER_ID] = msg->destination; 2342ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel //Kernel splits opcode/operand, but Android sends it in one byte array 2352ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel write_msg[CEC_OFFSET_OPCODE] = msg->body[0]; 2362ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if(msg->length > 1) { 2372ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel memcpy(&write_msg[CEC_OFFSET_OPERAND], &msg->body[1], 2382ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel sizeof(char)*(msg->length - 1)); 2392ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 2402ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel //msg length + initiator + destination 2412ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel write_msg[CEC_OFFSET_FRAME_LENGTH] = (unsigned char) (msg->length + 1); 2422ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel hex_to_string(write_msg, sizeof(write_msg), dump); 2432ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: message to driver: %s", __FUNCTION__, dump); 2442ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel snprintf(write_msg_path, sizeof(write_msg_path), "%s/cec/wr_msg", 2452ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->fb_sysfs_path); 2462ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel int retry_count = 0; 2472ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ssize_t err = 0; 2482ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel //HAL spec requires us to retry at least once. 2492ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel while (true) { 2502ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel err = write_node(write_msg_path, write_msg, sizeof(write_msg)); 2512ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel retry_count++; 2522ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if (err == -EAGAIN && retry_count <= MAX_SEND_MESSAGE_RETRIES) { 2532ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGE("%s: CEC line busy, retrying", __FUNCTION__); 2542ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } else { 2552ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel break; 2562ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 2572ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 2582ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 2592ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if (err < 0) { 2602ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if (err == -ENXIO) { 2612ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGI("%s: No device exists with the destination address", 2622ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel __FUNCTION__); 2632ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return HDMI_RESULT_NACK; 2642ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } else if (err == -EAGAIN) { 2652ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGE("%s: CEC line is busy, max retry count exceeded", 2662ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel __FUNCTION__); 2672ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return HDMI_RESULT_BUSY; 2682ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } else { 2692ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return HDMI_RESULT_FAIL; 2702ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGE("%s: Failed to send CEC message err: %zd - %s", 2712ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel __FUNCTION__, err, strerror(int(-err))); 2722ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 2732ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } else { 2742ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: Sent CEC message - %zd bytes written", 2752ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel __FUNCTION__, err); 2762ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return HDMI_RESULT_SUCCESS; 2772ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 2782ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 2792ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 2802ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelvoid cec_receive_message(cec_context_t *ctx, char *msg, ssize_t len) 2812ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 2822ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if(!ctx->system_control) 2832ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return; 2842ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 2852ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel char dump[128]; 2862ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if(len > 0) { 2872ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel hex_to_string(msg, len, dump); 2882ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: Message from driver: %s", __FUNCTION__, dump); 2892ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 2902ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 2912ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel hdmi_event_t event; 2922ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel event.type = HDMI_EVENT_CEC_MESSAGE; 2932ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel event.dev = (hdmi_cec_device *) ctx; 2942ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel // Remove initiator/destination from this calculation 2952ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel event.cec.length = msg[CEC_OFFSET_FRAME_LENGTH] - 1; 2962ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel event.cec.initiator = (cec_logical_address_t) msg[CEC_OFFSET_SENDER_ID]; 2972ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel event.cec.destination = (cec_logical_address_t) msg[CEC_OFFSET_RECEIVER_ID]; 2982ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel //Copy opcode and operand 2992ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel memcpy(event.cec.body, &msg[CEC_OFFSET_OPCODE], event.cec.length); 3002ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel hex_to_string((char *) event.cec.body, event.cec.length, dump); 3012ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: Message to framework: %s", __FUNCTION__, dump); 3022ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->callback.callback_func(&event, ctx->callback.callback_arg); 3032ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 3042ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 3052ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelvoid cec_hdmi_hotplug(cec_context_t *ctx, int connected) 3062ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 3072ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel //Ignore unplug events when system control is disabled 3082ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if(!ctx->system_control && connected == 0) 3092ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return; 3102ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel hdmi_event_t event; 3112ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel event.type = HDMI_EVENT_HOT_PLUG; 3122ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel event.dev = (hdmi_cec_device *) ctx; 3132ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel event.hotplug.connected = connected ? HDMI_CONNECTED : HDMI_NOT_CONNECTED; 3142ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->callback.callback_func(&event, ctx->callback.callback_arg); 3152ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 3162ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 3172ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic void cec_register_event_callback(const struct hdmi_cec_device* dev, 3182ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel event_callback_t callback, void* arg) 3192ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 3202ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: Registering callback", __FUNCTION__); 3212ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel cec_context_t* ctx = (cec_context_t*)(dev); 3222ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->callback.callback_func = callback; 3232ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->callback.callback_arg = arg; 3242ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 3252ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 3262ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic void cec_get_version(const struct hdmi_cec_device* dev, int* version) 3272ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 3282ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel cec_context_t* ctx = (cec_context_t*)(dev); 3292ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel *version = ctx->version; 3302ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: version: %d", __FUNCTION__, *version); 3312ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 3322ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 3332ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic void cec_get_vendor_id(const struct hdmi_cec_device* dev, 3342ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel uint32_t* vendor_id) 3352ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 3362ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel cec_context_t* ctx = (cec_context_t*)(dev); 3372ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel *vendor_id = ctx->vendor_id; 3382ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: vendor id: %u", __FUNCTION__, *vendor_id); 3392ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 3402ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 3412ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic void cec_get_port_info(const struct hdmi_cec_device* dev, 3422ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel struct hdmi_port_info* list[], int* total) 3432ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 3442ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: Get port info", __FUNCTION__); 3452ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel cec_context_t* ctx = (cec_context_t*)(dev); 3462ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel *total = NUM_HDMI_PORTS; 3472ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel *list = ctx->port_info; 3482ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 3492ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 3502ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic void cec_set_option(const struct hdmi_cec_device* dev, int flag, 3512ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel int value) 3522ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 3532ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel cec_context_t* ctx = (cec_context_t*)(dev); 3542ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel switch (flag) { 3552ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel case HDMI_OPTION_WAKEUP: 3562ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: Wakeup: value: %d", __FUNCTION__, value); 3572ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel //XXX 3582ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel break; 3592ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel case HDMI_OPTION_ENABLE_CEC: 3602ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: Enable CEC: value: %d", __FUNCTION__, value); 3612ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel cec_enable(ctx, value? 1 : 0); 3622ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel break; 3632ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel case HDMI_OPTION_SYSTEM_CEC_CONTROL: 3642ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: system_control: value: %d", 3652ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel __FUNCTION__, value); 3662ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->system_control = !!value; 3672ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel break; 3682ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 3692ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 3702ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 3712ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic void cec_set_audio_return_channel(const struct hdmi_cec_device* dev, 3722ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel int port, int flag) 3732ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 3742ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel cec_context_t* ctx = (cec_context_t*)(dev); 3752ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->arc_enabled = flag ? true : false; 3762ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: ARC flag: %d port: %d", __FUNCTION__, flag, port); 3772ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 3782ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 3792ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic int cec_is_connected(const struct hdmi_cec_device* dev, int port_id) 3802ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 3812ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel // Ignore port_id since we have only one port 3822ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel int connected = 0; 3832ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel cec_context_t* ctx = (cec_context_t*)(dev); 3842ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel char connected_path[MAX_PATH_LENGTH]; 3852ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel char connected_data[MAX_SYSFS_DATA]; 3862ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel snprintf (connected_path, sizeof(connected_path),"%s/connected", 3872ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->fb_sysfs_path); 3882ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ssize_t err = read_node(connected_path, connected_data); 3892ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel connected = atoi(connected_data); 3902ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 3912ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: HDMI at port %d is - %s", __FUNCTION__, port_id, 3922ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel connected ? "connected":"disconnected"); 3932ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if (err < 0) 3942ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return (int) err; 3952ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel else 3962ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return connected; 3972ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 3982ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 3992ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic int cec_device_close(struct hw_device_t *dev) 4002ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 4012ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: Close CEC HAL ", __FUNCTION__); 4022ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if (!dev) { 4032ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGE("%s: NULL device pointer", __FUNCTION__); 4042ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return -EINVAL; 4052ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 4062ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel cec_context_t* ctx = (cec_context_t*)(dev); 4072ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel cec_close_context(ctx); 4082ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel free(dev); 4092ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return 0; 4102ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 4112ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 4122ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic int cec_enable(cec_context_t *ctx, int enable) 4132ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 4142ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ssize_t err; 4152ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel // Enable CEC 4162ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel int value = enable ? 0x3 : 0x0; 4172ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel err = write_int_to_node(ctx, "cec/enable", value); 4182ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if(err < 0) { 4192ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGE("%s: Failed to toggle CEC: enable: %d", 4202ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel __FUNCTION__, enable); 4212ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return (int) err; 4222ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 4232ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->enabled = enable; 4242ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return 0; 4252ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 4262ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 4272ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic void cec_init_context(cec_context_t *ctx) 4282ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 4292ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: Initializing context", __FUNCTION__); 4302ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel cec_get_fb_node_number(ctx); 4312ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 4322ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel //Initialize ports - We support only one output port 4332ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->port_info = new hdmi_port_info[NUM_HDMI_PORTS]; 4342ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->port_info[0].type = HDMI_OUTPUT; 4352ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->port_info[0].port_id = 1; 4362ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->port_info[0].cec_supported = 1; 4372ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel //XXX: Enable ARC if supported 4382ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->port_info[0].arc_supported = 0; 4392ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel cec_get_physical_address((hdmi_cec_device *) ctx, 4402ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel &ctx->port_info[0].physical_address ); 4412ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 4422ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->version = 0x4; 4432ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->vendor_id = 0xA47733; 4442ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel cec_clear_logical_address((hdmi_cec_device_t*)ctx); 4452ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 4462ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel //Set up listener for HDMI events 4472ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->disp_client = new qClient::QHDMIClient(); 4482ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->disp_client->setCECContext(ctx); 4492ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ctx->disp_client->registerClient(ctx->disp_client); 4502ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 4512ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel //Enable CEC - framework expects it to be enabled by default 4522ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel cec_enable(ctx, true); 4532ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 4542ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD("%s: CEC enabled", __FUNCTION__); 4552ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 4562ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 4572ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic void cec_close_context(cec_context_t* ctx __unused) 4582ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 4592ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD("%s: Closing context", __FUNCTION__); 4602ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 4612ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 4622ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic int cec_device_open(const struct hw_module_t* module, 4632ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel const char* name, 4642ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel struct hw_device_t** device) 4652ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel{ 4662ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel ALOGD_IF(DEBUG, "%s: name: %s", __FUNCTION__, name); 4672ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel int status = -EINVAL; 4682ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if (!strcmp(name, HDMI_CEC_HARDWARE_INTERFACE )) { 4692ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel struct cec_context_t *dev; 4702ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel dev = (cec_context_t *) calloc (1, sizeof(*dev)); 4712ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel if (dev) { 4722ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel cec_init_context(dev); 4732ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 4742ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel //Setup CEC methods 4752ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel dev->device.common.tag = HARDWARE_DEVICE_TAG; 4762ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel dev->device.common.version = HDMI_CEC_DEVICE_API_VERSION_1_0; 4772ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel dev->device.common.module = const_cast<hw_module_t* >(module); 4782ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel dev->device.common.close = cec_device_close; 4792ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel dev->device.add_logical_address = cec_add_logical_address; 4802ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel dev->device.clear_logical_address = cec_clear_logical_address; 4812ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel dev->device.get_physical_address = cec_get_physical_address; 4822ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel dev->device.send_message = cec_send_message; 4832ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel dev->device.register_event_callback = cec_register_event_callback; 4842ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel dev->device.get_version = cec_get_version; 4852ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel dev->device.get_vendor_id = cec_get_vendor_id; 4862ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel dev->device.get_port_info = cec_get_port_info; 4872ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel dev->device.set_option = cec_set_option; 4882ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel dev->device.set_audio_return_channel = cec_set_audio_return_channel; 4892ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel dev->device.is_connected = cec_is_connected; 4902ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 4912ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel *device = &dev->device.common; 4922ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel status = 0; 4932ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } else { 4942ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel status = -EINVAL; 4952ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 4962ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 4972ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel return status; 4982ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel} 4992ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel}; //namespace qhdmicec 5002ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 5012ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel// Standard HAL module, should be outside qhdmicec namespace 5022ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelstatic struct hw_module_methods_t cec_module_methods = { 5032ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel .open = qhdmicec::cec_device_open 5042ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel}; 5052ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 5062ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudelhdmi_module_t HAL_MODULE_INFO_SYM = { 5072ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel .common = { 5082ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel .tag = HARDWARE_MODULE_TAG, 5092ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel .version_major = 1, 5102ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel .version_minor = 0, 5112ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel .id = HDMI_CEC_HARDWARE_MODULE_ID, 5122ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel .name = "QTI HDMI CEC module", 5132ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel .author = "The Linux Foundation", 5142ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel .methods = &cec_module_methods, 5152ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel } 5162ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel}; 5172ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 5182ebc25b87caae537b8cd97beb8a86a7ff5f0cdf4Thierry Strudel 519