aboutsummaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
authorNelson Castillo <arhuaco@freaks-unidos.net>2008-12-29 12:11:40 +0000
committerAndy Green <agreen@pads.home.warmcat.com>2008-12-29 12:11:40 +0000
commit39a497b0421174c3f23ef3dffb0675a4db3aa3a0 (patch)
treef3aedf29af619387353d074b326770f6eef843e9 /drivers/input
parentd494163d44eff907dac6bebc22daa586164bdf1e (diff)
Filter AUX key bouncing
This patch filters AUX key bouncing. We store the state of the AUX button and only change it when we notice that at least AUX_TIMER_CONSECUTIVE_EVENTS consecutive equal GPIO reads occur. This should solve #2185 (AUX button makes interrupt storm) but we still need the confirmation from someone affected by the IRQ storm. In my test setup I could see an improvement but I would only get 1 unwanted IRQ. The next step is to use the same timer for more keys. For that we could use the neo1973kbd_default_key_irq function for the AUX key also. Signed-off-by: Nelson Castillo <arhuaco@freaks-unidos.net>
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/keyboard/neo1973kbd.c67
1 files changed, 57 insertions, 10 deletions
diff --git a/drivers/input/keyboard/neo1973kbd.c b/drivers/input/keyboard/neo1973kbd.c
index 4d412e0b980..20f0a348a36 100644
--- a/drivers/input/keyboard/neo1973kbd.c
+++ b/drivers/input/keyboard/neo1973kbd.c
@@ -33,6 +33,7 @@ struct neo1973kbd {
struct input_dev *input;
struct device *cdev;
struct work_struct work;
+ int aux_state;
int work_in_progress;
int hp_irq_count_in_work;
int hp_irq_count;
@@ -88,22 +89,67 @@ static struct neo1973kbd_key keys[] = {
},
};
+/* This timer section filters AUX button IRQ bouncing */
-static irqreturn_t neo1973kbd_aux_irq(int irq, void *dev_id)
+static void aux_key_timer_f(unsigned long data);
+
+static struct timer_list aux_key_timer =
+ TIMER_INITIALIZER(aux_key_timer_f, 0, 0);
+
+#define AUX_TIMER_TIMEOUT (HZ >> 7)
+#define AUX_TIMER_ALLOWED_NOOP 2
+#define AUX_TIMER_CONSECUTIVE_EVENTS 5
+
+struct neo1973kbd *timer_kbd;
+
+static void aux_key_timer_f(unsigned long data)
+{
+ static int noop_counter;
+ static int last_key = -1;
+ static int last_count;
+ int key_pressed;
+
+ key_pressed =
+ !gpio_get_value(timer_kbd->pdev->resource[NEO1973_KEY_AUX].start);
+ if (machine_is_neo1973_gta02())
+ key_pressed = !key_pressed;
+
+ if (likely(key_pressed == last_key))
+ last_count++;
+ else {
+ last_count = 1;
+ last_key = key_pressed;
+ }
+
+ if (unlikely(last_count >= AUX_TIMER_CONSECUTIVE_EVENTS)) {
+ if (timer_kbd->aux_state != last_key) {
+ input_report_key(timer_kbd->input, KEY_PHONE, last_key);
+ input_sync(timer_kbd->input);
+
+ timer_kbd->aux_state = last_key;
+ noop_counter = 0;
+ }
+ last_count = 0;
+ if (unlikely(++noop_counter > AUX_TIMER_ALLOWED_NOOP)) {
+ noop_counter = 0;
+ return;
+ }
+ }
+
+ mod_timer(&aux_key_timer, jiffies + AUX_TIMER_TIMEOUT);
+}
+
+static irqreturn_t neo1973kbd_aux_irq(int irq, void *dev)
{
- struct neo1973kbd *kbd = dev_id;
- int key_pressed = !gpio_get_value(
- kbd->pdev->resource[NEO1973_KEY_AUX].start);
int *p = NULL;
+ /* if you stall inside resume then AUX will force a panic,
+ which in turn forces a dump of the pending syslog */
+
if (global_inside_suspend)
- printk("death %d\n", *p);
+ printk(KERN_ERR "death %d\n", *p);
- /* GTA02 has inverted sense level compared to GTA01 */
- if (machine_is_neo1973_gta02())
- key_pressed = !key_pressed;
- input_report_key(kbd->input, KEY_PHONE, key_pressed);
- input_sync(kbd->input);
+ mod_timer(&aux_key_timer, jiffies + AUX_TIMER_TIMEOUT);
return IRQ_HANDLED;
}
@@ -275,6 +321,7 @@ static int neo1973kbd_probe(struct platform_device *pdev)
}
neo1973kbd->pdev = pdev;
+ timer_kbd = neo1973kbd;
if (pdev->resource[0].flags != 0)
return -EINVAL;