summaryrefslogtreecommitdiffstats
path: root/target/linux/atheros/files/arch/mips/atheros/reset.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/linux/atheros/files/arch/mips/atheros/reset.c')
-rw-r--r--target/linux/atheros/files/arch/mips/atheros/reset.c108
1 files changed, 108 insertions, 0 deletions
diff --git a/target/linux/atheros/files/arch/mips/atheros/reset.c b/target/linux/atheros/files/arch/mips/atheros/reset.c
new file mode 100644
index 000000000..d62c5e1c4
--- /dev/null
+++ b/target/linux/atheros/files/arch/mips/atheros/reset.c
@@ -0,0 +1,108 @@
+#include <linux/module.h>
+#include <linux/timer.h>
+#include <linux/interrupt.h>
+#include <linux/kobject.h>
+#include <linux/workqueue.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <net/sock.h>
+#include <asm/uaccess.h>
+#include "ar531x.h"
+#include "ar5315/ar5315.h"
+
+struct event_t {
+ struct work_struct wq;
+ int set;
+ long int jiffies;
+};
+
+extern struct sock *uevent_sock;
+extern u64 uevent_next_seqnum(void);
+static int seen;
+
+static inline void add_msg(struct sk_buff *skb, char *msg)
+{
+ char *scratch;
+ scratch = skb_put(skb, strlen(msg) + 1);
+ sprintf(scratch, msg);
+}
+
+static void hotplug_button(struct work_struct *wq)
+{
+ struct sk_buff *skb;
+ struct event_t *event;
+ size_t len;
+ char *scratch, *s;
+ char buf[128];
+
+ event = container_of(wq, struct event_t, wq);
+ if (!uevent_sock)
+ goto done;
+
+ /* allocate message with the maximum possible size */
+ s = event->set ? "pressed" : "released";
+ len = strlen(s) + 2;
+ skb = alloc_skb(len + 2048, GFP_KERNEL);
+ if (!skb)
+ goto done;
+
+ /* add header */
+ scratch = skb_put(skb, len);
+ sprintf(scratch, "%s@",s);
+
+ /* copy keys to our continuous event payload buffer */
+ add_msg(skb, "HOME=/");
+ add_msg(skb, "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
+ add_msg(skb, "SUBSYSTEM=button");
+ add_msg(skb, "BUTTON=reset");
+ add_msg(skb, (event->set ? "ACTION=pressed" : "ACTION=released"));
+ sprintf(buf, "SEEN=%ld", (event->jiffies - seen)/HZ);
+ add_msg(skb, buf);
+ snprintf(buf, 128, "SEQNUM=%llu", uevent_next_seqnum());
+ add_msg(skb, buf);
+
+ NETLINK_CB(skb).dst_group = 1;
+ netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL);
+
+done:
+ kfree(event);
+}
+
+static irqreturn_t button_handler(int irq, void *dev_id)
+{
+ static int pressed = 0;
+ struct event_t *event;
+ u32 gpio = ~0;
+
+ event = (struct event_t *) kzalloc(sizeof(struct event_t), GFP_ATOMIC);
+ if (!event)
+ return IRQ_NONE;
+
+ pressed = !pressed;
+
+ DO_AR5315(gpio = sysRegRead(AR5315_GPIO_DI);)
+ gpio &= 1 << (irq - AR531X_GPIO_IRQ_BASE);
+
+ event->set = gpio;
+ event->jiffies = jiffies;
+
+ INIT_WORK(&event->wq, (void *)(void *)hotplug_button);
+ schedule_work(&event->wq);
+
+ seen = jiffies;
+
+ return IRQ_HANDLED;
+}
+
+int __init ar531x_init_reset(void)
+{
+ struct ar531x_boarddata *bcfg;
+ bcfg = (struct ar531x_boarddata *) board_config;
+
+ seen = jiffies;
+ request_irq(AR531X_GPIO_IRQ_BASE + bcfg->resetConfigGpio, &button_handler, IRQF_SAMPLE_RANDOM, "ar531x_reset", NULL);
+
+ return 0;
+}
+
+module_init(ar531x_init_reset);