3 Broadcom BCM43xx wireless driver
5 Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
6 Stefano Brivio <st3@riseup.net>
7 Michael Buesch <mbuesch@freenet.de>
8 Danny van Dyk <kugelfang@gentoo.org>
9 Andreas Jaggi <andreas.jaggi@waterwave.ch>
11 This program is free software; you can redistribute it and/or modify
12 it under the terms of the GNU General Public License as published by
13 the Free Software Foundation; either version 2 of the License, or
14 (at your option) any later version.
16 This program is distributed in the hope that it will be useful,
17 but WITHOUT ANY WARRANTY; without even the implied warranty of
18 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 GNU General Public License for more details.
21 You should have received a copy of the GNU General Public License
22 along with this program; see the file COPYING. If not, write to
23 the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
24 Boston, MA 02110-1301, USA.
28 #include "bcm43xx_leds.h"
29 #include "bcm43xx_radio.h"
32 #include <asm/bitops.h>
35 static void bcm43xx_led_changestate(struct bcm43xx_led *led)
37 struct bcm43xx_private *bcm = led->bcm;
38 const int index = bcm43xx_led_index(led);
39 const u16 mask = (1 << index);
42 assert(index >= 0 && index < BCM43xx_NR_LEDS);
43 assert(led->blink_interval);
44 ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
45 ledctl = (ledctl & mask) ? (ledctl & ~mask) : (ledctl | mask);
46 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
49 static void bcm43xx_led_blink(unsigned long d)
51 struct bcm43xx_led *led = (struct bcm43xx_led *)d;
52 struct bcm43xx_private *bcm = led->bcm;
55 spin_lock_irqsave(&bcm->leds_lock, flags);
56 if (led->blink_interval) {
57 bcm43xx_led_changestate(led);
58 mod_timer(&led->blink_timer, jiffies + led->blink_interval);
60 spin_unlock_irqrestore(&bcm->leds_lock, flags);
63 static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
64 unsigned long interval)
66 if (led->blink_interval)
68 led->blink_interval = interval;
69 bcm43xx_led_changestate(led);
70 led->blink_timer.expires = jiffies + interval;
71 add_timer(&led->blink_timer);
74 static void bcm43xx_led_blink_stop(struct bcm43xx_led *led, int sync)
76 struct bcm43xx_private *bcm = led->bcm;
77 const int index = bcm43xx_led_index(led);
80 if (!led->blink_interval)
83 del_timer_sync(&led->blink_timer);
85 del_timer(&led->blink_timer);
86 led->blink_interval = 0;
88 /* Make sure the LED is turned off. */
89 assert(index >= 0 && index < BCM43xx_NR_LEDS);
90 ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
92 ledctl |= (1 << index);
94 ledctl &= ~(1 << index);
95 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
98 static void bcm43xx_led_init_hardcoded(struct bcm43xx_private *bcm,
99 struct bcm43xx_led *led,
102 /* This function is called, if the behaviour (and activelow)
103 * information for a LED is missing in the SPROM.
104 * We hardcode the behaviour values for various devices here.
105 * Note that the BCM43xx_LED_TEST_XXX behaviour values can
106 * be used to figure out which led is mapped to which index.
111 led->behaviour = BCM43xx_LED_ACTIVITY;
113 if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ)
114 led->behaviour = BCM43xx_LED_RADIO_ALL;
117 led->behaviour = BCM43xx_LED_RADIO_B;
118 if (bcm->board_vendor == PCI_VENDOR_ID_ASUSTEK)
119 led->behaviour = BCM43xx_LED_ASSOC;
122 led->behaviour = BCM43xx_LED_RADIO_A;
125 led->behaviour = BCM43xx_LED_OFF;
132 int bcm43xx_leds_init(struct bcm43xx_private *bcm)
134 struct bcm43xx_led *led;
138 sprom[0] = bcm->sprom.wl0gpio0;
139 sprom[1] = bcm->sprom.wl0gpio1;
140 sprom[2] = bcm->sprom.wl0gpio2;
141 sprom[3] = bcm->sprom.wl0gpio3;
143 for (i = 0; i < BCM43xx_NR_LEDS; i++) {
144 led = &(bcm->leds[i]);
146 setup_timer(&led->blink_timer,
150 if (sprom[i] == 0xFF) {
151 bcm43xx_led_init_hardcoded(bcm, led, i);
153 led->behaviour = sprom[i] & BCM43xx_LED_BEHAVIOUR;
154 led->activelow = !!(sprom[i] & BCM43xx_LED_ACTIVELOW);
161 void bcm43xx_leds_exit(struct bcm43xx_private *bcm)
163 struct bcm43xx_led *led;
166 for (i = 0; i < BCM43xx_NR_LEDS; i++) {
167 led = &(bcm->leds[i]);
168 bcm43xx_led_blink_stop(led, 1);
170 bcm43xx_leds_switch_all(bcm, 0);
173 void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
175 struct bcm43xx_led *led;
176 struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
177 struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
178 const int transferring = (jiffies - bcm->stats.last_tx) < BCM43xx_LED_XFER_THRES;
180 unsigned long interval = 0;
184 spin_lock_irqsave(&bcm->leds_lock, flags);
185 ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
186 for (i = 0; i < BCM43xx_NR_LEDS; i++) {
187 led = &(bcm->leds[i]);
190 switch (led->behaviour) {
191 case BCM43xx_LED_INACTIVE:
193 case BCM43xx_LED_OFF:
194 case BCM43xx_LED_BCM4303_3:
199 case BCM43xx_LED_ACTIVITY:
200 case BCM43xx_LED_BCM4303_0:
203 case BCM43xx_LED_RADIO_ALL:
204 turn_on = radio->enabled && bcm43xx_is_hw_radio_enabled(bcm);
206 case BCM43xx_LED_RADIO_A:
207 case BCM43xx_LED_BCM4303_2:
208 turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
209 phy->type == BCM43xx_PHYTYPE_A);
211 case BCM43xx_LED_RADIO_B:
212 case BCM43xx_LED_BCM4303_1:
213 turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
214 (phy->type == BCM43xx_PHYTYPE_B ||
215 phy->type == BCM43xx_PHYTYPE_G));
217 case BCM43xx_LED_MODE_BG:
218 if (phy->type == BCM43xx_PHYTYPE_G && bcm43xx_is_hw_radio_enabled(bcm) &&
219 1/*FIXME: using G rates.*/)
222 case BCM43xx_LED_TRANSFER:
224 bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM);
226 bcm43xx_led_blink_stop(led, 0);
228 case BCM43xx_LED_APTRANSFER:
229 if (bcm->ieee->iw_mode == IW_MODE_MASTER) {
231 interval = BCM43xx_LEDBLINK_FAST;
236 if (0/*TODO: not assoc*/)
237 interval = BCM43xx_LEDBLINK_SLOW;
238 else if (transferring)
239 interval = BCM43xx_LEDBLINK_FAST;
244 bcm43xx_led_blink_start(led, interval);
246 bcm43xx_led_blink_stop(led, 0);
248 case BCM43xx_LED_WEIRD:
251 case BCM43xx_LED_ASSOC:
252 if (bcm->softmac->associnfo.associated)
255 #ifdef CONFIG_BCM43XX_DEBUG
256 case BCM43xx_LED_TEST_BLINKSLOW:
257 bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_SLOW);
259 case BCM43xx_LED_TEST_BLINKMEDIUM:
260 bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM);
262 case BCM43xx_LED_TEST_BLINKFAST:
263 bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_FAST);
265 #endif /* CONFIG_BCM43XX_DEBUG */
267 dprintkl(KERN_INFO PFX "Bad value in leds_update,"
268 " led->behaviour: 0x%x\n", led->behaviour);
278 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
279 spin_unlock_irqrestore(&bcm->leds_lock, flags);
282 void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
284 struct bcm43xx_led *led;
290 spin_lock_irqsave(&bcm->leds_lock, flags);
291 ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
292 for (i = 0; i < BCM43xx_NR_LEDS; i++) {
293 led = &(bcm->leds[i]);
294 if (led->behaviour == BCM43xx_LED_INACTIVE)
297 bit_on = led->activelow ? 0 : 1;
299 bit_on = led->activelow ? 1 : 0;
305 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
306 spin_unlock_irqrestore(&bcm->leds_lock, flags);