fixes reset button on atheros platform, ar5312 gpio_irqs will be added later
[openwrt/openwrt.git] / target / linux / atheros / files / arch / mips / atheros / reset.c
1 #include <linux/module.h>
2 #include <linux/timer.h>
3 #include <linux/interrupt.h>
4 #include <linux/kobject.h>
5 #include <linux/workqueue.h>
6 #include <linux/skbuff.h>
7 #include <linux/netlink.h>
8 #include <net/sock.h>
9 #include <asm/uaccess.h>
10 #include <ar531x.h>
11
12 #define AR531X_RESET_GPIO_IRQ (AR531X_GPIO_IRQ(bcfg->resetConfigGpio))
13
14 struct event_t {
15 struct work_struct wq;
16 int set;
17 unsigned long jiffies;
18 };
19
20 static struct ar531x_boarddata *bcfg;
21
22 extern struct sock *uevent_sock;
23 extern u64 uevent_next_seqnum(void);
24 static unsigned long seen;
25
26 static inline void add_msg(struct sk_buff *skb, char *msg)
27 {
28 char *scratch;
29 scratch = skb_put(skb, strlen(msg) + 1);
30 sprintf(scratch, msg);
31 }
32
33 static void hotplug_button(struct work_struct *wq)
34 {
35 struct sk_buff *skb;
36 struct event_t *event;
37 size_t len;
38 char *scratch, *s;
39 char buf[128];
40
41 event = container_of(wq, struct event_t, wq);
42 if (!uevent_sock)
43 goto done;
44
45 /* allocate message with the maximum possible size */
46 s = event->set ? "pressed" : "released";
47 len = strlen(s) + 2;
48 skb = alloc_skb(len + 2048, GFP_KERNEL);
49 if (!skb)
50 goto done;
51
52 /* add header */
53 scratch = skb_put(skb, len);
54 sprintf(scratch, "%s@",s);
55
56 /* copy keys to our continuous event payload buffer */
57 add_msg(skb, "HOME=/");
58 add_msg(skb, "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
59 add_msg(skb, "SUBSYSTEM=button");
60 add_msg(skb, "BUTTON=reset");
61 add_msg(skb, (event->set ? "ACTION=pressed" : "ACTION=released"));
62 sprintf(buf, "SEEN=%ld", (event->jiffies - seen)/HZ);
63 add_msg(skb, buf);
64 snprintf(buf, 128, "SEQNUM=%llu", uevent_next_seqnum());
65 add_msg(skb, buf);
66
67 NETLINK_CB(skb).dst_group = 1;
68 netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL);
69
70 done:
71 kfree(event);
72 }
73
74 static irqreturn_t button_handler(int irq, void *dev_id)
75 {
76 static int pressed = 0;
77 struct event_t *event;
78 u32 gpio = ~0;
79
80 event = (struct event_t *) kzalloc(sizeof(struct event_t), GFP_ATOMIC);
81 if (!event)
82 return IRQ_NONE;
83
84 pressed = !pressed;
85
86 DO_AR5315(gpio = sysRegRead(AR5315_GPIO_DI);)
87 gpio &= 1 << (irq - AR531X_GPIO_IRQ_BASE);
88
89 event->set = gpio;
90 event->jiffies = jiffies;
91
92 INIT_WORK(&event->wq, (void *)(void *)hotplug_button);
93 schedule_work(&event->wq);
94
95 seen = jiffies;
96
97 return IRQ_HANDLED;
98 }
99
100 void ar531x_disable_reset_button(void)
101 {
102 disable_irq(AR531X_RESET_GPIO_IRQ);
103 }
104
105 EXPORT_SYMBOL(ar531x_disable_reset_button);
106
107 int __init ar531x_init_reset(void)
108 {
109 bcfg = (struct ar531x_boarddata *) board_config;
110
111 seen = jiffies;
112
113 request_irq(AR531X_RESET_GPIO_IRQ, &button_handler, IRQF_SAMPLE_RANDOM, "ar531x_reset", NULL);
114
115 return 0;
116 }
117
118
119
120 module_init(ar531x_init_reset);