X-Git-Url: http://git.openwrt.org/?a=blobdiff_plain;f=target%2Flinux%2Fgoldfish%2Fpatches-2.6.30%2F0090-input-Add-keyreset-driver.patch;fp=target%2Flinux%2Fgoldfish%2Fpatches-2.6.30%2F0090-input-Add-keyreset-driver.patch;h=0af1c5617d743bd3e896bdec2074746845afa7d0;hb=f88360279f91387dc61725226ad38c3c95d3790a;hp=0000000000000000000000000000000000000000;hpb=a6d8f8be9e06c5ffb03f815c8c76ba743c64aa3d;p=openwrt%2Fopenwrt.git diff --git a/target/linux/goldfish/patches-2.6.30/0090-input-Add-keyreset-driver.patch b/target/linux/goldfish/patches-2.6.30/0090-input-Add-keyreset-driver.patch new file mode 100644 index 0000000000..0af1c5617d --- /dev/null +++ b/target/linux/goldfish/patches-2.6.30/0090-input-Add-keyreset-driver.patch @@ -0,0 +1,313 @@ +From eb92150c047e76960ecf8989b9037fd34b43a4af Mon Sep 17 00:00:00 2001 +From: =?utf-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= +Date: Fri, 21 Nov 2008 21:47:23 -0800 +Subject: [PATCH 090/134] input: Add keyreset driver. +MIME-Version: 1.0 +Content-Type: text/plain; charset=utf-8 +Content-Transfer-Encoding: 8bit + +Add a platform device in the board file to specify a reset key-combo. +The first time the key-combo is detected a work function that syncs +the filesystems is scheduled. If all the keys are released and then +pressed again, it calls panic. Reboot on panic should be set for +this to work. + +Signed-off-by: Arve Hjønnevåg +--- + drivers/input/Kconfig | 9 ++ + drivers/input/Makefile | 1 + + drivers/input/keyreset.c | 229 ++++++++++++++++++++++++++++++++++++++++++++++ + include/linux/keyreset.h | 27 ++++++ + 4 files changed, 266 insertions(+), 0 deletions(-) + create mode 100644 drivers/input/keyreset.c + create mode 100644 include/linux/keyreset.h + +--- a/drivers/input/Kconfig ++++ b/drivers/input/Kconfig +@@ -149,6 +149,15 @@ config INPUT_APMPOWER + To compile this driver as a module, choose M here: the + module will be called apm-power. + ++config INPUT_KEYRESET ++ tristate "Reset key" ++ depends on INPUT ++ ---help--- ++ Say Y here if you want to reboot when some keys are pressed; ++ ++ To compile this driver as a module, choose M here: the ++ module will be called keyreset. ++ + config XEN_KBDDEV_FRONTEND + tristate "Xen virtual keyboard and mouse support" + depends on XEN_FBDEV_FRONTEND +--- a/drivers/input/Makefile ++++ b/drivers/input/Makefile +@@ -23,5 +23,6 @@ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touch + obj-$(CONFIG_INPUT_MISC) += misc/ + + obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o ++obj-$(CONFIG_INPUT_KEYRESET) += keyreset.o + + obj-$(CONFIG_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o +--- /dev/null ++++ b/drivers/input/keyreset.c +@@ -0,0 +1,229 @@ ++/* drivers/input/keyreset.c ++ * ++ * Copyright (C) 2008 Google, Inc. ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++struct keyreset_state { ++ struct input_handler input_handler; ++ unsigned long keybit[BITS_TO_LONGS(KEY_CNT)]; ++ unsigned long upbit[BITS_TO_LONGS(KEY_CNT)]; ++ unsigned long key[BITS_TO_LONGS(KEY_CNT)]; ++ spinlock_t lock; ++ int key_down_target; ++ int key_down; ++ int key_up; ++ int restart_disabled; ++}; ++ ++int restart_requested; ++static void deferred_restart(struct work_struct *dummy) ++{ ++ restart_requested = 2; ++ sys_sync(); ++ restart_requested = 3; ++ kernel_restart(NULL); ++} ++static DECLARE_WORK(restart_work, deferred_restart); ++ ++static void keyreset_event(struct input_handle *handle, unsigned int type, ++ unsigned int code, int value) ++{ ++ unsigned long flags; ++ struct keyreset_state *state = handle->private; ++ ++ if (type != EV_KEY) ++ return; ++ ++ if (code >= KEY_MAX) ++ return; ++ ++ if (!test_bit(code, state->keybit)) ++ return; ++ ++ spin_lock_irqsave(&state->lock, flags); ++ if (!test_bit(code, state->key) == !value) ++ goto done; ++ __change_bit(code, state->key); ++ if (test_bit(code, state->upbit)) { ++ if (value) { ++ state->restart_disabled = 1; ++ state->key_up++; ++ } else ++ state->key_up--; ++ } else { ++ if (value) ++ state->key_down++; ++ else ++ state->key_down--; ++ } ++ if (state->key_down == 0 && state->key_up == 0) ++ state->restart_disabled = 0; ++ ++ pr_debug("reset key changed %d %d new state %d-%d-%d\n", code, value, ++ state->key_down, state->key_up, state->restart_disabled); ++ ++ if (value && !state->restart_disabled && ++ state->key_down == state->key_down_target) { ++ state->restart_disabled = 1; ++ if (restart_requested) ++ panic("keyboard reset failed, %d", restart_requested); ++ pr_info("keyboard reset\n"); ++ schedule_work(&restart_work); ++ restart_requested = 1; ++ } ++done: ++ spin_unlock_irqrestore(&state->lock, flags); ++} ++ ++static int keyreset_connect(struct input_handler *handler, ++ struct input_dev *dev, ++ const struct input_device_id *id) ++{ ++ int i; ++ int ret; ++ struct input_handle *handle; ++ struct keyreset_state *state = ++ container_of(handler, struct keyreset_state, input_handler); ++ ++ for (i = 0; i < KEY_MAX; i++) { ++ if (test_bit(i, state->keybit) && test_bit(i, dev->keybit)) ++ break; ++ } ++ if (i == KEY_MAX) ++ return -ENODEV; ++ ++ handle = kzalloc(sizeof(*handle), GFP_KERNEL); ++ if (!handle) ++ return -ENOMEM; ++ ++ handle->dev = dev; ++ handle->handler = handler; ++ handle->name = "keyreset"; ++ handle->private = state; ++ ++ ret = input_register_handle(handle); ++ if (ret) ++ goto err_input_register_handle; ++ ++ ret = input_open_device(handle); ++ if (ret) ++ goto err_input_open_device; ++ ++ pr_info("using input dev %s for key reset\n", dev->name); ++ ++ return 0; ++ ++err_input_open_device: ++ input_unregister_handle(handle); ++err_input_register_handle: ++ kfree(handle); ++ return ret; ++} ++ ++static void keyreset_disconnect(struct input_handle *handle) ++{ ++ input_close_device(handle); ++ input_unregister_handle(handle); ++ kfree(handle); ++} ++ ++static const struct input_device_id keyreset_ids[] = { ++ { ++ .flags = INPUT_DEVICE_ID_MATCH_EVBIT, ++ .evbit = { BIT_MASK(EV_KEY) }, ++ }, ++ { }, ++}; ++MODULE_DEVICE_TABLE(input, keyreset_ids); ++ ++static int keyreset_probe(struct platform_device *pdev) ++{ ++ int ret; ++ int key, *keyp; ++ struct keyreset_state *state; ++ struct keyreset_platform_data *pdata = pdev->dev.platform_data; ++ ++ if (!pdata) ++ return -EINVAL; ++ ++ state = kzalloc(sizeof(*state), GFP_KERNEL); ++ if (!state) ++ return -ENOMEM; ++ ++ spin_lock_init(&state->lock); ++ keyp = pdata->keys_down; ++ while ((key = *keyp++)) { ++ if (key >= KEY_MAX) ++ continue; ++ state->key_down_target++; ++ __set_bit(key, state->keybit); ++ } ++ if (pdata->keys_up) { ++ keyp = pdata->keys_up; ++ while ((key = *keyp++)) { ++ if (key >= KEY_MAX) ++ continue; ++ __set_bit(key, state->keybit); ++ __set_bit(key, state->upbit); ++ } ++ } ++ state->input_handler.event = keyreset_event; ++ state->input_handler.connect = keyreset_connect; ++ state->input_handler.disconnect = keyreset_disconnect; ++ state->input_handler.name = KEYRESET_NAME; ++ state->input_handler.id_table = keyreset_ids; ++ ret = input_register_handler(&state->input_handler); ++ if (ret) { ++ kfree(state); ++ return ret; ++ } ++ platform_set_drvdata(pdev, state); ++ return 0; ++} ++ ++int keyreset_remove(struct platform_device *pdev) ++{ ++ struct keyreset_state *state = platform_get_drvdata(pdev); ++ input_unregister_handler(&state->input_handler); ++ kfree(state); ++ return 0; ++} ++ ++ ++struct platform_driver keyreset_driver = { ++ .driver.name = KEYRESET_NAME, ++ .probe = keyreset_probe, ++ .remove = keyreset_remove, ++}; ++ ++static int __init keyreset_init(void) ++{ ++ return platform_driver_register(&keyreset_driver); ++} ++ ++static void __exit keyreset_exit(void) ++{ ++ return platform_driver_unregister(&keyreset_driver); ++} ++ ++module_init(keyreset_init); ++module_exit(keyreset_exit); +--- /dev/null ++++ b/include/linux/keyreset.h +@@ -0,0 +1,27 @@ ++/* ++ * include/linux/keyreset.h - platform data structure for resetkeys driver ++ * ++ * Copyright (C) 2008 Google, Inc. ++ * ++ * This software is licensed under the terms of the GNU General Public ++ * License version 2, as published by the Free Software Foundation, and ++ * may be copied, distributed, and modified under those terms. ++ * ++ * This program is distributed in the hope that it will be useful, ++ * but WITHOUT ANY WARRANTY; without even the implied warranty of ++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ++ * GNU General Public License for more details. ++ * ++ */ ++ ++#ifndef _LINUX_KEYRESET_H ++#define _LINUX_KEYRESET_H ++ ++#define KEYRESET_NAME "keyreset" ++ ++struct keyreset_platform_data { ++ int *keys_up; ++ int keys_down[]; /* 0 terminated */ ++}; ++ ++#endif /* _LINUX_KEYRESET_H */