Add support for the Asus power led, closes #349
[openwrt.git] / package / diag / src / diag.c
1 /*
2  * diag_led.c - replacement diag module
3  *
4  * Copyright (C) 2004 Mike Baker,
5  *                    Imre Kaloz <kaloz@dune.hu>
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$
22  */
23
24 /*
25  * ChangeLog:
26  * 2004/03/28 initial release 
27  * 2004/08/26 asus & buffalo support added
28  * 2005/03/14 asus wl-500g deluxe and buffalo v2 support added
29  * 2005/04/13 added licensing informations
30  * 2005/04/18 base reset polarity off initial readings
31  * 2006/02/07 motorola wa840g/we800g support added
32  * 2006/08/18 asus power led support added
33  */
34
35 #include <linux/module.h>
36 #include <linux/init.h>
37 #include <linux/kernel.h>
38 #include <linux/sysctl.h>
39 #include <asm/io.h>
40 #include <typedefs.h>
41 #include <osl.h>
42 #include <bcmdevs.h>
43 #include <sbutils.h>
44
45 extern char * nvram_get(const char *name);
46 static void *sbh;
47
48 // v2.x - - - - -
49 #define DIAG_GPIO (1<<1)
50 #define DMZ_GPIO  (1<<7)
51
52 static void set_gpio(uint32 mask, uint32 value) {
53         sb_gpiocontrol(sbh,mask, 0, GPIO_DRV_PRIORITY);
54         sb_gpioouten(sbh,mask,mask,GPIO_DRV_PRIORITY);
55         sb_gpioout(sbh,mask,value,GPIO_DRV_PRIORITY);
56 }
57
58 static void v2_set_diag(u8 state) {
59         set_gpio(DIAG_GPIO,state);
60 }
61 static void v2_set_dmz(u8 state) {
62         set_gpio(DMZ_GPIO,state);
63 }
64
65 // asus wl-500g (+deluxe)
66 #define ASUS_PWR_GPIO (1<<0)
67
68 static void asus_set_pwr(u8 state) {
69         set_gpio(ASUS_PWR_GPIO,state);
70 }
71
72 // v1.x - - - - -
73 #define LED_DIAG   0x13
74 #define LED_DMZ    0x12
75
76 static void v1_set_diag(u8 state) {
77         if (!state) {
78                 *(volatile u8*)(KSEG1ADDR(BCM4710_EUART)+LED_DIAG)=0xFF;
79         } else {
80                 *(volatile u8*)(KSEG1ADDR(BCM4710_EUART)+LED_DIAG);
81         }
82 }
83 static void v1_set_dmz(u8 state) {
84         if (!state) {
85                 *(volatile u8*)(KSEG1ADDR(BCM4710_EUART)+LED_DMZ)=0xFF;
86         } else {
87                 *(volatile u8*)(KSEG1ADDR(BCM4710_EUART)+LED_DMZ);
88         }
89 }
90
91 static void wap1_set_diag(u8 state) {
92        set_gpio(1<<3,state);
93 }
94 static void wap1_set_dmz(u8 state) {
95        set_gpio(1<<4,state);
96 }
97
98 // - - - - -
99 static void ignore(u8 ignored) {};
100
101 // - - - - -
102 #define BIT_DMZ         0x01
103 #define BIT_PWR         0x02
104 #define BIT_DIAG        0x04
105
106 void (*set_diag)(u8 state);
107 void (*set_dmz)(u8 state);
108 void (*set_pwr)(u8 state);
109
110 static unsigned int diag = 0x02; // default: diag off, pwr on, dmz off
111
112 static void diag_change(void)
113 {
114         set_diag(0xFF); // off
115         set_dmz(0xFF); // off
116         set_pwr(0xFF); // off
117
118         if(diag & BIT_DIAG)
119                 set_diag(0x00); // on
120         if(diag & BIT_DMZ)
121                 set_dmz(0x00); // on
122         if (diag & BIT_PWR)
123                 set_pwr(0x00);  //on
124 }
125
126 static int proc_diag(ctl_table *table, int write, struct file *filp,
127                 void *buffer, size_t *lenp)
128 {
129         int r;
130         r = proc_dointvec(table, write, filp, buffer, lenp);
131         if (write && !r) {
132                 diag_change();
133         }
134         return r;
135 }
136
137 // - - - - -
138 static unsigned char reset_gpio = 0;
139 static unsigned char reset_polarity = 0;
140 static unsigned int reset = 0;
141
142 static int proc_reset(ctl_table *table, int write, struct file *filp,
143                 void *buffer, size_t *lenp)
144 {
145
146         if (reset_gpio) {
147                 sb_gpiocontrol(sbh,reset_gpio,reset_gpio,GPIO_DRV_PRIORITY);
148                 sb_gpioouten(sbh,reset_gpio,0,GPIO_DRV_PRIORITY);
149                 reset=!(sb_gpioin(sbh)&reset_gpio);
150
151                 if (reset_polarity) reset=!reset;
152         } else {
153                 reset=0;
154         }
155
156         return proc_dointvec(table, write, filp, buffer, lenp);
157 }
158
159 // - - - - -
160 static struct ctl_table_header *diag_sysctl_header;
161
162 static ctl_table sys_diag[] = {
163          { 
164            ctl_name: 2000,
165            procname: "diag", 
166            data: &diag,
167            maxlen: sizeof(diag), 
168            mode: 0644,
169            proc_handler: proc_diag
170          },
171          {
172            ctl_name: 2001,
173            procname: "reset",
174            data: &reset,
175            maxlen: sizeof(reset),
176            mode: 0444,
177            proc_handler: proc_reset 
178          },
179          { 0 }
180 };
181
182 static int __init diag_init(void)
183 {
184         char *buf;
185         u32 board_type;
186         sbh = (void *)sb_kattach();
187         sb_gpiosetcore(sbh);
188
189         board_type = sb_boardtype(sbh);
190         printk(KERN_INFO "diag boardtype: %08x\n",board_type);
191
192         set_diag=ignore;
193         set_dmz=ignore;
194         set_pwr=ignore;
195         
196         buf=nvram_get("pmon_ver") ?: "";
197         if (((board_type & 0xf00) == 0x400) && (strncmp(buf, "CFE", 3) != 0)) {
198                 buf=nvram_get("boardtype")?:"";
199                 if (!strncmp(buf,"bcm94710dev",11)) {
200                         buf=nvram_get("boardnum")?:"";
201                         if (!strcmp(buf,"42")) {
202                                 // wrt54g v1.x
203                                 set_diag=v1_set_diag;
204                                 set_dmz=v1_set_dmz;
205                                 reset_gpio=(1<<6);
206                         }
207                         if (simple_strtoul(buf, NULL, 0) == 2) {
208                                 // wap54g v1.0
209                                 // do not use strcmp as PMON v5.3.22 has some built-in nvram 
210                                 // defaults with trailing \r
211                                 set_diag=wap1_set_diag;
212                                 // no dmz led on wap54g, used green led 
213                                 // labeled "WLAN Link" instead
214                                 set_dmz=wap1_set_dmz;
215                                 reset_gpio=(1<<0);
216                         }
217                         if (!strcmp(buf,"asusX")) {
218                                 //asus wl-500g
219                                 set_pwr=asus_set_pwr;
220                                 reset_gpio=(1<<6);
221                         }
222                         if (!strcmp(buf,"2")) {
223                                 //wa840g v1 / we800g v1
224                                 reset_gpio=(1<<0);
225                         }
226                 }
227                 if (!strcmp(buf,"bcm94710ap")) {
228                         buf=nvram_get("boardnum")?:"";
229                         if (!strcmp(buf,"42")) {
230                                 // buffalo
231                                 set_dmz=v2_set_dmz;
232                                 reset_gpio=(1<<4);
233                         }
234                         if (!strcmp(buf,"44")) {
235                                 //dell truemobile
236                                 set_dmz=v2_set_dmz;
237                                 reset_gpio=(1<<0);
238                         }
239                 }
240         } else {
241                 buf=nvram_get("boardnum")?:"";
242                 if (!strcmp(buf,"42")) {
243                         //linksys
244                         set_diag=v2_set_diag;
245                         set_dmz=v2_set_dmz;
246                         reset_gpio=(1<<6);
247                 }
248                 if (!strcmp(buf,"44")) {
249                         //motorola
250                         reset_gpio=(1<<5);
251                 }
252                 if (!strcmp(buf,"00")) {
253                         //buffalo
254                         reset_gpio=(1<<7);
255                 }
256                 if (!strcmp(buf,"45")) {
257                         //wl-500g deluxe
258                         set_pwr=asus_set_pwr;
259                         reset_gpio=(1<<6);
260                 }
261         }
262
263         
264         sb_gpiocontrol(sbh,reset_gpio,reset_gpio,GPIO_DRV_PRIORITY);
265         sb_gpioouten(sbh,reset_gpio,0,GPIO_DRV_PRIORITY);
266         reset_polarity=!(sb_gpioin(sbh)&reset_gpio);
267
268         diag_sysctl_header = register_sysctl_table(sys_diag, 0);
269         diag_change();
270
271         return 0;
272 }
273
274 static void __exit diag_exit(void)
275 {
276         unregister_sysctl_table(diag_sysctl_header);
277 }
278
279 EXPORT_NO_SYMBOLS;
280 MODULE_AUTHOR("openwrt.org");
281 MODULE_LICENSE("GPL");
282
283 module_init(diag_init);
284 module_exit(diag_exit);