linux/atheros: add 2.6.38 preliminary support
[openwrt.git] / target / linux / atheros / patches-2.6.38 / 210-reset_button.patch
1 --- a/arch/mips/ar231x/Makefile
2 +++ b/arch/mips/ar231x/Makefile
3 @@ -8,7 +8,7 @@
4  # Copyright (C) 2006-2009 Felix Fietkau <nbd@openwrt.org>
5  #
6  
7 -obj-y += board.o prom.o devices.o
8 +obj-y += board.o prom.o devices.o reset.o
9  
10  obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
11  
12 --- /dev/null
13 +++ b/arch/mips/ar231x/reset.c
14 @@ -0,0 +1,161 @@
15 +#include <linux/init.h>
16 +#include <linux/module.h>
17 +#include <linux/timer.h>
18 +#include <linux/interrupt.h>
19 +#include <linux/kobject.h>
20 +#include <linux/workqueue.h>
21 +#include <linux/skbuff.h>
22 +#include <linux/netlink.h>
23 +#include <net/sock.h>
24 +#include <asm/uaccess.h>
25 +#include <ar231x_platform.h>
26 +#include <ar231x.h>
27 +#include <gpio.h>
28 +#include "devices.h"
29 +
30 +#define AR531X_RESET_GPIO_IRQ  (AR531X_GPIO_IRQ(ar231x_board.config->resetConfigGpio))
31 +
32 +struct event_t {
33 +       struct work_struct wq;
34 +       int set;
35 +       unsigned long jiffies;
36 +};
37 +
38 +static struct timer_list rst_button_timer;
39 +static unsigned long seen;
40 +
41 +struct sock *uevent_sock = NULL;
42 +EXPORT_SYMBOL_GPL(uevent_sock);
43 +extern u64 uevent_next_seqnum(void);
44 +
45 +static int no_release_workaround = 1;
46 +module_param(no_release_workaround, int, 0);
47 +
48 +static inline void
49 +add_msg(struct sk_buff *skb, char *msg)
50 +{
51 +       char *scratch;
52 +       scratch = skb_put(skb, strlen(msg) + 1);
53 +       sprintf(scratch, msg);
54 +}
55 +
56 +static void
57 +hotplug_button(struct work_struct *wq)
58 +{
59 +       struct sk_buff *skb;
60 +       struct event_t *event;
61 +       size_t len;
62 +       char *scratch, *s;
63 +       char buf[128];
64 +
65 +       event = container_of(wq, struct event_t, wq);
66 +       if (!uevent_sock)
67 +               goto done;
68 +
69 +       /* allocate message with the maximum possible size */
70 +       s = event->set ? "pressed" : "released";
71 +       len = strlen(s) + 2;
72 +       skb = alloc_skb(NLMSG_GOODSIZE, GFP_KERNEL);
73 +       if (!skb)
74 +               goto done;
75 +
76 +       /* add header */
77 +       scratch = skb_put(skb, len);
78 +       sprintf(scratch, "%s@",s);
79 +
80 +       /* copy keys to our continuous event payload buffer */
81 +       add_msg(skb, "HOME=/");
82 +       add_msg(skb, "PATH=/sbin:/bin:/usr/sbin:/usr/bin");
83 +       add_msg(skb, "SUBSYSTEM=button");
84 +       add_msg(skb, "BUTTON=reset");
85 +       add_msg(skb, (event->set ? "ACTION=pressed" : "ACTION=released"));
86 +       sprintf(buf, "SEEN=%ld", (event->jiffies - seen)/HZ);
87 +       add_msg(skb, buf);
88 +       snprintf(buf, 128, "SEQNUM=%llu", uevent_next_seqnum());
89 +       add_msg(skb, buf);
90 +
91 +       NETLINK_CB(skb).dst_group = 1;
92 +       netlink_broadcast(uevent_sock, skb, 0, 1, GFP_KERNEL);
93 +
94 +done:
95 +       kfree(event);
96 +}
97 +
98 +static void
99 +reset_button_poll(unsigned long unused)
100 +{
101 +       struct event_t *event;
102 +       int gpio = ~0;
103 +
104 +       if(!no_release_workaround)
105 +               return;
106 +
107 +       gpio = ar231x_gpiodev->get();
108 +       gpio &= (1 << (AR531X_RESET_GPIO_IRQ - AR531X_GPIO_IRQ_BASE));
109 +       if(gpio) {
110 +               rst_button_timer.expires = jiffies + (HZ / 4);
111 +               add_timer(&rst_button_timer);
112 +               return;
113 +       }
114 +
115 +       event = (struct event_t *) kzalloc(sizeof(struct event_t), GFP_ATOMIC);
116 +       if (!event)
117 +               return;
118 +
119 +       event->set = 0;
120 +       event->jiffies = jiffies;
121 +       INIT_WORK(&event->wq, hotplug_button);
122 +       schedule_work(&event->wq);
123 +}
124 +
125 +static irqreturn_t
126 +button_handler(int irq, void *dev_id)
127 +{
128 +       static int pressed = 0;
129 +       struct event_t *event;
130 +       u32 gpio = ~0;
131 +
132 +       event = (struct event_t *) kzalloc(sizeof(struct event_t), GFP_ATOMIC);
133 +       if (!event)
134 +               return IRQ_NONE;
135 +
136 +       pressed = !pressed;
137 +
138 +       gpio = ar231x_gpiodev->get() & (1 << (irq - AR531X_GPIO_IRQ_BASE));
139 +
140 +       event->set = gpio;
141 +       if(!event->set)
142 +               no_release_workaround = 0;
143 +
144 +       event->jiffies = jiffies;
145 +
146 +       INIT_WORK(&event->wq, hotplug_button);
147 +       schedule_work(&event->wq);
148 +
149 +       seen = jiffies;
150 +       if(event->set && no_release_workaround)
151 +               mod_timer(&rst_button_timer, jiffies + (HZ / 4));
152 +
153 +       return IRQ_HANDLED;
154 +}
155 +
156 +
157 +static int __init
158 +ar231x_init_reset(void)
159 +{
160 +       seen = jiffies;
161 +
162 +       if (ar231x_board.config->resetConfigGpio == 0xffff)
163 +               return -ENODEV;
164 +
165 +       init_timer(&rst_button_timer);
166 +       rst_button_timer.function = reset_button_poll;
167 +       rst_button_timer.expires = jiffies + HZ / 50;
168 +       add_timer(&rst_button_timer);
169 +
170 +       request_irq(AR531X_RESET_GPIO_IRQ, &button_handler, IRQF_SAMPLE_RANDOM, "ar231x_reset", NULL);
171 +
172 +       return 0;
173 +}
174 +
175 +module_init(ar231x_init_reset);