root/trunk/freewrt/package/broadcom-diag/diag.c

Revision 2749, 24.3 kB (checked in by tg, 1 year ago)

unbreak hotplugging buttons (and with that, failsafe, I think)
on brcm-2.4 – this change may break other platforms, and I don't
care the least little bit; this has cost me a whole f.cking day

Line 
1 /*
2  * diag.c - GPIO interface driver for Broadcom boards
3  *
4  * Copyright (C) 2006 Mike Baker <mbm@openwrt.org>,
5  *                    Felix Fietkau <nbd@openwrt.org>
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  *
21  * $Id: diag.c 6562 2007-03-14 01:19:24Z nbd $
22  */
23 #include <linux/module.h>
24 #include <linux/pci.h>
25 #include <linux/kmod.h>
26 #include <linux/proc_fs.h>
27 #include <linux/timer.h>
28 #include <linux/version.h>
29 #include <asm/uaccess.h>
30
31 //#define hotplug_path uevent_helper
32
33 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
34 #include <linux/kobject.h>
35 #include <linux/workqueue.h>
36 #else
37 #include <linux/tqueue.h>
38 #define INIT_WORK INIT_TQUEUE
39 #define schedule_work schedule_task
40 #define work_struct tq_struct
41 #endif
42
43 #include "gpio.h"
44 #include "diag.h"
45 #define getvar(str) (nvram_get(str)?:"")
46
47 static unsigned int gpiomask = 0;
48 module_param(gpiomask, int, 0644);
49
50 enum {
51         /* Linksys */
52         WAP54GV1,
53         WAP54GV3,
54         WRT54GV1,
55         WRT54G,
56         WRTSL54GS,
57         WRT54G3G,
58         WRT350N,
59        
60         /* ASUS */
61         WLHDD,
62         WL300G,
63         WL500G,
64         WL500GD,
65         WL500GP,
66         WL500W,
67         ASUS_4702,
68         WL700GE,
69        
70         /* Buffalo */
71         WBR2_G54,
72         WHR_G54S,
73         WHR_HP_G54,
74         WHR2_A54G54,
75         WLA2_G54L,
76         WZR_G300N,
77         WZR_RS_G54,
78         WZR_RS_G54HP,
79         BUFFALO_UNKNOWN,
80         BUFFALO_UNKNOWN_4710,
81
82         /* Siemens */
83         SE505V1,
84         SE505V2,
85        
86         /* US Robotics */
87         USR5461,
88
89         /* Dell */
90         TM2300,
91
92         /* Motorola */
93         WE800G,
94         WR850GV1,
95         WR850GV2V3,
96
97         /* Belkin */
98         BELKIN_UNKNOWN,
99
100         /* Netgear */
101         WGT634U,
102
103         /* Trendware */
104         TEW411BRPP,
105        
106         /* SimpleTech */
107         STI_NAS,
108 };
109
110 static void __init bcm4780_init(void) {
111                 int pin = 1 << 3;
112
113                 /* Enables GPIO 3 that controls HDD and led power on ASUS WL-700gE */
114                 printk(MODULE_NAME ": Spinning up HDD and enabling leds\n");
115                 gpio_outen(pin, pin);
116                 gpio_control(pin, 0);
117                 gpio_out(pin, pin);
118
119                 /* Wait 5s, so the HDD can spin up */
120                 set_current_state(TASK_INTERRUPTIBLE);
121                 schedule_timeout(HZ * 5);
122 }
123
124 static struct platform_t __initdata platforms[] = {
125         /* Linksys */
126         [WAP54GV1] = {
127                 .name           = "Linksys WAP54G V1",
128                 .buttons        = {
129                         { .name = "reset",      .gpio = 1 << 0 },
130                 },
131                 .leds           = {
132                         { .name = "diag",       .gpio = 1 << 3 },
133                         { .name = "wlan",       .gpio = 1 << 4 },
134                 },
135         },
136         [WAP54GV3] = {
137                 .name           = "Linksys WAP54G V3",
138                 .buttons        = {
139                         /* FIXME: verify this */
140                         { .name = "reset",      .gpio = 1 << 7 },
141                         { .name = "ses",        .gpio = 1 << 0 },
142                 },
143                 .leds           = {
144                         /* FIXME: diag? */
145                         { .name = "ses",        .gpio = 1 << 1 },
146                 },
147         },
148         [WRT54GV1] = {
149                 .name           = "Linksys WRT54G V1.x",
150                 .buttons        = {
151                         { .name = "reset",      .gpio = 1 << 6 },
152                 },
153                 .leds           = {
154                         { .name = "diag",       .gpio = 0x13 | GPIO_TYPE_EXTIF, .polarity = NORMAL },
155                         { .name = "dmz",        .gpio = 0x12 | GPIO_TYPE_EXTIF, .polarity = NORMAL },
156                 },
157         },
158         [WRT54G] = {
159                 .name           = "Linksys WRT54G/GS/GL",
160                 .buttons        = {
161                         { .name = "reset",      .gpio = 1 << 6 },
162                         { .name = "ses",        .gpio = 1 << 4 },
163                 },
164                 .leds           = {
165                         { .name = "power",      .gpio = 1 << 1, .polarity = NORMAL },
166                         { .name = "dmz",        .gpio = 1 << 7, .polarity = REVERSE },
167                         { .name = "ses_white",  .gpio = 1 << 2, .polarity = REVERSE },
168                         { .name = "ses_orange", .gpio = 1 << 3, .polarity = REVERSE },
169                         { .name = "wlan",       .gpio = 1 << 0, .polarity = REVERSE },
170                 },
171         },
172         [WRTSL54GS] = {
173                 .name           = "Linksys WRTSL54GS",
174                 .buttons        = {
175                         { .name = "reset",      .gpio = 1 << 6 },
176                         { .name = "ses",        .gpio = 1 << 4 },
177                 },
178                 .leds           = {
179                         { .name = "power",      .gpio = 1 << 1, .polarity = NORMAL },
180                         { .name = "dmz",        .gpio = 1 << 0, .polarity = REVERSE },
181                         { .name = "ses_white",  .gpio = 1 << 5, .polarity = REVERSE },
182                         { .name = "ses_orange", .gpio = 1 << 7, .polarity = REVERSE },
183                 },
184         },
185         [WRT54G3G] = {
186                 .name           = "Linksys WRT54G3G",
187                 .buttons        = {
188                         { .name = "reset",      .gpio = 1 << 6 },
189                         { .name = "3g",         .gpio = 1 << 4 },
190                 },
191                 .leds           = {
192                         { .name = "power",      .gpio = 1 << 1, .polarity = NORMAL },
193                         { .name = "dmz",        .gpio = 1 << 7, .polarity = REVERSE },
194                         { .name = "3g_green",   .gpio = 1 << 2, .polarity = NORMAL },
195                         { .name = "3g_blue",    .gpio = 1 << 3, .polarity = NORMAL },
196                         { .name = "3g_blink",   .gpio = 1 << 5, .polarity = NORMAL },
197                 },
198         },
199         [WRT350N] = {
200                 .name           = "Linksys WRT350N",
201                 .buttons        = {
202                         { .name = "reset",      .gpio = 1 << 6 },
203                         { .name = "ses",        .gpio = 1 << 8 },
204                 },
205                 .leds           = {
206                         { .name = "power",      .gpio = 1 << 1, .polarity = NORMAL },
207                         { .name = "ses",        .gpio = 1 << 3, .polarity = REVERSE },
208                 },
209         },
210         /* Asus */
211         [WLHDD] = {
212                 .name           = "ASUS WL-HDD",
213                 .buttons        = {
214                         { .name = "reset",      .gpio = 1 << 6 },
215                 },
216                 .leds           = {
217                         { .name = "power",      .gpio = 1 << 0, .polarity = REVERSE },
218                         { .name = "usb",        .gpio = 1 << 2, .polarity = NORMAL },
219                 },
220         },
221         [WL300G] = {
222                 .name           = "ASUS WL-300g",
223                 .buttons        = {
224                         { .name = "reset",      .gpio = 1 << 6 },
225                 },
226                 .leds           = {
227                         { .name = "power",      .gpio = 1 << 0, .polarity = REVERSE },
228                 },
229         },
230         [WL500G] = {
231                 .name           = "ASUS WL-500g",
232                 .buttons        = {
233                         { .name = "reset",      .gpio = 1 << 6 },
234                 },
235                 .leds           = {
236                         { .name = "power",      .gpio = 1 << 0, .polarity = REVERSE },
237                 },
238         },
239         [WL500GD] = {
240                 .name           = "ASUS WL-500g Deluxe",
241                 .buttons        = {
242                         { .name = "reset",      .gpio = 1 << 6 },
243                 },
244                 .leds           = {
245                         { .name = "power",      .gpio = 1 << 0, .polarity = REVERSE },
246                 },
247         },
248         [WL500GP] = {
249                 .name           = "ASUS WL-500g Premium",
250                 .buttons        = {
251                         { .name = "reset",      .gpio = 1 << 0 },
252                         { .name = "ses",        .gpio = 1 << 4 },
253                 },
254                 .leds           = {
255                         { .name = "power",      .gpio = 1 << 1, .polarity = REVERSE },
256                 },
257         },
258         [WL500W] = {
259                 .name           = "ASUS WL-500W",
260                 .buttons        = {
261                         { .name = "reset",      .gpio = 1 << 6 },
262                         { .name = "ses",        .gpio = 1 << 7 },
263                 },
264                 .leds           = {
265                         { .name = "power",      .gpio = 1 << 5, .polarity = REVERSE },
266                 },
267         },
268         [ASUS_4702] = {
269                 .name           = "ASUS (unknown, BCM4702)",
270                 .buttons        = {
271                         { .name = "reset",      .gpio = 1 << 6 },
272                 },
273                 .leds           = {
274                         { .name = "power",      .gpio = 1 << 0, .polarity = REVERSE },
275                 },
276         },
277         [WL700GE] = {
278                 .name           = "ASUS WL-700gE",
279                 .buttons        = {
280                         { .name = "reset",      .gpio = 1 << 7 }, // on back, hardwired, always resets device regardless OS state
281                         { .name = "ses",        .gpio = 1 << 4 }, // on back, actual name ezsetup
282                         { .name = "power",      .gpio = 1 << 0 }, // on front
283                         { .name = "copy",       .gpio = 1 << 6 }, // on front
284                 },
285                 .leds           = {
286 #if 0
287                         // GPIO that controls power led also enables/disables some essential functions
288                         // - power to HDD
289                         // - switch leds
290                         { .name = "power",      .gpio = 1 << 3, .polarity = NORMAL },  // actual name power
291 #endif
292                         { .name = "diag",       .gpio = 1 << 1, .polarity = REVERSE }, // actual name ready
293                 },
294                 .platform_init = bcm4780_init,
295         },
296         /* Buffalo */
297         [WHR_G54S] = {
298                 .name           = "Buffalo WHR-G54S",
299                 .buttons        = {
300                         { .name = "reset",      .gpio = 1 << 4 },
301                         { .name = "bridge",     .gpio = 1 << 5 },
302                         { .name = "ses",        .gpio = 1 << 0 },
303                 },
304                 .leds           = {
305                         { .name = "diag",       .gpio = 1 << 7, .polarity = REVERSE },
306                         { .name = "internal",   .gpio = 1 << 3, .polarity = REVERSE },
307                         { .name = "ses",        .gpio = 1 << 6, .polarity = REVERSE },
308                         { .name = "bridge",     .gpio = 1 << 1, .polarity = REVERSE },
309                 },
310         },
311         [WBR2_G54] = {
312                 .name           = "Buffalo WBR2-G54",
313                 /* FIXME: verify */
314                 .buttons        = {
315                         { .name = "reset",      .gpio = 1 << 7 },
316                 },
317                 .leds           = {
318                         { .name = "diag",       .gpio = 1 << 1, .polarity = REVERSE },
319                 },
320         },
321         [WHR_HP_G54] = {
322                 .name           = "Buffalo WHR-HP-G54",
323                 .buttons        = {
324                         { .name = "reset",      .gpio = 1 << 4 },
325                         { .name = "bridge",     .gpio = 1 << 5 },
326                         { .name = "ses",        .gpio = 1 << 0 },
327                 },
328                 .leds           = {
329                         { .name = "diag",       .gpio = 1 << 7, .polarity = REVERSE },
330                         { .name = "bridge",     .gpio = 1 << 1, .polarity = REVERSE },
331                         { .name = "ses",        .gpio = 1 << 6, .polarity = REVERSE },
332                 },
333         },
334         [WHR2_A54G54] = {
335                 .name           = "Buffalo WHR2-A54G54",
336                 .buttons        = {
337                         { .name = "reset",      .gpio = 1 << 4 },
338                 },
339                 .leds           = {
340                         { .name = "diag",       .gpio = 1 << 7, .polarity = REVERSE },
341                 },
342         },
343         [WLA2_G54L] = {
344                 .name           = "Buffalo WLA2-G54L",
345                 /* FIXME: verify */
346                 .buttons        = {
347                         { .name = "reset",      .gpio = 1 << 7 },
348                 },
349                 .leds           = {
350                         { .name = "diag",       .gpio = 1 << 1, .polarity = REVERSE },
351                 },
352         },
353         [WZR_G300N] = {
354                 .name           = "Buffalo WZR-G300N",
355                 .buttons        = {
356                         { .name = "reset",      .gpio = 1 << 4 },
357                 },
358                 .leds           = {
359                         { .name = "diag",       .gpio = 1 << 7, .polarity = REVERSE },
360                         { .name = "bridge",     .gpio = 1 << 1, .polarity = REVERSE },
361                         { .name = "ses",        .gpio = 1 << 6, .polarity = REVERSE },
362                 },
363         },
364         [WZR_RS_G54] = {
365                 .name           = "Buffalo WZR-RS-G54",
366                 .buttons        = {
367                         { .name = "ses",        .gpio = 1 << 0 },
368                         { .name = "reset",      .gpio = 1 << 4 },
369                 },
370                 .leds           = {
371                         { .name = "diag",       .gpio = 1 << 7, .polarity = REVERSE },
372                         { .name = "ses",        .gpio = 1 << 6, .polarity = REVERSE },
373                         { .name = "vpn",        .gpio = 1 << 1, .polarity = REVERSE },
374                 },
375         },
376         [WZR_RS_G54HP] = {
377                 .name           = "Buffalo WZR-RS-G54HP",
378                 .buttons        = {
379                         { .name = "ses",        .gpio = 1 << 0 },
380                         { .name = "reset",      .gpio = 1 << 4 },
381                 },
382                 .leds           = {
383                         { .name = "diag",       .gpio = 1 << 7, .polarity = REVERSE },
384                         { .name = "ses",        .gpio = 1 << 6, .polarity = REVERSE },
385                         { .name = "vpn",        .gpio = 1 << 1, .polarity = REVERSE },
386                 },
387         },
388         [BUFFALO_UNKNOWN] = {
389                 .name           = "Buffalo (unknown)",
390                 .buttons        = {
391                         { .name = "reset",      .gpio = 1 << 7 },
392                 },
393                 .leds           = {
394                         { .name = "diag",       .gpio = 1 << 1, .polarity = REVERSE },
395                 },
396         },
397         [BUFFALO_UNKNOWN_4710] = {
398                 .name           = "Buffalo (unknown, BCM4710)",
399                 .buttons        = {
400                         { .name = "reset",      .gpio = 1 << 4 },
401                 },
402                 .leds           = {
403                         { .name = "diag",       .gpio = 1 << 1, .polarity = REVERSE },
404                 },
405         },
406         /* Siemens */
407         [SE505V1] = {
408                 .name           = "Siemens SE505 V1",
409                 .buttons        = {
410                         /* No usable buttons */
411                 },
412                 .leds           = {
413                         { .name = "dmz",        .gpio = 1 << 4, .polarity = REVERSE },
414                         { .name = "wlan",       .gpio = 1 << 3, .polarity = REVERSE },
415                 },
416         },
417         [SE505V2] = {
418                 .name           = "Siemens SE505 V2",
419                 .buttons        = {
420                         /* No usable buttons */
421                 },
422                 .leds           = {
423                         { .name = "power",      .gpio = 1 << 5, .polarity = REVERSE },
424                         { .name = "dmz",        .gpio = 1 << 0, .polarity = REVERSE },
425                         { .name = "wlan",       .gpio = 1 << 3, .polarity = REVERSE },
426                 },
427         },
428         /* US Robotics */
429         [USR5461] = {
430                 .name           = "U.S. Robotics USR5461",
431                 .buttons        = {
432                         /* No usable buttons */
433                 },
434                 .leds           = {
435                         { .name = "wlan",       .gpio = 1 << 0, .polarity = REVERSE },
436                         { .name = "printer",    .gpio = 1 << 1, .polarity = REVERSE },
437                 },
438         },
439         /* Dell */
440         [TM2300] = {
441                 .name           = "Dell TrueMobile 2300",
442                 .buttons        = {
443                         { .name = "reset",      .gpio = 1 << 0 },
444                 },
445                 .leds           = {
446                         { .name = "wlan",       .gpio = 1 << 6, .polarity = REVERSE },
447                         { .name = "power",      .gpio = 1 << 7, .polarity = REVERSE },
448                 },
449         },
450         /* Motorola */
451         [WE800G] = {
452                 .name           = "Motorola WE800G",
453                 .buttons        = {
454                         { .name = "reset",      .gpio = 1 << 0 },
455                 },
456                 .leds           = {
457                         { .name = "power",      .gpio = 1 << 4, .polarity = NORMAL },
458                         { .name = "diag",       .gpio = 1 << 2, .polarity = REVERSE },
459                         { .name = "wlan_amber", .gpio = 1 << 1, .polarity = NORMAL },
460                 },
461         },
462         [WR850GV1] = {
463                 .name           = "Motorola WR850G V1",
464                 .buttons        = {
465                         { .name = "reset",      .gpio = 1 << 0 },
466                 },
467                 .leds           = {
468                         { .name = "power",      .gpio = 1 << 4, .polarity = NORMAL },
469                         { .name = "diag",       .gpio = 1 << 3, .polarity = REVERSE },
470                         { .name = "dmz",        .gpio = 1 << 6, .polarity = NORMAL },
471                         { .name = "wlan_red",   .gpio = 1 << 5, .polarity = REVERSE },
472                         { .name = "wlan_green", .gpio = 1 << 7, .polarity = REVERSE },
473                 },
474         },
475         [WR850GV2V3] = {
476                 .name           = "Motorola WR850G V2/V3",
477                 .buttons        = {
478                         { .name = "reset",      .gpio = 1 << 5 },
479                 },
480                 .leds           = {
481                         { .name = "power",      .gpio = 1 << 1, .polarity = NORMAL },
482                         { .name = "wlan",       .gpio = 1 << 0, .polarity = REVERSE },
483                         { .name = "dmz",        .gpio = 1 << 6, .polarity = REVERSE },
484                         { .name = "diag",       .gpio = 1 << 7, .polarity = REVERSE },
485                 },
486         },
487         /* Belkin */
488         [BELKIN_UNKNOWN] = {
489                 .name           = "Belkin (unknown)",
490                 /* FIXME: verify & add detection */
491                 .buttons        = {
492                         { .name = "reset",      .gpio = 1 << 7 },
493                 },
494                 .leds           = {
495                         { .name = "power",      .gpio = 1 << 5, .polarity = NORMAL },
496                         { .name = "wlan",       .gpio = 1 << 3, .polarity = NORMAL },
497                         { .name = "connected",  .gpio = 1 << 0, .polarity = NORMAL },
498                 },
499         },
500         /* Netgear */
501         [WGT634U] = {
502                 .name           = "Netgear WGT634U",
503                 .buttons        = {
504                         { .name = "reset",      .gpio = 1 << 2 },
505                 },
506                 .leds           = {
507                         { .name = "power",      .gpio = 1 << 3, .polarity = REVERSE },
508                 },
509         },
510         /* Trendware */
511         [TEW411BRPP] = {
512                 .name           = "Trendware TEW411BRP+",
513                 .buttons        = {
514                         { /* No usable buttons */ },
515                 },
516                 .leds           = {
517                         { .name = "power",      .gpio = 1 << 7, .polarity = NORMAL },
518                         { .name = "wlan",       .gpio = 1 << 1, .polarity = NORMAL },
519                         { .name = "bridge",     .gpio = 1 << 6, .polarity = NORMAL },
520                 },
521         },
522         /* SimpleTech */
523         [STI_NAS] = {
524                 .name      = "SimpleTech SimpleShare NAS",
525                 .buttons        = {
526                         { .name = "reset",      .gpio = 1 << 7 }, // on back, hardwired, always resets device regardless OS state
527                         { .name = "power",      .gpio = 1 << 0 }, // on back
528                 },
529                 .leds      = {
530                         { .name = "diag",       .gpio = 1 << 1, .polarity = REVERSE }, // actual name ready
531                 },
532                 .platform_init = bcm4780_init,
533         },
534 };
535
536 static struct platform_t __init *platform_detect(void)
537 {
538         char *boardnum, *boardtype, *buf;
539
540         boardnum = getvar("boardnum");
541         boardtype = getvar("boardtype");
542
543         if (strcmp(getvar("nvram_type"), "cfe") == 0)
544                 return &platforms[WGT634U];
545        
546         if (strncmp(getvar("model_no"), "WL700",5) == 0)
547                 return &platforms[WL700GE];
548
549         if (strncmp(getvar("pmon_ver"), "CFE", 3) == 0) {
550                 /* CFE based - newer hardware */
551                 if (!strcmp(boardnum, "42")) { /* Linksys */
552                         if (!strcmp(boardtype, "0x478") && !strcmp(getvar("cardbus"), "1"))
553                                 return &platforms[WRT350N];
554
555                         if (!strcmp(boardtype, "0x0101") && !strcmp(getvar("boot_ver"), "v3.6"))
556                                 return &platforms[WRT54G3G];
557
558                         if (!strcmp(getvar("et1phyaddr"),"5") && !strcmp(getvar("et1mdcport"), "1"))
559                                 return &platforms[WRTSL54GS];
560                        
561                         /* default to WRT54G */
562                         return &platforms[WRT54G];
563                 }
564                
565                 if (!strcmp(boardnum, "45")) { /* ASUS */
566                         if (!strcmp(boardtype,"0x042f"))
567                                 return &platforms[WL500GP];
568                         else if (!strcmp(boardtype,"0x0472"))
569                                 return &platforms[WL500W];
570                         else
571                                 return &platforms[WL500GD];
572                 }
573                
574                 if (!strcmp(boardnum, "10496"))
575                         return &platforms[USR5461];
576         } else { /* PMON based - old stuff */
577
578                 /* Dell TrueMobile 2300 */
579                 if (!strcmp(getvar("ModelId"),"WX-5565"))
580                         return &platforms[TM2300];
581        
582                 if ((simple_strtoul(getvar("GemtekPmonVer"), NULL, 0) == 9) &&
583                         (simple_strtoul(getvar("et0phyaddr"), NULL, 0) == 30)) {
584                         if (!strncmp(getvar("ModelId"),"WE800G", 6))
585                                 return &platforms[WE800G];
586                         else
587                                 return &platforms[WR850GV1];
588                 }
589                 if (!strncmp(boardtype, "bcm94710dev", 11)) {
590                         if (!strcmp(boardnum, "42"))
591                                 return &platforms[WRT54GV1];
592                         if (simple_strtoul(boardnum, NULL, 0) == 2)
593                                 return &platforms[WAP54GV1];
594                 }
595                 if (!strncmp(getvar("hardware_version"), "WL500-", 6))
596                         return &platforms[WL500G];
597                 if (!strncmp(getvar("hardware_version"), "WL300-", 6)) {
598                         /* Either WL-300g or WL-HDD, do more extensive checks */
599                         if ((simple_strtoul(getvar("et0phyaddr"), NULL, 0) == 0) &&
600                                 (simple_strtoul(getvar("et1phyaddr"), NULL, 0) == 1))
601                                 return &platforms[WLHDD];
602                         if ((simple_strtoul(getvar("et0phyaddr"), NULL, 0) == 0) &&
603                                 (simple_strtoul(getvar("et1phyaddr"), NULL, 0) == 10))
604                                 return &platforms[WL300G];
605                 }
606
607                 /* unknown asus stuff, probably bcm4702 */
608                 if (!strncmp(boardnum, "asusX", 5))
609                         return &platforms[ASUS_4702];
610         }
611
612         if ((buf = (nvram_get("melco_id") ?: nvram_get("buffalo_id")))) {
613                 /* Buffalo hardware, check id for specific hardware matches */
614                 if (!strcmp(buf, "29bb0332"))
615                         return &platforms[WBR2_G54];
616                 if (!strcmp(buf, "29129"))
617                         return &platforms[WLA2_G54L];
618                 if (!strcmp(buf, "30189"))
619                         return &platforms[WHR_HP_G54];
620                 if (!strcmp(buf, "30182"))
621                         return &platforms[WHR_G54S];
622                 if (!strcmp(buf, "290441dd"))
623                         return &platforms[WHR2_A54G54];
624                 if (!strcmp(buf, "31120"))
625                         return &platforms[WZR_G300N];
626                 if (!strcmp(buf, "30083"))
627                         return &platforms[WZR_RS_G54];
628                 if (!strcmp(buf, "30103"))
629                         return &platforms[WZR_RS_G54HP];
630         }
631
632         if (buf || !strcmp(boardnum, "00")) {/* probably buffalo */
633                 if (!strncmp(boardtype, "bcm94710ap", 10))
634                         return &platforms[BUFFALO_UNKNOWN_4710];
635                 else
636                         return &platforms[BUFFALO_UNKNOWN];
637         }
638
639         if (!strcmp(getvar("CFEver"), "MotoWRv203") ||
640                 !strcmp(getvar("MOTO_BOARD_TYPE"), "WR_FEM1")) {
641
642                 return &platforms[WR850GV2V3];
643         }
644
645         if (!strcmp(boardnum, "44")) {  /* Trendware TEW-411BRP+ */
646                 return &platforms[TEW411BRPP];
647         }
648
649         if (!strncmp(boardnum, "04FN52", 6)) /* SimpleTech SimpleShare */
650                 return &platforms[STI_NAS];
651
652         /* not found */
653         return NULL;
654 }
655
656 static void register_buttons(struct button_t *b)
657 {
658         for (; b->name; b++)
659                 platform.button_mask |= b->gpio;
660
661         platform.button_mask &= ~gpiomask;
662
663         gpio_outen(platform.button_mask, 0);
664         gpio_control(platform.button_mask, 0);
665         platform.button_polarity = gpio_in() & platform.button_mask;
666         gpio_intpolarity(platform.button_mask, platform.button_polarity);
667         gpio_intmask(platform.button_mask, platform.button_mask);
668
669         gpio_set_irqenable(1, button_handler);
670 }
671
672 static void unregister_buttons(struct button_t *b)
673 {
674         gpio_intmask(platform.button_mask, 0);
675
676         gpio_set_irqenable(0, button_handler);
677 }
678
679 static void hotplug_button(struct event_t *event)
680 {
681 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
682         call_usermodehelper (event->argv[0], event->argv, event->envp, 1);
683 #else
684         call_usermodehelper (event->argv[0], event->argv, event->envp);
685 #endif
686         kfree(event);
687 }
688
689 static irqreturn_t button_handler(int irq, void *dev_id, struct pt_regs *regs)
690 {
691         struct button_t *b;
692         u32 in, changed;
693
694         in = gpio_in() & platform.button_mask;
695         gpio_intpolarity(platform.button_mask, in);
696         changed = platform.button_polarity ^ in;
697         platform.button_polarity = in;
698
699         changed &= ~gpio_outen(0, 0);
700
701         for (b = platform.buttons; b->name; b++) {
702                 struct event_t *event;
703
704                 if (!(b->gpio & changed)) continue;
705
706                 b->pressed ^= 1;
707
708                 if ((event = (struct event_t *)kmalloc (sizeof(struct event_t), GFP_ATOMIC))) {
709                         int i;
710                         char *scratch = event->buf;
711
712                         i = 0;
713                         event->argv[i++] = hotplug_path;
714                         event->argv[i++] = "button";
715                         event->argv[i] = 0;
716
717                         i = 0;
718                         event->envp[i++] = "HOME=/";
719                         event->envp[i++] = "PATH=/sbin:/bin:/usr/sbin:/usr/bin";
720                         event->envp[i++] = scratch;
721                         scratch += sprintf (scratch, "ACTION=%s", b->pressed?