Support Asus RT-N10U
[tomato.git] / release / src / router / rc / buttons.c
blob5aaff6ca32fb43acef2feca8e85ed31b2c924d1f
1 /*
3 Tomato Firmware
4 Copyright (C) 2006-2009 Jonathan Zarate
6 */
7 #include "rc.h"
9 #include <sys/reboot.h>
10 #include <wlutils.h>
11 #include <wlioctl.h>
13 // #define DEBUG_TEST
15 static int gf;
17 static int get_btn(const char *name, uint32_t *bit, uint32_t *pushed)
19 int gpio;
20 int inv;
22 if (nvget_gpio(name, &gpio, &inv)) {
23 *bit = 1 << gpio;
24 *pushed = inv ? 0 : *bit;
25 return 1;
27 return 0;
30 int buttons_main(int argc, char *argv[])
32 uint32_t gpio;
33 uint32_t mask;
34 uint32_t last;
35 uint32_t ses_mask;
36 uint32_t ses_pushed;
37 uint32_t reset_mask;
38 uint32_t reset_pushed;
39 uint32_t brau_mask;
40 uint32_t brau_state;
41 int brau_count_stable;
42 int brau_flag;
43 int count;
44 char s[16];
45 char *p;
46 int n;
47 int ses_led;
49 ses_mask = ses_pushed = 0;
50 reset_pushed = 0;
51 brau_mask = 0;
52 brau_state = ~0;
53 ses_led = LED_DIAG;
55 // moveme
56 switch (nvram_get_int("btn_override") ? MODEL_UNKNOWN : get_model()) {
57 case MODEL_WRT54G:
58 case MODEL_WRTSL54GS:
59 reset_mask = 1 << 6;
60 ses_mask = 1 << 4;
61 ses_led = LED_DMZ;
62 break;
63 /*
64 case MODEL_WRH54G:
65 reset_mask = 1 << 6;
66 break;
68 case MODEL_WTR54GS:
69 reset_mask = 1 << 3;
70 ses_mask = 1 << 2;
71 break;
72 case MODEL_WHRG54S:
73 case MODEL_WHRHPG54:
74 case MODEL_WHR2A54G54:
75 case MODEL_WHR3AG54:
76 case MODEL_WHRG125:
77 reset_mask = reset_pushed = 1 << 4;
78 ses_mask = 1 << 0;
79 brau_mask = 1 << 5;
80 break;
81 case MODEL_WBRG54:
82 reset_mask = reset_pushed = 1 << 4;
83 break;
84 case MODEL_WBR2G54:
85 reset_mask = reset_pushed = 1 << 7;
86 ses_mask = ses_pushed = 1 << 4;
87 ses_led = LED_AOSS;
88 break;
89 case MODEL_WZRG54:
90 case MODEL_WZRHPG54:
91 case MODEL_WZRRSG54:
92 case MODEL_WZRRSG54HP:
93 case MODEL_WVRG54NF:
94 reset_mask = reset_pushed = 1 << 4;
95 ses_mask = 1 << 0;
96 ses_led = LED_AOSS;
97 break;
98 case MODEL_WZRG108:
99 reset_mask = reset_pushed = 1 << 7;
100 ses_mask = 1 << 0;
101 ses_led = LED_AOSS;
102 break;
103 case MODEL_WR850GV1:
104 reset_mask = 1 << 0;
105 break;
106 case MODEL_WR850GV2:
107 case MODEL_WR100:
108 reset_mask = 1 << 5;
109 break;
110 case MODEL_WL500GP:
111 reset_mask = reset_pushed = 1 << 0;
112 ses_mask = ses_pushed = 1 << 4;
113 break;
114 case MODEL_WL500W:
115 reset_mask = reset_pushed = 1 << 6;
116 ses_mask = ses_pushed = 1 << 7;
117 break;
118 case MODEL_DIR320:
119 case MODEL_H618B:
120 reset_mask = 1 << 7;
121 ses_mask = 1 << 6; // WLAN button on H618B
122 break;
123 case MODEL_WL500GPv2:
124 case MODEL_WL520GU:
125 reset_mask = 1 << 2;
126 ses_mask = 1 << 3;
127 break;
128 // case MODEL_MN700:
129 //? reset_mask = reset_pushed = 1 << 7;
130 // break;
131 case MODEL_WLA2G54L:
132 reset_mask = reset_pushed = 1 << 7;
133 break;
134 case MODEL_WL1600GL:
135 reset_mask = 1 << 3;
136 ses_mask = 1 << 4;
137 ses_led = LED_AOSS;
138 break;
139 #ifdef CONFIG_BCMWL5
140 case MODEL_RTN10:
141 reset_mask = 1 << 3;
142 ses_mask = 1 << 2;
143 break;
144 case MODEL_RTN10U:
145 reset_mask = 1 << 21;
146 ses_mask = 1 << 20;
147 ses_led = LED_AOSS;
148 break;
149 case MODEL_RTN12:
150 reset_mask = 1 << 1;
151 ses_mask = 1 << 0;
152 brau_mask = (1 << 4) | (1 << 5) | (1 << 6);
153 break;
154 case MODEL_RTN16:
155 reset_mask = 1 << 6;
156 ses_mask = 1 << 8;
157 break;
158 case MODEL_RTN66U:
159 reset_mask = 1 << 9;
160 ses_mask = 1 << 4;
161 break;
162 case MODEL_WNR3500L:
163 reset_mask = 1 << 4;
164 ses_mask = 1 << 6;
165 ses_led = LED_AOSS;
166 break;
167 case MODEL_WNR2000v2:
168 reset_mask = 1 << 1;
169 ses_mask = 1 << 0;
170 ses_led = LED_AOSS;
171 break;
172 case MODEL_F7D3301:
173 case MODEL_F7D3302:
174 case MODEL_F7D4301:
175 case MODEL_F7D4302:
176 case MODEL_F5D8235v3:
177 reset_mask = 1 << 6;
178 ses_mask = 1 << 8;
179 ses_led = LED_AOSS;
180 break;
181 case MODEL_WRT160Nv3:
182 reset_mask = 1 << 6;
183 ses_mask = 1 << 5;
184 break;
185 case MODEL_WRT320N:
186 reset_mask = 1 << 8;
187 ses_mask = 1 << 5;
188 ses_led = LED_AMBER;
189 break;
190 case MODEL_WRT610Nv2:
191 reset_mask = 1 << 6;
192 ses_mask = 1 << 4;
193 ses_led = LED_AMBER;
194 break;
195 case MODEL_E4200:
196 reset_mask = 1 << 6;
197 ses_mask = 1 << 4;
198 ses_led = LED_WHITE;
199 break;
200 #endif
201 case MODEL_WRT160Nv1:
202 case MODEL_WRT300N:
203 reset_mask = 1 << 6;
204 ses_mask = 1 << 4;
205 break;
206 case MODEL_WRT310Nv1:
207 reset_mask = 1 << 6;
208 ses_mask = 1 << 8;
209 break;
210 default:
211 get_btn("btn_ses", &ses_mask, &ses_pushed);
212 if (!get_btn("btn_reset", &reset_mask, &reset_pushed)) {
213 // fprintf(stderr, "Not supported.\n");
214 return 1;
216 break;
218 mask = reset_mask | ses_mask | brau_mask;
220 #ifdef DEBUG_TEST
221 cprintf("reset_mask=0x%X reset_pushed=0x%X\n", reset_mask, reset_pushed);
222 cprintf("ses_mask=0x%X\n", ses_mask);
223 cprintf("brau_mask=0x%X\n", brau_mask);
224 cprintf("ses_led=%d\n", ses_led);
225 #else
226 if (fork() != 0) return 0;
227 setsid();
228 #endif
230 signal(SIGCHLD, chld_reap);
232 if ((gf = gpio_open(mask)) < 0) return 1;
234 last = 0;
235 brau_count_stable = 0;
236 brau_flag = 0;
237 while (1) {
238 if (((gpio = _gpio_read(gf)) == ~0) || (last == (gpio &= mask) && !brau_flag) || (check_action() != ACT_IDLE)) {
239 #ifdef DEBUG_TEST
240 cprintf("gpio = %X\n", gpio);
241 #endif
242 sleep(1);
243 continue;
246 if ((gpio & reset_mask) == reset_pushed) {
247 #ifdef DEBUG_TEST
248 cprintf("reset down\n");
249 #endif
251 led(LED_DIAG, 0);
253 count = 0;
254 do {
255 sleep(1);
256 if (++count == 3) led(LED_DIAG, 1);
257 } while (((gpio = _gpio_read(gf)) != ~0) && ((gpio & reset_mask) == reset_pushed));
259 #ifdef DEBUG_TEST
260 cprintf("reset count = %d\n", count);
261 #else
262 if (count >= 3) {
263 eval("mtd-erase", "-d", "nvram");
264 //nvram_set("restore_defaults", "1");
265 //nvram_commit();
266 sync();
267 reboot(RB_AUTOBOOT);
269 else {
270 led(LED_DIAG, 1);
271 set_action(ACT_REBOOT);
272 kill(1, SIGTERM);
274 exit(0);
275 #endif
278 if ((ses_mask) && ((gpio & ses_mask) == ses_pushed)) {
279 count = 0;
280 do {
281 // syslog(LOG_DEBUG, "ses-pushed: gpio=x%X, pushed=x%X, mask=x%X, count=%d", gpio, ses_pushed, ses_mask, count);
283 led(ses_led, LED_ON);
284 usleep(500000);
285 led(ses_led, LED_OFF);
286 usleep(500000);
287 ++count;
288 } while (((gpio = _gpio_read(gf)) != ~0) && ((gpio & ses_mask) == ses_pushed));
289 gpio &= mask;
291 if ((ses_led == LED_DMZ) && (nvram_get_int("dmz_enable") > 0)) led(LED_DMZ, 1);
293 // syslog(LOG_DEBUG, "ses-released: gpio=x%X, pushed=x%X, mask=x%X, count=%d", gpio, ses_pushed, ses_mask, count);
294 syslog(LOG_INFO, "SES pushed. Count was %d.", count);
296 if ((count != 3) && (count != 7) && (count != 11)) {
297 n = count >> 2;
298 if (n > 3) n = 3;
300 0-2 = func0
301 4-6 = func1
302 8-10 = func2
303 12+ = func3
306 #ifdef DEBUG_TEST
307 cprintf("ses func=%d\n", n);
308 #else
309 sprintf(s, "sesx_b%d", n);
310 // syslog(LOG_DEBUG, "ses-func: count=%d %s='%s'", count, s, nvram_safe_get(s));
311 if ((p = nvram_get(s)) != NULL) {
312 switch (*p) {
313 case '1': // toggle wl
314 nvram_set("rrules_radio", "-1");
315 eval("radio", "toggle");
316 break;
317 case '2': // reboot
318 kill(1, SIGTERM);
319 break;
320 case '3': // shutdown
321 kill(1, SIGQUIT);
322 break;
323 case '4': // run a script
324 sprintf(s, "%d", count);
325 run_nvscript("sesx_script", s, 2);
326 break;
327 #ifdef TCONFIG_USB
328 case '5': // !!TB: unmount all USB drives
329 add_remove_usbhost("-2", 0);
330 break;
331 #endif
334 #endif
339 if (brau_mask) {
340 if (last == gpio)
341 sleep(1);
342 last = (gpio & brau_mask);
343 if (brau_state != last) {
344 brau_flag = (brau_state != ~0); // set to 1 to run at startup
345 brau_state = last;
346 brau_count_stable = 0;
348 else if (brau_flag && ++brau_count_stable > 2) { // stable for 2+ seconds
349 brau_flag = 0;
350 switch (nvram_get_int("btn_override") ? MODEL_UNKNOWN : get_model()) {
351 #ifdef CONFIG_BCMWL5
352 case MODEL_RTN12:
353 p = (brau_state & (1 << 4)) ? "ap" : (brau_state & (1 << 5)) ? "repeater" : "router";
354 break;
355 #endif
356 default:
357 p = brau_state ? "auto" : "bridge";
358 break;
360 nvram_set("brau_state", p);
361 #ifdef DEBUG_TEST
362 cprintf("bridge/auto state = %s\n", p);
363 #else
364 run_nvscript("script_brau", p, 2);
365 #endif
369 last = gpio;
372 return 0;