Merge git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[wrt350n-kernel.git] / drivers / net / wireless / bcm43xx / bcm43xx_leds.c
blobcb51dc51cce6d36f73ad2efef9d1672436c48ce3
1 /*
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"
30 #include "bcm43xx.h"
32 #include <linux/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);
40 u16 ledctl;
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;
53 unsigned long flags;
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)
67 return;
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);
78 u16 ledctl;
80 if (!led->blink_interval)
81 return;
82 if (unlikely(sync))
83 del_timer_sync(&led->blink_timer);
84 else
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);
91 if (led->activelow)
92 ledctl |= (1 << index);
93 else
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,
100 int led_index)
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.
109 switch (led_index) {
110 case 0:
111 led->behaviour = BCM43xx_LED_ACTIVITY;
112 led->activelow = 1;
113 if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ)
114 led->behaviour = BCM43xx_LED_RADIO_ALL;
115 break;
116 case 1:
117 led->behaviour = BCM43xx_LED_RADIO_B;
118 if (bcm->board_vendor == PCI_VENDOR_ID_ASUSTEK)
119 led->behaviour = BCM43xx_LED_ASSOC;
120 break;
121 case 2:
122 led->behaviour = BCM43xx_LED_RADIO_A;
123 break;
124 case 3:
125 led->behaviour = BCM43xx_LED_OFF;
126 break;
127 default:
128 assert(0);
132 int bcm43xx_leds_init(struct bcm43xx_private *bcm)
134 struct bcm43xx_led *led;
135 u8 sprom[4];
136 int i;
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]);
145 led->bcm = bcm;
146 setup_timer(&led->blink_timer,
147 bcm43xx_led_blink,
148 (unsigned long)led);
150 if (sprom[i] == 0xFF) {
151 bcm43xx_led_init_hardcoded(bcm, led, i);
152 } else {
153 led->behaviour = sprom[i] & BCM43xx_LED_BEHAVIOUR;
154 led->activelow = !!(sprom[i] & BCM43xx_LED_ACTIVELOW);
158 return 0;
161 void bcm43xx_leds_exit(struct bcm43xx_private *bcm)
163 struct bcm43xx_led *led;
164 int i;
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;
179 int i, turn_on;
180 unsigned long interval = 0;
181 u16 ledctl;
182 unsigned long flags;
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]);
189 turn_on = 0;
190 switch (led->behaviour) {
191 case BCM43xx_LED_INACTIVE:
192 continue;
193 case BCM43xx_LED_OFF:
194 case BCM43xx_LED_BCM4303_3:
195 break;
196 case BCM43xx_LED_ON:
197 turn_on = 1;
198 break;
199 case BCM43xx_LED_ACTIVITY:
200 case BCM43xx_LED_BCM4303_0:
201 turn_on = activity;
202 break;
203 case BCM43xx_LED_RADIO_ALL:
204 turn_on = radio->enabled && bcm43xx_is_hw_radio_enabled(bcm);
205 break;
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);
210 break;
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));
216 break;
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.*/)
220 turn_on = 1;
221 break;
222 case BCM43xx_LED_TRANSFER:
223 if (transferring)
224 bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM);
225 else
226 bcm43xx_led_blink_stop(led, 0);
227 continue;
228 case BCM43xx_LED_APTRANSFER:
229 if (bcm->ieee->iw_mode == IW_MODE_MASTER) {
230 if (transferring) {
231 interval = BCM43xx_LEDBLINK_FAST;
232 turn_on = 1;
234 } else {
235 turn_on = 1;
236 if (0/*TODO: not assoc*/)
237 interval = BCM43xx_LEDBLINK_SLOW;
238 else if (transferring)
239 interval = BCM43xx_LEDBLINK_FAST;
240 else
241 turn_on = 0;
243 if (turn_on)
244 bcm43xx_led_blink_start(led, interval);
245 else
246 bcm43xx_led_blink_stop(led, 0);
247 continue;
248 case BCM43xx_LED_WEIRD:
249 //TODO
250 break;
251 case BCM43xx_LED_ASSOC:
252 if (bcm->softmac->associnfo.associated)
253 turn_on = 1;
254 break;
255 #ifdef CONFIG_BCM43XX_DEBUG
256 case BCM43xx_LED_TEST_BLINKSLOW:
257 bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_SLOW);
258 continue;
259 case BCM43xx_LED_TEST_BLINKMEDIUM:
260 bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM);
261 continue;
262 case BCM43xx_LED_TEST_BLINKFAST:
263 bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_FAST);
264 continue;
265 #endif /* CONFIG_BCM43XX_DEBUG */
266 default:
267 dprintkl(KERN_INFO PFX "Bad value in leds_update,"
268 " led->behaviour: 0x%x\n", led->behaviour);
271 if (led->activelow)
272 turn_on = !turn_on;
273 if (turn_on)
274 ledctl |= (1 << i);
275 else
276 ledctl &= ~(1 << i);
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;
285 u16 ledctl;
286 int i;
287 int bit_on;
288 unsigned long flags;
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)
295 continue;
296 if (on)
297 bit_on = led->activelow ? 0 : 1;
298 else
299 bit_on = led->activelow ? 1 : 0;
300 if (bit_on)
301 ledctl |= (1 << i);
302 else
303 ledctl &= ~(1 << i);
305 bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
306 spin_unlock_irqrestore(&bcm->leds_lock, flags);