2017-10-03 22:38:26 +00:00
|
|
|
#include <linux/mei_cl_bus.h>
|
|
|
|
|
|
|
|
#include "ipts.h"
|
|
|
|
#include "ipts-hid.h"
|
|
|
|
#include "ipts-resource.h"
|
|
|
|
#include "ipts-mei-msgs.h"
|
|
|
|
|
|
|
|
int ipts_handle_cmd(ipts_info_t *ipts, u32 cmd, void *data, int data_size)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
touch_sensor_msg_h2m_t h2m_msg;
|
|
|
|
int len = 0;
|
|
|
|
|
|
|
|
memset(&h2m_msg, 0, sizeof(h2m_msg));
|
|
|
|
|
|
|
|
h2m_msg.command_code = cmd;
|
|
|
|
len = sizeof(h2m_msg.command_code) + data_size;
|
|
|
|
if (data != NULL && data_size != 0)
|
|
|
|
memcpy(&h2m_msg.h2m_data, data, data_size); /* copy payload */
|
|
|
|
|
|
|
|
ret = mei_cldev_send(ipts->cldev, (u8*)&h2m_msg, len);
|
|
|
|
if (ret < 0) {
|
|
|
|
ipts_err(ipts, "mei_cldev_send() error 0x%X:%d\n",
|
|
|
|
cmd, ret);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ipts_send_feedback(ipts_info_t *ipts, int buffer_idx, u32 transaction_id)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
int cmd_len;
|
|
|
|
touch_sensor_feedback_ready_cmd_data_t fb_ready_cmd;
|
|
|
|
|
|
|
|
cmd_len = sizeof(touch_sensor_feedback_ready_cmd_data_t);
|
|
|
|
memset(&fb_ready_cmd, 0, cmd_len);
|
|
|
|
|
|
|
|
fb_ready_cmd.feedback_index = buffer_idx;
|
|
|
|
fb_ready_cmd.transaction_id = transaction_id;
|
|
|
|
|
|
|
|
ret = ipts_handle_cmd(ipts, TOUCH_SENSOR_FEEDBACK_READY_CMD,
|
|
|
|
&fb_ready_cmd, cmd_len);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ipts_send_sensor_quiesce_io_cmd(ipts_info_t *ipts)
|
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
int cmd_len;
|
|
|
|
touch_sensor_quiesce_io_cmd_data_t quiesce_io_cmd;
|
|
|
|
|
|
|
|
cmd_len = sizeof(touch_sensor_quiesce_io_cmd_data_t);
|
|
|
|
memset(&quiesce_io_cmd, 0, cmd_len);
|
|
|
|
|
|
|
|
ret = ipts_handle_cmd(ipts, TOUCH_SENSOR_QUIESCE_IO_CMD,
|
|
|
|
&quiesce_io_cmd, cmd_len);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ipts_send_sensor_hid_ready_for_data_cmd(ipts_info_t *ipts)
|
|
|
|
{
|
|
|
|
return ipts_handle_cmd(ipts, TOUCH_SENSOR_HID_READY_FOR_DATA_CMD, NULL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
int ipts_send_sensor_clear_mem_window_cmd(ipts_info_t *ipts)
|
|
|
|
{
|
|
|
|
return ipts_handle_cmd(ipts, TOUCH_SENSOR_CLEAR_MEM_WINDOW_CMD, NULL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int check_validity(touch_sensor_msg_m2h_t *m2h_msg, u32 msg_len)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
int valid_msg_len = sizeof(m2h_msg->command_code);
|
|
|
|
u32 cmd_code = m2h_msg->command_code;
|
|
|
|
|
|
|
|
switch (cmd_code) {
|
|
|
|
case TOUCH_SENSOR_SET_MODE_RSP:
|
|
|
|
valid_msg_len +=
|
|
|
|
sizeof(touch_sensor_set_mode_rsp_data_t);
|
|
|
|
break;
|
|
|
|
case TOUCH_SENSOR_SET_MEM_WINDOW_RSP:
|
|
|
|
valid_msg_len +=
|
|
|
|
sizeof(touch_sensor_set_mem_window_rsp_data_t);
|
|
|
|
break;
|
|
|
|
case TOUCH_SENSOR_QUIESCE_IO_RSP:
|
|
|
|
valid_msg_len +=
|
|
|
|
sizeof(touch_sensor_quiesce_io_rsp_data_t);
|
|
|
|
break;
|
|
|
|
case TOUCH_SENSOR_HID_READY_FOR_DATA_RSP:
|
|
|
|
valid_msg_len +=
|
|
|
|
sizeof(touch_sensor_hid_ready_for_data_rsp_data_t);
|
|
|
|
break;
|
|
|
|
case TOUCH_SENSOR_FEEDBACK_READY_RSP:
|
|
|
|
valid_msg_len +=
|
|
|
|
sizeof(touch_sensor_feedback_ready_rsp_data_t);
|
|
|
|
break;
|
|
|
|
case TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP:
|
|
|
|
valid_msg_len +=
|
|
|
|
sizeof(touch_sensor_clear_mem_window_rsp_data_t);
|
|
|
|
break;
|
|
|
|
case TOUCH_SENSOR_NOTIFY_DEV_READY_RSP:
|
|
|
|
valid_msg_len +=
|
|
|
|
sizeof(touch_sensor_notify_dev_ready_rsp_data_t);
|
|
|
|
break;
|
|
|
|
case TOUCH_SENSOR_SET_POLICIES_RSP:
|
|
|
|
valid_msg_len +=
|
|
|
|
sizeof(touch_sensor_set_policies_rsp_data_t);
|
|
|
|
break;
|
|
|
|
case TOUCH_SENSOR_GET_POLICIES_RSP:
|
|
|
|
valid_msg_len +=
|
|
|
|
sizeof(touch_sensor_get_policies_rsp_data_t);
|
|
|
|
break;
|
|
|
|
case TOUCH_SENSOR_RESET_RSP:
|
|
|
|
valid_msg_len +=
|
|
|
|
sizeof(touch_sensor_reset_rsp_data_t);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (valid_msg_len != msg_len) {
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ipts_start(ipts_info_t *ipts)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
/* TODO : check if we need to do SET_POLICIES_CMD
|
|
|
|
we need to do this when protocol version doesn't match with reported one
|
|
|
|
how we keep vendor specific data is the first thing to solve */
|
|
|
|
|
|
|
|
ipts_set_state(ipts, IPTS_STA_INIT);
|
|
|
|
ipts->num_of_parallel_data_buffers = TOUCH_SENSOR_MAX_DATA_BUFFERS;
|
|
|
|
|
|
|
|
#ifdef ENABLE_IPTS_DEBUG
|
2017-11-08 01:27:14 +00:00
|
|
|
ipts->sensor_mode = TOUCH_SENSOR_MODE_RAW_DATA; /* start with RAW_DATA */
|
2017-10-03 22:38:26 +00:00
|
|
|
#endif
|
|
|
|
|
|
|
|
ret = ipts_handle_cmd(ipts, TOUCH_SENSOR_NOTIFY_DEV_READY_CMD, NULL, 0);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ipts_stop(ipts_info_t *ipts)
|
|
|
|
{
|
|
|
|
ipts_state_t old_state;
|
|
|
|
|
|
|
|
old_state = ipts_get_state(ipts);
|
|
|
|
ipts_set_state(ipts, IPTS_STA_STOPPING);
|
|
|
|
|
|
|
|
if (old_state < IPTS_STA_RESOURCE_READY)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (old_state == IPTS_STA_RAW_DATA_STARTED ||
|
|
|
|
old_state == IPTS_STA_HID_STARTED) {
|
|
|
|
ipts_free_default_resource(ipts);
|
|
|
|
ipts_free_raw_data_resource(ipts);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
int ipts_restart(ipts_info_t *ipts)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
ipts_dbg(ipts, "ipts restart\n");
|
|
|
|
|
|
|
|
ipts_stop(ipts);
|
|
|
|
|
|
|
|
ipts->retry++;
|
|
|
|
if (ipts->retry == IPTS_MAX_RETRY &&
|
|
|
|
ipts->sensor_mode == TOUCH_SENSOR_MODE_RAW_DATA) {
|
|
|
|
/* try with HID mode */
|
|
|
|
ipts->sensor_mode = TOUCH_SENSOR_MODE_HID;
|
|
|
|
} else if (ipts->retry > IPTS_MAX_RETRY) {
|
|
|
|
return -EPERM;
|
|
|
|
}
|
|
|
|
|
|
|
|
ipts_send_sensor_quiesce_io_cmd(ipts);
|
|
|
|
ipts->restart = true;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int ipts_switch_sensor_mode(ipts_info_t *ipts, int new_sensor_mode)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
ipts->new_sensor_mode = new_sensor_mode;
|
|
|
|
ipts->switch_sensor_mode = true;
|
|
|
|
ret = ipts_send_sensor_quiesce_io_cmd(ipts);
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
#define rsp_failed(ipts, cmd, status) ipts_err(ipts, \
|
|
|
|
"0x%08x failed status = %d\n", cmd, status);
|
|
|
|
|
|
|
|
int ipts_handle_resp(ipts_info_t *ipts, touch_sensor_msg_m2h_t *m2h_msg,
|
|
|
|
u32 msg_len)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
int rsp_status = 0;
|
|
|
|
int cmd_status = 0;
|
|
|
|
int cmd_len = 0;
|
|
|
|
u32 cmd;
|
|
|
|
|
|
|
|
if (!check_validity(m2h_msg, msg_len)) {
|
|
|
|
ipts_err(ipts, "wrong rsp\n");
|
|
|
|
return -EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
rsp_status = m2h_msg->status;
|
|
|
|
cmd = m2h_msg->command_code;
|
|
|
|
|
|
|
|
switch (cmd) {
|
|
|
|
case TOUCH_SENSOR_NOTIFY_DEV_READY_RSP:
|
|
|
|
if (rsp_status != 0 &&
|
|
|
|
rsp_status != TOUCH_STATUS_SENSOR_FAIL_NONFATAL) {
|
|
|
|
rsp_failed(ipts, cmd, rsp_status);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd_status = ipts_handle_cmd(ipts,
|
|
|
|
TOUCH_SENSOR_GET_DEVICE_INFO_CMD,
|
|
|
|
NULL, 0);
|
|
|
|
break;
|
|
|
|
case TOUCH_SENSOR_GET_DEVICE_INFO_RSP:
|
|
|
|
if (rsp_status != 0 &&
|
|
|
|
rsp_status != TOUCH_STATUS_COMPAT_CHECK_FAIL) {
|
|
|
|
rsp_failed(ipts, cmd, rsp_status);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
memcpy(&ipts->device_info,
|
|
|
|
&m2h_msg->m2h_data.device_info_rsp_data,
|
|
|
|
sizeof(touch_sensor_get_device_info_rsp_data_t));
|
|
|
|
|
|
|
|
/*
|
|
|
|
TODO : support raw_request during HID init.
|
|
|
|
Although HID init happens here, technically most of
|
|
|
|
reports (for both direction) can be issued only
|
|
|
|
after SET_MEM_WINDOWS_CMD since they may require
|
|
|
|
ME or touch IC. If ipts vendor requires raw_request
|
|
|
|
during HID init, we need to consider to move HID init.
|
|
|
|
*/
|
|
|
|
if (ipts->hid_desc_ready == false) {
|
|
|
|
ret = ipts_hid_init(ipts);
|
|
|
|
if (ret)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd_status = ipts_send_sensor_clear_mem_window_cmd(ipts);
|
|
|
|
|
|
|
|
break;
|
|
|
|
case TOUCH_SENSOR_CLEAR_MEM_WINDOW_RSP:
|
|
|
|
{
|
|
|
|
touch_sensor_set_mode_cmd_data_t sensor_mode_cmd;
|
|
|
|
|
|
|
|
if (rsp_status != 0 &&
|
|
|
|
rsp_status != TOUCH_STATUS_TIMEOUT) {
|
|
|
|
rsp_failed(ipts, cmd, rsp_status);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* allocate default resource : common & hid only */
|
|
|
|
if (!ipts_is_default_resource_ready(ipts)) {
|
|
|
|
ret = ipts_allocate_default_resource(ipts);
|
|
|
|
if (ret)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ipts->sensor_mode == TOUCH_SENSOR_MODE_RAW_DATA &&
|
|
|
|
!ipts_is_raw_data_resource_ready(ipts)) {
|
|
|
|
ret = ipts_allocate_raw_data_resource(ipts);
|
|
|
|
if (ret) {
|
|
|
|
ipts_free_default_resource(ipts);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
ipts_set_state(ipts, IPTS_STA_RESOURCE_READY);
|
|
|
|
|
|
|
|
cmd_len = sizeof(touch_sensor_set_mode_cmd_data_t);
|
|
|
|
memset(&sensor_mode_cmd, 0, cmd_len);
|
|
|
|
sensor_mode_cmd.sensor_mode = ipts->sensor_mode;
|
|
|
|
cmd_status = ipts_handle_cmd(ipts,
|
|
|
|
TOUCH_SENSOR_SET_MODE_CMD,
|
|
|
|
&sensor_mode_cmd, cmd_len);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TOUCH_SENSOR_SET_MODE_RSP:
|
|
|
|
{
|
|
|
|
touch_sensor_set_mem_window_cmd_data_t smw_cmd;
|
|
|
|
|
|
|
|
if (rsp_status != 0) {
|
|
|
|
rsp_failed(ipts, cmd, rsp_status);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd_len = sizeof(touch_sensor_set_mem_window_cmd_data_t);
|
|
|
|
memset(&smw_cmd, 0, cmd_len);
|
|
|
|
ipts_get_set_mem_window_cmd_data(ipts, &smw_cmd);
|
|
|
|
cmd_status = ipts_handle_cmd(ipts,
|
|
|
|
TOUCH_SENSOR_SET_MEM_WINDOW_CMD,
|
|
|
|
&smw_cmd, cmd_len);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TOUCH_SENSOR_SET_MEM_WINDOW_RSP:
|
|
|
|
if (rsp_status != 0) {
|
|
|
|
rsp_failed(ipts, cmd, rsp_status);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
cmd_status = ipts_send_sensor_hid_ready_for_data_cmd(ipts);
|
|
|
|
if (cmd_status)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (ipts->sensor_mode == TOUCH_SENSOR_MODE_HID) {
|
|
|
|
ipts_set_state(ipts, IPTS_STA_HID_STARTED);
|
|
|
|
} else if (ipts->sensor_mode == TOUCH_SENSOR_MODE_RAW_DATA) {
|
|
|
|
ipts_set_state(ipts, IPTS_STA_RAW_DATA_STARTED);
|
|
|
|
}
|
|
|
|
|
|
|
|
ipts_err(ipts, "touch enabled %d\n", ipts_get_state(ipts));
|
|
|
|
|
|
|
|
break;
|
|
|
|
case TOUCH_SENSOR_HID_READY_FOR_DATA_RSP:
|
|
|
|
{
|
|
|
|
touch_sensor_hid_ready_for_data_rsp_data_t *hid_data;
|
|
|
|
ipts_state_t state;
|
|
|
|
|
|
|
|
if (rsp_status != 0 &&
|
|
|
|
rsp_status != TOUCH_STATUS_SENSOR_DISABLED) {
|
|
|
|
rsp_failed(ipts, cmd, rsp_status);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
state = ipts_get_state(ipts);
|
|
|
|
if (ipts->sensor_mode == TOUCH_SENSOR_MODE_HID &&
|
|
|
|
state == IPTS_STA_HID_STARTED) {
|
|
|
|
|
|
|
|
hid_data = &m2h_msg->m2h_data.hid_ready_for_data_rsp_data;
|
|
|
|
|
|
|
|
/* HID mode only uses buffer 0 */
|
|
|
|
if (hid_data->touch_data_buffer_index != 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* handle hid data */
|
|
|
|
ipts_handle_hid_data(ipts, hid_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case TOUCH_SENSOR_FEEDBACK_READY_RSP:
|
|
|
|
if (rsp_status != 0 &&
|
|
|
|
rsp_status != TOUCH_STATUS_COMPAT_CHECK_FAIL) {
|
|
|
|
rsp_failed(ipts, cmd, rsp_status);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (m2h_msg->m2h_data.feedback_ready_rsp_data.
|
|
|
|
feedback_index == TOUCH_HID_2_ME_BUFFER_ID)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (ipts->sensor_mode == TOUCH_SENSOR_MODE_HID) {
|
|
|
|
cmd_status = ipts_handle_cmd(ipts,
|
|
|
|
TOUCH_SENSOR_HID_READY_FOR_DATA_CMD,
|
|
|
|
NULL, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reset retry since we are getting touch data */
|
|
|
|
ipts->retry = 0;
|
|
|
|
|
|
|
|
break;
|
|
|
|
case TOUCH_SENSOR_QUIESCE_IO_RSP:
|
|
|
|
{
|
|
|
|
ipts_state_t state;
|
|
|
|
|
|
|
|
if (rsp_status != 0) {
|
|
|
|
rsp_failed(ipts, cmd, rsp_status);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
state = ipts_get_state(ipts);
|
|
|
|
if (state == IPTS_STA_STOPPING && ipts->restart) {
|
|
|
|
ipts_dbg(ipts, "restart\n");
|
|
|
|
ipts_start(ipts);
|
|
|
|
ipts->restart = 0;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* support sysfs debug node for switch sensor mode */
|
|
|
|
if (ipts->switch_sensor_mode) {
|
|
|
|
ipts_set_state(ipts, IPTS_STA_INIT);
|
|
|
|
ipts->sensor_mode = ipts->new_sensor_mode;
|
|
|
|
ipts->switch_sensor_mode = false;
|
|
|
|
|
|
|
|
ipts_send_sensor_clear_mem_window_cmd(ipts);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* handle error in rsp_status */
|
|
|
|
if (rsp_status != 0) {
|
|
|
|
switch (rsp_status) {
|
|
|
|
case TOUCH_STATUS_SENSOR_EXPECTED_RESET:
|
|
|
|
case TOUCH_STATUS_SENSOR_UNEXPECTED_RESET:
|
|
|
|
ipts_dbg(ipts, "sensor reset %d\n", rsp_status);
|
|
|
|
ipts_restart(ipts);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
ipts_dbg(ipts, "cmd : 0x%08x, status %d\n",
|
|
|
|
cmd,
|
|
|
|
rsp_status);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cmd_status) {
|
|
|
|
ipts_restart(ipts);
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|