summaryrefslogtreecommitdiff
authorTao Zeng <tao.zeng@amlogic.com>2016-01-22 06:04:12 (GMT)
committer Tao Zeng <tao.zeng@amlogic.com>2016-01-22 06:16:06 (GMT)
commit1e159c44e5ed3cdae4ebec0f5a429ea6013c5191 (patch)
tree593d74925fc5e982542576daf601a7fc5c3144a8
parent196602fd1b668810caf44787a81c4a6888064799 (diff)
downloadhdmi_cec-1e159c44e5ed3cdae4ebec0f5a429ea6013c5191.zip
hdmi_cec-1e159c44e5ed3cdae4ebec0f5a429ea6013c5191.tar.gz
hdmi_cec-1e159c44e5ed3cdae4ebec0f5a429ea6013c5191.tar.bz2
PD#116318: change send result check for HAL
1. write call direct return result of send process, no need use ioctrl to get it again. 2. sync jni operations from Android M, we may use it later. Change-Id: Ic46f0dddcb9529af50ff9799fdf5d6ba4e11f94d
Diffstat
-rw-r--r--hdmi_cec.c292
1 files changed, 259 insertions, 33 deletions
diff --git a/hdmi_cec.c b/hdmi_cec.c
index e729b0c..c6cc38a 100644
--- a/hdmi_cec.c
+++ b/hdmi_cec.c
@@ -40,6 +40,8 @@
#include <hardware/hardware.h>
#include <cutils/properties.h>
#include "hdmi_cec.h"
+#include <jni.h>
+#include <JNIHelp.h>
#ifdef LOG_TAG
#undef LOG_TAG
@@ -61,6 +63,8 @@
#define CEC_FILE "/dev/cec"
#define MAX_PORT 32
+#define MESSAGE_SET_MENU_LANGUAGE 0x32
+
/*
* structures for platform cec implement
* @device_type : indentify type of cec device, such as tv or mbox
@@ -73,6 +77,10 @@
* @cb : event call back for cec message RX
* @dev : for hdmi_cec_device type
* @port_data : array for port data
+ * @onCecMessageRx : for JNI call if got message
+ * @onAddAddress : for event to extend process
+ * @env : saved JNI enverioment
+ * @javavm : java vm for jni
*/
struct aml_cec_hal {
int device_type;
@@ -81,12 +89,18 @@ struct aml_cec_hal {
int addr_bitmap;
int fd;
int total_port;
+ int ext_control;
+ int flag;
unsigned int con_status;
pthread_t ThreadId;
void *cb_data;
event_callback_t cb;
struct hdmi_cec_device *dev;
struct hdmi_port_info *port_data;
+ jmethodID onCecMessageRx;
+ jmethodID onAddAddress;
+ jobject obj;
+ JavaVM *javavm;
};
struct aml_cec_hal *hal_info = NULL;
@@ -130,12 +144,12 @@ static void check_connect_status(struct aml_cec_hal *hal)
event.dev = hal->dev;
event.hotplug.connected = port;
event.hotplug.port_id = hal->port_data[i].port_id;
- if (hal->cb) {
+ if (hal->cb && (hal->flag & (1 << HDMI_OPTION_SYSTEM_CEC_CONTROL))) {
hal->cb(&event, hal_info->cb_data);
}
prev_status &= ~(bit);
prev_status |= ((port ? 1 : 0) << i);
- D("now status:%x\n", prev_status);
+ D("now mask:%x\n", prev_status);
}
}
hal->con_status = prev_status;
@@ -151,6 +165,9 @@ static void *cec_rx_loop(void *data)
char buf[64] = {};
int size = 0, i;
#endif
+ JNIEnv *env;
+ JavaVM *Vm;
+ int ret;
D("start\n");
while (hal_info->fd < 0) {
@@ -182,8 +199,33 @@ static void *cec_rx_loop(void *data)
event.cec.initiator = (msg_buf[0] >> 4) & 0xf;
event.cec.destination = (msg_buf[0] >> 0) & 0xf;
event.cec.length = r - 1;
- if (hal->cb) {
- hal->cb(&event, hal_info->cb_data);
+ if (hal->device_type == DEV_TYPE_TX &&
+ msg_buf[1] == 0x32 &&
+ hal->ext_control) {
+ D("ignore menu language change for tx\n");
+ } else {
+ if (hal->cb && (hal->flag & (1 << HDMI_OPTION_SYSTEM_CEC_CONTROL))) {
+ hal->cb(&event, hal_info->cb_data);
+ }
+ }
+ /* call java method to process cec message for ext control */
+ if ((hal->ext_control == 0x03) &&
+ (hal->device_type == DEV_TYPE_TX) &&
+ (hal->flag & (1 << HDMI_OPTION_SYSTEM_CEC_CONTROL)) &&
+ (hal->javavm)) {
+ Vm = hal->javavm;
+ ret = (*Vm)->GetEnv(Vm, (void**)&env, JNI_VERSION_1_4);
+ if (ret < 0) {
+ ret = (*Vm)->AttachCurrentThread(Vm, &env, NULL);
+ if (ret < 0) {
+ D("can't attach Vm");
+ continue;
+ }
+ }
+ jbyteArray array = (*env)->NewByteArray(env, r);
+ (*env)->SetByteArrayRegion(env, array, 0, r, msg_buf);
+ (*env)->CallVoidMethod(env, hal->obj, hal->onCecMessageRx, array);
+ (*env)->DeleteLocalRef(env, array);
}
}
D("end\n");
@@ -205,10 +247,31 @@ static void *cec_rx_loop(void *data)
*/
static int cec_add_logical_address(const struct hdmi_cec_device* dev, cec_logical_address_t addr)
{
+ JNIEnv *env;
+ JavaVM *Vm;
+ int ret;
+
if (!hal_info || hal_info->fd < 0)
return -EINVAL;
if (addr < CEC_ADDR_BROADCAST)
hal_info->addr_bitmap |= (1 << addr);
+
+ if (hal_info->ext_control) {
+ hal_info->ext_control |= (0x02);
+ if ((hal_info->device_type == DEV_TYPE_TX) &&
+ (hal_info->obj != NULL)) {
+ Vm = hal_info->javavm;
+ ret = (*Vm)->GetEnv(Vm, (void**)&env, JNI_VERSION_1_4);
+ if (ret < 0) {
+ ret = (*Vm)->AttachCurrentThread(Vm, &env, NULL);
+ if (ret < 0) {
+ D("can't attach Vm");
+ }
+ } else if (hal_info->onAddAddress) {
+ (*env)->CallVoidMethod(env, hal_info->obj, hal_info->onAddAddress, addr);
+ }
+ }
+ }
D("dev:%p, addr:%x, bitmap:%x\n", dev, addr, hal_info->addr_bitmap);
return ioctl(hal_info->fd, CEC_IOC_ADD_LOGICAL_ADDR, addr);
}
@@ -226,6 +289,9 @@ static void cec_clear_logical_address(const struct hdmi_cec_device* dev)
return ;
hal_info->addr_bitmap = (1 << CEC_ADDR_BROADCAST);
D("dev:%p, bitmap:%x\n", dev, hal_info->addr_bitmap);
+ if (hal_info->ext_control) {
+ hal_info->ext_control &= ~(0x02);
+ }
ioctl(hal_info->fd, CEC_IOC_CLR_LOGICAL_ADDR, 0);
}
@@ -250,6 +316,22 @@ static int cec_get_physical_address(const struct hdmi_cec_device* dev, uint16_t*
return ret;
}
+static char *get_send_result(int r)
+{
+ switch (r) {
+ case HDMI_RESULT_SUCCESS:
+ return "success";
+ case HDMI_RESULT_NACK:
+ return "no ack";
+ case HDMI_RESULT_BUSY:
+ return "busy";
+ case HDMI_RESULT_FAIL:
+ return "fail other";
+ default:
+ return "unknown fail code";
+ }
+}
+
/*
* (*send_message)() transmits HDMI-CEC message to other HDMI device.
*
@@ -266,46 +348,63 @@ static int cec_get_physical_address(const struct hdmi_cec_device* dev, uint16_t*
static int cec_send_message(const struct hdmi_cec_device* dev, const cec_message_t* msg)
{
int i, ret;
- unsigned fail_reason = 0;
unsigned char msg_buf[CEC_MESSAGE_BODY_MAX_LENGTH] = {};
#if DEBUG
char buf[64] = {};
int size = 0;
#endif
- if (!hal_info || hal_info->fd < 0)
+ /* should not send cec message if no connection */
+ if (!hal_info || hal_info->fd < 0 || !hal_info->con_status)
return HDMI_RESULT_FAIL;
+ /* don't send message if controled by extend */
+ if (hal_info->ext_control == 0x03 && dev) {
+ return HDMI_RESULT_SUCCESS;
+ }
+
+ memset(msg_buf, 0, sizeof(msg_buf));
+ msg_buf[0] = ((msg->initiator & 0xf) << 4) | (msg->destination & 0xf);
+ memcpy(msg_buf + 1, msg->body, msg->length);
+ ret = write(hal_info->fd, msg_buf, msg->length + 1);
#if DEBUG
memset(buf, 0, sizeof(buf));
for (i = 0; i < (int)msg->length; i++) {
size += sprintf(buf + size, "%02x ", msg->body[i]);
}
- if (msg->length) {
- D("[%x -> %x],len:%d, body:%s",
- msg->initiator, msg->destination, msg->length, buf);
- }
+ D("[%x -> %x]len:%d, body:%s, result:%s\n",
+ msg->initiator, msg->destination, msg->length,
+ buf, get_send_result(ret));
#endif
+ return ret;
+}
- memset(msg_buf, 0, sizeof(msg_buf));
- msg_buf[0] = ((msg->initiator & 0xf) << 4) | (msg->destination & 0xf);
- memcpy(msg_buf + 1, msg->body, msg->length);
- ret = write(hal_info->fd, msg_buf, msg->length + 1);
- if (ret > 0) {
- return HDMI_RESULT_SUCCESS;
- } else {
- ioctl(hal_info->fd, CEC_IOC_GET_SEND_FAIL_REASON, &fail_reason);
- if (msg->length)
- D("fail reason:%x\n", fail_reason);
- switch (fail_reason) {
- case CEC_FAIL_NACK:
- return HDMI_RESULT_NACK;
- case CEC_FAIL_BUSY:
- return HDMI_RESULT_BUSY;
- default:
- return HDMI_RESULT_FAIL;
+/*
+ * export cec send message API for other usage
+ */
+int cec_send_message_ext(int dest, int len, unsigned char *buffer)
+{
+ int addr;
+ int i;
+ cec_message_t msg;
+
+ if (hal_info->device_type == DEV_TYPE_TX) {
+ addr = hal_info->addr_bitmap;
+ addr &= 0x7fff;
+ for (i = 0; i < 15; i++) {
+ if (addr & 1) {
+ break;
+ }
+ addr >>= 1;
}
+ msg.initiator = i;
+ } else {
+ msg.initiator = 0; /* root for TV */
}
+ msg.destination = dest;
+ msg.length = len;
+ memcpy(msg.body, buffer, len);
+ return cec_send_message(NULL, &msg);
}
/*
@@ -407,6 +506,10 @@ static void cec_set_option(const struct hdmi_cec_device* dev, int flag, int valu
case HDMI_OPTION_SYSTEM_CEC_CONTROL:
ret = ioctl(hal_info->fd, CEC_IOC_SET_OPTION_SYS_CTRL, value);
+ if (value)
+ hal_info->flag |= (1 << HDMI_OPTION_SYSTEM_CEC_CONTROL);
+ else
+ hal_info->flag &= ~(1 << HDMI_OPTION_SYSTEM_CEC_CONTROL);
break;
case HDMI_OPTION_SET_LANG:
@@ -416,7 +519,8 @@ static void cec_set_option(const struct hdmi_cec_device* dev, int flag, int valu
default:
break;
}
- D("dev:%p, flag:%x, value:%x, ret:%d\n", dev, flag, value, ret);
+ D("dev:%p, flag:%x, value:%x, ret:%d, hal_flag:%x\n",
+ dev, flag, value, ret, hal_info->flag);
}
/*
@@ -483,12 +587,12 @@ static int open_cec( const struct hw_module_t* module, char const *name,
char value[PROPERTY_VALUE_MAX] = {};
int ret;
- D("name:%s\n", name);
hal_info = malloc(sizeof(*hal_info));
if (!hal_info) {
D("%s, alloc memory failed\n", __func__);
return -EINVAL;
}
+ memset(hal_info, 0, sizeof(*hal_info));
if (strcmp(name, HDMI_CEC_HARDWARE_INTERFACE) != 0) {
D("cec strcmp fail !!!");
return -EINVAL;
@@ -504,6 +608,14 @@ static int open_cec( const struct hw_module_t* module, char const *name,
} else {
hal_info->device_type = DEV_TYPE_RX;
}
+ memset(value, 0, sizeof(value));
+ property_get("persist.sys.hdmi.keep_awake", value, "true");
+ if (!strcmp(value, "false")) {
+ hal_info->ext_control = 1;
+ } else {
+ hal_info->ext_control = 0;
+ }
+ D("ext control:%d, %s", hal_info->ext_control, value);
hdmi_cec_device_t *dev = malloc(sizeof(hdmi_cec_device_t));
memset(dev, 0, sizeof(hdmi_cec_device_t));
@@ -538,16 +650,16 @@ static int open_cec( const struct hw_module_t* module, char const *name,
hal_info->cb_data = NULL;
hal_info->cb = NULL;
hal_info->fd = open(CEC_FILE, O_RDWR);
+ hal_info->javavm = NULL;
+ hal_info->obj = NULL;
+ hal_info->flag = 0;
if (hal_info->fd < 0) {
E("can't open %s\n", CEC_FILE);
return -EINVAL;
}
- ioctl(hal_info->fd, CEC_IOC_SET_DEV_TYPE, hal_info->device_type);
+ ret = ioctl(hal_info->fd, CEC_IOC_SET_DEV_TYPE, hal_info->device_type);
pthread_create(&hal_info->ThreadId, NULL, cec_rx_loop, hal_info);
- D("creat thread:%ld for poll cec message, fd:%d\n",
- hal_info->ThreadId, hal_info->fd);
-
return 0;
}
@@ -570,3 +682,117 @@ struct hdmi_cec_module HAL_MODULE_INFO_SYM = {
},
};
+JNIEXPORT int JNICALL
+Java_com_droidlogic_app_HdmiCecExtend_nativeSendCecMessage(JNIEnv *env, jobject thiz, jint dest, jbyteArray body)
+{
+ jbyte *ba = (*env)->GetByteArrayElements(env, body, JNI_FALSE);
+ jsize len = (*env)->GetArrayLength(env, body);
+
+ return cec_send_message_ext(dest, len, ba);
+}
+
+JNIEXPORT void JNICALL
+Java_com_droidlogic_app_HdmiCecExtend_nativeInit(JNIEnv *env, jobject thiz, jobject obj)
+{
+ jobject obj1;
+ if (hal_info != NULL) {
+ obj1 = (*env)->NewGlobalRef(env, obj);
+ hal_info->obj = obj1;
+ }
+}
+
+JNIEXPORT jint JNICALL
+Java_com_droidlogic_app_HdmiCecExtend_nativeGetPhysicalAddr(JNIEnv *env, jobject thiz)
+{
+ unsigned short addr = -1;
+ if (cec_get_physical_address(hal_info->dev, &addr) < 0) {
+ return -1;
+ }
+
+ return addr;
+}
+
+JNIEXPORT jint JNICALL
+Java_com_droidlogic_app_HdmiCecExtend_nativeGetVendorId(JNIEnv *env, jobject thiz)
+{
+ unsigned int id = 0;
+
+ cec_get_vendor_id(hal_info->dev, &id);
+ return id;
+}
+
+JNIEXPORT jint JNICALL
+Java_com_droidlogic_app_HdmiCecExtend_nativeGetCecVersion(JNIEnv *env, jobject thiz)
+{
+ int version = 0;
+
+ cec_get_version(hal_info->dev, &version);
+ return version;
+}
+
+static JNINativeMethod hdmiExtend_method[] = {
+ {"nativeSendCecMessage", "(I[B)I", (void *)Java_com_droidlogic_app_HdmiCecExtend_nativeSendCecMessage},
+ {"nativeInit", "(Lcom/droidlogic/HdmiCecExtend;)V", (void *)Java_com_droidlogic_app_HdmiCecExtend_nativeInit},
+ {"nativeGetPhysicalAddr", "()I", (void *)Java_com_droidlogic_app_HdmiCecExtend_nativeGetPhysicalAddr},
+ {"nativeGetVendorId", "()I", (void *)Java_com_droidlogic_app_HdmiCecExtend_nativeGetVendorId},
+ {"nativeGetCecVersion", "()I", (void *)Java_com_droidlogic_app_HdmiCecExtend_nativeGetCecVersion},
+};
+
+static int registerNativeMethods(JNIEnv* env, const char* className,
+ const JNINativeMethod* methods, int numMethods)
+{
+ int rc;
+ jclass clazz;
+ clazz = (*env)->FindClass(env, className);
+
+ if (clazz == NULL) {
+ D("NULL clazz\n");
+ return -1;
+ }
+
+ if ((rc = ((*env)->RegisterNatives(env, clazz, methods, numMethods))) < 0) {
+ return -1;
+ }
+
+ if (hal_info != NULL) {
+ hal_info->onCecMessageRx = (*env)->GetMethodID(env, clazz, "onCecMessageRx", "([B)V");
+ if (hal_info->onCecMessageRx == NULL) {
+ D("can't found method onCecMessageRx");
+ } else {
+ D("got method onCecMessageRx, env:%p", env);
+ }
+ hal_info->onAddAddress = (*env)->GetMethodID(env, clazz, "onAddAddress", "(I)V");
+ if (hal_info->onAddAddress == NULL) {
+ D("can't found method onAddAddress");
+ } else {
+ D("got method onAddAddress, env:%p", env);
+ }
+ }
+
+ return 0;
+}
+
+
+JNIEXPORT jint
+JNI_OnLoad(JavaVM* vm, void* reserved)
+{
+ JNIEnv* env = NULL;
+ jint result = -1;
+
+ if ((*vm)->GetEnv(vm, (void**) &env, JNI_VERSION_1_4) != JNI_OK) {
+ D("GetEnv failed!\n");
+ return result;
+ }
+ if (registerNativeMethods(env,
+ "com/droidlogic/HdmiCecExtend",
+ hdmiExtend_method,
+ NELEM(hdmiExtend_method)) < 0) {
+ D("registerNativeMethods failed\n");
+ }
+ if (hal_info) {
+ hal_info->javavm = vm;
+ }
+
+ return JNI_VERSION_1_4;
+}
+