diff options
author | Michael Buesch <mb@bu3sch.de> | 2007-09-18 15:39:42 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 19:51:37 -0400 |
commit | e4d6b7951812d98417feb10784e400e253caf633 (patch) | |
tree | 4f653c52b4cffd5ade2eb166a56b306c9181ed08 /drivers/net/wireless/b43/leds.c | |
parent | 61e115a56d1aafd6e6a8a9fee8ac099a6128ac7b (diff) |
[B43]: add mac80211-based driver for modern BCM43xx devices
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/wireless/b43/leds.c')
-rw-r--r-- | drivers/net/wireless/b43/leds.c | 299 |
1 files changed, 299 insertions, 0 deletions
diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c new file mode 100644 index 000000000000..535f960412d7 --- /dev/null +++ b/drivers/net/wireless/b43/leds.c | |||
@@ -0,0 +1,299 @@ | |||
1 | /* | ||
2 | |||
3 | Broadcom B43 wireless driver | ||
4 | |||
5 | Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, | ||
6 | Stefano Brivio <st3@riseup.net> | ||
7 | Michael Buesch <mb@bu3sch.de> | ||
8 | Danny van Dyk <kugelfang@gentoo.org> | ||
9 | Andreas Jaggi <andreas.jaggi@waterwave.ch> | ||
10 | |||
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. | ||
15 | |||
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. | ||
20 | |||
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. | ||
25 | |||
26 | */ | ||
27 | |||
28 | #include "b43.h" | ||
29 | #include "leds.h" | ||
30 | #include "main.h" | ||
31 | |||
32 | static void b43_led_changestate(struct b43_led *led) | ||
33 | { | ||
34 | struct b43_wldev *dev = led->dev; | ||
35 | const int index = b43_led_index(led); | ||
36 | const u16 mask = (1 << index); | ||
37 | u16 ledctl; | ||
38 | |||
39 | B43_WARN_ON(!(index >= 0 && index < B43_NR_LEDS)); | ||
40 | B43_WARN_ON(!led->blink_interval); | ||
41 | ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); | ||
42 | ledctl = (ledctl & mask) ? (ledctl & ~mask) : (ledctl | mask); | ||
43 | b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); | ||
44 | } | ||
45 | |||
46 | static void b43_led_blink(unsigned long d) | ||
47 | { | ||
48 | struct b43_led *led = (struct b43_led *)d; | ||
49 | struct b43_wldev *dev = led->dev; | ||
50 | unsigned long flags; | ||
51 | |||
52 | spin_lock_irqsave(&dev->wl->leds_lock, flags); | ||
53 | if (led->blink_interval) { | ||
54 | b43_led_changestate(led); | ||
55 | mod_timer(&led->blink_timer, jiffies + led->blink_interval); | ||
56 | } | ||
57 | spin_unlock_irqrestore(&dev->wl->leds_lock, flags); | ||
58 | } | ||
59 | |||
60 | static void b43_led_blink_start(struct b43_led *led, unsigned long interval) | ||
61 | { | ||
62 | if (led->blink_interval) | ||
63 | return; | ||
64 | led->blink_interval = interval; | ||
65 | b43_led_changestate(led); | ||
66 | led->blink_timer.expires = jiffies + interval; | ||
67 | add_timer(&led->blink_timer); | ||
68 | } | ||
69 | |||
70 | static void b43_led_blink_stop(struct b43_led *led, int sync) | ||
71 | { | ||
72 | struct b43_wldev *dev = led->dev; | ||
73 | const int index = b43_led_index(led); | ||
74 | u16 ledctl; | ||
75 | |||
76 | if (!led->blink_interval) | ||
77 | return; | ||
78 | if (unlikely(sync)) | ||
79 | del_timer_sync(&led->blink_timer); | ||
80 | else | ||
81 | del_timer(&led->blink_timer); | ||
82 | led->blink_interval = 0; | ||
83 | |||
84 | /* Make sure the LED is turned off. */ | ||
85 | B43_WARN_ON(!(index >= 0 && index < B43_NR_LEDS)); | ||
86 | ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); | ||
87 | if (led->activelow) | ||
88 | ledctl |= (1 << index); | ||
89 | else | ||
90 | ledctl &= ~(1 << index); | ||
91 | b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); | ||
92 | } | ||
93 | |||
94 | static void b43_led_init_hardcoded(struct b43_wldev *dev, | ||
95 | struct b43_led *led, int led_index) | ||
96 | { | ||
97 | struct ssb_bus *bus = dev->dev->bus; | ||
98 | |||
99 | /* This function is called, if the behaviour (and activelow) | ||
100 | * information for a LED is missing in the SPROM. | ||
101 | * We hardcode the behaviour values for various devices here. | ||
102 | * Note that the B43_LED_TEST_XXX behaviour values can | ||
103 | * be used to figure out which led is mapped to which index. | ||
104 | */ | ||
105 | |||
106 | switch (led_index) { | ||
107 | case 0: | ||
108 | led->behaviour = B43_LED_ACTIVITY; | ||
109 | led->activelow = 1; | ||
110 | if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) | ||
111 | led->behaviour = B43_LED_RADIO_ALL; | ||
112 | break; | ||
113 | case 1: | ||
114 | led->behaviour = B43_LED_RADIO_B; | ||
115 | if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) | ||
116 | led->behaviour = B43_LED_ASSOC; | ||
117 | break; | ||
118 | case 2: | ||
119 | led->behaviour = B43_LED_RADIO_A; | ||
120 | break; | ||
121 | case 3: | ||
122 | led->behaviour = B43_LED_OFF; | ||
123 | break; | ||
124 | default: | ||
125 | B43_WARN_ON(1); | ||
126 | } | ||
127 | } | ||
128 | |||
129 | int b43_leds_init(struct b43_wldev *dev) | ||
130 | { | ||
131 | struct b43_led *led; | ||
132 | u8 sprom[4]; | ||
133 | int i; | ||
134 | |||
135 | sprom[0] = dev->dev->bus->sprom.r1.gpio0; | ||
136 | sprom[1] = dev->dev->bus->sprom.r1.gpio1; | ||
137 | sprom[2] = dev->dev->bus->sprom.r1.gpio2; | ||
138 | sprom[3] = dev->dev->bus->sprom.r1.gpio3; | ||
139 | |||
140 | for (i = 0; i < B43_NR_LEDS; i++) { | ||
141 | led = &(dev->leds[i]); | ||
142 | led->dev = dev; | ||
143 | setup_timer(&led->blink_timer, | ||
144 | b43_led_blink, (unsigned long)led); | ||
145 | |||
146 | if (sprom[i] == 0xFF) { | ||
147 | b43_led_init_hardcoded(dev, led, i); | ||
148 | } else { | ||
149 | led->behaviour = sprom[i] & B43_LED_BEHAVIOUR; | ||
150 | led->activelow = !!(sprom[i] & B43_LED_ACTIVELOW); | ||
151 | } | ||
152 | } | ||
153 | |||
154 | return 0; | ||
155 | } | ||
156 | |||
157 | void b43_leds_exit(struct b43_wldev *dev) | ||
158 | { | ||
159 | struct b43_led *led; | ||
160 | int i; | ||
161 | |||
162 | for (i = 0; i < B43_NR_LEDS; i++) { | ||
163 | led = &(dev->leds[i]); | ||
164 | b43_led_blink_stop(led, 1); | ||
165 | } | ||
166 | b43_leds_switch_all(dev, 0); | ||
167 | } | ||
168 | |||
169 | void b43_leds_update(struct b43_wldev *dev, int activity) | ||
170 | { | ||
171 | struct b43_led *led; | ||
172 | struct b43_phy *phy = &dev->phy; | ||
173 | const int transferring = | ||
174 | (jiffies - dev->stats.last_tx) < B43_LED_XFER_THRES; | ||
175 | int i, turn_on; | ||
176 | unsigned long interval = 0; | ||
177 | u16 ledctl; | ||
178 | unsigned long flags; | ||
179 | |||
180 | spin_lock_irqsave(&dev->wl->leds_lock, flags); | ||
181 | ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); | ||
182 | for (i = 0; i < B43_NR_LEDS; i++) { | ||
183 | led = &(dev->leds[i]); | ||
184 | |||
185 | turn_on = 0; | ||
186 | switch (led->behaviour) { | ||
187 | case B43_LED_INACTIVE: | ||
188 | continue; | ||
189 | case B43_LED_OFF: | ||
190 | break; | ||
191 | case B43_LED_ON: | ||
192 | turn_on = 1; | ||
193 | break; | ||
194 | case B43_LED_ACTIVITY: | ||
195 | turn_on = activity; | ||
196 | break; | ||
197 | case B43_LED_RADIO_ALL: | ||
198 | turn_on = phy->radio_on && b43_is_hw_radio_enabled(dev); | ||
199 | break; | ||
200 | case B43_LED_RADIO_A: | ||
201 | turn_on = (phy->radio_on && b43_is_hw_radio_enabled(dev) | ||
202 | && phy->type == B43_PHYTYPE_A); | ||
203 | break; | ||
204 | case B43_LED_RADIO_B: | ||
205 | turn_on = (phy->radio_on && b43_is_hw_radio_enabled(dev) | ||
206 | && (phy->type == B43_PHYTYPE_B | ||
207 | || phy->type == B43_PHYTYPE_G)); | ||
208 | break; | ||
209 | case B43_LED_MODE_BG: | ||
210 | if (phy->type == B43_PHYTYPE_G | ||
211 | && b43_is_hw_radio_enabled(dev) | ||
212 | && 1 /*FIXME: using G rates. */ ) | ||
213 | turn_on = 1; | ||
214 | break; | ||
215 | case B43_LED_TRANSFER: | ||
216 | if (transferring) | ||
217 | b43_led_blink_start(led, B43_LEDBLINK_MEDIUM); | ||
218 | else | ||
219 | b43_led_blink_stop(led, 0); | ||
220 | continue; | ||
221 | case B43_LED_APTRANSFER: | ||
222 | if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) { | ||
223 | if (transferring) { | ||
224 | interval = B43_LEDBLINK_FAST; | ||
225 | turn_on = 1; | ||
226 | } | ||
227 | } else { | ||
228 | turn_on = 1; | ||
229 | if (0 /*TODO: not assoc */ ) | ||
230 | interval = B43_LEDBLINK_SLOW; | ||
231 | else if (transferring) | ||
232 | interval = B43_LEDBLINK_FAST; | ||
233 | else | ||
234 | turn_on = 0; | ||
235 | } | ||
236 | if (turn_on) | ||
237 | b43_led_blink_start(led, interval); | ||
238 | else | ||
239 | b43_led_blink_stop(led, 0); | ||
240 | continue; | ||
241 | case B43_LED_WEIRD: | ||
242 | //TODO | ||
243 | break; | ||
244 | case B43_LED_ASSOC: | ||
245 | if (1 /*dev->softmac->associated */ ) | ||
246 | turn_on = 1; | ||
247 | break; | ||
248 | #ifdef CONFIG_B43_DEBUG | ||
249 | case B43_LED_TEST_BLINKSLOW: | ||
250 | b43_led_blink_start(led, B43_LEDBLINK_SLOW); | ||
251 | continue; | ||
252 | case B43_LED_TEST_BLINKMEDIUM: | ||
253 | b43_led_blink_start(led, B43_LEDBLINK_MEDIUM); | ||
254 | continue; | ||
255 | case B43_LED_TEST_BLINKFAST: | ||
256 | b43_led_blink_start(led, B43_LEDBLINK_FAST); | ||
257 | continue; | ||
258 | #endif /* CONFIG_B43_DEBUG */ | ||
259 | default: | ||
260 | B43_WARN_ON(1); | ||
261 | }; | ||
262 | |||
263 | if (led->activelow) | ||
264 | turn_on = !turn_on; | ||
265 | if (turn_on) | ||
266 | ledctl |= (1 << i); | ||
267 | else | ||
268 | ledctl &= ~(1 << i); | ||
269 | } | ||
270 | b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); | ||
271 | spin_unlock_irqrestore(&dev->wl->leds_lock, flags); | ||
272 | } | ||
273 | |||
274 | void b43_leds_switch_all(struct b43_wldev *dev, int on) | ||
275 | { | ||
276 | struct b43_led *led; | ||
277 | u16 ledctl; | ||
278 | int i; | ||
279 | int bit_on; | ||
280 | unsigned long flags; | ||
281 | |||
282 | spin_lock_irqsave(&dev->wl->leds_lock, flags); | ||
283 | ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); | ||
284 | for (i = 0; i < B43_NR_LEDS; i++) { | ||
285 | led = &(dev->leds[i]); | ||
286 | if (led->behaviour == B43_LED_INACTIVE) | ||
287 | continue; | ||
288 | if (on) | ||
289 | bit_on = led->activelow ? 0 : 1; | ||
290 | else | ||
291 | bit_on = led->activelow ? 1 : 0; | ||
292 | if (bit_on) | ||
293 | ledctl |= (1 << i); | ||
294 | else | ||
295 | ledctl &= ~(1 << i); | ||
296 | } | ||
297 | b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); | ||
298 | spin_unlock_irqrestore(&dev->wl->leds_lock, flags); | ||
299 | } | ||