4 Copyright (C) 2006-2009 Jonathan Zarate
12 #include <sys/types.h>
22 const char *led_names
[] = { "wlan", "diag", "white", "amber", "dmz", "aoss", "bridge", "usb", "5g"};
23 const char *led_modes
[] = { "Off", "On", "Blink", "Probe"};
32 #include <sys/ioctl.h>
33 #include <linux_gpio.h>
35 static int _gpio_ioctl(int f
, int gpioreg
, unsigned int mask
, unsigned int val
)
37 struct gpio_ioctl gpio
;
42 if (ioctl(f
, gpioreg
, &gpio
) < 0) {
43 _dprintf("Invalid gpioreg %d\n", gpioreg
);
49 static int _gpio_open()
51 int f
= open("/dev/gpio", O_RDWR
);
53 _dprintf ("Failed to open /dev/gpio\n");
57 int gpio_open(uint32_t mask
)
63 if ((f
>= 0) && mask
) {
64 for (i
= 0; i
<= 15; i
++) {
66 if ((mask
& bit
) == bit
) {
67 _gpio_ioctl(f
, GPIO_IOC_RESERVE
, bit
, bit
);
68 _gpio_ioctl(f
, GPIO_IOC_OUTEN
, bit
, 0);
78 void gpio_write(uint32_t bit
, int en
)
82 if ((f
= gpio_open(0)) < 0) return;
84 _gpio_ioctl(f
, GPIO_IOC_RESERVE
, bit
, bit
);
85 _gpio_ioctl(f
, GPIO_IOC_OUTEN
, bit
, bit
);
86 _gpio_ioctl(f
, GPIO_IOC_OUT
, bit
, en
? bit
: 0);
90 uint32_t _gpio_read(int f
)
93 // r = _gpio_ioctl(f, GPIO_IOC_IN, 0xFFFF, 0);
94 r
= _gpio_ioctl(f
, GPIO_IOC_IN
, 0x07FF, 0);
99 uint32_t gpio_read(void)
104 if ((f
= gpio_open(0)) < 0) return ~0;
112 int gpio_open(uint32_t mask
)
114 int f
= open(DEV_GPIO(in
), O_RDONLY
|O_SYNC
);
116 _dprintf ("Failed to open %s\n", DEV_GPIO(in
));
120 void gpio_write(uint32_t bit
, int en
)
125 if ((f
= open(DEV_GPIO(control
), O_RDWR
)) < 0) return;
126 read(f
, &r
, sizeof(r
));
128 write(f
, &r
, sizeof(r
));
131 if ((f
= open(DEV_GPIO(outen
), O_RDWR
)) < 0) return;
132 read(f
, &r
, sizeof(r
));
134 write(f
, &r
, sizeof(r
));
137 if ((f
= open(DEV_GPIO(out
), O_RDWR
)) < 0) return;
138 read(f
, &r
, sizeof(r
));
141 write(f
, &r
, sizeof(r
));
145 uint32_t _gpio_read(int f
)
148 return (read(f
, &v
, sizeof(v
)) == sizeof(v
)) ? v
: ~0;
151 uint32_t gpio_read(void)
156 if ((f
= open(DEV_GPIO(in
), O_RDONLY
)) < 0) return ~0;
164 int nvget_gpio(const char *name
, int *gpio
, int *inv
)
169 if (((p
= nvram_get(name
)) != NULL
) && (*p
)) {
170 n
= strtoul(p
, NULL
, 0);
171 if ((n
& 0xFFFFFF70) == 0) {
173 *inv
= ((n
& 0x80) != 0);
180 // Routine to write to shift register
181 // Note that the controls are active low, but input as high = on
182 void gpio_write_shiftregister(unsigned int led_status
, int clk
, int data
, int max_shifts
)
186 gpio_write(1 << data
, 1); /* set data to 1 to start (disable) */
187 gpio_write(1 << clk
, 0); /* and clear clock ... */
189 for (i
= max_shifts
; i
>= 0; i
--) {
190 if (led_status
& (1 << i
))
191 gpio_write(1 << data
, 0); /* on, pull low (active low) */
193 gpio_write(1 << data
, 1); /* off, pull high (active low) */
195 gpio_write(1 << clk
, 1); /* pull high to trigger */
196 gpio_write(1 << clk
, 0); /* reset to low -> finish clock cycle*/
200 /* strBits: convert binary value to string (binary file representation) */
202 char * strBits(int input
, int binarySize
)
207 if (binarySize
> 0) {
212 for(i
= 0; i
< binarySize
; i
++) {
213 if (input
& (1 << ((binarySize
-1)-i
)))
219 strConvert
[binarySize
] = '\0';
220 return (char *)strConvert
;
227 /* return 0 success, 1 fail */
228 /* debug == 1, output to syslog */
229 int led_bit(int b
, int mode
, int debug
)
231 FILE *fileExtGPIOstatus
; // For WNDR4000, keep track of extended bit status (shift register), as cannot read from HW!
232 unsigned int intExtendedLEDStatus
; // Status of Extended LED's (shift register on WNDR4000) ... and WNDR3700v3, it's the same!
234 if ((mode
== LED_ON
) || (mode
== LED_OFF
)) {
236 // Read bit-mask from file, for tracking / updates (as this process is called clean each LED update, so cannot use static variable!)
237 if (!(fileExtGPIOstatus
= fopen("/tmp/.ext_led_value", "rb"))) {
238 fscanf(fileExtGPIOstatus
, "Shift Register Status: 0x%x\n", &intExtendedLEDStatus
);
239 fclose(fileExtGPIOstatus
);
241 if (debug
) syslog(LOG_INFO
, "Netgear Shift Register (do_led): Read Shift Register status from file, intExtendedLEDStatus = %s\n", strBits(intExtendedLEDStatus
, 8));
243 // Read Error (tracking file) - set all LED's to off
244 syslog(LOG_INFO
, "Netgear Shift Register (do_led): Error Reading /tmp/.ext_led_value, set state to all OFF\n");
245 intExtendedLEDStatus
= 0x00;
248 if (mode
== LED_ON
) {
249 // Bitwise OR, turn corresponding bit on
250 intExtendedLEDStatus
|= (1 << b
);
251 if (debug
) syslog(LOG_INFO
, "Netgear Shift Register (do_led): Mode = LED_ON (%d), Bitwise OR = %s\n", mode
, strBits((1 << b
), 8));
253 // Bitwise AND, with bitwise inverted shift ... so turn bit off
254 intExtendedLEDStatus
&= (~(1 << b
));
255 if(debug
) syslog(LOG_INFO
, "Netgear Shift Register (do_led): Mode = LED_OFF (%d), Bitwise AND = %s\n", mode
, strBits((~(1 << b
)), 8));
258 // And write to LEDs (Shift Register)
259 if(debug
) syslog(LOG_INFO
, "Netgear Shift Register (do_led): Writing to Shift Register, intExtendedLEDStatus = %s\n", strBits(intExtendedLEDStatus
, 8));
260 gpio_write_shiftregister(intExtendedLEDStatus
, 7, 6, 7);
261 // Write bit-mask to file, for tracking / updates (as this process is called clean each LED update, so cannot use static variable!)
262 if (!(fileExtGPIOstatus
= fopen("/tmp/.ext_led_value", "wb"))) {
263 fprintf(fileExtGPIOstatus
, "Shift Register Status: 0x%x\n", intExtendedLEDStatus
);
264 fprintf(fileExtGPIOstatus
, "Shift Register Status: 0b%s\n", strBits(intExtendedLEDStatus
, 8));
265 fclose(fileExtGPIOstatus
);
271 int do_led(int which
, int mode
)
273 // WLAN DIAG WHITE AMBER DMZ AOSS BRIDG MYST/USB 5G
274 // ----- ----- ----- ----- ----- ----- ----- ----- --
275 static int wrt54g
[] = { 255, 1, 2, 3, 7, 255, 255, 255, 255};
276 static int wrtsl
[] = { 255, 1, 5, 7, 0, 255, 255, 255, 255};
277 static int whrg54
[] = { 2, 7, 255, 255, 255, 6, 1, 3 , 255};
278 static int wbr2g54
[] = { 255, -1, 255, 255, 255, -6, 255, 255, 255};
279 static int wzrg54
[] = { 2, 7, 255, 255, 255, 6, 255, 255, 255};
280 static int wr850g1
[] = { 7, 3, 255, 255, 255, 255, 255, 255, 255};
281 static int wr850g2
[] = { 0, 1, 255, 255, 255, 255, 255, 255, 255};
282 static int wtr54gs
[] = { 1, -1, 255, 255, 255, 255, 255, 255, 255};
283 static int dir320
[] = { -99, 1, 4, 3, 255, 255, 255, -5, 255};
284 static int h618b
[] = { 255, -1, 255, 255, 255, -5, -3, -4, 255};
285 static int wl1600gl
[] = { 1, -5, 0, 255, 255, 2, 255, 255, 255};
286 static int wrt310nv1
[] = { 255, 1, 9, 3, 255, 255, 255, 255, 255};
287 static int wrt160nv1
[] = { 255, 1, 5, 3, 255, 255, 255, 255, 255};
289 static int wnr3500
[] = { 255, 255, 2, 255, 255, -1, 255, 255, 255};
290 static int wnr2000v2
[] = { 255, 255, 255, 255, 255, -7, 255, 255, 255};
291 static int wndr4000
[] = { 3, 1, 0, 1, 255, 6, 255, 5, 4};
292 static int wndr3400
[] = { -9, -7, -3, -7, 255, 255, 255, 2, -99}; // Note: 5 = Switch, 4 = Reset button, 8 = SES button
293 static int f7d
[] = { 255, 255, 255, 255, 12, 13, 255, 14, 255};
294 static int wrt160nv3
[] = { 255, 1, 4, 2, 255, 255, 255, 255, 255};
295 static int e900
[] = { 255, -6, 8, 255, 255, 255, 255, 255, 255};
296 static int e1000v2
[] = { 255, -6, 8, 7, 255, 255, 255, 255, 255};
297 static int e3200
[] = { 255, -3, 255, 255, 255, 255, 255, 255, 255};
298 static int wrt320n
[] = { 255, 2, 3, 4, 255, 255, 255, 255, 255};
299 static int wrt610nv2
[] = { 255, 5, 3, 0, 255, 255, 255, -7, 255};
300 static int e4200
[] = { 255, 5, -3, 255, 255, 255, 255, 255, 255};
301 static int rtn10u
[] = { 255, 255, 255, 255, 255, -7, 255, -8, 255};
302 static int rtn10p
[] = { 255, -6, 255, 255, 255, -7, 255, 255, 255};
303 static int rtn12b1
[] = { -5, 255, 255, 255, 255, 255, 255, 225, 255};
304 static int rtn15u
[] = { 1, 255, 3, 255, 255, 255, 255, -9, 255};
305 static int rtn53
[] = { 0, -17, 255, 255, 255, 255, 255, 255, 255};
306 static int l600n
[] = { 255, 255, 255, 255, 255, -7, 255, -8, 255};
307 static int dir620c1
[] = { -6, -8, 255, 255, 255, -7, 255, 255, 255};
308 static int rtn66u
[] = { 255, -12, 255, 255, 255, 255, 255, 15, 13};
309 static int w1800r
[] = { 255, -13, 255, 255, 255, 255, 255, -12, -5};
310 static int d1800h
[] = { -12, -13, 8, 255, 255, -10, 255, 15, 11};
311 static int tdn6
[] = { 255, -6, 8, 255, 255, 255, 255, 255, 255};
312 static int dir865l
[] = { 255, -99, 2, 1, 255, 3, 255, 255, 255};
313 static int tdn60
[] = { 255, -6, 8, 255, 255, 255, 255, 9, 255};
314 static int r6300v1
[] = { 11, 3, 255, 255, 255, 255, 255, 8, 11};
315 static int wndr4500
[] = { 9, 3, 2, 3, 255, 255, 255, 14, 11};
316 // WLAN DIAG WHITE AMBER DMZ AOSS BRIDG MYST/USB 5G
322 int b
= 255, c
= 255;
325 if ((which
< 0) || (which
>= LED_COUNT
)) return ret
;
327 switch (nvram_match("led_override", "1") ? MODEL_UNKNOWN
: get_model()) {
329 if (check_hw_type() == HW_BCM4702
) {
331 if ((which
!= LED_DIAG
) && (which
!= LED_DMZ
)) return ret
;
332 b
= (which
== LED_DMZ
) ? 1 : 4;
333 if (mode
!= LED_PROBE
) {
334 if (f_read_string("/proc/sys/diag", s
, sizeof(s
)) > 0) {
336 sprintf(s
, "%u", mode
? (n
| b
) : (n
& ~b
));
337 f_write_string("/proc/sys/diag", s
, 0, 0);
345 if (!supports(SUP_WHAM_LED
)) return ret
;
353 case MODEL_WRTSL54GS
:
364 case MODEL_WZRRSG54HP
:
366 case MODEL_WHR2A54G54
:
372 case MODEL_WHR2A54G54:
373 if (which != LED_DIAG) return ret;
378 if (which
!= LED_DIAG
) return ret
;
392 if (which
!= LED_DIAG
) return ret
;
393 b
= -1; // power light
396 if (which
!= LED_DIAG
) return ret
;
397 b
= -5; // power light
408 case MODEL_WL500GPv2
:
412 if (which
!= LED_DIAG
) return ret
;
413 b
= -99; // Invert power light as diag indicator
417 if (which
!= LED_DIAG
) return ret
;
418 b
= -2; // power light
422 if (which
!= LED_DIAG
) return ret
;
423 b
= -1; // power light
443 if (which
== LED_DIAG
) {
444 // power led gpio: 0x02 - white, 0x13 - red
451 case MODEL_WNR3500LV2
:
452 if (which
== LED_DIAG
) {
453 // power led gpio: 0x03 - green, 0x07 - amber
460 case MODEL_WNDR4500V2
:
461 if (which
== LED_DIAG
) {
462 // power led gpio: 0x102 - green, 0x103 - amber
472 case MODEL_WNR2000v2
:
473 if (which
== LED_DIAG
) {
474 // power led gpio: 0x01 - green, 0x02 - amber
478 b
= wnr2000v2
[which
];
481 case MODEL_WNDR3700v3
:
482 // Special Case, shift register control ... so write accordingly. Syslog below for debugging, turn back on if needed.
484 //syslog(LOG_INFO, "WNDR4000 Shift Register (do_led): Bit Name = %s, which = %d, b = %d, Mode = %s\n", led_names[which], which, b, led_modes[mode]);
489 case MODEL_WNDR3400v2
:
496 case MODEL_F5D8235v3
:
497 if (which
== LED_DIAG
) {
498 // power led gpio: 10 - green, 11 - red
499 b
= (mode
) ? 11 : -10;
500 c
= (mode
) ? -10 : 11;
516 case MODEL_WRT160Nv3
:
517 b
= wrt160nv3
[which
];
522 case MODEL_WRT610Nv2
:
523 b
= wrt610nv2
[which
];
553 if (which
!= LED_DIAG
) return ret
;
557 if (which
!= LED_DIAG
) return ret
;
561 if (which
!= LED_DIAG
) return ret
;
564 case MODEL_WRT310Nv1
:
565 b
= wrt310nv1
[which
];
567 case MODEL_WRT160Nv1
:
568 b
= wrt160nv1
[which
];
571 sprintf(s
, "led_%s", led_names
[which
]);
572 if (nvget_gpio(s
, &b
, &n
)) {
573 if ((mode
!= LED_PROBE
) && (n
)) mode
= !mode
;
574 ret
= (n
) ? b
: ((b
) ? -b
: -99);
582 if (b
== -99) b
= 0; // -0 substitute
585 else if (mode
!= LED_PROBE
) {
591 if (mode
!= LED_PROBE
) {
592 gpio_write(1 << b
, mode
);
599 if (c
< 16) gpio_write(1 << c
, mode
);