[atheros]: move files for kernel 2.6.26 to a special directory.
[openwrt.git] / target / linux / atheros / files-2.6.26 / 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 static struct timer_list rst_button_timer;
22
23 extern struct sock *uevent_sock;
24 extern u64 uevent_next_seqnum(void);
25 static unsigned long seen;
26
27 static inline void add_msg(struct sk_buff *skb, char *msg)
28 {
29         char *scratch;
30         scratch = skb_put(skb, strlen(msg) + 1);
31         sprintf(scratch, msg);
32 }
33
34 static void hotplug_button(struct work_struct *wq)
35 {
36         struct sk_buff *skb;
37         struct event_t *event;
38         size_t len;
39         char *scratch, *s;
40         char buf[128];
41
42         event = container_of(wq, struct event_t, wq);
43         if (!uevent_sock)
44                 goto done;
45
46         /* allocate message with the maximum possible size */
47         s = event->set ? "pressed" : "released";
48         len = strlen(s) + 2;
49         skb = alloc_skb(len + 2048, GFP_KERNEL);
50         if (!skb)
51                 goto done;
52
53         /* add header */
54         scratch = skb_put(skb, len);
55         sprintf(scratch, "%s@",s);
56
57         /* copy keys to our continuous event payload buffer */
58         add_msg(skb, "HOME=/");
59         add_msg(skb, "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
60         add_msg(skb, "SUBSYSTEM=button");
61         add_msg(skb, "BUTTON=reset");
62         add_msg(skb, (event->set ? "ACTION=pressed" : "ACTION=released"));
63         sprintf(buf, "SEEN=%ld", (event->jiffies - seen)/HZ);
64         add_msg(skb, buf);
65         snprintf(buf, 128, "SEQNUM=%llu", uevent_next_seqnum());
66         add_msg(skb, buf);
67
68         NETLINK_CB(skb).dst_group = 1;
69         netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL);
70
71 done:
72         kfree(event);
73 }
74
75 static int no_release_workaround = 1;
76
77 static void
78 reset_button_poll(unsigned long unused)
79 {
80         struct event_t *event;
81         int gpio = ~0;
82
83         if(!no_release_workaround)
84                 return;
85
86         DO_AR5315(gpio = sysRegRead(AR5315_GPIO_DI);)
87     gpio &= 1 << (AR531X_RESET_GPIO_IRQ - AR531X_GPIO_IRQ_BASE);
88         if(gpio)
89         {
90                 rst_button_timer.expires = jiffies + (HZ / 4);
91                 add_timer(&rst_button_timer);
92         } else {
93                 event = (struct event_t *) kzalloc(sizeof(struct event_t), GFP_ATOMIC);
94                 if (!event)
95                 {
96                         printk("Could not alloc hotplug event\n");
97                         return;
98                 }
99                 event->set = 0;
100                 event->jiffies = jiffies;
101                 INIT_WORK(&event->wq, (void *)(void *)hotplug_button);
102                 schedule_work(&event->wq);
103         }
104 }
105
106 static irqreturn_t button_handler(int irq, void *dev_id)
107 {
108         static int pressed = 0;
109         struct event_t *event;
110         u32 gpio = ~0;
111
112         event = (struct event_t *) kzalloc(sizeof(struct event_t), GFP_ATOMIC);
113         if (!event)
114                 return IRQ_NONE;
115
116         pressed = !pressed;
117
118         DO_AR5315(gpio = sysRegRead(AR5315_GPIO_DI);)
119         gpio &= 1 << (irq - AR531X_GPIO_IRQ_BASE);
120
121         event->set = gpio;
122         if(!event->set)
123                 no_release_workaround = 0;
124
125         event->jiffies = jiffies;
126
127         INIT_WORK(&event->wq, (void *)(void *)hotplug_button);
128         schedule_work(&event->wq);
129
130         seen = jiffies;
131         if(event->set && no_release_workaround)
132                 mod_timer(&rst_button_timer, jiffies + (HZ / 4));
133
134         return IRQ_HANDLED;
135 }
136
137 void ar531x_disable_reset_button(void)
138 {
139         disable_irq(AR531X_RESET_GPIO_IRQ);
140 }
141
142 EXPORT_SYMBOL(ar531x_disable_reset_button);
143
144 int __init ar531x_init_reset(void)
145 {
146         bcfg = (struct ar531x_boarddata *) board_config;
147
148         seen = jiffies;
149
150         init_timer(&rst_button_timer);
151         rst_button_timer.function = reset_button_poll;
152         rst_button_timer.expires = jiffies + HZ / 50;
153         add_timer(&rst_button_timer);
154
155         request_irq(AR531X_RESET_GPIO_IRQ, &button_handler, IRQF_SAMPLE_RANDOM, "ar531x_reset", NULL);
156
157         return 0;
158 }
159
160
161
162 module_init(ar531x_init_reset);