概述
高通驱动实现 GPIO 中断上报键值
- 一、 确认keycode值,同步修改上层键值映射表
- Tips 1: 选择一个好的键值的好处
- Tips 2: 如何确认驱动代是否ok
- 二、 驱动代码编写
- 三、代码调试
- 四、 驱动代码另一种实现方法——dts 实现
- 4.1 DTS 配置
- 4.2 添加 gpio-keys.c 的log
- 五、上层代码 加log 分析 keycode 方法
- 5.1 添加 Activity.java --->dispatchKeyEvent() 函数打印log
- 5.2 添加 View.java --->dispatchKeyEvent() 函数打印log
- 5.3 添加 KeyEvent.java --->dispatchKeyEvent() 函数打印log
- 六、 代码内容
- 6.1 msm8909-mtp.dtsi 文件内容
- 6.2 gpio-keys.c 文件内容
- 6.3 aw9523.c 文件内容
一、 确认keycode值,同步修改上层键值映射表
从Generic.kl文件中,我们可以看到 key 204 (0xCC)是没人使用的,
为避免和默认代码有冲突,我们使用 key 204 (0xCC)来做为按键 keycoe。
@frameworksbasedatakeyboardsGeneric.kl
# key 202 "KEY_PROG3"
# key 203 "KEY_PROG4"
# key 204 (undefined)
key 204 "KEY_SOS" WAKE
# key 205 "KEY_SUSPEND"
# key 206 "KEY_CLOSE"
@ deviceqcommsm8909gpio-keys.kl
key 102 HOME WAKE
key 528 FOCUS
key 766 CAMERA
key 204 "KEY_SOS" WAKE
以上代码确认生效方法 ----->
(1)编译前,剪切或者删除这个目录到其他地方:outtargetproductmsm8937_32gosystemusrkeylayout
(2)整编译大版本 make all
(3)编成功后 看下 outtargetproductmsm8937_32gosystemusrkeylayoutgpio-keys.kl 和 Generic.kl ,看下有没有自已的修改。
(4)下载版本到手机,adb 下 进入 system/usr/keylayout/*.kl 确认是否生效
Tips 1: 选择一个好的键值的好处
系统默认使用了很多键值,如果使用的键值和系统重复了,可能存在这样一种情况。
在上层我们自已写的代码中,永远都监听不到这个事件,因为这个事件已经被别人处理了!!!
为了避免这个情况的发生,建议选择一个未使用过的键值。
Tips 2: 如何确认驱动代是否ok
把键值 改成 KEY_POWER (0x74), 看下跑到代码中后,是否会亮灭屏。
如果会亮灭屏,恭喜你,驱动代码是OK的,接下来检查键值就好了。
二、 驱动代码编写
//for gpio91 SOS 20190921 +++
#define KEY_SOS 204 // (0xCC) key code
static int gpio_sos_num 91 // (GPIO 91)
int gpio_sos_num_irq = 0;
static struct work_struct gpio_sos_work;
static void gpio_sos_work_handler(struct work_struct *work)
{
struct aw9523_kpad_platform_data *pdata;
pdata = g_aw9523_data;
input_report_key(pdata->input, KEY_SOS, 1);
input_sync(pdata->input);
input_report_key(pdata->input, KEY_SOS, 0);
input_sync(pdata->input);
// 为了快速看到现象, 可以上报 KEY_POWER 事件, 看是否会亮灭屏,后续注释该代码 ++++
input_report_key(pdata->input, KEY_POWER, 1);
input_sync(pdata->input);
input_report_key(pdata->input, KEY_POWER, 0);
input_sync(pdata->input);
// 为了快速看到现象, 可以上报 KEY_POWER 事件, 看是否会亮灭屏,后续注释该代码 ----
printk("[hyl_sos][%s] input_report_key KEY_SOS=%d(0x%x)", __func__, KEY_SOS);
enable_irq(gpio_sos_irq);
}
static irqreturn_t gpio_sos_irq_handler(int irq, void *handle)
{
struct i2c_client *client = handle;
struct aw9523_kpad_platform_data *pdata;
disable_irq_nosync(gpio_sos_irq);
schedule_work(&gpio_sos_work);
return IRQ_HANDLED;
}
//for gpio91 SOS 20190921 ---
static int aw9523_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
pdata->input = input_allocate_device();//为新添加的输入设备分配内存
if (!pdata->input) {
error = -ENOMEM;
goto err_free_mem;
}
pdata->client = client;
pdata->input->name = "aw9523-keys";
pdata->input->phys = "aw9523-keys/input0";
pdata->input->dev.parent = &client->dev;
input_set_drvdata(pdata->input, pdata);//函数用来设置device的私有数据,保存驱动的私有数据。
__set_bit(EV_KEY, pdata->input->evbit);//支持的事件,EV_KEY事件,事件类型由input_dev.evbit表示
//gpio91 SOS 20190921 +++
// 为了快速看到现象, 可以上报 KEY_POWER 事件, 看是否会亮灭屏,后续注释该代码 ++++
__set_bit(KEY_POWER & KEY_MAX, pdata->input->keybit);
// 为了快速看到现象, 可以上报 KEY_POWER 事件, 看是否会亮灭屏,后续注释该代码 ----
__set_bit(KEY_SOS & KEY_MAX, pdata->input->keybit);
ret = gpio_request(gpio_sos_num, "gpio_sos");
if (ret) {
dev_err(&client->dev, "[hyl_sos]unable to request gpio [%d]n", gpio_sos_num);
}
ret = gpio_direction_input(gpio_sos_num);
if (ret) {
dev_err(&client->dev, "[hyl_sos]unable to set direction for gpio [%d]n", gpio_sos_num);
}
gpio_sos_num_irq = gpio_to_irq(gpio_sos_num);
ret = devm_request_threaded_irq(&client->dev, gpio_sos_num_irq, NULL,
gpio_sos_irq_handler, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING | IRQF_ONESHOT,
"gpio_sos_irq", client);
if (ret) {
dev_err(&client->dev, "[hyl_sos]Failed irq=%d request ret = %dn", gpio_sos_num_irq, ret);
}
printk("[hyl_sos][%s] request irq success, gpio_sos_num_irq=%d, KEY_SOS=%d(0x%x) n",
__func__, gpio_sos_num_irq , KEY_SOS);
INIT_WORK(&gpio_sos_work, gpio_sos_work_handler);
//for gpio91 SOS 20190921 ---
error = input_register_device(pdata->input);//将input_dev(输入设备结构体)注册到输入子系统核心中
}
static int aw9523_remove(struct i2c_client *client)
{
cancel_work_sync(gpio_sos_work);
}
三、代码调试
getevent -l 看下是否按键是否有键值 上报。
注意: 如果要 getevent -l 看到具体名字话,请参考第一章修改。
如下:
C:UsersAdministrator>adb shell
ASUS_X00P_1:/ # getevent -l
add device 2: /dev/input/event8
name: "msm8952-snd-card-mtp Button Jack"
add device 3: /dev/input/event7
name: "msm8952-snd-card-mtp Headset Jack"
add device 9: /dev/input/event0
name: "qpnp_pon"
could not get driver version for /dev/input/mice, Not a typewriter
add device 10: /dev/input/event5
name: "gpio-keys"
/dev/input/event0: EV_KEY KEY_VOLUMEDOWN DOWN
/dev/input/event0: EV_SYN SYN_REPORT 00000000
/dev/input/event0: EV_KEY KEY_VOLUMEDOWN UP
/dev/input/event0: EV_SYN SYN_REPORT 00000000
如果映射不对,可以调用
adb shell dumpsys input
看下调用的是哪个 kl 文件,然后把对应的键值 定义在 kl 文件中,就可以了。
如下:
ASUS_X00P_1:/ # dumpsys input
INPUT MANAGER (dumpsys input)
Input Manager State:
Interactive: false
System UI Visibility: 0x8608
Pointer Speed: 0
Pointer Gestures Enabled: true
Show Touches: false
Pointer Capture Enabled: false
Event Hub State:
BuiltInKeyboardId: -2
Devices:
-1: Virtual
Classes: 0x40000023
Path: <virtual>
Descriptor: a718a782d34bc767f4689c232d64d527998ea7fd
Location:
ControllerNumber: 0
UniqueId: <virtual>
Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000
KeyLayoutFile: /system/usr/keylayout/Generic.kl
KeyCharacterMapFile: /system/usr/keychars/Virtual.kcm
ConfigurationFile:
HaveKeyboardLayoutOverlay: false
1: uinput-fpsensor
Classes: 0x80000001
Path: /dev/input/event9
Descriptor: 485d69228e24f5e46da1598745890b214130dbc4
Location:
ControllerNumber: 0
UniqueId:
Identifier: bus=0x0003, vendor=0x0001, product=0x0001, version=0x0001
KeyLayoutFile: /system/usr/keylayout/Generic.kl
KeyCharacterMapFile: /system/usr/keychars/Generic.kcm
ConfigurationFile:
HaveKeyboardLayoutOverlay: false
2: msm8952-snd-card-mtp Button Jack
Classes: 0x00000001
Path: /dev/input/event8
Descriptor: ab997034df873c1d418cf7db1475423a61777921
Location: ALSA
ControllerNumber: 0
UniqueId:
Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000
KeyLayoutFile: /system/usr/keylayout/Generic.kl
KeyCharacterMapFile: /system/usr/keychars/Generic.kcm
ConfigurationFile:
HaveKeyboardLayoutOverlay: false
3: msm8952-snd-card-mtp Headset Jack
Classes: 0x00000080
Path: /dev/input/event7
Descriptor: 863975bb9064de0fc8a7277b87ac846c366d49c1
Location: ALSA
ControllerNumber: 0
UniqueId:
Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000
KeyLayoutFile:
KeyCharacterMapFile:
ConfigurationFile:
HaveKeyboardLayoutOverlay: false
4: goodix-ts
Classes: 0x00000015
Path: /dev/input/event6
Descriptor: 9e6143a1bc5dd41251b165ed559e32d49b5aad8f
Location: input/ts
ControllerNumber: 0
UniqueId:
Identifier: bus=0x0018, vendor=0xdead, product=0xbeef, version=0x28bb
KeyLayoutFile: /system/usr/keylayout/Generic.kl
KeyCharacterMapFile: /system/usr/keychars/Generic.kcm
ConfigurationFile:
HaveKeyboardLayoutOverlay: false
5: rf-keys
Classes: 0x00000001
Path: /dev/input/event4
Descriptor: bd7533fcf563b1a6b2c798f0e54e396a7aa1eecf
Location:
ControllerNumber: 0
UniqueId:
Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000
KeyLayoutFile: /system/usr/keylayout/Generic.kl
KeyCharacterMapFile: /system/usr/keychars/Generic.kcm
ConfigurationFile:
HaveKeyboardLayoutOverlay: false
6: hbtp_vm
Classes: 0x00000008
Path: /dev/input/event3
Descriptor: 793e303307c34fc398863d5f83ee4c6ea6a7c5c6
Location:
ControllerNumber: 0
UniqueId:
Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000
KeyLayoutFile:
KeyCharacterMapFile:
ConfigurationFile:
HaveKeyboardLayoutOverlay: false
7: sf-keys
Classes: 0x00000001
Path: /dev/input/event2
Descriptor: 1d04485d5413d18cadf673bafa785070142031c8
Location:
ControllerNumber: 0
UniqueId:
Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000
KeyLayoutFile: /system/usr/keylayout/Generic.kl
KeyCharacterMapFile: /system/usr/keychars/Generic.kcm
ConfigurationFile:
HaveKeyboardLayoutOverlay: false
8: madev
Classes: 0x00000001
Path: /dev/input/event1
Descriptor: 6e687c668d87f7a84f420f31851eb0fabc6ebb08
Location:
ControllerNumber: 0
UniqueId:
Identifier: bus=0x001c, vendor=0x0000, product=0x0000, version=0x0000
KeyLayoutFile: /system/usr/keylayout/Generic.kl
KeyCharacterMapFile: /system/usr/keychars/Generic.kcm
ConfigurationFile:
HaveKeyboardLayoutOverlay: false
9: qpnp_pon
Classes: 0x00000001
Path: /dev/input/event0
Descriptor: fb60d4f4370f5dbe8267b63d38dea852987571ab
Location: qpnp_pon/input0
ControllerNumber: 0
UniqueId:
Identifier: bus=0x0000, vendor=0x0000, product=0x0000, version=0x0000
KeyLayoutFile: /system/usr/keylayout/qpnp_pon.kl
KeyCharacterMapFile: /system/usr/keychars/Generic.kcm
ConfigurationFile:
HaveKeyboardLayoutOverlay: false
10: gpio-keys
Classes: 0x00000001
Path: /dev/input/event5
Descriptor: d2c52ff0f656fac4cd7b7a118d575e0109a9fe1c
Location: gpio-keys/input0
ControllerNumber: 0
UniqueId:
Identifier: bus=0x0019, vendor=0x0001, product=0x0001, version=0x0100
KeyLayoutFile: /system/usr/keylayout/gpio-keys.kl
KeyCharacterMapFile: /system/usr/keychars/Generic.kcm
ConfigurationFile:
HaveKeyboardLayoutOverlay: false
四、 驱动代码另一种实现方法——dts 实现
4.1 DTS 配置
@frameworksbasedatakeyboardsGeneric.kl
# key 204 (undefined)
key 204 "KEY_SOS"
# key 205 "KEY_SUSPEND"
@ deviceqcommsm8909gpio-keys.kl
key 102 HOME WAKE
key 204 "KEY_SOS" WAKE
@ kernelmsm-3.18archarmbootdtsqcommsm8909-mtp.dtsi
gpio_keys {
compatible = "gpio-keys";
input-name = "gpio-keys";
pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend";
pinctrl-0 = <&gpio_key_active>;
pinctrl-1 = <&gpio_key_suspend>;
gpio_sos{
label = "gpio_sos";
gpios = <&msm_gpio 91 0x1>;
linux,input-type = <1>;
linux,code = <0xCC>; // 0x204
gpio-key,wakeup;
debounce-interval = <15>;
};
/* 注释这段代码
camera_focus {
label = "camera_focus";
gpios = <&msm_gpio 91 0x1>;
linux,input-type = <1>;
linux,code = <0x210>;
gpio-key,wakeup;
debounce-interval = <15>;
};
*/
camera_snapshot {
label = "camera_snapshot";
gpios = <&msm_gpio 92 0x1>;
linux,input-type = <1>;
linux,code = <0x2fe>;
gpio-key,wakeup;
debounce-interval = <15>;
};
vol_up {
label = "volume_up";
gpios = <&msm_gpio 90 0x1>;
linux,input-type = <1>;
linux,code = <115>;
gpio-key,wakeup;
debounce-interval = <15>;
};
};
4.2 添加 gpio-keys.c 的log
@ kernel.....gpio-keys.c
// 添加 DTS 解析的log
static struct gpio_keys_platform_data * gpio_keys_get_devtree_pdata(struct device *dev)
{
gpio = of_get_gpio_flags(pp, 0, &flags);
button = &pdata->buttons[i++];
button->gpio = gpio;
button->active_low = flags & OF_GPIO_ACTIVE_LOW;
if (of_property_read_u32(pp, "linux,code", &button->code)) {
dev_err(dev, "Button without keycode: 0x%xn", button->gpio);
return ERR_PTR(-EINVAL);
}
button->desc = of_get_property(pp, "label", NULL);
if (of_property_read_u32(pp, "linux,input-type", &button->type))
button->type = EV_KEY;
button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
if (of_property_read_u32(pp, "debounce-interval", &button->debounce_interval))
button->debounce_interval = 5;
dev_err(dev, "[hyl_sos] [gpio_keys_get_devtree_pdata], gpio:%d, keycode,%d(0x%x), lable=%s n",
button->gpio, button->code,
button->code, button->type); ///+++++++++++++++++++++++++++++++++
}
// 添加 gpio 上报 key event 的log
static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
{
state = (__gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low;
if (type == EV_ABS) {
input_event(input, type, button->code, button->value);
} else {
input_event(input, type, button->code, !!state);
}
input_sync(input);
printk("[hyl_sos][gpio_keys_gpio_report_event], gpio:%d, keycode,%d(0x%x), lable=%s have report to inputsystemn",
button->gpio, button->code,
button->code, button->type); ///+++++++++++++++++++++++++++++++++
}
// 在 按键中断中 上报键值,添加 log 打印 按下按键的log
static irqreturn_t gpio_keys_irq_isr(int irq, void *dev_id)
{
input_event(input, EV_KEY, button->code, 1);
input_sync(input);
printk("[hyl_sos][gpio_keys_irq_isr], gpio:%d, keycode,%d(0x%x), lable=%s have report 1(pressed) to inputsystemn",
bdata->button->gpio, bdata->button->code,
bdata->button->code, bdata->button->type); ///+++++++++++++++++++++++++++++++++
}
// 在 定时器中,添加 log 打印 释放按键的log
static void gpio_keys_irq_timer(unsigned long _data)
{
if (bdata->key_pressed) {
input_event(input, EV_KEY, bdata->button->code, 0);
input_sync(input);
printk("[hyl_sos][gpio_keys_irq_timer], gpio:%d, keycode,%d(0x%x), lable=%s have report 0(released) to inputsystemn",
bdata->button->gpio, bdata->button->code,
bdata->button->code, bdata->button->type); ///+++++++++++++++++++++++++++++++++
bdata->key_pressed = false;
}
}
五、上层代码 加log 分析 keycode 方法
在上层中,最早处理 keyevent 的时候是在
frameworksbasecorejavaandroidappActivity.java 中
可以按如下流程添加log,分析 上层接收到的 keycode 值。
5.1 添加 Activity.java —>dispatchKeyEvent() 函数打印log
@ frameworksbasecorejavaandroidappActivity.java
public boolean dispatchKeyEvent(KeyEvent event) {
onUserInteraction();
// Let action bars open menus in response to the menu key prioritized over
// the window handling it
final int keyCode = event.getKeyCode();
// add log begin +++++++
Slog.v(TAG, "[hyl_sos][dispatchKeyEvent] " + this + ": " + keyCode); ///+++++++++++++++++++++++++++++++++
// add log end --------
if (keyCode == KeyEvent.KEYCODE_MENU &&
mActionBar != null && mActionBar.onMenuKeyEvent(event)) {
return true;
}
Window win = getWindow();
if (win.superDispatchKeyEvent(event)) {
return true;
}
View decor = mDecor;
if (decor == null) decor = win.getDecorView();
return event.dispatch(this, decor != null
? decor.getKeyDispatcherState() : null, this);
}
public boolean onKeyDown(int keyCode, KeyEvent event) {
Slog.v(TAG, "[hyl_sos][onKeyDown] " + this + ": " + keyCode); ///+++++++++++++++++++++++++++++++++
if (keyCode == KeyEvent.KEYCODE_BACK) {
if (getApplicationInfo().targetSdkVersion
>= Build.VERSION_CODES.ECLAIR) {
event.startTracking();
} else {
onBackPressed();
}
return true;
}
public boolean onKeyUp(int keyCode, KeyEvent event) {
Slog.v(TAG, "[hyl_sos][onKeyUp] " + this + ": " + keyCode); ///+++++++++++++++++++++++++++++++++
if (getApplicationInfo().targetSdkVersion
>= Build.VERSION_CODES.ECLAIR) {
if (keyCode == KeyEvent.KEYCODE_BACK && event.isTracking()
&& !event.isCanceled()) {
onBackPressed();
return true;
}
}
return false;
}
5.2 添加 View.java —>dispatchKeyEvent() 函数打印log
frameworksbasecorejavaandroidviewView.java
/**
* Dispatch a key event to the next view on the focus path. This path runs
* from the top of the view tree down to the currently focused view. If this
* view has focus, it will dispatch to itself. Otherwise it will dispatch
* the next node down the focus path. This method also fires any key
* listeners.
*
* @param event The key event to be dispatched.
* @return True if the event was handled, false otherwise.
*/
public boolean dispatchKeyEvent(KeyEvent event) {
final int keyCode = event.getKeyCode();
Log.e(VIEW_LOG_TAG, "[hyl_sos][View.java][dispatchKeyEvent] keyCode = %d n", keyCode); ///+++++++++++++++++++++++++++++++++
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onKeyEvent(event, 0);
}
// Give any attached key listener a first crack at the event.
//noinspection SimplifiableIfStatement
ListenerInfo li = mListenerInfo;
if (li != null && li.mOnKeyListener != null && (mViewFlags & ENABLED_MASK) == ENABLED
&& li.mOnKeyListener.onKey(this, event.getKeyCode(), event)) {
return true;
}
if (event.dispatch(this, mAttachInfo != null
? mAttachInfo.mKeyDispatchState : null, this)) {
return true;
}
if (mInputEventConsistencyVerifier != null) {
mInputEventConsistencyVerifier.onUnhandledEvent(event, 0);
}
return false;
}
5.3 添加 KeyEvent.java —>dispatchKeyEvent() 函数打印log
在 所有 KeyEvent的函中,打印 keycode 值:
Log.v(TAG, "[hyl_sos][KeyEvent(4) ] Keycode = " + mKeyCode);
代码如下
frameworksbasecorejavaandroidviewKeyEvent.java
public class KeyEvent extends InputEvent implements Parcelable {
*/
public final boolean dispatch(Callback receiver, DispatcherState state,
Object target) {
Log.v(TAG, "[hyl_sos][KeyEvent][dispatch] Keycode = " + mKeyCode); ///+++++++++++++++++++++++++++++++++
switch (mAction) {
case ACTION_DOWN:
boolean res = receiver.onKeyDown(mKeyCode, this);
case ACTION_UP:
return receiver.onKeyUp(mKeyCode, this);
case ACTION_MULTIPLE:
receiver.onKeyMultiple(code, count, this))
if (code != KeyEvent.KEYCODE_UNKNOWN) {
mAction = ACTION_DOWN;
mRepeatCount = 0;
boolean handled = receiver.onKeyDown(code, this);
if (handled) {
mAction = ACTION_UP;
receiver.onKeyUp(code, this);
}
}
public KeyEvent(int action, int code) {
mAction = action;
mKeyCode = code;
mRepeatCount = 0;
mDeviceId = KeyCharacterMap.VIRTUAL_KEYBOARD;
Log.v(TAG, "[hyl_sos][KeyEvent(int action, int code)] Keycode = " + mKeyCode); ///+++++++++++++++++++++++++++++++++
}
public KeyEvent(long downTime, long eventTime, int action,
int code, int repeat) {
mDownTime = downTime;
mEventTime = eventTime;
mAction = action;
mKeyCode = code;
mRepeatCount = repeat;
mDeviceId = KeyCharacterMap.VIRTUAL_KEYBOARD;
Log.v(TAG, "[hyl_sos][KeyEvent(5) ] Keycode = " + mKeyCode); ///+++++++++++++++++++++++++++++++++
}
public KeyEvent(long downTime, long eventTime, int action,
int code, int repeat, int metaState) {
mDownTime = downTime;
mEventTime = eventTime;
mAction = action;
mKeyCode = code;
mRepeatCount = repeat;
mMetaState = metaState;
mDeviceId = KeyCharacterMap.VIRTUAL_KEYBOARD;
Log.v(TAG, "[hyl_sos][KeyEvent(6) ] Keycode = " + mKeyCode); ///+++++++++++++++++++++++++++++++++
}
public KeyEvent(long downTime, long eventTime, int action,
int code, int repeat, int metaState,
int deviceId, int scancode) {
mDownTime = downTime;
mEventTime = eventTime;
mAction = action;
mKeyCode = code;
mRepeatCount = repeat;
mMetaState = metaState;
mDeviceId = deviceId;
mScanCode = scancode;
Log.v(TAG, "[hyl_sos][KeyEvent(8) ] Keycode = " + mKeyCode); ///+++++++++++++++++++++++++++++++++
}
public KeyEvent(long downTime, long eventTime, int action,
int code, int repeat, int metaState,
int deviceId, int scancode, int flags) {
mDownTime = downTime;
mEventTime = eventTime;
mAction = action;
mKeyCode = code;
mRepeatCount = repeat;
mMetaState = metaState;
mDeviceId = deviceId;
mScanCode = scancode;
mFlags = flags;
Log.v(TAG, "[hyl_sos][KeyEvent(9) ] Keycode = " + mKeyCode); ///+++++++++++++++++++++++++++++++++
}
public KeyEvent(long downTime, long eventTime, int action,
int code, int repeat, int metaState,
int deviceId, int scancode, int flags, int source) {
mDownTime = downTime;
mEventTime = eventTime;
mAction = action;
mKeyCode = code;
mRepeatCount = repeat;
mMetaState = metaState;
mDeviceId = deviceId;
mScanCode = scancode;
mFlags = flags;
mSource = source;
Log.v(TAG, "[hyl_sos][KeyEvent(10) ] Keycode = " + mKeyCode); ///+++++++++++++++++++++++++++++++++
}
public KeyEvent(long time, String characters, int deviceId, int flags) {
mDownTime = time;
mEventTime = time;
mCharacters = characters;
mAction = ACTION_MULTIPLE;
mKeyCode = KEYCODE_UNKNOWN;
mRepeatCount = 0;
mDeviceId = deviceId;
mFlags = flags;
mSource = InputDevice.SOURCE_KEYBOARD;
Log.v(TAG, "[hyl_sos][KeyEvent(4) ] Keycode = " + mKeyCode); ///+++++++++++++++++++++++++++++++++
}
public KeyEvent(KeyEvent origEvent) {
mDownTime = origEvent.mDownTime;
mEventTime = origEvent.mEventTime;
mAction = origEvent.mAction;
mKeyCode = origEvent.mKeyCode;
mRepeatCount = origEvent.mRepeatCount;
mMetaState = origEvent.mMetaState;
mDeviceId = origEvent.mDeviceId;
mSource = origEvent.mSource;
mScanCode = origEvent.mScanCode;
mFlags = origEvent.mFlags;
mCharacters = origEvent.mCharacters;
Log.v(TAG, "[hyl_sos][KeyEvent(KeyEvent origEvent) ] Keycode = " + mKeyCode); ///+++++++++++++++++++++++++++++++++
}
public KeyEvent(KeyEvent origEvent, long eventTime, int newRepeat) {
mDownTime = origEvent.mDownTime;
mEventTime = eventTime;
mAction = origEvent.mAction;
mKeyCode = origEvent.mKeyCode;
mRepeatCount = newRepeat;
mMetaState = origEvent.mMetaState;
mDeviceId = origEvent.mDeviceId;
mSource = origEvent.mSource;
mScanCode = origEvent.mScanCode;
mFlags = origEvent.mFlags;
mCharacters = origEvent.mCharacters;
Log.v(TAG, "[hyl_sos][KeyEvent(3)] Keycode = " + mKeyCode); ///+++++++++++++++++++++++++++++++++
}
private KeyEvent(KeyEvent origEvent, int action) {
mDownTime = origEvent.mDownTime;
mEventTime = origEvent.mEventTime;
mAction = action;
mKeyCode = origEvent.mKeyCode;
mRepeatCount = origEvent.mRepeatCount;
mMetaState = origEvent.mMetaState;
mDeviceId = origEvent.mDeviceId;
mSource = origEvent.mSource;
mScanCode = origEvent.mScanCode;
mFlags = origEvent.mFlags;
Log.v(TAG, "[hyl_sos][KeyEvent(KeyEvent origEvent, int action) ] Keycode = " + mKeyCode); ///+++++++++++++++++++++++++++++++++
// Don't copy mCharacters, since one way or the other we'll lose it
// when changing the action.
}
private KeyEvent(Parcel in) {
mDeviceId = in.readInt();
mSource = in.readInt();
mAction = in.readInt();
mKeyCode = in.readInt();
mRepeatCount = in.readInt();
mMetaState = in.readInt();
mScanCode = in.readInt();
mFlags = in.readInt();
mDownTime = in.readLong();
mEventTime = in.readLong();
Log.v(TAG, "[hyl_sos][KeyEvent(Parcel in)] Keycode = " + mKeyCode); ///+++++++++++++++++++++++++++++++++
}
不知不觉就这么晚,实在扛不住,睡觉了
Date:2019/09/25 - 0:30
六、 代码内容
6.1 msm8909-mtp.dtsi 文件内容
@ kernelmsm-3.18archarmbootdtsqcommsm8909-mtp.dtsi
gpio_keys {
compatible = "gpio-keys";
input-name = "gpio-keys";
pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend";
pinctrl-0 = <&gpio_key_active>;
pinctrl-1 = <&gpio_key_suspend>;
gpio_sos{
label = "gpio_sos";
gpios = <&msm_gpio 91 0x1>;
linux,input-type = <1>;
linux,code = <0xCC>; // 0x204
gpio-key,wakeup;
debounce-interval = <15>;
};
/* 注释这段代码
camera_focus {
label = "camera_focus";
gpios = <&msm_gpio 91 0x1>;
linux,input-type = <1>;
linux,code = <0x210>;
gpio-key,wakeup;
debounce-interval = <15>;
};
*/
camera_snapshot {
label = "camera_snapshot";
gpios = <&msm_gpio 92 0x1>;
linux,input-type = <1>;
linux,code = <0x2fe>;
gpio-key,wakeup;
debounce-interval = <15>;
};
vol_up {
label = "volume_up";
gpios = <&msm_gpio 90 0x1>;
linux,input-type = <1>;
linux,code = <115>;
gpio-key,wakeup;
debounce-interval = <15>;
};
};
6.2 gpio-keys.c 文件内容
/*
* Driver for keys on GPIO lines capable of generating interrupts.
*
* Copyright 2005 Phil Blundell
* Copyright 2010, 2011 David Jander <david@protonic.nl>
* Copyright (c) 2015, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
#include <linux/sched.h>
#include <linux/pm.h>
#include <linux/slab.h>
#include <linux/sysctl.h>
#include <linux/proc_fs.h>
#include <linux/delay.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/gpio_keys.h>
#include <linux/workqueue.h>
#include <linux/gpio.h>
#include <linux/of.h>
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/spinlock.h>
#include <linux/pinctrl/consumer.h>
#include <linux/syscore_ops.h>
struct gpio_button_data {
const struct gpio_keys_button *button;
struct input_dev *input;
struct timer_list timer;
struct work_struct work;
unsigned int timer_debounce; /* in msecs */
unsigned int irq;
spinlock_t lock;
bool disabled;
bool key_pressed;
};
struct gpio_keys_drvdata {
const struct gpio_keys_platform_data *pdata;
struct pinctrl *key_pinctrl;
struct input_dev *input;
struct mutex disable_lock;
struct gpio_button_data data[0];
};
static struct device *global_dev;
static struct syscore_ops gpio_keys_syscore_pm_ops;
static void gpio_keys_syscore_resume(void);
/*
* SYSFS interface for enabling/disabling keys and switches:
*
* There are 4 attributes under /sys/devices/platform/gpio-keys/
* keys [ro] - bitmap of keys (EV_KEY) which can be
* disabled
* switches [ro] - bitmap of switches (EV_SW) which can be
* disabled
* disabled_keys [rw] - bitmap of keys currently disabled
* disabled_switches [rw] - bitmap of switches currently disabled
*
* Userland can change these values and hence disable event generation
* for each key (or switch). Disabling a key means its interrupt line
* is disabled.
*
* For example, if we have following switches set up as gpio-keys:
* SW_DOCK = 5
* SW_CAMERA_LENS_COVER = 9
* SW_KEYPAD_SLIDE = 10
* SW_FRONT_PROXIMITY = 11
* This is read from switches:
* 11-9,5
* Next we want to disable proximity (11) and dock (5), we write:
* 11,5
* to file disabled_switches. Now proximity and dock IRQs are disabled.
* This can be verified by reading the file disabled_switches:
* 11,5
* If we now want to enable proximity (11) switch we write:
* 5
* to disabled_switches.
*
* We can disable only those keys which don't allow sharing the irq.
*/
/**
* get_n_events_by_type() - returns maximum number of events per @type
* @type: type of button (%EV_KEY, %EV_SW)
*
* Return value of this function can be used to allocate bitmap
* large enough to hold all bits for given type.
*/
static inline int get_n_events_by_type(int type)
{
BUG_ON(type != EV_SW && type != EV_KEY);
return (type == EV_KEY) ? KEY_CNT : SW_CNT;
}
/**
* gpio_keys_disable_button() - disables given GPIO button
* @bdata: button data for button to be disabled
*
* Disables button pointed by @bdata. This is done by masking
* IRQ line. After this function is called, button won't generate
* input events anymore. Note that one can only disable buttons
* that don't share IRQs.
*
* Make sure that @bdata->disable_lock is locked when entering
* this function to avoid races when concurrent threads are
* disabling buttons at the same time.
*/
static void gpio_keys_disable_button(struct gpio_button_data *bdata)
{
if (!bdata->disabled) {
/*
* Disable IRQ and possible debouncing timer.
*/
disable_irq(bdata->irq);
if (bdata->timer_debounce)
del_timer_sync(&bdata->timer);
bdata->disabled = true;
}
}
/**
* gpio_keys_enable_button() - enables given GPIO button
* @bdata: button data for button to be disabled
*
* Enables given button pointed by @bdata.
*
* Make sure that @bdata->disable_lock is locked when entering
* this function to avoid races with concurrent threads trying
* to enable the same button at the same time.
*/
static void gpio_keys_enable_button(struct gpio_button_data *bdata)
{
if (bdata->disabled) {
enable_irq(bdata->irq);
bdata->disabled = false;
}
}
/**
* gpio_keys_attr_show_helper() - fill in stringified bitmap of buttons
* @ddata: pointer to drvdata
* @buf: buffer where stringified bitmap is written
* @type: button type (%EV_KEY, %EV_SW)
* @only_disabled: does caller want only those buttons that are
* currently disabled or all buttons that can be
* disabled
*
* This function writes buttons that can be disabled to @buf. If
* @only_disabled is true, then @buf contains only those buttons
* that are currently disabled. Returns 0 on success or negative
* errno on failure.
*/
static ssize_t gpio_keys_attr_show_helper(struct gpio_keys_drvdata *ddata,
char *buf, unsigned int type,
bool only_disabled)
{
int n_events = get_n_events_by_type(type);
unsigned long *bits;
ssize_t ret;
int i;
bits = kcalloc(BITS_TO_LONGS(n_events), sizeof(*bits), GFP_KERNEL);
if (!bits)
return -ENOMEM;
for (i = 0; i < ddata->pdata->nbuttons; i++) {
struct gpio_button_data *bdata = &ddata->data[i];
if (bdata->button->type != type)
continue;
if (only_disabled && !bdata->disabled)
continue;
__set_bit(bdata->button->code, bits);
}
ret = bitmap_scnlistprintf(buf, PAGE_SIZE - 2, bits, n_events);
buf[ret++] = 'n';
buf[ret] = '