From: sangjin3.kim Date: Thu, 8 Mar 2012 07:48:50 +0000 (+0900) Subject: [Title] input bridge driver added to enable lockupinfo dump. X-Git-Tag: 2.2.1_release^2~161 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=aae5d2fb3565ba302eb144813a6952ca34077556;p=sdk%2Femulator%2Femulator-kernel.git [Title] input bridge driver added to enable lockupinfo dump. [Type] Feature [Module] driver/input [Priority] [CQ#] [Redmine#] [Problem] lockupinfo dump does not work in emulator. [Cause] [Solution] input bridge driver added. [TestCase] --- diff --git a/arch/x86/configs/i386_emul_defconfig b/arch/x86/configs/i386_emul_defconfig index 8656d3662e9e..cd64046a9c85 100644 --- a/arch/x86/configs/i386_emul_defconfig +++ b/arch/x86/configs/i386_emul_defconfig @@ -1,7 +1,7 @@ # # Automatically generated make config: don't edit # Linux kernel version: 2.6.32.9 -# Tue Feb 28 17:32:07 2012 +# Thu Mar 8 16:47:36 2012 # # CONFIG_64BIT is not set CONFIG_X86_32=y @@ -1104,6 +1104,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768 # CONFIG_INPUT_JOYDEV is not set CONFIG_INPUT_EVDEV=y # CONFIG_INPUT_EVBUG is not set +CONFIG_INPUT_SECBRIDGE=y # # Input Device Drivers diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index cd50c00ab20f..789bf24ae887 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig @@ -158,6 +158,13 @@ config XEN_KBDDEV_FRONTEND keyboard and mouse device driver. It communicates with a back-end in another domain. +config INPUT_SECBRIDGE + bool "Specific input event handler for Samsung" + depends on INPUT + default n + help + This driver implements the sec-input-bridge + comment "Input Device Drivers" source "drivers/input/keyboard/Kconfig" diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 4c9c745a7020..be0af27d1abd 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile @@ -25,3 +25,4 @@ obj-$(CONFIG_INPUT_MISC) += misc/ obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o obj-$(CONFIG_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o +obj-$(CONFIG_INPUT_SECBRIDGE) += sec-input-bridge.o diff --git a/drivers/input/sec-input-bridge.c b/drivers/input/sec-input-bridge.c new file mode 100644 index 000000000000..a69ee3e36ff0 --- /dev/null +++ b/drivers/input/sec-input-bridge.c @@ -0,0 +1,416 @@ +/* + * sec-input-bridge.c - Specific control inpt event bridge for Samsung Electronics + * + * Copyright (C) 2010 Samsung Electronics + * Yongsul Oh + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +#include + +extern int bkl_warning_operation(int on_off, int gamma); + +#ifdef CONFIG_KERNEL_LOGGING +int rb_dump_ram_log_extract_to_file(char* file_path); +#ifdef CONFIG_RB_DUMP_USE_NAND +int rb_dump_nand_log_extract_to_file(char* file_path); +#endif +#endif // CONFIG_RB_DUMP_USE_NAND + +struct sec_input_bridge { + struct sec_input_bridge_platform_data *pdata; + struct work_struct work; + struct mutex lock; + struct platform_device *dev; + + u8 check_index; +}; + +static void input_bridge_set_ids(struct input_device_id *ids, unsigned int type, unsigned int code) +{ + switch (type) { + case EV_KEY: + ids->flags = INPUT_DEVICE_ID_MATCH_KEYBIT; + __set_bit(code, ids->keybit); + break; + + case EV_REL: + ids->flags = INPUT_DEVICE_ID_MATCH_RELBIT; + __set_bit(code, ids->relbit); + break; + + case EV_ABS: + ids->flags = INPUT_DEVICE_ID_MATCH_ABSBIT; + __set_bit(code, ids->absbit); + break; + + case EV_MSC: + ids->flags = INPUT_DEVICE_ID_MATCH_MSCIT; + __set_bit(code, ids->mscbit); + break; + + case EV_SW: + ids->flags = INPUT_DEVICE_ID_MATCH_SWBIT; + __set_bit(code, ids->swbit); + break; + + case EV_LED: + ids->flags = INPUT_DEVICE_ID_MATCH_LEDBIT; + __set_bit(code, ids->ledbit); + break; + + case EV_SND: + ids->flags = INPUT_DEVICE_ID_MATCH_SNDBIT; + __set_bit(code, ids->sndbit); + break; + + case EV_FF: + ids->flags = INPUT_DEVICE_ID_MATCH_FFBIT; + __set_bit(code, ids->ffbit); + break; + + case EV_PWR: + /* do nothing */ + break; + + default: + printk(KERN_ERR + "input_bridge_set_ids: unknown type %u (code %u)\n", + type, code); + return; + } + + ids->flags |= INPUT_DEVICE_ID_MATCH_EVBIT; + __set_bit(type, ids->evbit); +} + +static void input_bridge_work(struct work_struct *work) { + struct sec_input_bridge *bridge = container_of(work, + struct sec_input_bridge, work); + int state = -EINVAL; + char env_str[16]; + char *envp[] = { env_str, NULL }; + +#ifdef CONFIG_KERNEL_LOGGING + rb_dump_ram_log_extract_to_file(NULL); +#ifdef CONFIG_RB_DUMP_USE_NAND + rb_dump_nand_log_extract_to_file(NULL); +#endif +#endif + + mutex_lock(&bridge->lock); + + if (bridge->pdata->send_uevent) { + sprintf(env_str, "%s=%s", bridge->pdata->uevent_env_str , bridge->pdata->uevent_env_value); + state = kobject_uevent_env(&bridge->dev->dev.kobj, bridge->pdata->uevent_action, envp); +// state = kobject_uevent(&bridge->dev->dev.kobj, bridge->pdata->uevent_action); + if (state != 0) + printk(KERN_ERR + " with action : %d\n",bridge->pdata->uevent_action); + } + + if (bridge->pdata->pre_event_func && (state == 0)) { + bridge->pdata->pre_event_func(bridge->pdata->event_data); + } + + /* LCD on/off to confirm action*/ +#if 0 // emulator + ssleep(2); + + for (i=0 ; i<8 ; i++) { + bkl_warning_operation(1, 0); + msleep(500); + + bkl_warning_operation(1, 10); + msleep(500); + } + + /* recovery first state*/ + bkl_warning_operation(0, 0); +#endif + + mutex_unlock(&bridge->lock); +} + +static void input_bridge_event(struct input_handle *handle, unsigned int type, + unsigned int code, int value) +{ + int rep_check; + + struct input_handler *sec_bridge_handler = handle->handler; + struct sec_input_bridge *sec_bridge = sec_bridge_handler->private; + + rep_check = test_bit(EV_REP,sec_bridge_handler->id_table->evbit); + rep_check = (rep_check << 1) | 1; + + switch (type) { + case EV_KEY: + if ( value & rep_check ) { + printk(KERN_INFO + "sec-input-bridge: KEY input intercepted, type : %d , code : %d , value %d, index : %d, mkey_max : %d \n", + type,code,value, sec_bridge->check_index, sec_bridge->pdata->num_mkey); + if ( sec_bridge->pdata->mkey_map[sec_bridge->check_index].code == code) { + sec_bridge->check_index++; + printk(KERN_INFO "sec-input-bridge: code ok!\n"); + if ( (sec_bridge->check_index) >= (sec_bridge->pdata->num_mkey) ) { + printk(KERN_INFO "sec-input-bridge: index is max \n"); + schedule_work(&sec_bridge->work); + sec_bridge->check_index = 0; + } + } else { + sec_bridge->check_index = 0; + } + } + break; + + default: + break; + } + +} + +static int input_bridge_connect(struct input_handler *handler, + struct input_dev *dev, + const struct input_device_id *id) +{ + struct input_handle *handle; + int error; + + handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL); + if (!handle) + return -ENOMEM; + + handle->dev = dev; + handle->handler = handler; + handle->name = "sec-input-bridge"; + + error = input_register_handle(handle); + if (error) { + printk(KERN_ERR + "sec-input-bridge: Failed to register input bridge handler, " + "error %d\n", error); + kfree(handle); + return error; + } + + error = input_open_device(handle); + if (error) { + printk(KERN_ERR + "sec-input-bridge: Failed to open input bridge device, " + "error %d\n", error); + input_unregister_handle(handle); + kfree(handle); + return error; + } + + return 0; +} + +static void input_bridge_disconnect(struct input_handle *handle) +{ + input_close_device(handle); + input_unregister_handle(handle); + kfree(handle); +} + +static struct input_handler input_bridge_handler = { + .event = input_bridge_event, + .connect = input_bridge_connect, + .disconnect = input_bridge_disconnect, + .name = "sec-input-bridge", +}; + +static int __devinit sec_input_bridge_probe(struct platform_device *dev) +{ + struct sec_input_bridge_platform_data *pdata; + struct sec_input_bridge *bridge; + struct input_device_id *input_bridge_ids; + + int state; + int i; + + pdata = dev->dev.platform_data; + if (!pdata) { + dev_err(&dev->dev, "No samsung input bridge platform data.\n"); + return -EINVAL; + } + + if (pdata->num_mkey == 0) { + dev_err(&dev->dev, "No samsung input bridge platform data. num_mkey == 0\n"); + return -EINVAL; + } + + bridge = kzalloc(sizeof(struct sec_input_bridge), GFP_KERNEL); + if (!bridge) + return -ENOMEM; + + input_bridge_ids = kzalloc(sizeof(struct input_device_id[(pdata->num_mkey +1)]), GFP_KERNEL); + if(!input_bridge_ids) { + kfree(bridge); + return -ENOMEM; + } + memset(input_bridge_ids, 0x00, sizeof(input_bridge_ids)); + + for( i=0 ; i < pdata->num_mkey ; i++ ) { + input_bridge_set_ids(&input_bridge_ids[i], pdata->mkey_map[i].type, pdata->mkey_map[i].code); + } + + input_bridge_handler.private = bridge; + input_bridge_handler.id_table = input_bridge_ids; + + state = input_register_handler(&input_bridge_handler); + if (state) + goto input_register_fail; + + bridge->dev = dev; + bridge->pdata = pdata; + + INIT_WORK(&bridge->work, input_bridge_work); + mutex_init(&bridge->lock); + + platform_set_drvdata(dev, bridge); + + return 0; + +input_register_fail: + cancel_work_sync(&bridge->work); + mutex_destroy(&bridge->lock); + kfree(bridge); + kfree(input_bridge_ids); + + return state; + +} + +static int __devexit sec_input_bridge_remove(struct platform_device *dev) +{ + struct sec_input_bridge *bridge = platform_get_drvdata(dev); + + cancel_work_sync(&bridge->work); + mutex_destroy(&bridge->lock); + kfree(input_bridge_handler.id_table); + input_unregister_handler(&input_bridge_handler); + kfree(bridge); + platform_set_drvdata(dev, NULL); + + return 0; +} + + +#ifdef CONFIG_PM +static int sec_input_bridge_suspend(struct platform_device *dev, pm_message_t state) +{ + return 0; +} + +static int sec_input_bridge_resume(struct platform_device *dev) +{ + return 0; +} +#else +#define sec_input_bridge_suspend NULL +#define sec_input_bridge_resume NULL +#endif + +static struct platform_driver sec_input_bridge_driver = { + .probe = sec_input_bridge_probe, + .remove = __devexit_p(sec_input_bridge_remove), + .suspend = sec_input_bridge_suspend, + .resume = sec_input_bridge_resume, + .driver = { + .name = "samsung_input_bridge", + }, +}; + +static const struct sec_input_bridge_mkey emul_mkey_map[] = { + { .type = EV_KEY , .code = KEY_VOLUMEUP }, + { .type = EV_KEY , .code = KEY_VOLUMEDOWN }, + { .type = EV_KEY , .code = KEY_FRONT }, + { .type = EV_KEY , .code = KEY_FRONT }, + { .type = EV_KEY , .code = KEY_VOLUMEUP }, + { .type = EV_KEY , .code = KEY_VOLUMEDOWN }, + { .type = EV_KEY , .code = KEY_VOLUMEUP }, + { .type = EV_KEY , .code = KEY_FRONT }, +}; + +static struct sec_input_bridge_platform_data emul_input_bridge_data = { + + .mkey_map = emul_mkey_map , + .num_mkey = ARRAY_SIZE(emul_mkey_map), + + .send_uevent = 1, + .uevent_action = KOBJ_CHANGE, + .uevent_env_str = "RB_DUMP", + .uevent_env_value = "ON", +}; + +static struct platform_device emul_input_bridge = { + .name = "samsung_input_bridge", + .id = -1, + .dev = { + .platform_data = &emul_input_bridge_data, + }, +}; + +//static struct platform_device *sec_input_bridge_device; + +static int __init sec_input_bridge_init(void) +{ + int err = 0; + + platform_device_register(&emul_input_bridge); + + err = platform_driver_register(&sec_input_bridge_driver); + + /* + if (!err) { + sec_input_bridge_device = platform_device_alloc("samsung_input_bridge", 0); + if (sec_input_bridge_device) + err = platform_device_add(sec_input_bridge_device); + else + err = -ENOMEM; + + if (err) { + platform_device_put(sec_input_bridge_device); + platform_driver_unregister(&sec_input_bridge_driver); + return err; + } + } + */ + return err; +} + +static void __exit sec_input_bridge_exit(void) +{ + platform_driver_unregister(&sec_input_bridge_driver); +} + + +module_init(sec_input_bridge_init); + +#ifdef CONFIG_CHARGER_DETECT_BOOT +charger_module_init(sec_input_bridge_init); +#endif + +module_exit(sec_input_bridge_exit); + +MODULE_AUTHOR("Yongsul Oh "); +MODULE_DESCRIPTION("Input Event -> Specific Control Bridge"); +MODULE_LICENSE("GPL"); diff --git a/include/linux/input/sec-input-bridge.h b/include/linux/input/sec-input-bridge.h new file mode 100644 index 000000000000..cf0ef836cf43 --- /dev/null +++ b/include/linux/input/sec-input-bridge.h @@ -0,0 +1,31 @@ +#ifndef LINUX_INPUT_SEC_INPUT_BRIDGE_H +#define LINUX_INPUT_SEC_INPUT_BRIDGE_H + +#include + +enum mkey_check_option { + MKEY_CHECK_AUTO, + MKEY_CHECK_AWAYS +}; + +struct sec_input_bridge_mkey { + unsigned int type; + unsigned int code; + enum mkey_check_option option; +}; + +struct sec_input_bridge_platform_data { + void (*pre_event_func)(void *event_data); + void *event_data; + + const struct sec_input_bridge_mkey *mkey_map; + unsigned int num_mkey; + + unsigned char send_uevent; + enum kobject_action uevent_action; + const char *uevent_env_str; + const char *uevent_env_value; +}; + +#endif /* LINUX_INPUT_SEC_INPUT_BRIDGE_H */ +