From 5e5cc5a7c80c86b8780902b437354f5dcdb1be54 Mon Sep 17 00:00:00 2001
From: John Crispin <john@openwrt.org>
Date: Tue, 5 Aug 2008 22:17:16 +0000
Subject: add proper uci/hotplug based button handling on atheros and work
 around boards, where the gpio release irq does not fire correctly

SVN-Revision: 12179
---
 target/linux/atheros/base-files/etc/config/system  | 17 ++++++++
 .../base-files/etc/hotplug.d/button/00-button      | 24 +++++++++++
 .../linux/atheros/files/arch/mips/atheros/reset.c  | 46 +++++++++++++++++++++-
 3 files changed, 86 insertions(+), 1 deletion(-)
 create mode 100644 target/linux/atheros/base-files/etc/config/system
 create mode 100644 target/linux/atheros/base-files/etc/hotplug.d/button/00-button

diff --git a/target/linux/atheros/base-files/etc/config/system b/target/linux/atheros/base-files/etc/config/system
new file mode 100644
index 0000000000..47faa3cc50
--- /dev/null
+++ b/target/linux/atheros/base-files/etc/config/system
@@ -0,0 +1,17 @@
+config system
+	option hostname OpenWrt
+	option timezone UTC
+
+config button
+	option button	reset
+	option action	released
+	option handler	"logger reboot"
+	option min		0
+	option max		4
+
+config button
+	option button	reset
+	option action	released
+	option handler	"logger factory default"
+	option min		5
+	option max		30
diff --git a/target/linux/atheros/base-files/etc/hotplug.d/button/00-button b/target/linux/atheros/base-files/etc/hotplug.d/button/00-button
new file mode 100644
index 0000000000..857a59b4a8
--- /dev/null
+++ b/target/linux/atheros/base-files/etc/hotplug.d/button/00-button
@@ -0,0 +1,24 @@
+. /etc/functions.sh
+do_button () {
+	local button
+	local action
+	local handler
+	local min
+	local max
+
+	config_get button $1 button
+	config_get action $1 action
+	config_get handler $1 handler
+	config_get min $1 min
+	config_get max $1 max
+	
+	[ "$ACTION" = "$action" -a "$BUTTON" = "$button" -a -n "$handler" ] && {
+		[ -z "$min" -o -z "$max" ] && eval $handler 
+		[ -n "$min" -a -n "$max" ] && {
+			[ $min -le $SEEN -a $max -ge $SEEN ] && eval $handler 
+		}
+	}
+}
+
+config_load system
+config_foreach do_button button
diff --git a/target/linux/atheros/files/arch/mips/atheros/reset.c b/target/linux/atheros/files/arch/mips/atheros/reset.c
index 876fa29ba7..a94954d091 100644
--- a/target/linux/atheros/files/arch/mips/atheros/reset.c
+++ b/target/linux/atheros/files/arch/mips/atheros/reset.c
@@ -18,6 +18,7 @@ struct event_t {
 };
 
 static struct ar531x_boarddata *bcfg;
+static struct timer_list rst_button_timer;
 
 extern struct sock *uevent_sock;
 extern u64 uevent_next_seqnum(void);
@@ -71,6 +72,37 @@ done:
 	kfree(event);
 }
 
+static int no_release_workaround = 1;
+
+static void
+reset_button_poll(unsigned long unused)
+{
+	struct event_t *event;
+	int gpio = ~0;
+
+	if(!no_release_workaround)
+		return;
+
+	DO_AR5315(gpio = sysRegRead(AR5315_GPIO_DI);)
+    gpio &= 1 << (AR531X_RESET_GPIO_IRQ - AR531X_GPIO_IRQ_BASE);
+	if(gpio)
+	{
+		rst_button_timer.expires = jiffies + (HZ / 4);
+		add_timer(&rst_button_timer);
+	} else {
+		event = (struct event_t *) kzalloc(sizeof(struct event_t), GFP_ATOMIC);
+		if (!event)
+		{
+			printk("Could not alloc hotplug event\n");
+			return;
+		}
+		event->set = 0;
+		event->jiffies = jiffies;
+		INIT_WORK(&event->wq, (void *)(void *)hotplug_button);
+		schedule_work(&event->wq);
+	}
+}
+
 static irqreturn_t button_handler(int irq, void *dev_id)
 {
 	static int pressed = 0;
@@ -87,13 +119,20 @@ static irqreturn_t button_handler(int irq, void *dev_id)
 	gpio &= 1 << (irq - AR531X_GPIO_IRQ_BASE);
 
 	event->set = gpio;
+	if(!event->set)
+		no_release_workaround = 0;
+
 	event->jiffies = jiffies;
 
 	INIT_WORK(&event->wq, (void *)(void *)hotplug_button);
 	schedule_work(&event->wq);
 
 	seen = jiffies;
-
+	if(event->set && no_release_workaround)
+	{
+		rst_button_timer.expires = jiffies + (HZ / 4);
+		add_timer(&rst_button_timer);
+	}
 	return IRQ_HANDLED;
 }
 
@@ -110,6 +149,11 @@ int __init ar531x_init_reset(void)
 
 	seen = jiffies;
 
+	init_timer(&rst_button_timer);
+	rst_button_timer.function = reset_button_poll;
+	rst_button_timer.expires = jiffies + HZ / 50;
+	add_timer(&rst_button_timer);
+
 	request_irq(AR531X_RESET_GPIO_IRQ, &button_handler, IRQF_SAMPLE_RANDOM, "ar531x_reset", NULL);
 
 	return 0;
-- 
cgit v1.2.3