M7350/kernel/drivers/video/msm/mdss/mhl3/mhl_rcp_inputdev.c
2024-09-09 08:57:42 +00:00

846 lines
23 KiB
C

/*
* SiI8620 Linux Driver
*
* Copyright (C) 2013-2014 Silicon Image, Inc.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation version 2.
* This program is distributed AS-IS WITHOUT ANY WARRANTY of any
* kind, whether express or implied; INCLUDING without the implied warranty
* of MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE or NON-INFRINGEMENT.
* See the GNU General Public License for more details at
* http://www.gnu.org/licenses/gpl-2.0.html.
*/
#include <linux/input.h>
#include <linux/cdev.h>
#include <linux/hrtimer.h>
#include "si_fw_macros.h"
#include "si_infoframe.h"
#include "si_edid.h"
#include "si_mhl_defs.h"
#include "si_mhl2_edid_3d_api.h"
#include "si_mhl_tx_hw_drv_api.h"
#ifdef MEDIA_DATA_TUNNEL_SUPPORT
#include "si_mdt_inputdev.h"
#endif
#include "mhl_linux_tx.h"
#include "platform.h"
#include "mhl_rcp_inputdev.h"
enum rcp_state_e {
PH0_IDLE,
PH3_PRESS_AND_HOLD_KEY,
ph8_hold_mode,
num_rcp_states
};
static char *state_strings[num_rcp_states] = {
"idle",
"press_and_hold_key",
"hold_mode"
};
enum rcp_event_e {
RCP_NORMAL_KEY_PRESS,
RCP_NORMAL_KEY_PRESS_SAME,
RCP_NORMAL_KEY_RELEASE,
RCP_NORMAL_KEY_RELEASE_SAME,
RCP_HOLD_KEY_PRESS,
RCP_HOLD_KEY_PRESS_SAME,
RCP_HOLD_KEY_RELEASE,
RCP_HOLD_KEY_RELEASE_SAME,
RCP_T_HOLD_MAINTAIN_EXPIRED,
RCP_T_PRESS_MODE_EXPIRED,
NUM_RCP_EVENTS
};
static char *event_strings[NUM_RCP_EVENTS] = {
"normal_key_press",
"normal_key_press_same",
"normal_key_release",
"normal_key_release_same",
"press_and_hold_key_press",
"press_and_hold_key_press_same",
"press_and_hold_key_release",
"press_and_hold_key_release_same",
"rcp_T_hold_maintain_expired",
"rcp_T_press_mode_expired"
};
enum rcp_state_e current_rcp_state = PH0_IDLE;
uint8_t rcp_previous_key = 0, rcp_current_key = 0;
struct rcp_keymap_t rcpSupportTable[MHL_NUM_RCP_KEY_CODES] = {
{0, 0, 0, {KEY_SELECT, 0}, (MHL_DEV_LD_GUI)}, /* 0x00 */
{0, 1, 0, {KEY_UP, 0}, (MHL_DEV_LD_GUI)}, /* 0x01 */
{0, 1, 0, {KEY_DOWN, 0}, (MHL_DEV_LD_GUI)}, /* 0x02 */
{0, 1, 0, {KEY_LEFT, 0}, (MHL_DEV_LD_GUI)}, /* 0x03 */
{0, 1, 0, {KEY_RIGHT, 0}, (MHL_DEV_LD_GUI)}, /* 0x04 */
{1, 1, 0, {KEY_RIGHT, KEY_UP}, (MHL_DEV_LD_GUI)}, /* 0x05 */
{1, 1, 0, {KEY_RIGHT, KEY_DOWN}, (MHL_DEV_LD_GUI)}, /* 0x06 */
{1, 1, 0, {KEY_LEFT, KEY_UP}, (MHL_DEV_LD_GUI)}, /* 0x07 */
{1, 1, 0, {KEY_LEFT, KEY_DOWN}, (MHL_DEV_LD_GUI)}, /* 0x08 */
{0, 0, 0, {KEY_MENU, 0}, (MHL_DEV_LD_GUI)}, /* 0x09 */
{0, 0, 0, {KEY_UNKNOWN, 0}, 0}, /* 0x0A */
{0, 0, 0, {KEY_UNKNOWN, 0}, 0}, /* 0x0B */
{0, 0, 0, {KEY_BOOKMARKS, 0}, 0}, /* 0x0C */
{0, 0, 0, {KEY_EXIT, 0}, (MHL_DEV_LD_GUI)}, /* 0x0D */
/* 0x0E - 0x1F Reserved */
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
/* 0x20 Numeric 0 */
{0, 0, 0, {KEY_NUMERIC_0, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x21 Numeric 1 */
{0, 0, 0, {KEY_NUMERIC_1, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x22 Numeric 2 */
{0, 0, 0, {KEY_NUMERIC_2, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x23 Numeric 3 */
{0, 0, 0, {KEY_NUMERIC_3, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x24 Numeric 4 */
{0, 0, 0, {KEY_NUMERIC_4, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x25 Numeric 5 */
{0, 0, 0, {KEY_NUMERIC_5, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x26 Numeric 6 */
{0, 0, 0, {KEY_NUMERIC_6, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x27 Numeric 7 */
{0, 0, 0, {KEY_NUMERIC_7, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x28 Numeric 8 */
{0, 0, 0, {KEY_NUMERIC_8, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x29 Numeric 9 */
{0, 0, 0, {KEY_NUMERIC_9, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x2A Dot */
{0, 0, 0, {KEY_DOT, 0}, 0},
/* 0x2B Enter */
{0, 0, 0, {KEY_ENTER, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x2C Clear */
{0, 0, 0, {KEY_CLEAR, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO |
MHL_DEV_LD_MEDIA | MHL_DEV_LD_TUNER)},
/* 0x2D - 0x2F Reserved */
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
/* 0x30 Channel Up */
{0, 1, 0, {KEY_CHANNELUP, 0}, (MHL_DEV_LD_TUNER)},
/* 0x31 Channel Down */
{0, 1, 0, {KEY_CHANNELDOWN, 0}, (MHL_DEV_LD_TUNER)},
/* 0x32 Previous Channel */
{0, 0, 0, {KEY_UNKNOWN, 0}, (MHL_DEV_LD_TUNER)},
/* 0x33 Sound Select */
{0, 0, 0, {KEY_SOUND, 0}, (MHL_DEV_LD_AUDIO)},
/* 0x34 Input Select */
{0, 0, 0, {KEY_UNKNOWN, 0}, 0},
/* 0x35 Show Information */
{0, 0, 0, {KEY_PROGRAM, 0}, 0},
/* 0x36 Help */
{0, 0, 0, {KEY_UNKNOWN, 0}, 0},
/* 0x37 Page Up */
{0, 1, 0, {KEY_PAGEUP, 0}, 0},
/* 0x38 Page Down */
{0, 1, 0, {KEY_PAGEDOWN, 0}, 0},
/* 0x39 - 0x40 Reserved */
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
/* 0x41 Volume Up */
{0, 1, 0, {KEY_VOLUMEUP, 0}, (MHL_DEV_LD_SPEAKER)},
/* 0x42 Volume Down */
{0, 1, 0, {KEY_VOLUMEDOWN, 0}, (MHL_DEV_LD_SPEAKER)},
/* 0x43 Mute */
{0, 0, 0, {KEY_MUTE, 0}, (MHL_DEV_LD_SPEAKER)},
/* 0x44 Play */
{0, 0, 0, {KEY_PLAY, 0}, (MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO)},
/* 0x45 Stop */
{0, 0, 0, {KEY_STOP, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO | MHL_DEV_LD_RECORD)},
/* 0x46 Pause */
{0, 0, 0, {KEY_PLAYPAUSE, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO | MHL_DEV_LD_RECORD)},
/* 0x47 Record */
{0, 0, 0, {KEY_RECORD, 0}, (MHL_DEV_LD_RECORD)},
/* 0x48 Rewind */
{0, 1, 0, {KEY_REWIND, 0}, (MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO)},
/* 0x49 Fast Forward */
{0, 1, 0, {KEY_FASTFORWARD, 0}, (MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO)},
/* 0x4A Eject */
{0, 0, 0, {KEY_EJECTCD, 0}, (MHL_DEV_LD_MEDIA)},
/* 0x4B Forward */
{0, 1, 0, {KEY_NEXTSONG, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO | MHL_DEV_LD_MEDIA)},
/* 0x4C Backward */
{0, 1, 0, {KEY_PREVIOUSSONG, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO | MHL_DEV_LD_MEDIA)},
/* 0x4D - 0x4F Reserved */
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
/* 0x50 = Angle */
{0, 0, 0, {KEY_UNKNOWN, 0}, 0},
/* 0x51 = Subpicture */
{0, 0, 0, {KEY_UNKNOWN, 0}, 0},
/* 0x52 - 0x5F Reserved */
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
/* 0x60 Play */
{0, 0, 0, {KEY_PLAYPAUSE, 0}, (MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO)},
/* 0x60 = Pause the Play */
{0, 0, 0, {KEY_PLAYPAUSE, 0}, (MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO)},
/* 0x62 = Record */
{0, 0, 0, {KEY_RECORD, 0}, (MHL_DEV_LD_RECORD)},
/* 0x63 = Pause the Record */
{0, 0, 0, {KEY_PAUSE, 0}, (MHL_DEV_LD_RECORD)},
/* 0x64 = Stop */
{0, 0, 0, {KEY_STOP, 0},
(MHL_DEV_LD_VIDEO | MHL_DEV_LD_AUDIO | MHL_DEV_LD_RECORD)},
/* 0x65 = Mute */
{0, 0, 0, {KEY_MUTE, 0}, (MHL_DEV_LD_SPEAKER)},
/* 0x66 = Restore Mute */
{0, 0, 0, {KEY_MUTE, 0}, (MHL_DEV_LD_SPEAKER)},
/* 0x67 - 0x68 Undefined */
{0, 0, 0, {KEY_UNKNOWN, 0}, 0},
{0, 0, 0, {KEY_UNKNOWN, 0}, 0},
/* 0x69 - 0x70 Reserved */
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
/* 0x71 - 0x75 F1 - F5 */
{0, 0, 0, {KEY_F1, 0}, 0},
{0, 0, 0, {KEY_F2, 0}, 0},
{0, 0, 0, {KEY_F3, 0}, 0},
{0, 0, 0, {KEY_F4, 0}, 0},
{0, 0, 0, {KEY_F5, 0}, 0},
/* 0x76 - 0x7D Reserved */
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
{0, 0, 0, {KEY_RESERVED, 0}, 0},
/* 0x7E Vendor */
{0, 0, 0, {KEY_VENDOR, 0}, 0},
/* 0x7F reserved */
{0, 0, 0, {KEY_RESERVED, 0}, 0}
};
static u16 rcp_def_keymap[MHL_NUM_RCP_KEY_CODES]
#ifdef OLD_KEYMAP_TABLE
= {
KEY_SELECT,
KEY_UP,
KEY_DOWN,
KEY_LEFT,
KEY_RIGHT,
KEY_UNKNOWN, /* right-up */
KEY_UNKNOWN, /* right-down */
KEY_UNKNOWN, /* left-up */
KEY_UNKNOWN, /* left-down */
KEY_MENU,
KEY_UNKNOWN, /* setup */
KEY_UNKNOWN, /* contents */
KEY_UNKNOWN, /* favorite */
KEY_EXIT,
KEY_RESERVED, /* 0x0e */
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED, /* 0x1F */
KEY_NUMERIC_0,
KEY_NUMERIC_1,
KEY_NUMERIC_2,
KEY_NUMERIC_3,
KEY_NUMERIC_4,
KEY_NUMERIC_5,
KEY_NUMERIC_6,
KEY_NUMERIC_7,
KEY_NUMERIC_8,
KEY_NUMERIC_9,
KEY_DOT,
KEY_ENTER,
KEY_CLEAR,
KEY_RESERVED, /* 0x2D */
KEY_RESERVED,
KEY_RESERVED, /* 0x2F */
KEY_UNKNOWN, /* channel up */
KEY_UNKNOWN, /* channel down */
KEY_UNKNOWN, /* previous channel */
KEY_UNKNOWN, /* sound select */
KEY_UNKNOWN, /* input select */
KEY_UNKNOWN, /* show information */
KEY_UNKNOWN, /* help */
KEY_UNKNOWN, /* page up */
KEY_UNKNOWN, /* page down */
KEY_RESERVED, /* 0x39 */
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED, /* 0x3F */
KEY_RESERVED, /* 0x40 */
KEY_UNKNOWN, /* volume up */
KEY_UNKNOWN, /* volume down */
KEY_UNKNOWN, /* mute */
KEY_PLAY,
KEY_STOP,
KEY_PLAYPAUSE,
KEY_UNKNOWN, /* record */
KEY_REWIND,
KEY_FASTFORWARD,
KEY_UNKNOWN, /* eject */
KEY_NEXTSONG,
KEY_PREVIOUSSONG,
KEY_RESERVED, /* 0x4D */
KEY_RESERVED,
KEY_RESERVED, /* 0x4F */
KEY_UNKNOWN, /* angle */
KEY_UNKNOWN, /* subtitle */
KEY_RESERVED, /* 0x52 */
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED, /* 0x5F */
KEY_PLAY,
KEY_PAUSE,
KEY_UNKNOWN, /* record_function */
KEY_UNKNOWN, /* pause_record_function */
KEY_STOP,
KEY_UNKNOWN, /* mute_function */
KEY_UNKNOWN, /* restore_volume_function */
KEY_UNKNOWN, /* tune_function */
KEY_UNKNOWN, /* select_media_function */
KEY_RESERVED, /* 0x69 */
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED, /* 0x70 */
KEY_UNKNOWN, /* F1 */
KEY_UNKNOWN, /* F2 */
KEY_UNKNOWN, /* F3 */
KEY_UNKNOWN, /* F4 */
KEY_UNKNOWN, /* F5 */
KEY_RESERVED, /* 0x76 */
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED, /* 0x7D */
KEY_VENDOR,
KEY_RESERVED, /* 0x7F */
}
#endif
;
#ifdef OLD_KEYMAP_TABLE
int generate_rcp_input_event(struct mhl_dev_context *dev_context,
uint8_t rcp_keycode)
{
int status = -EINVAL;
if (dev_context->rcp_input_dev) {
if (rcp_keycode < ARRAY_SIZE(rcp_def_keymap) &&
rcp_def_keymap[rcp_keycode] != KEY_UNKNOWN &&
rcp_def_keymap[rcp_keycode] != KEY_RESERVED) {
input_report_key(dev_context->rcp_input_dev,
rcp_keycode, 1);
input_report_key(dev_context->rcp_input_dev,
rcp_keycode, 0);
input_sync(dev_context->rcp_input_dev);
status = 0;
}
}
return status;
}
#else
static int rcp_trigger_key_action(struct mhl_dev_context *dev_context,
uint8_t index, bool press_release)
{
int status = -EINVAL;
index &= MHL_RCP_KEY_ID_MASK;
if (dev_context->rcp_input_dev) {
input_report_key(dev_context->rcp_input_dev,
rcpSupportTable[index].map[0], press_release);
MHL_TX_DBG_ERR("input_report_key(0x%x,%d)\n",
rcpSupportTable[index].map[0], press_release)
if (rcpSupportTable[index].multicode) {
input_report_key(dev_context->rcp_input_dev,
rcpSupportTable[index].map[1], press_release);
MHL_TX_DBG_ERR("input_report_key(0x%x,%d)\n",
rcpSupportTable[index].map[1], press_release)
}
input_sync(dev_context->rcp_input_dev);
status = 0;
}
return status;
}
static int handle_rcp_event(struct mhl_dev_context *dev_context,
uint8_t current_key, uint8_t prev_key, enum rcp_event_e event)
{
int status = 0;
uint8_t current_index = current_key & MHL_RCP_KEY_ID_MASK;
uint8_t prev_index = prev_key & MHL_RCP_KEY_ID_MASK;
MHL_TX_DBG_ERR("received 0x%02x: %s(%d) in state: %s(%d)\n",
current_key, event_strings[event], event,
state_strings[current_rcp_state], current_rcp_state);
/* now process the event according to the current state */
switch (current_rcp_state) {
case PH0_IDLE:
switch (event) {
case RCP_NORMAL_KEY_PRESS:
case RCP_NORMAL_KEY_PRESS_SAME:
status =
rcp_trigger_key_action(dev_context, current_index,
1);
/* no update for current_rcp_state */
break;
case RCP_NORMAL_KEY_RELEASE:
case RCP_NORMAL_KEY_RELEASE_SAME:
status =
rcp_trigger_key_action(dev_context, current_index,
0);
/* no update for current_rcp_state */
break;
case RCP_HOLD_KEY_PRESS:
case RCP_HOLD_KEY_PRESS_SAME:
status =
rcp_trigger_key_action(dev_context, current_index,
1);
/* no break here */
mhl_tx_start_timer(dev_context,
dev_context->timer_T_press_mode,
T_PRESS_MODE);
current_rcp_state = PH3_PRESS_AND_HOLD_KEY;
break;
case RCP_HOLD_KEY_RELEASE:
case RCP_HOLD_KEY_RELEASE_SAME:
MHL_TX_DBG_ERR("unexpected %s(%d) in state: %s(%d)\n",
event_strings[event], event,
state_strings[current_rcp_state],
current_rcp_state);
break;
default:
MHL_TX_DBG_ERR("unexpected event: %d in state: %d\n",
event, current_rcp_state);
/* no update for current_rcp_state */
status = -EINVAL;
}
break;
case PH3_PRESS_AND_HOLD_KEY:
switch (event) {
case RCP_NORMAL_KEY_PRESS:
case RCP_NORMAL_KEY_PRESS_SAME:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_press_mode);
rcp_trigger_key_action(dev_context, prev_index, 0);
/* OK to overwrite status */
status =
rcp_trigger_key_action(dev_context, current_index,
1);
current_rcp_state = PH0_IDLE;
break;
case RCP_NORMAL_KEY_RELEASE:
case RCP_NORMAL_KEY_RELEASE_SAME:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_press_mode);
rcp_trigger_key_action(dev_context, prev_index, 0);
rcp_trigger_key_action(dev_context, current_index, 1);
status =
rcp_trigger_key_action(dev_context, current_index,
0);
current_rcp_state = PH0_IDLE;
break;
case RCP_HOLD_KEY_PRESS:
mhl_tx_start_timer(dev_context,
dev_context->timer_T_press_mode,
T_PRESS_MODE);
status =
rcp_trigger_key_action(dev_context, prev_index, 1);
/* no update for current_rcp_state */
break;
case RCP_HOLD_KEY_PRESS_SAME:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_press_mode);
mhl_tx_start_timer(dev_context,
dev_context->timer_T_hold_maintain,
T_HOLD_MAINTAIN);
status =
rcp_trigger_key_action(dev_context, prev_index, 1);
current_rcp_state = ph8_hold_mode;
break;
case RCP_HOLD_KEY_RELEASE:
case RCP_HOLD_KEY_RELEASE_SAME:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_press_mode);
status =
rcp_trigger_key_action(dev_context, prev_index, 0);
current_rcp_state = PH0_IDLE;
break;
case RCP_T_PRESS_MODE_EXPIRED:
mhl_tx_start_timer(dev_context,
dev_context->timer_T_hold_maintain,
T_HOLD_MAINTAIN);
status =
rcp_trigger_key_action(dev_context, prev_index, 0);
current_rcp_state = ph8_hold_mode;
break;
default:
MHL_TX_DBG_ERR("unexpected event: %d in state: %d\n",
event, current_rcp_state);
/* no update for current_rcp_state */
status = -EINVAL;
}
break;
case ph8_hold_mode:
switch (event) {
case RCP_NORMAL_KEY_PRESS:
case RCP_NORMAL_KEY_PRESS_SAME:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_hold_maintain);
rcp_trigger_key_action(dev_context, prev_index, 0);
status =
rcp_trigger_key_action(dev_context, current_index,
1);
current_rcp_state = PH0_IDLE;
break;
case RCP_NORMAL_KEY_RELEASE:
case RCP_NORMAL_KEY_RELEASE_SAME:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_hold_maintain);
rcp_trigger_key_action(dev_context, prev_index, 0);
rcp_trigger_key_action(dev_context, current_index, 1);
status =
rcp_trigger_key_action(dev_context, current_index,
0);
current_rcp_state = PH0_IDLE;
break;
case RCP_HOLD_KEY_PRESS:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_hold_maintain);
mhl_tx_start_timer(dev_context,
dev_context->timer_T_press_mode,
T_PRESS_MODE);
status =
rcp_trigger_key_action(dev_context, prev_index, 1);
current_rcp_state = PH3_PRESS_AND_HOLD_KEY;
break;
case RCP_HOLD_KEY_PRESS_SAME:
mhl_tx_start_timer(dev_context,
dev_context->timer_T_hold_maintain,
T_HOLD_MAINTAIN);
status =
rcp_trigger_key_action(dev_context, prev_index, 1);
/* no update for current_rcp_state */
break;
case RCP_HOLD_KEY_RELEASE:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_hold_maintain);
rcp_trigger_key_action(dev_context, prev_index, 0);
rcp_trigger_key_action(dev_context, current_index, 1);
status =
rcp_trigger_key_action(dev_context, current_index,
0);
current_rcp_state = PH0_IDLE;
break;
case RCP_HOLD_KEY_RELEASE_SAME:
mhl_tx_stop_timer(dev_context,
dev_context->timer_T_hold_maintain);
status =
rcp_trigger_key_action(dev_context, prev_index, 0);
current_rcp_state = PH0_IDLE;
break;
case RCP_T_HOLD_MAINTAIN_EXPIRED:
status =
rcp_trigger_key_action(dev_context, prev_index, 0);
current_rcp_state = PH0_IDLE;
break;
default:
MHL_TX_DBG_ERR("unexpected event: %d in state: %d\n",
event, current_rcp_state);
/* no update for current_rcp_state */
status = -EINVAL;
}
break;
default:
MHL_TX_DBG_ERR("irrational state value:%d\n",
current_rcp_state);
}
return status;
}
static void timer_callback_T_hold_maintain_handler(void *param)
{
struct mhl_dev_context *dev_context = (struct mhl_dev_context *)param;
handle_rcp_event(dev_context, rcp_current_key, rcp_previous_key,
RCP_T_HOLD_MAINTAIN_EXPIRED);
}
static void timer_callback_T_press_mode_handler(void *param)
{
struct mhl_dev_context *dev_context = (struct mhl_dev_context *)param;
handle_rcp_event(dev_context, rcp_current_key, rcp_previous_key,
RCP_T_PRESS_MODE_EXPIRED);
}
int generate_rcp_input_event(struct mhl_dev_context *dev_context,
uint8_t rcp_keycode)
{
/*
Since, in MHL, bit 7 == 1 indicates key release,
and, in Linux, zero means key release,
we use XOR (^) to invert the sense.
*/
int status = -EINVAL;
int index = rcp_keycode & MHL_RCP_KEY_ID_MASK;
if (rcp_def_keymap[index] != KEY_UNKNOWN &&
rcp_def_keymap[index] != KEY_RESERVED) {
enum rcp_event_e event;
int mhl_key_press =
(rcp_keycode & MHL_RCP_KEY_RELEASED_MASK) ? 0 : 1;
if (mhl_key_press) {
if (rcpSupportTable[index].press_and_hold_key) {
if (index == rcp_previous_key)
event = RCP_HOLD_KEY_PRESS_SAME;
else
event = RCP_HOLD_KEY_PRESS;
} else {
if (index == rcp_previous_key)
event = RCP_NORMAL_KEY_PRESS_SAME;
else
event = RCP_NORMAL_KEY_PRESS;
}
} else {
if (rcpSupportTable[index].press_and_hold_key) {
if (index == rcp_previous_key)
event = RCP_HOLD_KEY_RELEASE_SAME;
else
event = RCP_HOLD_KEY_RELEASE;
} else {
if (index == rcp_previous_key)
event = RCP_NORMAL_KEY_RELEASE_SAME;
else
event = RCP_NORMAL_KEY_RELEASE;
}
}
status =
handle_rcp_event(dev_context, rcp_keycode, rcp_current_key,
event);
}
rcp_previous_key = rcp_current_key;
rcp_current_key = rcp_keycode;
return status;
}
#endif
int init_rcp_input_dev(struct mhl_dev_context *dev_context)
{
unsigned int i;
struct input_dev *rcp_input_dev;
int ret;
if (dev_context->rcp_input_dev != NULL) {
MHL_TX_DBG_INFO("RCP input device already exists!\n");
return 0;
}
rcp_input_dev = input_allocate_device();
if (!rcp_input_dev) {
MHL_TX_DBG_ERR("Failed to allocate RCP input device\n");
return -ENOMEM;
}
set_bit(EV_KEY, rcp_input_dev->evbit);
rcp_input_dev->name = "MHL Remote Control";
rcp_input_dev->keycode = rcp_def_keymap;
rcp_input_dev->keycodesize = sizeof(u16);
rcp_input_dev->keycodemax = ARRAY_SIZE(rcp_def_keymap);
for (i = 0; i < ARRAY_SIZE(rcp_def_keymap); i++) {
#ifdef OLD_KEYMAP_TABLE
u16 keycode = rcp_def_keymap[i];
#else
u16 keycode = rcpSupportTable[i].map[0];
rcp_def_keymap[i] = keycode;
#endif
if (keycode != KEY_UNKNOWN && keycode != KEY_RESERVED)
set_bit(keycode, rcp_input_dev->keybit);
}
rcp_input_dev->id.bustype = BUS_VIRTUAL;
ret = input_register_device(rcp_input_dev);
if (ret) {
MHL_TX_DBG_ERR("Failed to register device\n");
input_free_device(rcp_input_dev);
return ret;
}
ret = mhl_tx_create_timer(dev_context,
timer_callback_T_press_mode_handler,
dev_context, &dev_context->timer_T_press_mode);
if (ret != 0) {
MHL_TX_DBG_ERR("failed in created timer_T_press_mode!\n");
} else {
ret = mhl_tx_create_timer(dev_context,
timer_callback_T_hold_maintain_handler,
dev_context, &dev_context->timer_T_hold_maintain);
if (ret != 0) {
MHL_TX_DBG_ERR
("failed to create timer_T_hold_maintain!\n");
} else {
MHL_TX_DBG_INFO("device created\n");
dev_context->rcp_input_dev = rcp_input_dev;
return 0;
}
mhl_tx_delete_timer(dev_context,
&dev_context->timer_T_press_mode);
}
return ret;
}
void destroy_rcp_input_dev(struct mhl_dev_context *dev_context)
{
if (dev_context->timer_T_press_mode) {
mhl_tx_delete_timer(dev_context,
&dev_context->timer_T_press_mode);
}
if (dev_context->timer_T_hold_maintain) {
mhl_tx_delete_timer(dev_context,
&dev_context->timer_T_hold_maintain);
}
if (dev_context->rcp_input_dev) {
input_unregister_device(dev_context->rcp_input_dev);
dev_context->rcp_input_dev = NULL;
}
}
void rcp_input_dev_one_time_init(struct mhl_dev_context *dev_context)
{
int i;
for (i = 0; i < MHL_NUM_RCP_KEY_CODES; ++i)
rcp_def_keymap[i] = rcpSupportTable[i].map[0];
}