846 lines
23 KiB
C
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];
|
|
}
|