source: trunk/package/broadcom-diag/src/diag.c @ 15245

Last change on this file since 15245 was 15245, checked in by nico, 7 years ago

remove 'svn:keywords' property, not needed anymore after [15242]

  • Property svn:eol-style set to native
File size: 33.9 KB
Line 
1/*
2 * diag.c - GPIO interface driver for Broadcom boards
3 *
4 * Copyright (C) 2006 Mike Baker <mbm@openwrt.org>,
5 * Copyright (C) 2006-2007 Felix Fietkau <nbd@openwrt.org>
6 * Copyright (C) 2008 Andy Boyett <agb@openwrt.org>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License
10 * as published by the Free Software Foundation; either version 2
11 * of the License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21 *
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#ifndef LINUX_2_4
32#include <linux/workqueue.h>
33#include <linux/skbuff.h>
34#include <linux/netlink.h>
35#include <net/sock.h>
36extern struct sock *uevent_sock;
37extern u64 uevent_next_seqnum(void);
38#else
39#include <linux/tqueue.h>
40#define INIT_WORK INIT_TQUEUE
41#define schedule_work schedule_task
42#define work_struct tq_struct
43#endif
44
45#include "gpio.h"
46#include "diag.h"
47#define getvar(str) (nvram_get(str)?:"")
48
49static inline int startswith (char *source, char *cmp) { return !strncmp(source,cmp,strlen(cmp)); }
50static int fill_event(struct event_t *);
51static unsigned int gpiomask = 0;
52module_param(gpiomask, int, 0644);
53
54enum {
55        /* Linksys */
56        WAP54GV1,
57        WAP54GV3,
58        WRT54GV1,
59        WRT54G,
60        WRTSL54GS,
61        WRT54G3G,
62        WRT350N,
63        WRT600N,
64        WRT600NV11,
65
66        /* ASUS */
67        WLHDD,
68        WL300G,
69        WL320GE,
70        WL330GE,
71        WL500G,
72        WL500GD,
73        WL500GP,
74        WL500GPV2,
75        WL500W,
76        WL520GC,
77        WL520GU,
78        ASUS_4702,
79        WL700GE,
80
81        /* Buffalo */
82        WBR2_G54,
83        WHR_G54S,
84        WHR_HP_G54,
85        WHR_G125,
86        WHR2_A54G54,
87        WLA2_G54L,
88        WZR_G300N,
89        WZR_RS_G54,
90        WZR_RS_G54HP,
91        BUFFALO_UNKNOWN,
92        BUFFALO_UNKNOWN_4710,
93
94        /* Siemens */
95        SE505V1,
96        SE505V2,
97
98        /* US Robotics */
99        USR5461,
100
101        /* Dell */
102        TM2300,
103        TM2300V2,
104
105        /* Motorola */
106        WE800G,
107        WR850GV1,
108        WR850GV2V3,
109        WR850GP,
110
111        /* Belkin */
112        BELKIN_UNKNOWN,
113
114        /* Netgear */
115        WGT634U,
116
117        /* Trendware */
118        TEW411BRPP,
119
120        /* SimpleTech */
121        STI_NAS,
122
123        /* D-Link */
124        DIR130,
125        DIR330,
126        DWL3150,
127
128        /* Sitecom */
129        WL105B,
130};
131
132static void __init bcm4780_init(void) {
133                int pin = 1 << 3;
134
135                /* Enables GPIO 3 that controls HDD and led power on ASUS WL-700gE */
136                printk(MODULE_NAME ": Spinning up HDD and enabling leds\n");
137                gpio_outen(pin, pin);
138                gpio_control(pin, 0);
139                gpio_out(pin, pin);
140
141                /* Wait 5s, so the HDD can spin up */
142                set_current_state(TASK_INTERRUPTIBLE);
143                schedule_timeout(HZ * 5);
144}
145
146static void __init bcm57xx_init(void) {
147        int pin = 1 << 2;
148
149#ifndef LINUX_2_4
150        /* FIXME: switch comes up, but port mappings/vlans not right */
151        gpio_outen(pin, pin);
152        gpio_control(pin, 0);
153        gpio_out(pin, pin);
154#endif
155}
156
157static struct platform_t __initdata platforms[] = {
158        /* Linksys */
159        [WAP54GV1] = {
160                .name           = "Linksys WAP54G V1",
161                .buttons        = {
162                        { .name = "reset",      .gpio = 1 << 0 },
163                },
164                .leds           = {
165                        { .name = "diag",       .gpio = 1 << 3 },
166                        { .name = "wlan",       .gpio = 1 << 4 },
167                },
168        },
169        [WAP54GV3] = {
170                .name           = "Linksys WAP54G V3",
171                .buttons        = {
172                        /* FIXME: verify this */
173                        { .name = "reset",      .gpio = 1 << 7 },
174                        { .name = "ses",        .gpio = 1 << 0 },
175                },
176                .leds           = {
177                        /* FIXME: diag? */
178                        { .name = "ses",        .gpio = 1 << 1 },
179                },
180        },
181        [WRT54GV1] = {
182                .name           = "Linksys WRT54G V1.x",
183                .buttons        = {
184                        { .name = "reset",      .gpio = 1 << 6 },
185                },
186                .leds           = {
187                        { .name = "diag",       .gpio = 0x13 | GPIO_TYPE_EXTIF, .polarity = NORMAL },
188                        { .name = "dmz",        .gpio = 0x12 | GPIO_TYPE_EXTIF, .polarity = NORMAL },
189                },
190        },
191        [WRT54G] = {
192                .name           = "Linksys WRT54G/GS/GL",
193                .buttons        = {
194                        { .name = "reset",      .gpio = 1 << 6 },
195                        { .name = "ses",        .gpio = 1 << 4 },
196                },
197                .leds           = {
198                        { .name = "power",      .gpio = 1 << 1, .polarity = NORMAL },
199                        { .name = "dmz",        .gpio = 1 << 7, .polarity = REVERSE },
200                        { .name = "ses_white",  .gpio = 1 << 2, .polarity = REVERSE },
201                        { .name = "ses_orange", .gpio = 1 << 3, .polarity = REVERSE },
202                        { .name = "wlan",       .gpio = 1 << 0, .polarity = REVERSE },
203                },
204        },
205        [WRTSL54GS] = {
206                .name           = "Linksys WRTSL54GS",
207                .buttons        = {
208                        { .name = "reset",      .gpio = 1 << 6 },
209                        { .name = "ses",        .gpio = 1 << 4 },
210                },
211                .leds           = {
212                        { .name = "power",      .gpio = 1 << 1, .polarity = NORMAL },
213                        { .name = "dmz",        .gpio = 1 << 0, .polarity = REVERSE },
214                        { .name = "ses_white",  .gpio = 1 << 5, .polarity = REVERSE },
215                        { .name = "ses_orange", .gpio = 1 << 7, .polarity = REVERSE },
216                },
217        },
218        [WRT54G3G] = {
219                .name           = "Linksys WRT54G3G",
220                .buttons        = {
221                        { .name = "reset",      .gpio = 1 << 6 },
222                        { .name = "3g",         .gpio = 1 << 4 },
223                },
224                .leds           = {
225                        { .name = "power",      .gpio = 1 << 1, .polarity = NORMAL },
226                        { .name = "dmz",        .gpio = 1 << 7, .polarity = REVERSE },
227                        { .name = "3g_green",   .gpio = 1 << 2, .polarity = NORMAL },
228                        { .name = "3g_blue",    .gpio = 1 << 3, .polarity = NORMAL },
229                        { .name = "3g_blink",   .gpio = 1 << 5, .polarity = NORMAL },
230                },
231        },
232        [WRT350N] = {
233                .name           = "Linksys WRT350N",
234                .buttons        = {
235                        { .name = "reset",      .gpio = 1 << 6 },
236                        { .name = "ses",        .gpio = 1 << 8 },
237                },
238                .leds           = {
239                        { .name = "power",      .gpio = 1 << 1, .polarity = NORMAL },
240                        { .name = "ses_amber",  .gpio = 1 << 3, .polarity = REVERSE },
241                        { .name = "ses_green",  .gpio = 1 << 9, .polarity = REVERSE },
242                        { .name = "usb_blink",  .gpio = 1 << 10, .polarity = REVERSE },
243                        { .name = "usb",        .gpio = 1 << 11, .polarity = REVERSE },
244                },
245                .platform_init = bcm57xx_init,
246        },
247        [WRT600N] = {
248                .name           = "Linksys WRT600N",
249                .buttons        = {
250                        { .name = "reset",      .gpio = 1 << 6 },
251                        { .name = "ses",        .gpio = 1 << 7 },
252                },
253                .leds           = {
254                        { .name = "power",              .gpio = 1 << 2,  .polarity = REVERSE }, // Power LED
255                        { .name = "usb",                .gpio = 1 << 3,  .polarity = REVERSE }, // USB LED
256                        { .name = "wl0_ses_amber",      .gpio = 1 << 8,  .polarity = REVERSE }, // 2.4Ghz LED Amber
257                        { .name = "wl0_ses_green",      .gpio = 1 << 9,  .polarity = REVERSE }, // 2.4Ghz LED Green
258                        { .name = "wl1_ses_amber",      .gpio = 1 << 10, .polarity = REVERSE }, // 5.6Ghz LED Amber
259                        { .name = "wl1_ses_green",      .gpio = 1 << 11, .polarity = REVERSE }, // 5.6Ghz LED Green
260                },
261                .platform_init = bcm57xx_init,
262        },
263        [WRT600NV11] = {
264                .name           = "Linksys WRT600N V1.1",
265                .buttons        = {
266                        { .name = "reset",      .gpio = 1 << 6 },
267                        { .name = "ses",        .gpio = 1 << 7 },
268                },
269                .leds           = {
270                        { .name = "power",             .gpio = 1 << 2,  .polarity = REVERSE }, // Power LED
271                        { .name = "usb",                .gpio = 1 << 3,  .polarity = REVERSE }, // USB LED
272                        { .name = "wl0_ses_amber",      .gpio = 1 << 8,  .polarity = REVERSE }, // 2.4Ghz LED Amber
273                        { .name = "wl0_ses_green",     .gpio = 1 << 9,  .polarity = REVERSE }, // 2.4Ghz LED Green
274                        { .name = "wl1_ses_amber",      .gpio = 1 << 10, .polarity = REVERSE }, // 5.6Ghz LED Amber
275                        { .name = "wl1_ses_green",      .gpio = 1 << 11, .polarity = REVERSE }, // 5.6Ghz LED Green
276                },
277                .platform_init = bcm57xx_init,
278        },
279        /* Asus */
280        [WLHDD] = {
281                .name           = "ASUS WL-HDD",
282                .buttons        = {
283                        { .name = "reset",      .gpio = 1 << 6 },
284                },
285                .leds           = {
286                        { .name = "power",      .gpio = 1 << 0, .polarity = REVERSE },
287                        { .name = "usb",        .gpio = 1 << 2, .polarity = NORMAL },
288                },
289        },
290        [WL300G] = {
291                .name           = "ASUS WL-300g",
292                .buttons        = {
293                        { .name = "reset",      .gpio = 1 << 6 },
294                },
295                .leds           = {
296                        { .name = "power",      .gpio = 1 << 0, .polarity = REVERSE },
297                },
298        },
299        [WL320GE] = {
300                .name           = "ASUS WL-320gE/WL-320gP",
301                .buttons        = {
302                        { .name = "reset",      .gpio = 1 << 6 },
303                },
304                .leds           = {
305                        { .name = "wlan",       .gpio = 1 << 0, .polarity = REVERSE },
306                        { .name = "power",      .gpio = 1 << 2, .polarity = REVERSE },
307                        { .name = "link",       .gpio = 1 << 11, .polarity = REVERSE },
308                },
309        },
310        [WL330GE] = {
311                .name           = "ASUS WL-330gE",
312                .buttons        = {
313                        { .name = "reset",      .gpio = 1 << 2 },
314                },
315                .leds           = {
316                        { .name = "power",      .gpio = 1 << 0, .polarity = REVERSE },
317                },
318        },
319        [WL500G] = {
320                .name           = "ASUS WL-500g",
321                .buttons        = {
322                        { .name = "reset",      .gpio = 1 << 6 },
323                },
324                .leds           = {
325                        { .name = "power",      .gpio = 1 << 0, .polarity = REVERSE },
326                },
327        },
328        [WL500GD] = {
329                .name           = "ASUS WL-500g Deluxe",
330                .buttons        = {
331                        { .name = "reset",      .gpio = 1 << 6 },
332                },
333                .leds           = {
334                        { .name = "power",      .gpio = 1 << 0, .polarity = REVERSE },
335                },
336        },
337        [WL500GP] = {
338                .name           = "ASUS WL-500g Premium",
339                .buttons        = {
340                        { .name = "reset",      .gpio = 1 << 0 },
341                        { .name = "ses",        .gpio = 1 << 4 },
342                },
343                .leds           = {
344                        { .name = "power",      .gpio = 1 << 1, .polarity = REVERSE },
345                },
346        },
347        [WL500GPV2] = {
348                .name           = "ASUS WL-500g Premium V2",
349                .buttons        = {
350                        { .name = "reset",      .gpio = 1 << 2 },
351                        { .name = "ses",        .gpio = 1 << 3 },
352                },
353                .leds           = {
354                        { .name = "power",      .gpio = 1 << 0, .polarity = REVERSE },
355                        { .name = "wlan",       .gpio = 1 << 1, .polarity = REVERSE },
356                },
357        },
358        [WL500W] = {
359                .name           = "ASUS WL-500W",
360                .buttons        = {
361                        { .name = "reset",      .gpio = 1 << 6 },
362                        { .name = "ses",        .gpio = 1 << 7 },
363                },
364                .leds           = {
365                        { .name = "power",      .gpio = 1 << 5, .polarity = REVERSE },
366                },
367        },
368        [WL520GC] = {
369                .name           = "ASUS WL-520GC",
370                .buttons        = {
371                        { .name = "reset",      .gpio = 1 << 2 },
372                        { .name = "ses",        .gpio = 1 << 3 },
373                },
374                .leds           = {
375                { .name = "power",      .gpio = 1 << 0, .polarity = REVERSE },
376                        { .name = "wlan",       .gpio = 1 << 1, .polarity = REVERSE },
377                },
378        },
379        [WL520GU] = {
380                .name           = "ASUS WL-520gU",
381                .buttons        = {
382                        { .name = "reset",      .gpio = 1 << 2 },
383                        { .name = "ses",        .gpio = 1 << 3 },
384                },
385                .leds           = {
386                        { .name = "power",      .gpio = 1 << 0, .polarity = REVERSE },
387                        { .name = "wlan",       .gpio = 1 << 1, .polarity = REVERSE },
388                },
389        },
390        [ASUS_4702] = {
391                .name           = "ASUS (unknown, BCM4702)",
392                .buttons        = {
393                        { .name = "reset",      .gpio = 1 << 6 },
394                },
395                .leds           = {
396                        { .name = "power",      .gpio = 1 << 0, .polarity = REVERSE },
397                },
398        },
399        [WL700GE] = {
400                .name           = "ASUS WL-700gE",
401                .buttons        = {
402                        { .name = "reset",      .gpio = 1 << 7 }, // on back, hardwired, always resets device regardless OS state
403                        { .name = "ses",        .gpio = 1 << 4 }, // on back, actual name ezsetup
404                        { .name = "power",      .gpio = 1 << 0 }, // on front
405                        { .name = "copy",       .gpio = 1 << 6 }, // on front
406                },
407                .leds           = {
408#if 0
409                        // GPIO that controls power led also enables/disables some essential functions
410                        // - power to HDD
411                        // - switch leds
412                        { .name = "power",      .gpio = 1 << 3, .polarity = NORMAL },  // actual name power
413#endif
414                        { .name = "diag",       .gpio = 1 << 1, .polarity = REVERSE }, // actual name ready
415                },
416                .platform_init = bcm4780_init,
417        },
418        /* Buffalo */
419        [WHR_G54S] = {
420                .name           = "Buffalo WHR-G54S",
421                .buttons        = {
422                        { .name = "reset",      .gpio = 1 << 4 },
423                        { .name = "bridge",     .gpio = 1 << 5 },
424                        { .name = "ses",        .gpio = 1 << 0 },
425                },
426                .leds           = {
427                        { .name = "diag",       .gpio = 1 << 7, .polarity = REVERSE },
428                        { .name = "internal",   .gpio = 1 << 3, .polarity = REVERSE },
429                        { .name = "ses",        .gpio = 1 << 6, .polarity = REVERSE },
430                        { .name = "bridge",     .gpio = 1 << 1, .polarity = REVERSE },
431                        { .name = "wlan",       .gpio = 1 << 2, .polarity = REVERSE },
432                },
433        },
434        [WBR2_G54] = {
435                .name           = "Buffalo WBR2-G54",
436                /* FIXME: verify */
437                .buttons        = {
438                        { .name = "reset",      .gpio = 1 << 7 },
439                },
440                .leds           = {
441                        { .name = "diag",       .gpio = 1 << 1, .polarity = REVERSE },
442                },
443        },
444        [WHR_HP_G54] = {
445                .name           = "Buffalo WHR-HP-G54",
446                .buttons        = {
447                        { .name = "reset",      .gpio = 1 << 4 },
448                        { .name = "bridge",     .gpio = 1 << 5 },
449                        { .name = "ses",        .gpio = 1 << 0 },
450                },
451                .leds           = {
452                        { .name = "diag",       .gpio = 1 << 7, .polarity = REVERSE },
453                        { .name = "internal",   .gpio = 1 << 3, .polarity = REVERSE },
454                        { .name = "bridge",     .gpio = 1 << 1, .polarity = REVERSE },
455                        { .name = "ses",        .gpio = 1 << 6, .polarity = REVERSE },
456                        { .name = "wlan",       .gpio = 1 << 2, .polarity = REVERSE },
457                },
458        },
459        [WHR_G125] = {
460                .name           = "Buffalo WHR-G125",
461                .buttons        = {
462                        { .name = "reset",      .gpio = 1 << 4 },
463                        { .name = "bridge",     .gpio = 1 << 5 },
464                        { .name = "ses",        .gpio = 1 << 0 },
465                },
466                .leds           = {
467                        { .name = "diag",       .gpio = 1 << 7, .polarity = REVERSE },
468                        { .name = "internal",   .gpio = 1 << 3, .polarity = REVERSE },
469                        { .name = "bridge",     .gpio = 1 << 1, .polarity = REVERSE },
470                        { .name = "ses",        .gpio = 1 << 6, .polarity = REVERSE },
471                        { .name = "wlan",       .gpio = 1 << 2, .polarity = REVERSE },
472                },
473        },
474        [WHR2_A54G54] = {
475                .name           = "Buffalo WHR2-A54G54",
476                .buttons        = {
477                        { .name = "reset",      .gpio = 1 << 4 },
478                },
479                .leds           = {
480                        { .name = "diag",       .gpio = 1 << 7, .polarity = REVERSE },
481                },
482        },
483        [WLA2_G54L] = {
484                .name           = "Buffalo WLA2-G54L",
485                /* FIXME: verify */
486                .buttons        = {
487                        { .name = "reset",      .gpio = 1 << 7 },
488                },
489                .leds           = {
490                        { .name = "diag",       .gpio = 1 << 1, .polarity = REVERSE },
491                },
492        },
493        [WZR_G300N] = {
494                .name           = "Buffalo WZR-G300N",
495                .buttons        = {
496                        { .name = "reset",      .gpio = 1 << 4 },
497                },
498                .leds           = {
499                        { .name = "diag",       .gpio = 1 << 7, .polarity = REVERSE },
500                        { .name = "bridge",     .gpio = 1 << 1, .polarity = REVERSE },
501                        { .name = "ses",        .gpio = 1 << 6, .polarity = REVERSE },
502                },
503        },
504        [WZR_RS_G54] = {
505                .name           = "Buffalo WZR-RS-G54",
506                .buttons        = {
507                        { .name = "ses",        .gpio = 1 << 0 },
508                        { .name = "reset",      .gpio = 1 << 4 },
509                },
510                .leds           = {
511                        { .name = "diag",       .gpio = 1 << 7, .polarity = REVERSE },
512                        { .name = "ses",        .gpio = 1 << 6, .polarity = REVERSE },
513                        { .name = "vpn",        .gpio = 1 << 1, .polarity = REVERSE },
514                },
515        },
516        [WZR_RS_G54HP] = {
517                .name           = "Buffalo WZR-RS-G54HP",
518                .buttons        = {
519                        { .name = "ses",        .gpio = 1 << 0 },
520                        { .name = "reset",      .gpio = 1 << 4 },
521                },
522                .leds           = {
523                        { .name = "diag",       .gpio = 1 << 7, .polarity = REVERSE },
524                        { .name = "ses",        .gpio = 1 << 6, .polarity = REVERSE },
525                        { .name = "vpn",        .gpio = 1 << 1, .polarity = REVERSE },
526                },
527        },
528        [BUFFALO_UNKNOWN] = {
529                .name           = "Buffalo (unknown)",
530                .buttons        = {
531                        { .name = "reset",      .gpio = 1 << 7 },
532                },
533                .leds           = {
534                        { .name = "diag",       .gpio = 1 << 1, .polarity = REVERSE },
535                },
536        },
537        [BUFFALO_UNKNOWN_4710] = {
538                .name           = "Buffalo (unknown, BCM4710)",
539                .buttons        = {
540                        { .name = "reset",      .gpio = 1 << 4 },
541                },
542                .leds           = {
543                        { .name = "diag",       .gpio = 1 << 1, .polarity = REVERSE },
544                },
545        },
546        /* Siemens */
547        [SE505V1] = {
548                .name           = "Siemens SE505 V1",
549                .buttons        = {
550                        /* No usable buttons */
551                },
552                .leds           = {
553//                      { .name = "power",      .gpio = 1 << 0  .polarity = REVERSE },  // Usable when retrofitting D26 (?)
554                        { .name = "dmz",        .gpio = 1 << 4, .polarity = REVERSE },  // actual name WWW
555                        { .name = "wlan",       .gpio = 1 << 3, .polarity = REVERSE },
556                },
557        },
558        [SE505V2] = {
559                .name           = "Siemens SE505 V2",
560                .buttons        = {
561                        /* No usable buttons */
562                },
563                .leds           = {
564                        { .name = "power",      .gpio = 1 << 5, .polarity = REVERSE },
565                        { .name = "dmz",        .gpio = 1 << 0, .polarity = REVERSE },  // actual name WWW
566                        { .name = "wlan",       .gpio = 1 << 3, .polarity = REVERSE },
567                },
568        },
569        /* US Robotics */
570        [USR5461] = {
571                .name           = "U.S. Robotics USR5461",
572                .buttons        = {
573                        /* No usable buttons */
574                },
575                .leds           = {
576                        { .name = "wlan",       .gpio = 1 << 0, .polarity = REVERSE },
577                        { .name = "printer",    .gpio = 1 << 1, .polarity = REVERSE },
578                },
579        },
580        /* Dell */
581        [TM2300] = {
582                .name           = "Dell TrueMobile 2300",
583                .buttons        = {
584                        { .name = "reset",      .gpio = 1 << 0 },
585                },
586                .leds           = {
587                        { .name = "wlan",       .gpio = 1 << 6, .polarity = REVERSE },
588                        { .name = "power",      .gpio = 1 << 7, .polarity = REVERSE },
589                },
590        },
591        [TM2300V2] = {
592                .name           = "Dell TrueMobile 2300 v2",
593                .buttons        = {
594                        { .name = "reset",      .gpio = 1 << 0 },
595                },
596                .leds           = {
597                        { .name = "wlan",       .gpio = 1 << 6, .polarity = REVERSE },
598                        { .name = "power",      .gpio = 1 << 7, .polarity = REVERSE },
599                },
600        },
601        /* Motorola */
602        [WE800G] = {
603                .name           = "Motorola WE800G",
604                .buttons        = {
605                        { .name = "reset",      .gpio = 1 << 0 },
606                },
607                .leds           = {
608                        { .name = "power",      .gpio = 1 << 4, .polarity = NORMAL },
609                        { .name = "diag",       .gpio = 1 << 2, .polarity = REVERSE },
610                        { .name = "wlan_amber", .gpio = 1 << 1, .polarity = NORMAL },
611                },
612        },
613        [WR850GV1] = {
614                .name           = "Motorola WR850G V1",
615                .buttons        = {
616                        { .name = "reset",      .gpio = 1 << 0 },
617                },
618                .leds           = {
619                        { .name = "power",      .gpio = 1 << 4, .polarity = NORMAL },
620                        { .name = "diag",       .gpio = 1 << 3, .polarity = REVERSE },
621                        { .name = "dmz",        .gpio = 1 << 6, .polarity = NORMAL },
622                        { .name = "wlan_red",   .gpio = 1 << 5, .polarity = REVERSE },
623                        { .name = "wlan_green", .gpio = 1 << 7, .polarity = REVERSE },
624                },
625        },
626        [WR850GV2V3] = {
627                .name           = "Motorola WR850G V2/V3",
628                .buttons        = {
629                        { .name = "reset",      .gpio = 1 << 5 },
630                },
631                .leds           = {
632                        { .name = "power",      .gpio = 1 << 1, .polarity = NORMAL },
633                        { .name = "wlan",       .gpio = 1 << 0, .polarity = REVERSE },
634                        { .name = "wan",        .gpio = 1 << 6, .polarity = INPUT },
635                        { .name = "diag",       .gpio = 1 << 7, .polarity = REVERSE },
636                },
637        },
638        [WR850GP] = {
639                .name           = "Motorola WR850GP",
640                .buttons        = {
641                        { .name = "reset",      .gpio = 1 << 5 },
642                },
643                .leds           = {
644                        { .name = "power",      .gpio = 1 << 1, .polarity = NORMAL },
645                        { .name = "wlan",       .gpio = 1 << 0, .polarity = REVERSE },
646                        { .name = "dmz",        .gpio = 1 << 6, .polarity = REVERSE },
647                        { .name = "diag",       .gpio = 1 << 7, .polarity = REVERSE },
648                },
649        },
650
651        /* Belkin */
652        [BELKIN_UNKNOWN] = {
653                .name           = "Belkin (unknown)",
654                /* FIXME: verify & add detection */
655                .buttons        = {
656                        { .name = "reset",      .gpio = 1 << 7 },
657                },
658                .leds           = {
659                        { .name = "power",      .gpio = 1 << 5, .polarity = NORMAL },
660                        { .name = "wlan",       .gpio = 1 << 3, .polarity = NORMAL },
661                        { .name = "connected",  .gpio = 1 << 0, .polarity = NORMAL },
662                },
663        },
664        /* Netgear */
665        [WGT634U] = {
666                .name           = "Netgear WGT634U",
667                .buttons        = {
668                        { .name = "reset",      .gpio = 1 << 2 },
669                },
670                .leds           = {
671                        { .name = "power",      .gpio = 1 << 3, .polarity = NORMAL },
672                },
673        },
674        /* Trendware */
675        [TEW411BRPP] = {
676                .name           = "Trendware TEW411BRP+",
677                .buttons        = {
678                        { /* No usable buttons */ },
679                },
680                .leds           = {
681                        { .name = "power",      .gpio = 1 << 7, .polarity = NORMAL },
682                        { .name = "wlan",       .gpio = 1 << 1, .polarity = NORMAL },
683                        { .name = "bridge",     .gpio = 1 << 6, .polarity = NORMAL },
684                },
685        },
686        /* SimpleTech */
687        [STI_NAS] = {
688                .name      = "SimpleTech SimpleShare NAS",
689                .buttons        = {
690                        { .name = "reset",      .gpio = 1 << 7 }, // on back, hardwired, always resets device regardless OS state
691                        { .name = "power",      .gpio = 1 << 0 }, // on back
692                },
693                .leds      = {
694                        { .name = "diag",       .gpio = 1 << 1, .polarity = REVERSE }, // actual name ready
695                },
696                .platform_init = bcm4780_init,
697        },
698        /* D-Link */
699        [DIR130] = {
700                .name     = "D-Link DIR-130",
701                .buttons        = {
702                        { .name = "reset",      .gpio = 1 << 3},
703                        { .name = "reserved",   .gpio = 1 << 7},
704                },
705                .leds      = {
706                        { .name = "diag",       .gpio = 1 << 0},
707                        { .name = "blue",       .gpio = 1 << 6},
708                },
709        },
710        [DIR330] = {
711                .name     = "D-Link DIR-330",
712                .buttons        = {
713                        { .name = "reset",      .gpio = 1 << 3},
714                        { .name = "reserved",   .gpio = 1 << 7},
715                },
716                .leds      = {
717                        { .name = "diag",       .gpio = 1 << 0},
718                        { .name = "usb",        .gpio = 1 << 4},
719                        { .name = "blue",       .gpio = 1 << 6},
720                },
721        },
722        [DWL3150] = {
723                .name   = "D-Link DWL-3150",
724                .buttons        = {
725                        { .name = "reset",      .gpio = 1 << 7},
726                },
727                .leds     = {
728                        { .name = "diag",       .gpio = 1 << 2},
729                        { .name = "status",     .gpio = 1 << 1},
730                },
731        },
732        /* Double check */
733        [WL105B] = {
734                .name   = "Sitecom WL-105b",
735                .buttons        = {
736                        { .name = "reset",      .gpio = 1 << 10},
737                },
738                .leds     = {
739                        { .name = "wlan",       .gpio = 1 << 4},
740                        { .name = "power",      .gpio = 1 << 3},
741                },
742        },
743};
744
745static struct platform_t __init *platform_detect(void)
746{
747        char *boardnum, *boardtype, *buf;
748
749        if (strcmp(getvar("nvram_type"), "cfe") == 0)
750                return &platforms[WGT634U];
751
752        /* Look for a model identifier */
753
754        /* Based on "model_name" */
755        if ((buf = nvram_get("model_name"))) {
756                if (!strcmp(buf, "DIR-130"))
757                        return &platforms[DIR130];
758                if (!strcmp(buf, "DIR-330"))
759                        return &platforms[DIR330];
760        }
761
762        /* Based on "model_no" */
763        if ((buf = nvram_get("model_no"))) {
764                if (startswith(buf,"WL700")) /* WL700* */
765                        return &platforms[WL700GE];
766        }
767
768        /* Based on "hardware_version" */
769        if ((buf = nvram_get("hardware_version"))) {
770                if (startswith(buf,"WL500GPV2-")) /* WL500GPV2-* */
771                        return &platforms[WL500GPV2];
772                if (startswith(buf,"WL520GC-")) /* WL520GU-* */
773                        return &platforms[WL520GC];
774                if (startswith(buf,"WL520GU-")) /* WL520GU-* */
775                        return &platforms[WL520GU];
776                if (startswith(buf,"WL330GE-")) /* WL330GE-* */
777                        return &platforms[WL330GE];
778        }
779
780        /* Based on "ModelId" */
781        if ((buf = nvram_get("ModelId"))) {
782                if (!strcmp(buf, "WR850GP"))
783                        return &platforms[WR850GP];
784                if (!strcmp(buf, "WX-5565") && !strcmp(getvar("boardtype"),"bcm94710ap"))
785                        return &platforms[TM2300]; /* Dell TrueMobile 2300 */
786                if (startswith(buf,"WE800G")) /* WE800G* */
787                        return &platforms[WE800G];
788        }
789
790        /* Buffalo */
791        if ((buf = (nvram_get("melco_id") ?: nvram_get("buffalo_id")))) {
792                /* Buffalo hardware, check id for specific hardware matches */
793                if (!strcmp(buf, "29bb0332"))
794                        return &platforms[WBR2_G54];
795                if (!strcmp(buf, "29129"))
796                        return &platforms[WLA2_G54L];
797                if (!strcmp(buf, "30189"))
798                        return &platforms[WHR_HP_G54];
799                if (!strcmp(buf, "32093"))
800                        return &platforms[WHR_G125];
801                if (!strcmp(buf, "30182"))
802                        return &platforms[WHR_G54S];
803                if (!strcmp(buf, "290441dd"))
804                        return &platforms[WHR2_A54G54];
805                if (!strcmp(buf, "31120"))
806                        return &platforms[WZR_G300N];
807                if (!strcmp(buf, "30083"))
808                        return &platforms[WZR_RS_G54];
809                if (!strcmp(buf, "30103"))
810                        return &platforms[WZR_RS_G54HP];
811        }
812
813        /* no easy model number, attempt to guess */
814        boardnum = getvar("boardnum");
815        boardtype = getvar("boardtype");
816
817        if (!strcmp(boardnum, "20070615")) { /* Linksys WRT600N  v1/V1.1 */
818                if (!strcmp(boardtype, "0x478") && !strcmp(getvar("cardbus"), "0") && !strcmp(getvar("switch_type"),"BCM5395"))
819                        return &platforms[WRT600NV11];
820
821        if (!strcmp(boardtype, "0x478") && !strcmp(getvar("cardbus"), "0"))
822                        return &platforms[WRT600N];
823        }
824
825        if (startswith(getvar("pmon_ver"), "CFE")) {
826                /* CFE based - newer hardware */
827                if (!strcmp(boardnum, "42")) { /* Linksys */
828                        if (!strcmp(boardtype, "0x478") && !strcmp(getvar("cardbus"), "1"))
829                                return &platforms[WRT350N];
830
831                        if (!strcmp(boardtype, "0x0101") && !strcmp(getvar("boot_ver"), "v3.6"))
832                                return &platforms[WRT54G3G];
833
834                        if (!strcmp(getvar("et1phyaddr"),"5") && !strcmp(getvar("et1mdcport"), "1"))
835                                return &platforms[WRTSL54GS];
836
837                        /* default to WRT54G */
838                        return &platforms[WRT54G];
839                }
840
841                if (!strcmp(boardnum, "44") || !strcmp(boardnum, "44\r")) {
842                        if (!strcmp(boardtype,"0x0101") || !strcmp(boardtype, "0x0101\r"))
843                                return &platforms[TM2300V2]; /* Dell TrueMobile 2300 v2 */
844                }
845
846                if (!strcmp(boardnum, "45")) { /* ASUS */
847                        if (!strcmp(boardtype,"0x042f"))
848                                return &platforms[WL500GP];
849                        else if (!strcmp(boardtype,"0x0472"))
850                                return &platforms[WL500W];
851                        else if (!strcmp(boardtype,"0x467"))
852                                return &platforms[WL320GE];
853                        else
854                                return &platforms[WL500GD];
855                }
856
857                if (!strcmp(boardnum, "10496"))
858                        return &platforms[USR5461];
859
860                if (!strcmp(getvar("boardtype"), "0x0101") && !strcmp(getvar("boardrev"), "0x10")) /* SE505V2 With Modified CFE */
861                        return &platforms[SE505V2];
862
863        } else { /* PMON based - old stuff */
864                if ((simple_strtoul(getvar("GemtekPmonVer"), NULL, 0) == 9) &&
865                        (simple_strtoul(getvar("et0phyaddr"), NULL, 0) == 30)) {
866                        return &platforms[WR850GV1];
867                }
868                if (startswith(boardtype, "bcm94710dev")) {
869                        if (!strcmp(boardnum, "42"))
870                                return &platforms[WRT54GV1];
871                        if (simple_strtoul(boardnum, NULL, 0) == 2)
872                                return &platforms[WAP54GV1];
873                }
874                if (startswith(getvar("hardware_version"), "WL500-"))
875                        return &platforms[WL500G];
876                if (startswith(getvar("hardware_version"), "WL300-")) {
877                        /* Either WL-300g or WL-HDD, do more extensive checks */
878                        if ((simple_strtoul(getvar("et0phyaddr"), NULL, 0) == 0) &&
879                                (simple_strtoul(getvar("et1phyaddr"), NULL, 0) == 1))
880                                return &platforms[WLHDD];
881                        if ((simple_strtoul(getvar("et0phyaddr"), NULL, 0) == 0) &&
882                                (simple_strtoul(getvar("et1phyaddr"), NULL, 0) == 10))
883                                return &platforms[WL300G];
884                }
885                /* Sitecom WL-105b */
886                if (startswith(boardnum, "2") && simple_strtoul(getvar("GemtekPmonVer"), NULL, 0) == 1)
887                        return &platforms[WL105B];
888
889                /* unknown asus stuff, probably bcm4702 */
890                if (startswith(boardnum, "asusX"))
891                        return &platforms[ASUS_4702];
892        }
893
894        if (buf || !strcmp(boardnum, "00")) {/* probably buffalo */
895                if (startswith(boardtype, "bcm94710ap"))
896                        return &platforms[BUFFALO_UNKNOWN_4710];
897                else
898                        return &platforms[BUFFALO_UNKNOWN];
899        }
900
901        if (startswith(getvar("CFEver"), "MotoWRv2") ||
902                startswith(getvar("CFEver"), "MotoWRv3") ||
903                !strcmp(getvar("MOTO_BOARD_TYPE"), "WR_FEM1")) {
904
905                return &platforms[WR850GV2V3];
906        }
907
908        if (!strcmp(boardnum, "44") && !strcmp(getvar("boardflags"),"0x0388")) {  /* Trendware TEW-411BRP+ */
909                return &platforms[TEW411BRPP];
910        }
911
912        if (startswith(boardnum, "04FN52")) /* SimpleTech SimpleShare */
913                return &platforms[STI_NAS];
914
915        if (!strcmp(getvar("boardnum"), "10") && !strcmp(getvar("boardrev"), "0x13")) /* D-Link DWL-3150 */
916                return &platforms[DWL3150];
917
918        /* not found */
919        return NULL;
920}
921
922static void register_buttons(struct button_t *b)
923{
924        for (; b->name; b++)
925                platform.button_mask |= b->gpio;
926
927        platform.button_mask &= ~gpiomask;
928
929        gpio_outen(platform.button_mask, 0);
930        gpio_control(platform.button_mask, 0);
931        platform.button_polarity = gpio_in() & platform.button_mask;
932        gpio_intpolarity(platform.button_mask, platform.button_polarity);
933        gpio_setintmask(platform.button_mask, platform.button_mask);
934
935        gpio_set_irqenable(1, button_handler);
936}
937
938static void unregister_buttons(struct button_t *b)
939{
940        gpio_setintmask(platform.button_mask, 0);
941
942        gpio_set_irqenable(0, button_handler);
943}
944
945
946#ifndef LINUX_2_4
947static void add_msg(struct event_t *event, char *msg, int argv)
948{
949        char *s;
950
951        if (argv)
952                return;
953
954        s = skb_put(event->skb, strlen(msg) + 1);
955        strcpy(s, msg);
956}
957
958static void hotplug_button(struct work_struct *work)
959{
960        struct event_t *event = container_of(work, struct event_t, wq);
961        char *s;
962
963        if (!uevent_sock)
964                return;
965
966        event->skb = alloc_skb(2048, GFP_KERNEL);
967
968        s = skb_put(event->skb, strlen(event->action) + 2);
969        sprintf(s, "%s@", event->action);
970        fill_event(event);
971
972        NETLINK_CB(event->skb).dst_group = 1;
973        netlink_broadcast(uevent_sock, event->skb, 0, 1, GFP_KERNEL);
974
975        kfree(event);
976}
977
978#else /* !LINUX_2_4 */
979static inline char *kzalloc(unsigned int size, unsigned int gfp)
980{
981        char *p;
982
983        p = kmalloc(size, gfp);
984        if (p == NULL)
985                return NULL;
986
987        memset(p, 0, size);
988
989        return p;
990}
991
992static void add_msg(struct event_t *event, char *msg, int argv)
993{
994        if (argv)
995                event->argv[event->anr++] = event->scratch;
996        else
997                event->envp[event->enr++] = event->scratch;
998
999        event->scratch += sprintf(event->scratch, "%s", msg) + 1;
1000}
1001
1002static void hotplug_button(struct event_t *event)
1003{
1004        char *scratch = kzalloc(256, GFP_KERNEL);
1005        event->scratch = scratch;
1006
1007        add_msg(event, hotplug_path, 1);
1008        add_msg(event, "button", 1);
1009        fill_event(event);
1010        call_usermodehelper (event->argv[0], event->argv, event->envp);
1011        kfree(scratch);
1012        kfree(event);
1013}
1014#endif /* !LINUX_2_4 */
1015
1016static int fill_event (struct event_t *event)
1017{
1018        static char buf[128];
1019
1020        add_msg(event, "HOME=/", 0);
1021        add_msg(event, "PATH=/sbin:/bin:/usr/sbin:/usr/bin", 0);
1022        add_msg(event, "SUBSYSTEM=button", 0);
1023        snprintf(buf, 128, "ACTION=%s", event->action);
1024        add_msg(event, buf, 0);
1025        snprintf(buf, 128, "BUTTON=%s", event->name);
1026        add_msg(event, buf, 0);
1027        snprintf(buf, 128, "SEEN=%ld", event->seen);
1028        add_msg(event, buf, 0);
1029#ifndef LINUX_2_4
1030        snprintf(buf, 128, "SEQNUM=%llu", uevent_next_seqnum());
1031        add_msg(event, buf, 0);
1032#endif
1033
1034        return 0;
1035}
1036
1037
1038#ifndef LINUX_2_4
1039static irqreturn_t button_handler(int irq, void *dev_id)
1040#else
1041static irqreturn_t button_handler(int irq, void *dev_id, struct pt_regs *regs)
1042#endif
1043{
1044        struct button_t *b;
1045        u32 in, changed;
1046
1047        in = gpio_in() & platform.button_mask;
1048        gpio_intpolarity(platform.button_mask, in);
1049        changed = platform.button_polarity ^ in;
1050        platform.button_polarity = in;
1051
1052        changed &= ~gpio_outen(0, 0);
1053
1054        for (b = platform.buttons; b->name; b++) {
1055                struct event_t *event;
1056
1057                if (!(b->gpio & changed)) continue;
1058
1059                b->pressed ^= 1;
1060
1061                if ((event = (struct event_t *)kzalloc (sizeof(struct event_t), GFP_ATOMIC))) {
1062                        event->seen = (jiffies - b->seen)/HZ;
1063                        event->name = b->name;
1064                        event->action = b->pressed ? "pressed" : "released";
1065#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
1066                        INIT_WORK(&event->wq, (void *)(void *)hotplug_button);
1067#else
1068                        INIT_WORK(&event->wq, (void *)(void *)hotplug_button, (void *)event);
1069#endif
1070                        schedule_work(&event->wq);
1071                }
1072
1073                b->seen = jiffies;
1074        }
1075        return IRQ_HANDLED;
1076}
1077
1078static void register_leds(struct led_t *l)
1079{
1080        struct proc_dir_entry *p;
1081        u32 mask = 0;
1082        u32 oe_mask = 0;
1083        u32 val = 0;
1084
1085        leds = proc_mkdir("led", diag);
1086        if (!leds)
1087                return;
1088
1089        for(; l->name; l++) {
1090                if (l->gpio & gpiomask)
1091                        continue;
1092
1093                if (l->gpio & GPIO_TYPE_EXTIF) {
1094                        l->state = 0;
1095                        set_led_extif(l);
1096                } else {
1097                        if (l->polarity != INPUT) oe_mask |= l->gpio;
1098                        mask |= l->gpio;
1099                        val |= (l->polarity == NORMAL)?0:l->gpio;
1100                }
1101
1102                if (l->polarity == INPUT) continue;
1103
1104                if ((p = create_proc_entry(l->name, S_IRUSR, leds))) {
1105                        l->proc.type = PROC_LED;
1106                        l->proc.ptr = l;
1107                        p->data = (void *) &l->proc;
1108                        p->proc_fops = &diag_proc_fops;
1109                }
1110        }
1111
1112        gpio_outen(mask, oe_mask);
1113        gpio_control(mask, 0);
1114        gpio_out(mask, val);
1115        gpio_setintmask(mask, 0);
1116}
1117
1118static void unregister_leds(struct led_t *l)
1119{
1120        for(; l->name; l++)
1121                remove_proc_entry(l->name, leds);
1122
1123        remove_proc_entry("led", diag);
1124}
1125
1126static void set_led_extif(struct led_t *led)
1127{
1128        gpio_set_extif(led->gpio, led->state);
1129}
1130
1131static void led_flash(unsigned long dummy) {
1132        struct led_t *l;
1133        u32 mask = 0;
1134        u8 extif_blink = 0;
1135
1136        for (l = platform.leds; l->name; l++) {
1137                if (l->flash) {
1138                        if (l->gpio & GPIO_TYPE_EXTIF) {
1139                                extif_blink = 1;
1140                                l->state = !l->state;
1141                                set_led_extif(l);
1142                        } else {
1143                                mask |= l->gpio;
1144                        }
1145                }
1146        }
1147
1148        mask &= ~gpiomask;
1149        if (mask) {
1150                u32 val = ~gpio_in();
1151
1152                gpio_outen(mask, mask);
1153                gpio_control(mask, 0);
1154                gpio_out(mask, val);
1155        }
1156        if (mask || extif_blink) {
1157                mod_timer(&led_timer, jiffies + FLASH_TIME);
1158        }
1159}
1160
1161static ssize_t diag_proc_read(struct file *file, char *buf, size_t count, loff_t *ppos)
1162{
1163#ifdef LINUX_2_4
1164        struct inode *inode = file->f_dentry->d_inode;
1165        struct proc_dir_entry *dent = inode->u.generic_ip;
1166#else
1167        struct proc_dir_entry *dent = PDE(file->f_dentry->d_inode);
1168#endif
1169        char *page;
1170        int len = 0;
1171
1172        if ((page = kmalloc(1024, GFP_KERNEL)) == NULL)
1173                return -ENOBUFS;
1174
1175        if (dent->data != NULL) {
1176                struct prochandler_t *handler = (struct prochandler_t *) dent->data;
1177                switch (handler->type) {
1178                        case PROC_LED: {
1179                                struct led_t * led = (struct led_t *) handler->ptr;
1180                                if (led->flash) {
1181                                        len = sprintf(page, "f\n");
1182                                } else {
1183                                        if (led->gpio & GPIO_TYPE_EXTIF) {
1184                                                len = sprintf(page, "%d\n", led->state);
1185                                        } else {
1186                                                u32 in = (gpio_in() & led->gpio ? 1 : 0);
1187                                                u8 p = (led->polarity == NORMAL ? 0 : 1);
1188                                                len = sprintf(page, "%d\n", ((in ^ p) ? 1 : 0));
1189                                        }
1190                                }
1191                                break;
1192                        }
1193                        case PROC_MODEL:
1194                                len = sprintf(page, "%s\n", platform.name);
1195                                break;
1196                        case PROC_GPIOMASK:
1197                                len = sprintf(page, "0x%04x\n", gpiomask);
1198                                break;
1199                }
1200        }
1201        len += 1;
1202
1203        if (*ppos < len) {
1204                len = min_t(int, len - *ppos, count);
1205                if (copy_to_user(buf, (page + *ppos), len)) {
1206                        kfree(page);
1207                        return -EFAULT;
1208                }
1209                *ppos += len;
1210        } else {
1211                len = 0;
1212        }
1213
1214        kfree(page);
1215        return len;
1216}
1217
1218
1219static ssize_t diag_proc_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
1220{
1221#ifdef LINUX_2_4
1222        struct inode *inode = file->f_dentry->d_inode;
1223        struct proc_dir_entry *dent = inode->u.generic_ip;
1224#else
1225        struct proc_dir_entry *dent = PDE(file->f_dentry->d_inode);
1226#endif
1227        char *page;
1228        int ret = -EINVAL;
1229
1230        if ((page = kmalloc(count + 1, GFP_KERNEL)) == NULL)
1231                return -ENOBUFS;
1232
1233        if (copy_from_user(page, buf, count)) {
1234                kfree(page);
1235                return -EINVAL;
1236        }
1237        page[count] = 0;
1238
1239        if (dent->data != NULL) {
1240                struct prochandler_t *handler = (struct prochandler_t *) dent->data;
1241                switch (handler->type) {
1242                        case PROC_LED: {
1243                                struct led_t *led = (struct led_t *) handler->ptr;
1244                                int p = (led->polarity == NORMAL ? 0 : 1);
1245
1246                                if (page[0] == 'f') {
1247                                        led->flash = 1;
1248                                        led_flash(0);
1249                                } else {
1250                                        led->flash = 0;
1251                                        if (led->gpio & GPIO_TYPE_EXTIF) {
1252                                                led->state = p ^ ((page[0] == '1') ? 1 : 0);
1253                                                set_led_extif(led);
1254                                        } else {
1255                                                gpio_outen(led->gpio, led->gpio);
1256                                                gpio_control(led->gpio, 0);
1257                                                gpio_out(led->gpio, ((p ^ (page[0] == '1')) ? led->gpio : 0));
1258                                        }
1259                                }
1260                                break;
1261                        }
1262                        case PROC_GPIOMASK:
1263                                gpiomask = simple_strtoul(page, NULL, 0);
1264
1265                                if (platform.buttons) {
1266                                        unregister_buttons(platform.buttons);
1267                                        register_buttons(platform.buttons);
1268                                }
1269
1270                                if (platform.leds) {
1271                                        unregister_leds(platform.leds);
1272                                        register_leds(platform.leds);
1273                                }
1274                                break;
1275                }
1276                ret = count;
1277        }
1278
1279        kfree(page);
1280        return ret;
1281}
1282
1283static int __init diag_init(void)
1284{
1285        static struct proc_dir_entry *p;
1286        static struct platform_t *detected;
1287
1288        detected = platform_detect();
1289        if (!detected) {
1290                printk(MODULE_NAME ": Router model not detected.\n");
1291                return -ENODEV;
1292        }
1293        memcpy(&platform, detected, sizeof(struct platform_t));
1294
1295        printk(MODULE_NAME ": Detected '%s'\n", platform.name);
1296        if (platform.platform_init != NULL) {
1297                platform.platform_init();
1298        }
1299
1300        if (!(diag = proc_mkdir("diag", NULL))) {
1301                printk(MODULE_NAME ": proc_mkdir on /proc/diag failed\n");
1302                return -EINVAL;
1303        }
1304
1305        if ((p = create_proc_entry("model", S_IRUSR, diag))) {
1306                p->data = (void *) &proc_model;
1307                p->proc_fops = &diag_proc_fops;
1308        }
1309
1310        if ((p = create_proc_entry("gpiomask", S_IRUSR | S_IWUSR, diag))) {
1311                p->data = (void *) &proc_gpiomask;
1312                p->proc_fops = &diag_proc_fops;
1313        }
1314
1315        if (platform.buttons)
1316                register_buttons(platform.buttons);
1317
1318        if (platform.leds)
1319                register_leds(platform.leds);
1320
1321        return 0;
1322}
1323
1324static void __exit diag_exit(void)
1325{
1326        del_timer(&led_timer);
1327
1328        if (platform.buttons)
1329                unregister_buttons(platform.buttons);
1330
1331        if (platform.leds)
1332                unregister_leds(platform.leds);
1333
1334        remove_proc_entry("model", diag);
1335        remove_proc_entry("gpiomask", diag);
1336        remove_proc_entry("diag", NULL);
1337}
1338
1339module_init(diag_init);
1340module_exit(diag_exit);
1341
1342MODULE_AUTHOR("Mike Baker, Felix Fietkau / OpenWrt.org");
1343MODULE_LICENSE("GPL");
Note: See TracBrowser for help on using the repository browser.