ar71xx: support for D-LINK DIR-615 rev. E4
[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);
This page took 0.070791 seconds and 5 git commands to generate.