]>
Commit | Line | Data |
---|---|---|
75388acd LF |
1 | /* |
2 | ||
3 | Broadcom B43legacy 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 | Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net> | |
11 | ||
12 | This program is free software; you can redistribute it and/or modify | |
13 | it under the terms of the GNU General Public License as published by | |
14 | the Free Software Foundation; either version 2 of the License, or | |
15 | (at your option) any later version. | |
16 | ||
17 | This program is distributed in the hope that it will be useful, | |
18 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
19 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
20 | GNU General Public License for more details. | |
21 | ||
22 | You should have received a copy of the GNU General Public License | |
23 | along with this program; see the file COPYING. If not, write to | |
24 | the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor, | |
25 | Boston, MA 02110-1301, USA. | |
26 | ||
27 | */ | |
28 | ||
29 | #include "leds.h" | |
30 | #include "b43legacy.h" | |
31 | #include "main.h" | |
32 | ||
33 | static void b43legacy_led_changestate(struct b43legacy_led *led) | |
34 | { | |
35 | struct b43legacy_wldev *dev = led->dev; | |
36 | const int index = led->index; | |
37 | u16 ledctl; | |
38 | ||
39 | B43legacy_WARN_ON(!(index >= 0 && index < B43legacy_NR_LEDS)); | |
40 | B43legacy_WARN_ON(!led->blink_interval); | |
41 | ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); | |
42 | ledctl ^= (1 << index); | |
43 | b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl); | |
44 | } | |
45 | ||
46 | static void b43legacy_led_blink(unsigned long d) | |
47 | { | |
48 | struct b43legacy_led *led = (struct b43legacy_led *)d; | |
49 | struct b43legacy_wldev *dev = led->dev; | |
50 | unsigned long flags; | |
51 | ||
52 | spin_lock_irqsave(&dev->wl->leds_lock, flags); | |
53 | if (led->blink_interval) { | |
54 | b43legacy_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 b43legacy_led_blink_start(struct b43legacy_led *led, | |
61 | unsigned long interval) | |
62 | { | |
63 | if (led->blink_interval) | |
64 | return; | |
65 | led->blink_interval = interval; | |
66 | b43legacy_led_changestate(led); | |
67 | led->blink_timer.expires = jiffies + interval; | |
68 | add_timer(&led->blink_timer); | |
69 | } | |
70 | ||
71 | static void b43legacy_led_blink_stop(struct b43legacy_led *led, int sync) | |
72 | { | |
73 | struct b43legacy_wldev *dev = led->dev; | |
74 | const int index = led->index; | |
75 | u16 ledctl; | |
76 | ||
77 | if (!led->blink_interval) | |
78 | return; | |
79 | if (unlikely(sync)) | |
80 | del_timer_sync(&led->blink_timer); | |
81 | else | |
82 | del_timer(&led->blink_timer); | |
83 | led->blink_interval = 0; | |
84 | ||
85 | /* Make sure the LED is turned off. */ | |
86 | B43legacy_WARN_ON(!(index >= 0 && index < B43legacy_NR_LEDS)); | |
87 | ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); | |
88 | if (led->activelow) | |
89 | ledctl |= (1 << index); | |
90 | else | |
91 | ledctl &= ~(1 << index); | |
92 | b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl); | |
93 | } | |
94 | ||
95 | static void b43legacy_led_init_hardcoded(struct b43legacy_wldev *dev, | |
96 | struct b43legacy_led *led, | |
97 | int led_index) | |
98 | { | |
99 | struct ssb_bus *bus = dev->dev->bus; | |
100 | ||
101 | /* This function is called, if the behaviour (and activelow) | |
102 | * information for a LED is missing in the SPROM. | |
103 | * We hardcode the behaviour values for various devices here. | |
104 | * Note that the B43legacy_LED_TEST_XXX behaviour values can | |
105 | * be used to figure out which led is mapped to which index. | |
106 | */ | |
107 | ||
108 | switch (led_index) { | |
109 | case 0: | |
110 | led->behaviour = B43legacy_LED_ACTIVITY; | |
111 | led->activelow = 1; | |
112 | if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) | |
113 | led->behaviour = B43legacy_LED_RADIO_ALL; | |
114 | break; | |
115 | case 1: | |
116 | led->behaviour = B43legacy_LED_RADIO_B; | |
117 | if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) | |
118 | led->behaviour = B43legacy_LED_ASSOC; | |
119 | break; | |
120 | case 2: | |
121 | led->behaviour = B43legacy_LED_RADIO_A; | |
122 | break; | |
123 | case 3: | |
124 | led->behaviour = B43legacy_LED_OFF; | |
125 | break; | |
126 | default: | |
127 | B43legacy_BUG_ON(1); | |
128 | } | |
129 | } | |
130 | ||
131 | int b43legacy_leds_init(struct b43legacy_wldev *dev) | |
132 | { | |
133 | struct b43legacy_led *led; | |
134 | u8 sprom[4]; | |
135 | int i; | |
136 | ||
137 | sprom[0] = dev->dev->bus->sprom.r1.gpio0; | |
138 | sprom[1] = dev->dev->bus->sprom.r1.gpio1; | |
139 | sprom[2] = dev->dev->bus->sprom.r1.gpio2; | |
140 | sprom[3] = dev->dev->bus->sprom.r1.gpio3; | |
141 | ||
142 | for (i = 0; i < B43legacy_NR_LEDS; i++) { | |
143 | led = &(dev->leds[i]); | |
144 | led->index = i; | |
145 | led->dev = dev; | |
146 | setup_timer(&led->blink_timer, | |
147 | b43legacy_led_blink, | |
148 | (unsigned long)led); | |
149 | ||
150 | if (sprom[i] == 0xFF) | |
151 | b43legacy_led_init_hardcoded(dev, led, i); | |
152 | else { | |
153 | led->behaviour = sprom[i] & B43legacy_LED_BEHAVIOUR; | |
154 | led->activelow = !!(sprom[i] & | |
155 | B43legacy_LED_ACTIVELOW); | |
156 | } | |
157 | } | |
158 | ||
159 | return 0; | |
160 | } | |
161 | ||
162 | void b43legacy_leds_exit(struct b43legacy_wldev *dev) | |
163 | { | |
164 | struct b43legacy_led *led; | |
165 | int i; | |
166 | ||
167 | for (i = 0; i < B43legacy_NR_LEDS; i++) { | |
168 | led = &(dev->leds[i]); | |
169 | b43legacy_led_blink_stop(led, 1); | |
170 | } | |
171 | b43legacy_leds_switch_all(dev, 0); | |
172 | } | |
173 | ||
174 | void b43legacy_leds_update(struct b43legacy_wldev *dev, int activity) | |
175 | { | |
176 | struct b43legacy_led *led; | |
177 | struct b43legacy_phy *phy = &dev->phy; | |
178 | const int transferring = (jiffies - dev->stats.last_tx) | |
179 | < B43legacy_LED_XFER_THRES; | |
180 | int i; | |
181 | int turn_on; | |
182 | unsigned long interval = 0; | |
183 | u16 ledctl; | |
184 | unsigned long flags; | |
185 | ||
186 | spin_lock_irqsave(&dev->wl->leds_lock, flags); | |
187 | ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); | |
188 | for (i = 0; i < B43legacy_NR_LEDS; i++) { | |
189 | led = &(dev->leds[i]); | |
190 | ||
191 | turn_on = 0; | |
192 | switch (led->behaviour) { | |
193 | case B43legacy_LED_INACTIVE: | |
194 | continue; | |
195 | case B43legacy_LED_OFF: | |
196 | break; | |
197 | case B43legacy_LED_ON: | |
198 | turn_on = 1; | |
199 | break; | |
200 | case B43legacy_LED_ACTIVITY: | |
201 | turn_on = activity; | |
202 | break; | |
203 | case B43legacy_LED_RADIO_ALL: | |
204 | turn_on = phy->radio_on && | |
205 | b43legacy_is_hw_radio_enabled(dev); | |
206 | break; | |
207 | case B43legacy_LED_RADIO_A: | |
208 | break; | |
209 | case B43legacy_LED_RADIO_B: | |
210 | turn_on = (phy->radio_on && | |
211 | b43legacy_is_hw_radio_enabled(dev) && | |
212 | (phy->type == B43legacy_PHYTYPE_B || | |
213 | phy->type == B43legacy_PHYTYPE_G)); | |
214 | break; | |
215 | case B43legacy_LED_MODE_BG: | |
216 | if (phy->type == B43legacy_PHYTYPE_G && | |
217 | b43legacy_is_hw_radio_enabled(dev)) | |
218 | turn_on = 1; | |
219 | break; | |
220 | case B43legacy_LED_TRANSFER: | |
221 | if (transferring) | |
222 | b43legacy_led_blink_start(led, | |
223 | B43legacy_LEDBLINK_MEDIUM); | |
224 | else | |
225 | b43legacy_led_blink_stop(led, 0); | |
226 | continue; | |
227 | case B43legacy_LED_APTRANSFER: | |
228 | if (b43legacy_is_mode(dev->wl, | |
229 | IEEE80211_IF_TYPE_AP)) { | |
230 | if (transferring) { | |
231 | interval = B43legacy_LEDBLINK_FAST; | |
232 | turn_on = 1; | |
233 | } | |
234 | } else { | |
235 | turn_on = 1; | |
236 | if (transferring) | |
237 | interval = B43legacy_LEDBLINK_FAST; | |
238 | else | |
239 | turn_on = 0; | |
240 | } | |
241 | if (turn_on) | |
242 | b43legacy_led_blink_start(led, interval); | |
243 | else | |
244 | b43legacy_led_blink_stop(led, 0); | |
245 | continue; | |
246 | case B43legacy_LED_WEIRD: | |
247 | break; | |
248 | case B43legacy_LED_ASSOC: | |
249 | turn_on = 1; | |
250 | #ifdef CONFIG_B43LEGACY_DEBUG | |
251 | case B43legacy_LED_TEST_BLINKSLOW: | |
252 | b43legacy_led_blink_start(led, B43legacy_LEDBLINK_SLOW); | |
253 | continue; | |
254 | case B43legacy_LED_TEST_BLINKMEDIUM: | |
255 | b43legacy_led_blink_start(led, | |
256 | B43legacy_LEDBLINK_MEDIUM); | |
257 | continue; | |
258 | case B43legacy_LED_TEST_BLINKFAST: | |
259 | b43legacy_led_blink_start(led, B43legacy_LEDBLINK_FAST); | |
260 | continue; | |
261 | #endif /* CONFIG_B43LEGACY_DEBUG */ | |
262 | default: | |
263 | B43legacy_BUG_ON(1); | |
264 | }; | |
265 | ||
266 | if (led->activelow) | |
267 | turn_on = !turn_on; | |
268 | if (turn_on) | |
269 | ledctl |= (1 << i); | |
270 | else | |
271 | ledctl &= ~(1 << i); | |
272 | } | |
273 | b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl); | |
274 | spin_unlock_irqrestore(&dev->wl->leds_lock, flags); | |
275 | } | |
276 | ||
277 | void b43legacy_leds_switch_all(struct b43legacy_wldev *dev, int on) | |
278 | { | |
279 | struct b43legacy_led *led; | |
280 | u16 ledctl; | |
281 | int i; | |
282 | int bit_on; | |
283 | unsigned long flags; | |
284 | ||
285 | spin_lock_irqsave(&dev->wl->leds_lock, flags); | |
286 | ledctl = b43legacy_read16(dev, B43legacy_MMIO_GPIO_CONTROL); | |
287 | for (i = 0; i < B43legacy_NR_LEDS; i++) { | |
288 | led = &(dev->leds[i]); | |
289 | if (led->behaviour == B43legacy_LED_INACTIVE) | |
290 | continue; | |
291 | if (on) | |
292 | bit_on = led->activelow ? 0 : 1; | |
293 | else | |
294 | bit_on = led->activelow ? 1 : 0; | |
295 | if (bit_on) | |
296 | ledctl |= (1 << i); | |
297 | else | |
298 | ledctl &= ~(1 << i); | |
299 | } | |
300 | b43legacy_write16(dev, B43legacy_MMIO_GPIO_CONTROL, ledctl); | |
301 | spin_unlock_irqrestore(&dev->wl->leds_lock, flags); | |
302 | } |