enable start-stop-daemon by default, i want to use this to clean up a few init script...
[15.05/openwrt.git] / target / linux / atheros-2.6 / 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 #include "ar5315/ar5315.h"
12
13 struct event_t {
14         struct work_struct wq;
15         int set;
16         long int jiffies;
17 };
18
19 extern struct sock *uevent_sock;
20 extern u64 uevent_next_seqnum(void);
21 static int seen;
22
23 static inline void add_msg(struct sk_buff *skb, char *msg)
24 {
25         char *scratch;
26         scratch = skb_put(skb, strlen(msg) + 1);
27         sprintf(scratch, msg);
28 }
29
30 static void hotplug_button(struct work_struct *wq)
31 {
32         struct sk_buff *skb;
33         struct event_t *event;
34         size_t len;
35         char *scratch, *s;
36         char buf[128];
37         
38         event = container_of(wq, struct event_t, wq);
39         if (!uevent_sock)
40                 goto done;
41
42         /* allocate message with the maximum possible size */
43         s = event->set ? "pressed" : "released";
44         len = strlen(s) + 2;
45         skb = alloc_skb(len + 2048, GFP_KERNEL);
46         if (!skb)
47                 goto done;
48         
49         /* add header */
50         scratch = skb_put(skb, len);
51         sprintf(scratch, "%s@",s);
52
53         /* copy keys to our continuous event payload buffer */
54         add_msg(skb, "HOME=/");
55         add_msg(skb, "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
56         add_msg(skb, "SUBSYSTEM=button");
57         add_msg(skb, "BUTTON=reset");
58         add_msg(skb, (event->set ? "ACTION=pressed" : "ACTION=released"));
59         sprintf(buf, "SEEN=%ld", (event->jiffies - seen)/HZ);
60         add_msg(skb, buf);
61         snprintf(buf, 128, "SEQNUM=%llu", uevent_next_seqnum());
62         add_msg(skb, buf);
63
64         NETLINK_CB(skb).dst_group = 1;
65         netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL);
66
67 done:
68         kfree(event);
69 }
70
71 static irqreturn_t button_handler(int irq, void *dev_id)
72 {
73         static int pressed = 0;
74         struct event_t *event;
75         u32 gpio = ~0;
76
77         event = (struct event_t *) kzalloc(sizeof(struct event_t), GFP_ATOMIC);
78         if (!event)
79                 return IRQ_NONE;
80         
81         pressed = !pressed;
82
83         DO_AR5315(gpio = sysRegRead(AR5315_GPIO_DI);)
84         gpio &= 1 << (irq - AR531X_GPIO_IRQ_BASE);
85
86         event->set = gpio;
87         event->jiffies = jiffies;
88
89         INIT_WORK(&event->wq, (void *)(void *)hotplug_button);
90         schedule_work(&event->wq);
91
92         seen = jiffies;
93
94         return IRQ_HANDLED;
95 }
96
97 int __init ar531x_init_reset(void)
98 {
99         struct ar531x_boarddata *bcfg;
100         bcfg = (struct ar531x_boarddata *) board_config;
101
102         seen = jiffies;
103         request_irq(AR531X_GPIO_IRQ_BASE + bcfg->resetConfigGpio, &button_handler, IRQF_SAMPLE_RANDOM, "ar531x_reset", NULL);
104
105         return 0;
106 }
107
108 module_init(ar531x_init_reset);