diff options
Diffstat (limited to 'packages/linux/simpad/linux-2.6.24-SIMpad-ucb1x00-switches.patch')
-rw-r--r-- | packages/linux/simpad/linux-2.6.24-SIMpad-ucb1x00-switches.patch | 359 |
1 files changed, 359 insertions, 0 deletions
diff --git a/packages/linux/simpad/linux-2.6.24-SIMpad-ucb1x00-switches.patch b/packages/linux/simpad/linux-2.6.24-SIMpad-ucb1x00-switches.patch new file mode 100644 index 0000000000..20cb56d11b --- /dev/null +++ b/packages/linux/simpad/linux-2.6.24-SIMpad-ucb1x00-switches.patch @@ -0,0 +1,359 @@ +diff -Nur linux-2.6.24.vanilla/drivers/mfd/Kconfig linux-2.6.24/drivers/mfd/Kconfig +--- linux-2.6.24.vanilla/drivers/mfd/Kconfig 2008-01-24 23:58:37.000000000 +0100 ++++ linux-2.6.24/drivers/mfd/Kconfig 2008-02-20 21:17:07.000000000 +0100 +@@ -38,4 +38,7 @@ + tristate "Touchscreen interface support" + depends on MCP_UCB1200 && INPUT + ++config MCP_UCB1200_SWITCHES ++ tristate "SIMpad Switches support" ++ depends on MCP_UCB1200 && INPUT + endmenu +diff -Nur linux-2.6.24.vanilla/drivers/mfd/Makefile linux-2.6.24/drivers/mfd/Makefile +--- linux-2.6.24.vanilla/drivers/mfd/Makefile 2008-01-24 23:58:37.000000000 +0100 ++++ linux-2.6.24/drivers/mfd/Makefile 2008-02-20 21:17:07.000000000 +0100 +@@ -8,7 +8,7 @@ + obj-$(CONFIG_MCP_SA11X0) += mcp-sa11x0.o + obj-$(CONFIG_MCP_UCB1200) += ucb1x00-core.o + obj-$(CONFIG_MCP_UCB1200_TS) += ucb1x00-ts.o +- ++obj-$(CONFIG_MCP_UCB1200_SWITCHES) += ucb1x00-switches.o + ifeq ($(CONFIG_SA1100_ASSABET),y) + obj-$(CONFIG_MCP_UCB1200) += ucb1x00-assabet.o + endif +diff -Nur linux-2.6.24.vanilla/drivers/mfd/ucb1x00-switches.c linux-2.6.24/drivers/mfd/ucb1x00-switches.c +--- linux-2.6.24.vanilla/drivers/mfd/ucb1x00-switches.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.6.24/drivers/mfd/ucb1x00-switches.c 2008-02-20 21:17:07.000000000 +0100 +@@ -0,0 +1,332 @@ ++/* ++ * linux/drivers/mfd/ucb1x00-switches.c ++ * ++ * Copyright (C) 2007 Bernhard Guillon. ++ * ++ * 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; either version 2 of the License. ++ * ++ * This driver is for the Switches of Siemens SIMpad (CL4,SL4,SLC), T-Sinus-Pad and ++ * Swisscom WP50 devices. ++ * ++ * Six switches are routed to GPIO pins on the UCB1300: S3 -- S8. ++ * ++ * This driver is based on the 2.4 ucb1x00-switches, the 2.6 ucb1x00-assabet ++ * and the ucb1x00-ts driver. ++ * ++ * 2007/06/21 mrdata: ++ * - create new thread kswd() to handle irq_events for ucb1300-gpio's ++ * - found out, that not every key-press or key-release ++ * generate a irq_event ++ * -> establish key_state handling ++ * key_state, key_state_last <-> KEY_PRESS, KEY_RELEASE ++ * -> after irq_event polling the ucb1300-gpio's till all keys ++ * in key_state = KEY_RELEASE ++ * ++ */ ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/input.h> ++#include <linux/device.h> ++#include <linux/sched.h> ++#include <linux/freezer.h> ++#include <linux/kthread.h> ++ ++#include <asm/dma.h> ++ ++#include "ucb1x00.h" ++ ++#define KEY_PRESS 1 ++#define KEY_RELEASE 0 ++ ++static int key [6] = { KEY_PROG1,KEY_PROG2,KEY_UP,KEY_DOWN,KEY_LEFT,KEY_RIGHT }; ++ ++static unsigned short int key_state [6] = { 0, 0, 0, 0, 0, 0}; ++static unsigned short int key_state_last [6] = { 1, 1, 1, 1, 1, 1}; ++ ++struct ucb1x00_switches { ++ struct input_dev *idev; ++ struct ucb1x00 *ucb; ++ ++ wait_queue_head_t irq_wait; ++ struct task_struct *rtask; ++ ++ int idx; ++ ++ unsigned int valid:1; ++}; ++ ++static int ucb1x00_thread(void *_switches_id) ++{ ++ unsigned short int this; ++ int idx_tmp; ++ int i; ++ struct ucb1x00_switches *switches = _switches_id; ++ struct input_dev *idev = switches->idev; ++ struct task_struct *tsk = current; ++ DECLARE_WAITQUEUE(wait, tsk); ++ ++ add_wait_queue(&switches->irq_wait, &wait); ++ ++ while (!kthread_should_stop()) ++ { ++ signed long timeout; ++ ++ if ((switches->idx >= 0) && (switches->idx <= 5) && (switches->valid == 1)) ++ { ++ switches->valid = 0; ++ ++ idx_tmp = switches->idx; ++ ++ ucb1x00_enable(switches->ucb); ++ ++ this = ~ucb1x00_io_read(switches->ucb); ++ ++ ucb1x00_disable(switches->ucb); ++ ++ if (key_state[idx_tmp] == KEY_RELEASE) ++ { ++ key_state_last[idx_tmp] = KEY_RELEASE; ++ key_state[idx_tmp] = KEY_PRESS; ++ ++ input_report_key(idev, key[idx_tmp], KEY_PRESS); ++ input_sync(idev); ++ } ++ ++ for (i = 0; i < 6; i++) ++ { ++ if ((key_state[i] == KEY_RELEASE) && (((this & (1 << i)) ? 1 : 0) == KEY_PRESS)) ++ { ++ key_state_last[i] = KEY_RELEASE; ++ key_state[i] = KEY_PRESS; ++ ++ input_report_key(idev, key[i], KEY_PRESS); ++ input_sync(idev); ++ } ++ } ++ ++ for(;;) ++ { ++ ucb1x00_enable(switches->ucb); ++ this = ~ucb1x00_io_read(switches->ucb); ++ ucb1x00_disable(switches->ucb); ++ ++ for (i = 0; i < 6; i++) ++ { ++ if ((key_state[i] == KEY_PRESS) && (((this & (1 << i)) ? 1 : 0) == KEY_RELEASE)) ++ { ++ key_state_last[i] = KEY_PRESS; ++ key_state[i] = KEY_RELEASE; ++ ++ input_report_key(idev, key[i], KEY_RELEASE); ++ input_sync(idev); ++ } ++ ++ if ((key_state[i] == KEY_RELEASE) && (((this & (1 << i)) ? 1 : 0) == KEY_PRESS)) ++ { ++ key_state_last[i] = KEY_RELEASE; ++ key_state[i] = KEY_PRESS; ++ ++ input_report_key(idev, key[i], KEY_PRESS); ++ input_sync(idev); ++ } ++ ++ } ++ ++ // left loop, if no key press detect ++ if ((this | 0xff80) == 0xff80) ++ { ++ break; ++ } ++ ++ set_task_state(tsk, TASK_INTERRUPTIBLE); ++ ++ try_to_freeze(); ++ ++ timeout = HZ / 100; ++ ++ schedule_timeout(timeout); ++ } ++ } ++ ++ set_task_state(tsk, TASK_INTERRUPTIBLE); ++ ++ try_to_freeze(); ++ ++ timeout = MAX_SCHEDULE_TIMEOUT; ++ ++ schedule_timeout(timeout); ++ } ++ ++ remove_wait_queue(&switches->irq_wait, &wait); ++ ++ switches->rtask = NULL; ++ ++ return 0; ++} ++ ++ ++static void ucb1x00_dev_irq(int idx, void *id) ++{ ++ struct ucb1x00_switches *switches = id; ++ ++ switches->idx = idx; ++ switches->valid = 1; ++ ++ wake_up(&switches->irq_wait); ++} ++ ++static int ucb1x00_switches_add(struct ucb1x00_dev *dev) ++{ ++ struct ucb1x00_switches *switches; ++ struct input_dev *idev; ++ int err,i; ++ ++ switches = kzalloc(sizeof(struct ucb1x00_switches), GFP_KERNEL); ++ idev = input_allocate_device(); ++ ++ if (!switches || !idev) { ++ err = -ENOMEM; ++ goto fail; ++ } ++ ++ switches->ucb = dev->ucb; ++ ++ idev->private = switches; ++ idev->name = "SIMpad Switches"; ++ idev->id.product = switches->ucb->id; ++ ++ __set_bit(EV_KEY, idev->evbit); ++ __set_bit(EV_REP, idev->evbit); ++ __set_bit(KEY_PROG1, idev->keybit); ++ __set_bit(KEY_PROG2, idev->keybit); ++ __set_bit(KEY_UP, idev->keybit); ++ __set_bit(KEY_DOWN, idev->keybit); ++ __set_bit(KEY_LEFT, idev->keybit); ++ __set_bit(KEY_RIGHT, idev->keybit); ++ ++ err = input_register_device(idev); ++ if (err) ++ goto fail; ++ switches->idev = idev; ++ dev->priv = switches; ++ ++ BUG_ON(switches->rtask); ++ ++ init_waitqueue_head(&switches->irq_wait); ++ ++ ucb1x00_enable(switches->ucb); ++ ++ ucb1x00_io_set_dir(switches->ucb, ++ UCB_IO_0 | UCB_IO_1 | UCB_IO_2 | ++ UCB_IO_3 | UCB_IO_4 | UCB_IO_5, ++ UCB_IO_8 | UCB_IO_9); ++ ++ ucb1x00_disable(switches->ucb); ++ ++ for (i = 0; i < 6; ++i) { ++ ucb1x00_enable_irq(switches->ucb, i, UCB_RISING | UCB_FALLING); ++ ++ if (ucb1x00_hook_irq(switches->ucb, i, ucb1x00_dev_irq, switches) < 0) { ++ printk(KERN_ERR "unable to hook IRQ for " ++ "UCB1300 SWITCH_%d\n", i); ++ return -EBUSY; ++ } ++ } ++ ++ switches->rtask = kthread_run(ucb1x00_thread, switches, "kswd"); ++ if (!IS_ERR(switches->rtask)) ++ { ++ return 0; ++ } ++ else ++ { ++ input_unregister_device(switches->idev); ++ ++ for (i = 5; i >= 0; --i) { ++ ucb1x00_disable_irq(switches->ucb, i, UCB_RISING | UCB_FALLING); ++ ++ /* Only error conditions are ENOENT and EINVAL; silently ++ * ignore: ++ */ ++ ucb1x00_free_irq(switches->ucb, i, NULL); ++ } ++ switches->rtask = NULL; ++ ucb1x00_disable(switches->ucb); ++ kfree(switches); ++ ++ return -EFAULT; ++ } ++ ++fail: ++ input_free_device(idev); ++ kfree(switches); ++ return err; ++ ++} ++ ++static void ucb1x00_switches_remove(struct ucb1x00_dev *dev) ++{ ++ int i; ++ struct ucb1x00_switches *switches = dev->priv; ++ ++ if (switches->rtask) ++ kthread_stop(switches->rtask); ++ ++ switches->rtask = NULL; ++ ++ input_unregister_device(switches->idev); ++ ++ for (i = 5; i >= 0; --i) { ++ ucb1x00_disable_irq(switches->ucb, i, UCB_RISING | UCB_FALLING); ++ ++ /* Only error conditions are ENOENT and EINVAL; silently ++ * ignore: ++ */ ++ ucb1x00_free_irq(switches->ucb, i, NULL); ++ } ++ ucb1x00_disable(switches->ucb); ++ kfree(switches); ++} ++ ++#ifdef CONFIG_PM ++static int ucb1x00_switches_resume(struct ucb1x00_dev *dev) ++{ ++ struct ucb1x00_switches *switches = dev->priv; ++ ++ if (switches->rtask != NULL) ++ { ++ switches->valid = 0; ++ wake_up(&switches->irq_wait); ++ ++ printk(KERN_DEBUG "ucb1x00-switches.c -> _switches_resume() kswd - restart *DONE*\n"); ++ } ++ return 0; ++} ++#else ++#define ucb1x00_switches_resume NULL ++#endif ++ ++static struct ucb1x00_driver ucb1x00_switches_driver = { ++ .add = ucb1x00_switches_add, ++ .remove = ucb1x00_switches_remove, ++ .resume = ucb1x00_switches_resume, ++}; ++ ++static int __init ucb1x00_switches_init(void) ++{ ++ return ucb1x00_register_driver(&ucb1x00_switches_driver); ++} ++ ++static void __exit ucb1x00_switches_exit(void) ++{ ++ ucb1x00_unregister_driver(&ucb1x00_switches_driver); ++} ++ ++module_init(ucb1x00_switches_init); ++module_exit(ucb1x00_switches_exit); ++ ++MODULE_AUTHOR("Bernhard Guillon <Bernhard.Guillon@opensimpad.org>"); ++MODULE_DESCRIPTION("UCB1x00 Switches driver for Siemens SIMpad"); ++MODULE_LICENSE("GPL"); |