allow coexistance of N build and AC build.
[tomato.git] / release / src / router / rc / buttons.c
blobe403df46870d6ac481137717c22c30419138a6ab
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 case MODEL_WL330GE:
126 reset_mask = 1 << 2;
127 ses_mask = 1 << 3;
128 break;
129 // case MODEL_MN700:
130 //? reset_mask = reset_pushed = 1 << 7;
131 // break;
132 case MODEL_WLA2G54L:
133 reset_mask = reset_pushed = 1 << 7;
134 break;
135 case MODEL_WL1600GL:
136 reset_mask = 1 << 3;
137 ses_mask = 1 << 4;
138 ses_led = LED_AOSS;
139 break;
140 #ifdef CONFIG_BCMWL5
141 case MODEL_RTN10:
142 reset_mask = 1 << 3;
143 ses_mask = 1 << 2;
144 break;
145 case MODEL_RTN10U:
146 reset_mask = 1 << 21;
147 ses_mask = 1 << 20;
148 ses_led = LED_AOSS;
149 break;
150 case MODEL_RTN12:
151 reset_mask = 1 << 1;
152 ses_mask = 1 << 0;
153 brau_mask = (1 << 4) | (1 << 5) | (1 << 6);
154 break;
155 case MODEL_RTN15U:
156 reset_mask = 1 << 5;
157 ses_mask = 1 << 8;
158 break;
159 case MODEL_RTN16:
160 reset_mask = 1 << 6;
161 ses_mask = 1 << 8;
162 break;
163 case MODEL_RTN53:
164 reset_mask = 1 << 3;
165 ses_mask = 1 << 7;
166 break;
167 case MODEL_RTN66U:
168 reset_mask = 1 << 9;
169 ses_mask = 1 << 4;
170 break;
171 case MODEL_W1800R:
172 reset_mask = 1 << 14;
173 break;
174 case MODEL_WNR3500L:
175 case MODEL_WNR3500LV2:
176 reset_mask = 1 << 4;
177 ses_mask = 1 << 6;
178 ses_led = LED_AOSS;
179 break;
180 case MODEL_WNR2000v2:
181 reset_mask = 1 << 1;
182 ses_mask = 1 << 0;
183 ses_led = LED_AOSS;
184 break;
185 case MODEL_F7D3301:
186 case MODEL_F7D3302:
187 case MODEL_F7D4301:
188 case MODEL_F7D4302:
189 case MODEL_F5D8235v3:
190 reset_mask = 1 << 6;
191 ses_mask = 1 << 8;
192 ses_led = LED_AOSS;
193 break;
194 case MODEL_E900:
195 case MODEL_E1000v2:
196 case MODEL_E1500:
197 case MODEL_E1550:
198 case MODEL_E2500:
199 reset_mask = 1 << 10;
200 ses_mask = 1 << 9;
201 break;
202 case MODEL_E3200:
203 reset_mask = 1 << 5;
204 ses_mask = 1 << 8;
205 break;
206 case MODEL_WRT160Nv3:
207 reset_mask = 1 << 6;
208 ses_mask = 1 << 5;
209 break;
210 case MODEL_WRT320N:
211 reset_mask = 1 << 8;
212 ses_mask = 1 << 5;
213 ses_led = LED_AMBER;
214 break;
215 case MODEL_WRT610Nv2:
216 reset_mask = 1 << 6;
217 ses_mask = 1 << 4;
218 ses_led = LED_AMBER;
219 break;
220 case MODEL_E4200:
221 reset_mask = 1 << 6;
222 ses_mask = 1 << 4;
223 ses_led = LED_WHITE;
224 break;
225 #endif
226 case MODEL_WRT160Nv1:
227 case MODEL_WRT300N:
228 reset_mask = 1 << 6;
229 ses_mask = 1 << 4;
230 break;
231 case MODEL_WRT310Nv1:
232 reset_mask = 1 << 6;
233 ses_mask = 1 << 8;
234 break;
235 // Added by BWQ
236 case MODEL_RG200E_CA:
237 case MODEL_H218N:
238 reset_mask = 1 << 30;
239 ses_mask = 1 << 28;
240 break;
241 case MODEL_HG320:
242 reset_mask = 1 << 30;
243 ses_mask = 1 << 29;
244 break;
245 // BWQ end.
246 default:
247 get_btn("btn_ses", &ses_mask, &ses_pushed);
248 if (!get_btn("btn_reset", &reset_mask, &reset_pushed)) {
249 // fprintf(stderr, "Not supported.\n");
250 return 1;
252 break;
254 mask = reset_mask | ses_mask | brau_mask;
256 #ifdef DEBUG_TEST
257 cprintf("reset_mask=0x%X reset_pushed=0x%X\n", reset_mask, reset_pushed);
258 cprintf("ses_mask=0x%X\n", ses_mask);
259 cprintf("brau_mask=0x%X\n", brau_mask);
260 cprintf("ses_led=%d\n", ses_led);
261 #else
262 if (fork() != 0) return 0;
263 setsid();
264 #endif
266 signal(SIGCHLD, chld_reap);
268 if ((gf = gpio_open(mask)) < 0) return 1;
270 last = 0;
271 brau_count_stable = 0;
272 brau_flag = 0;
273 while (1) {
274 if (((gpio = _gpio_read(gf)) == ~0) || (last == (gpio &= mask) && !brau_flag) || (check_action() != ACT_IDLE)) {
275 #ifdef DEBUG_TEST
276 cprintf("gpio = %X\n", gpio);
277 #endif
278 sleep(1);
279 continue;
282 if ((gpio & reset_mask) == reset_pushed) {
283 #ifdef DEBUG_TEST
284 cprintf("reset down\n");
285 #endif
287 led(LED_DIAG, 0);
289 count = 0;
290 do {
291 sleep(1);
292 if (++count == 3) led(LED_DIAG, 1);
293 } while (((gpio = _gpio_read(gf)) != ~0) && ((gpio & reset_mask) == reset_pushed));
295 #ifdef DEBUG_TEST
296 cprintf("reset count = %d\n", count);
297 #else
298 if (count >= 3) {
299 eval("mtd-erase", "-d", "nvram");
300 //nvram_set("restore_defaults", "1");
301 //nvram_commit();
302 sync();
303 reboot(RB_AUTOBOOT);
305 else {
306 led(LED_DIAG, 1);
307 set_action(ACT_REBOOT);
308 kill(1, SIGTERM);
310 exit(0);
311 #endif
314 if ((ses_mask) && ((gpio & ses_mask) == ses_pushed)) {
315 count = 0;
316 do {
317 // syslog(LOG_DEBUG, "ses-pushed: gpio=x%X, pushed=x%X, mask=x%X, count=%d", gpio, ses_pushed, ses_mask, count);
319 led(ses_led, LED_ON);
320 usleep(500000);
321 led(ses_led, LED_OFF);
322 usleep(500000);
323 ++count;
324 } while (((gpio = _gpio_read(gf)) != ~0) && ((gpio & ses_mask) == ses_pushed));
325 gpio &= mask;
327 if ((ses_led == LED_DMZ) && (nvram_get_int("dmz_enable") > 0)) led(LED_DMZ, 1);
329 // syslog(LOG_DEBUG, "ses-released: gpio=x%X, pushed=x%X, mask=x%X, count=%d", gpio, ses_pushed, ses_mask, count);
330 syslog(LOG_INFO, "SES pushed. Count was %d.", count);
332 if ((count != 3) && (count != 7) && (count != 11)) {
333 n = count >> 2;
334 if (n > 3) n = 3;
336 0-2 = func0
337 4-6 = func1
338 8-10 = func2
339 12+ = func3
342 #ifdef DEBUG_TEST
343 cprintf("ses func=%d\n", n);
344 #else
345 sprintf(s, "sesx_b%d", n);
346 // syslog(LOG_DEBUG, "ses-func: count=%d %s='%s'", count, s, nvram_safe_get(s));
347 if ((p = nvram_get(s)) != NULL) {
348 switch (*p) {
349 case '1': // toggle wl
350 nvram_set("rrules_radio", "-1");
351 eval("radio", "toggle");
352 break;
353 case '2': // reboot
354 kill(1, SIGTERM);
355 break;
356 case '3': // shutdown
357 kill(1, SIGQUIT);
358 break;
359 case '4': // run a script
360 sprintf(s, "%d", count);
361 run_nvscript("sesx_script", s, 2);
362 break;
363 #ifdef TCONFIG_USB
364 case '5': // !!TB: unmount all USB drives
365 add_remove_usbhost("-2", 0);
366 break;
367 #endif
370 #endif
375 if (brau_mask) {
376 if (last == gpio)
377 sleep(1);
378 last = (gpio & brau_mask);
379 if (brau_state != last) {
380 brau_flag = (brau_state != ~0); // set to 1 to run at startup
381 brau_state = last;
382 brau_count_stable = 0;
384 else if (brau_flag && ++brau_count_stable > 2) { // stable for 2+ seconds
385 brau_flag = 0;
386 switch (nvram_get_int("btn_override") ? MODEL_UNKNOWN : get_model()) {
387 #ifdef CONFIG_BCMWL5
388 case MODEL_RTN12:
389 p = (brau_state & (1 << 4)) ? "ap" : (brau_state & (1 << 5)) ? "repeater" : "router";
390 break;
391 #endif
392 default:
393 p = brau_state ? "auto" : "bridge";
394 break;
396 nvram_set("brau_state", p);
397 #ifdef DEBUG_TEST
398 cprintf("bridge/auto state = %s\n", p);
399 #else
400 run_nvscript("script_brau", p, 2);
401 #endif
405 last = gpio;
408 return 0;