diff options
author | Michael Buesch <mb@bu3sch.de> | 2007-09-27 09:31:40 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-10 19:54:11 -0400 |
commit | 21954c367e4088c491122edd263964345bc1d3bf (patch) | |
tree | 149faa19794ff6834c56f3af4501fe921880092e /drivers/net/wireless | |
parent | 20405c08412a4d89357870d7220f9fb1c458b286 (diff) |
[B43]: LED triggers support
Drive the LEDs through the generic LED triggers.
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Cc: Larry Finger <larry.finger@lwfinger.net>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/b43/Kconfig | 6 | ||||
-rw-r--r-- | drivers/net/wireless/b43/Makefile | 3 | ||||
-rw-r--r-- | drivers/net/wireless/b43/b43.h | 6 | ||||
-rw-r--r-- | drivers/net/wireless/b43/leds.c | 395 | ||||
-rw-r--r-- | drivers/net/wireless/b43/leds.h | 63 | ||||
-rw-r--r-- | drivers/net/wireless/b43/main.c | 51 |
6 files changed, 229 insertions, 295 deletions
diff --git a/drivers/net/wireless/b43/Kconfig b/drivers/net/wireless/b43/Kconfig index 4620119891f2..1575654556b0 100644 --- a/drivers/net/wireless/b43/Kconfig +++ b/drivers/net/wireless/b43/Kconfig | |||
@@ -61,6 +61,12 @@ config B43_PCMCIA | |||
61 | 61 | ||
62 | If unsure, say N. | 62 | If unsure, say N. |
63 | 63 | ||
64 | # LED support | ||
65 | config B43_LEDS | ||
66 | bool | ||
67 | depends on MAC80211_LEDS | ||
68 | default y | ||
69 | |||
64 | config B43_DEBUG | 70 | config B43_DEBUG |
65 | bool "Broadcom 43xx debugging" | 71 | bool "Broadcom 43xx debugging" |
66 | depends on B43 | 72 | depends on B43 |
diff --git a/drivers/net/wireless/b43/Makefile b/drivers/net/wireless/b43/Makefile index 370935b84c5e..e6331414c4ca 100644 --- a/drivers/net/wireless/b43/Makefile +++ b/drivers/net/wireless/b43/Makefile | |||
@@ -3,9 +3,10 @@ b43-y += main.o | |||
3 | b43-y += tables.o | 3 | b43-y += tables.o |
4 | b43-y += phy.o | 4 | b43-y += phy.o |
5 | b43-y += sysfs.o | 5 | b43-y += sysfs.o |
6 | b43-y += leds.o | ||
7 | b43-y += xmit.o | 6 | b43-y += xmit.o |
8 | b43-y += lo.o | 7 | b43-y += lo.o |
8 | # b43 LED support | ||
9 | b43-$(CONFIG_B43_LEDS) += leds.o | ||
9 | # b43 PCMCIA support | 10 | # b43 PCMCIA support |
10 | b43-$(CONFIG_B43_PCMCIA) += pcmcia.o | 11 | b43-$(CONFIG_B43_PCMCIA) += pcmcia.o |
11 | # b43 debugging | 12 | # b43 debugging |
diff --git a/drivers/net/wireless/b43/b43.h b/drivers/net/wireless/b43/b43.h index 2c8fa1c3465e..6e6b59227e16 100644 --- a/drivers/net/wireless/b43/b43.h +++ b/drivers/net/wireless/b43/b43.h | |||
@@ -696,8 +696,10 @@ struct b43_wldev { | |||
696 | /* Various statistics about the physical device. */ | 696 | /* Various statistics about the physical device. */ |
697 | struct b43_stats stats; | 697 | struct b43_stats stats; |
698 | 698 | ||
699 | #define B43_NR_LEDS 4 | 699 | /* The device LEDs. */ |
700 | struct b43_led leds[B43_NR_LEDS]; | 700 | struct b43_led led_tx; |
701 | struct b43_led led_rx; | ||
702 | struct b43_led led_assoc; | ||
701 | 703 | ||
702 | /* Reason code of the last interrupt. */ | 704 | /* Reason code of the last interrupt. */ |
703 | u32 irq_reason; | 705 | u32 irq_reason; |
diff --git a/drivers/net/wireless/b43/leds.c b/drivers/net/wireless/b43/leds.c index 0f155b4f34eb..ddab856f1140 100644 --- a/drivers/net/wireless/b43/leds.c +++ b/drivers/net/wireless/b43/leds.c | |||
@@ -1,12 +1,13 @@ | |||
1 | /* | 1 | /* |
2 | 2 | ||
3 | Broadcom B43 wireless driver | 3 | Broadcom B43 wireless driver |
4 | LED control | ||
4 | 5 | ||
5 | Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, | 6 | Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>, |
6 | Stefano Brivio <st3@riseup.net> | 7 | Copyright (c) 2005 Stefano Brivio <st3@riseup.net> |
7 | Michael Buesch <mb@bu3sch.de> | 8 | Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de> |
8 | Danny van Dyk <kugelfang@gentoo.org> | 9 | Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org> |
9 | Andreas Jaggi <andreas.jaggi@waterwave.ch> | 10 | Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch> |
10 | 11 | ||
11 | This program is free software; you can redistribute it and/or modify | 12 | 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 | it under the terms of the GNU General Public License as published by |
@@ -27,272 +28,204 @@ | |||
27 | 28 | ||
28 | #include "b43.h" | 29 | #include "b43.h" |
29 | #include "leds.h" | 30 | #include "leds.h" |
30 | #include "main.h" | ||
31 | 31 | ||
32 | static void b43_led_changestate(struct b43_led *led) | ||
33 | { | ||
34 | struct b43_wldev *dev = led->dev; | ||
35 | const int index = led->index; | ||
36 | u16 ledctl; | ||
37 | |||
38 | B43_WARN_ON(!(index >= 0 && index < B43_NR_LEDS)); | ||
39 | B43_WARN_ON(!led->blink_interval); | ||
40 | ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); | ||
41 | ledctl ^= (1 << index); | ||
42 | b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); | ||
43 | } | ||
44 | 32 | ||
45 | static void b43_led_blink(unsigned long d) | 33 | static void b43_led_turn_on(struct b43_wldev *dev, u8 led_index, |
34 | bool activelow) | ||
46 | { | 35 | { |
47 | struct b43_led *led = (struct b43_led *)d; | 36 | struct b43_wl *wl = dev->wl; |
48 | struct b43_wldev *dev = led->dev; | ||
49 | unsigned long flags; | 37 | unsigned long flags; |
38 | u16 ctl; | ||
50 | 39 | ||
51 | spin_lock_irqsave(&dev->wl->leds_lock, flags); | 40 | spin_lock_irqsave(&wl->leds_lock, flags); |
52 | if (led->blink_interval) { | 41 | ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); |
53 | b43_led_changestate(led); | 42 | if (activelow) |
54 | mod_timer(&led->blink_timer, jiffies + led->blink_interval); | 43 | ctl &= ~(1 << led_index); |
55 | } | 44 | else |
56 | spin_unlock_irqrestore(&dev->wl->leds_lock, flags); | 45 | ctl |= (1 << led_index); |
46 | b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl); | ||
47 | spin_unlock_irqrestore(&wl->leds_lock, flags); | ||
57 | } | 48 | } |
58 | 49 | ||
59 | static void b43_led_blink_start(struct b43_led *led, unsigned long interval) | 50 | static void b43_led_turn_off(struct b43_wldev *dev, u8 led_index, |
51 | bool activelow) | ||
60 | { | 52 | { |
61 | if (led->blink_interval) | 53 | struct b43_wl *wl = dev->wl; |
62 | return; | 54 | unsigned long flags; |
63 | led->blink_interval = interval; | 55 | u16 ctl; |
64 | b43_led_changestate(led); | 56 | |
65 | led->blink_timer.expires = jiffies + interval; | 57 | spin_lock_irqsave(&wl->leds_lock, flags); |
66 | add_timer(&led->blink_timer); | 58 | ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); |
59 | if (activelow) | ||
60 | ctl |= (1 << led_index); | ||
61 | else | ||
62 | ctl &= ~(1 << led_index); | ||
63 | b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl); | ||
64 | spin_unlock_irqrestore(&wl->leds_lock, flags); | ||
67 | } | 65 | } |
68 | 66 | ||
69 | static void b43_led_blink_stop(struct b43_led *led, int sync) | 67 | /* Callback from the LED subsystem. */ |
68 | static void b43_led_brightness_set(struct led_classdev *led_dev, | ||
69 | enum led_brightness brightness) | ||
70 | { | 70 | { |
71 | struct b43_led *led = container_of(led_dev, struct b43_led, led_dev); | ||
71 | struct b43_wldev *dev = led->dev; | 72 | struct b43_wldev *dev = led->dev; |
72 | const int index = led->index; | 73 | bool radio_enabled; |
73 | u16 ledctl; | ||
74 | 74 | ||
75 | if (!led->blink_interval) | 75 | /* Checking the radio-enabled status here is slightly racy, |
76 | return; | 76 | * but we want to avoid the locking overhead and we don't care |
77 | if (unlikely(sync)) | 77 | * whether the LED has the wrong state for a second. */ |
78 | del_timer_sync(&led->blink_timer); | 78 | radio_enabled = (dev->phy.radio_on && dev->radio_hw_enable); |
79 | else | ||
80 | del_timer(&led->blink_timer); | ||
81 | led->blink_interval = 0; | ||
82 | 79 | ||
83 | /* Make sure the LED is turned off. */ | 80 | if (brightness == LED_OFF || !radio_enabled) |
84 | B43_WARN_ON(!(index >= 0 && index < B43_NR_LEDS)); | 81 | b43_led_turn_off(dev, led->index, led->activelow); |
85 | ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); | ||
86 | if (led->activelow) | ||
87 | ledctl |= (1 << index); | ||
88 | else | 82 | else |
89 | ledctl &= ~(1 << index); | 83 | b43_led_turn_on(dev, led->index, led->activelow); |
90 | b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); | ||
91 | } | 84 | } |
92 | 85 | ||
93 | static void b43_led_init_hardcoded(struct b43_wldev *dev, | 86 | static int b43_register_led(struct b43_wldev *dev, struct b43_led *led, |
94 | struct b43_led *led, int led_index) | 87 | const char *name, char *default_trigger, |
88 | u8 led_index, bool activelow) | ||
95 | { | 89 | { |
96 | struct ssb_bus *bus = dev->dev->bus; | 90 | int err; |
91 | |||
92 | b43_led_turn_off(dev, led_index, activelow); | ||
93 | if (led->dev) | ||
94 | return -EEXIST; | ||
95 | if (!default_trigger) | ||
96 | return -EINVAL; | ||
97 | led->dev = dev; | ||
98 | led->index = led_index; | ||
99 | led->activelow = activelow; | ||
100 | strncpy(led->name, name, sizeof(led->name)); | ||
101 | |||
102 | led->led_dev.name = led->name; | ||
103 | led->led_dev.default_trigger = default_trigger; | ||
104 | led->led_dev.brightness_set = b43_led_brightness_set; | ||
105 | |||
106 | err = led_classdev_register(dev->dev->dev, &led->led_dev); | ||
107 | if (err) { | ||
108 | b43warn(dev->wl, "LEDs: Failed to register %s\n", name); | ||
109 | led->dev = NULL; | ||
110 | return err; | ||
111 | } | ||
112 | return 0; | ||
113 | } | ||
114 | |||
115 | static void b43_unregister_led(struct b43_led *led) | ||
116 | { | ||
117 | if (!led->dev) | ||
118 | return; | ||
119 | led_classdev_unregister(&led->led_dev); | ||
120 | b43_led_turn_off(led->dev, led->index, led->activelow); | ||
121 | led->dev = NULL; | ||
122 | } | ||
97 | 123 | ||
98 | /* This function is called, if the behaviour (and activelow) | 124 | static void b43_map_led(struct b43_wldev *dev, |
99 | * information for a LED is missing in the SPROM. | 125 | u8 led_index, |
100 | * We hardcode the behaviour values for various devices here. | 126 | enum b43_led_behaviour behaviour, |
101 | * Note that the B43_LED_TEST_XXX behaviour values can | 127 | bool activelow) |
102 | * be used to figure out which led is mapped to which index. | 128 | { |
103 | */ | 129 | struct ieee80211_hw *hw = dev->wl->hw; |
130 | char name[B43_LED_MAX_NAME_LEN + 1]; | ||
104 | 131 | ||
105 | switch (led_index) { | 132 | /* Map the b43 specific LED behaviour value to the |
106 | case 0: | 133 | * generic LED triggers. */ |
107 | led->behaviour = B43_LED_ACTIVITY; | 134 | switch (behaviour) { |
108 | led->activelow = 1; | 135 | case B43_LED_INACTIVE: |
109 | if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) | 136 | break; |
110 | led->behaviour = B43_LED_RADIO_ALL; | 137 | case B43_LED_OFF: |
138 | b43_led_turn_off(dev, led_index, activelow); | ||
111 | break; | 139 | break; |
112 | case 1: | 140 | case B43_LED_ON: |
113 | led->behaviour = B43_LED_RADIO_B; | 141 | b43_led_turn_on(dev, led_index, activelow); |
114 | if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) | ||
115 | led->behaviour = B43_LED_ASSOC; | ||
116 | break; | 142 | break; |
117 | case 2: | 143 | case B43_LED_ACTIVITY: |
118 | led->behaviour = B43_LED_RADIO_A; | 144 | case B43_LED_TRANSFER: |
145 | case B43_LED_APTRANSFER: | ||
146 | snprintf(name, sizeof(name), | ||
147 | "b43-%s:tx", wiphy_name(hw->wiphy)); | ||
148 | b43_register_led(dev, &dev->led_tx, name, | ||
149 | ieee80211_get_tx_led_name(hw), | ||
150 | led_index, activelow); | ||
151 | snprintf(name, sizeof(name), | ||
152 | "b43-%s:rx", wiphy_name(hw->wiphy)); | ||
153 | b43_register_led(dev, &dev->led_rx, name, | ||
154 | ieee80211_get_rx_led_name(hw), | ||
155 | led_index, activelow); | ||
119 | break; | 156 | break; |
120 | case 3: | 157 | /*FIXME: We need another trigger for the "radio-on" LEDs below. |
121 | led->behaviour = B43_LED_OFF; | 158 | * Wiggle that somehow into the rfkill subsystem. */ |
159 | case B43_LED_RADIO_ALL: | ||
160 | case B43_LED_RADIO_A: | ||
161 | case B43_LED_RADIO_B: | ||
162 | case B43_LED_MODE_BG: | ||
163 | case B43_LED_WEIRD: | ||
164 | case B43_LED_ASSOC: | ||
165 | snprintf(name, sizeof(name), | ||
166 | "b43-%s:assoc", wiphy_name(hw->wiphy)); | ||
167 | b43_register_led(dev, &dev->led_assoc, name, | ||
168 | ieee80211_get_assoc_led_name(hw), | ||
169 | led_index, activelow); | ||
122 | break; | 170 | break; |
123 | default: | 171 | default: |
124 | B43_WARN_ON(1); | 172 | b43warn(dev->wl, "LEDs: Unknown behaviour 0x%02X\n", |
173 | behaviour); | ||
174 | break; | ||
125 | } | 175 | } |
126 | } | 176 | } |
127 | 177 | ||
128 | int b43_leds_init(struct b43_wldev *dev) | 178 | void b43_leds_init(struct b43_wldev *dev) |
129 | { | 179 | { |
130 | struct b43_led *led; | 180 | struct ssb_bus *bus = dev->dev->bus; |
131 | u8 sprom[4]; | 181 | u8 sprom[4]; |
132 | int i; | 182 | int i; |
183 | enum b43_led_behaviour behaviour; | ||
184 | bool activelow; | ||
133 | 185 | ||
134 | sprom[0] = dev->dev->bus->sprom.r1.gpio0; | 186 | sprom[0] = bus->sprom.r1.gpio0; |
135 | sprom[1] = dev->dev->bus->sprom.r1.gpio1; | 187 | sprom[1] = bus->sprom.r1.gpio1; |
136 | sprom[2] = dev->dev->bus->sprom.r1.gpio2; | 188 | sprom[2] = bus->sprom.r1.gpio2; |
137 | sprom[3] = dev->dev->bus->sprom.r1.gpio3; | 189 | sprom[3] = bus->sprom.r1.gpio3; |
138 | |||
139 | for (i = 0; i < B43_NR_LEDS; i++) { | ||
140 | led = &(dev->leds[i]); | ||
141 | led->index = i; | ||
142 | led->dev = dev; | ||
143 | setup_timer(&led->blink_timer, | ||
144 | b43_led_blink, (unsigned long)led); | ||
145 | 190 | ||
191 | for (i = 0; i < 4; i++) { | ||
146 | if (sprom[i] == 0xFF) { | 192 | if (sprom[i] == 0xFF) { |
147 | b43_led_init_hardcoded(dev, led, i); | 193 | /* There is no LED information in the SPROM |
194 | * for this LED. Hardcode it here. */ | ||
195 | activelow = 0; | ||
196 | switch (i) { | ||
197 | case 0: | ||
198 | behaviour = B43_LED_ACTIVITY; | ||
199 | activelow = 1; | ||
200 | if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ) | ||
201 | behaviour = B43_LED_RADIO_ALL; | ||
202 | break; | ||
203 | case 1: | ||
204 | behaviour = B43_LED_RADIO_B; | ||
205 | if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK) | ||
206 | behaviour = B43_LED_ASSOC; | ||
207 | break; | ||
208 | case 2: | ||
209 | behaviour = B43_LED_RADIO_A; | ||
210 | break; | ||
211 | case 3: | ||
212 | behaviour = B43_LED_OFF; | ||
213 | break; | ||
214 | default: | ||
215 | B43_WARN_ON(1); | ||
216 | return; | ||
217 | } | ||
148 | } else { | 218 | } else { |
149 | led->behaviour = sprom[i] & B43_LED_BEHAVIOUR; | 219 | behaviour = sprom[i] & B43_LED_BEHAVIOUR; |
150 | led->activelow = !!(sprom[i] & B43_LED_ACTIVELOW); | 220 | activelow = !!(sprom[i] & B43_LED_ACTIVELOW); |
151 | } | 221 | } |
222 | b43_map_led(dev, i, behaviour, activelow); | ||
152 | } | 223 | } |
153 | |||
154 | return 0; | ||
155 | } | 224 | } |
156 | 225 | ||
157 | void b43_leds_exit(struct b43_wldev *dev) | 226 | void b43_leds_exit(struct b43_wldev *dev) |
158 | { | 227 | { |
159 | struct b43_led *led; | 228 | b43_unregister_led(&dev->led_tx); |
160 | int i; | 229 | b43_unregister_led(&dev->led_rx); |
161 | 230 | b43_unregister_led(&dev->led_assoc); | |
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 | bool radio_enabled = (phy->radio_on && dev->radio_hw_enable); | ||
180 | |||
181 | spin_lock_irqsave(&dev->wl->leds_lock, flags); | ||
182 | ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); | ||
183 | for (i = 0; i < B43_NR_LEDS; i++) { | ||
184 | led = &(dev->leds[i]); | ||
185 | |||
186 | turn_on = 0; | ||
187 | switch (led->behaviour) { | ||
188 | case B43_LED_INACTIVE: | ||
189 | continue; | ||
190 | case B43_LED_OFF: | ||
191 | break; | ||
192 | case B43_LED_ON: | ||
193 | turn_on = 1; | ||
194 | break; | ||
195 | case B43_LED_ACTIVITY: | ||
196 | turn_on = activity; | ||
197 | break; | ||
198 | case B43_LED_RADIO_ALL: | ||
199 | turn_on = radio_enabled; | ||
200 | break; | ||
201 | case B43_LED_RADIO_A: | ||
202 | turn_on = (radio_enabled && phy->type == B43_PHYTYPE_A); | ||
203 | break; | ||
204 | case B43_LED_RADIO_B: | ||
205 | turn_on = (radio_enabled && | ||
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 | && radio_enabled) | ||
212 | turn_on = 1; | ||
213 | break; | ||
214 | case B43_LED_TRANSFER: | ||
215 | if (transferring) | ||
216 | b43_led_blink_start(led, B43_LEDBLINK_MEDIUM); | ||
217 | else | ||
218 | b43_led_blink_stop(led, 0); | ||
219 | continue; | ||
220 | case B43_LED_APTRANSFER: | ||
221 | if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) { | ||
222 | if (transferring) { | ||
223 | interval = B43_LEDBLINK_FAST; | ||
224 | turn_on = 1; | ||
225 | } | ||
226 | } else { | ||
227 | turn_on = 1; | ||
228 | if (0 /*TODO: not assoc */ ) | ||
229 | interval = B43_LEDBLINK_SLOW; | ||
230 | else if (transferring) | ||
231 | interval = B43_LEDBLINK_FAST; | ||
232 | else | ||
233 | turn_on = 0; | ||
234 | } | ||
235 | if (turn_on) | ||
236 | b43_led_blink_start(led, interval); | ||
237 | else | ||
238 | b43_led_blink_stop(led, 0); | ||
239 | continue; | ||
240 | case B43_LED_WEIRD: | ||
241 | //TODO | ||
242 | break; | ||
243 | case B43_LED_ASSOC: | ||
244 | if (1 /*dev->softmac->associated */ ) | ||
245 | turn_on = 1; | ||
246 | break; | ||
247 | #ifdef CONFIG_B43_DEBUG | ||
248 | case B43_LED_TEST_BLINKSLOW: | ||
249 | b43_led_blink_start(led, B43_LEDBLINK_SLOW); | ||
250 | continue; | ||
251 | case B43_LED_TEST_BLINKMEDIUM: | ||
252 | b43_led_blink_start(led, B43_LEDBLINK_MEDIUM); | ||
253 | continue; | ||
254 | case B43_LED_TEST_BLINKFAST: | ||
255 | b43_led_blink_start(led, B43_LEDBLINK_FAST); | ||
256 | continue; | ||
257 | #endif /* CONFIG_B43_DEBUG */ | ||
258 | default: | ||
259 | B43_WARN_ON(1); | ||
260 | }; | ||
261 | |||
262 | if (led->activelow) | ||
263 | turn_on = !turn_on; | ||
264 | if (turn_on) | ||
265 | ledctl |= (1 << i); | ||
266 | else | ||
267 | ledctl &= ~(1 << i); | ||
268 | } | ||
269 | b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); | ||
270 | spin_unlock_irqrestore(&dev->wl->leds_lock, flags); | ||
271 | } | ||
272 | |||
273 | void b43_leds_switch_all(struct b43_wldev *dev, int on) | ||
274 | { | ||
275 | struct b43_led *led; | ||
276 | u16 ledctl; | ||
277 | int i; | ||
278 | int bit_on; | ||
279 | unsigned long flags; | ||
280 | |||
281 | spin_lock_irqsave(&dev->wl->leds_lock, flags); | ||
282 | ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL); | ||
283 | for (i = 0; i < B43_NR_LEDS; i++) { | ||
284 | led = &(dev->leds[i]); | ||
285 | if (led->behaviour == B43_LED_INACTIVE) | ||
286 | continue; | ||
287 | if (on) | ||
288 | bit_on = led->activelow ? 0 : 1; | ||
289 | else | ||
290 | bit_on = led->activelow ? 1 : 0; | ||
291 | if (bit_on) | ||
292 | ledctl |= (1 << i); | ||
293 | else | ||
294 | ledctl &= ~(1 << i); | ||
295 | } | ||
296 | b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl); | ||
297 | spin_unlock_irqrestore(&dev->wl->leds_lock, flags); | ||
298 | } | 231 | } |
diff --git a/drivers/net/wireless/b43/leds.h b/drivers/net/wireless/b43/leds.h index d94851d291c0..b8b1dd521243 100644 --- a/drivers/net/wireless/b43/leds.h +++ b/drivers/net/wireless/b43/leds.h | |||
@@ -1,29 +1,33 @@ | |||
1 | #ifndef B43_LEDS_H_ | 1 | #ifndef B43_LEDS_H_ |
2 | #define B43_LEDS_H_ | 2 | #define B43_LEDS_H_ |
3 | 3 | ||
4 | struct b43_wldev; | ||
5 | |||
6 | #ifdef CONFIG_B43_LEDS | ||
7 | |||
4 | #include <linux/types.h> | 8 | #include <linux/types.h> |
5 | #include <linux/timer.h> | 9 | #include <linux/leds.h> |
10 | |||
11 | |||
12 | #define B43_LED_MAX_NAME_LEN 31 | ||
6 | 13 | ||
7 | struct b43_led { | 14 | struct b43_led { |
8 | u8 behaviour; | ||
9 | bool activelow; | ||
10 | /* Index in the "leds" array in b43_wldev */ | ||
11 | u8 index; | ||
12 | struct b43_wldev *dev; | 15 | struct b43_wldev *dev; |
13 | struct timer_list blink_timer; | 16 | /* The LED class device */ |
14 | unsigned long blink_interval; | 17 | struct led_classdev led_dev; |
18 | /* The index number of the LED. */ | ||
19 | u8 index; | ||
20 | /* If activelow is true, the LED is ON if the | ||
21 | * bit is switched off. */ | ||
22 | bool activelow; | ||
23 | /* The unique name string for this LED device. */ | ||
24 | char name[B43_LED_MAX_NAME_LEN + 1]; | ||
15 | }; | 25 | }; |
16 | 26 | ||
17 | /* Delay between state changes when blinking in jiffies */ | ||
18 | #define B43_LEDBLINK_SLOW (HZ / 1) | ||
19 | #define B43_LEDBLINK_MEDIUM (HZ / 4) | ||
20 | #define B43_LEDBLINK_FAST (HZ / 8) | ||
21 | |||
22 | #define B43_LED_XFER_THRES (HZ / 100) | ||
23 | |||
24 | #define B43_LED_BEHAVIOUR 0x7F | 27 | #define B43_LED_BEHAVIOUR 0x7F |
25 | #define B43_LED_ACTIVELOW 0x80 | 28 | #define B43_LED_ACTIVELOW 0x80 |
26 | enum { /* LED behaviour values */ | 29 | /* LED behaviour values */ |
30 | enum b43_led_behaviour { | ||
27 | B43_LED_OFF, | 31 | B43_LED_OFF, |
28 | B43_LED_ON, | 32 | B43_LED_ON, |
29 | B43_LED_ACTIVITY, | 33 | B43_LED_ACTIVITY, |
@@ -36,20 +40,25 @@ enum { /* LED behaviour values */ | |||
36 | B43_LED_WEIRD, //FIXME | 40 | B43_LED_WEIRD, //FIXME |
37 | B43_LED_ASSOC, | 41 | B43_LED_ASSOC, |
38 | B43_LED_INACTIVE, | 42 | B43_LED_INACTIVE, |
39 | |||
40 | /* Behaviour values for testing. | ||
41 | * With these values it is easier to figure out | ||
42 | * the real behaviour of leds, in case the SPROM | ||
43 | * is missing information. | ||
44 | */ | ||
45 | B43_LED_TEST_BLINKSLOW, | ||
46 | B43_LED_TEST_BLINKMEDIUM, | ||
47 | B43_LED_TEST_BLINKFAST, | ||
48 | }; | 43 | }; |
49 | 44 | ||
50 | int b43_leds_init(struct b43_wldev *dev); | 45 | void b43_leds_init(struct b43_wldev *dev); |
51 | void b43_leds_exit(struct b43_wldev *dev); | 46 | void b43_leds_exit(struct b43_wldev *dev); |
52 | void b43_leds_update(struct b43_wldev *dev, int activity); | 47 | |
53 | void b43_leds_switch_all(struct b43_wldev *dev, int on); | 48 | |
49 | #else /* CONFIG_B43_LEDS */ | ||
50 | /* LED support disabled */ | ||
51 | |||
52 | struct b43_led { | ||
53 | /* empty */ | ||
54 | }; | ||
55 | |||
56 | static inline void b43_leds_init(struct b43_wldev *dev) | ||
57 | { | ||
58 | } | ||
59 | static inline void b43_leds_exit(struct b43_wldev *dev) | ||
60 | { | ||
61 | } | ||
62 | #endif /* CONFIG_B43_LEDS */ | ||
54 | 63 | ||
55 | #endif /* B43_LEDS_H_ */ | 64 | #endif /* B43_LEDS_H_ */ |
diff --git a/drivers/net/wireless/b43/main.c b/drivers/net/wireless/b43/main.c index 72467c86f8d4..2b81bd6165d8 100644 --- a/drivers/net/wireless/b43/main.c +++ b/drivers/net/wireless/b43/main.c | |||
@@ -84,10 +84,6 @@ static int modparam_long_retry = B43_DEFAULT_LONG_RETRY_LIMIT; | |||
84 | module_param_named(long_retry, modparam_long_retry, int, 0444); | 84 | module_param_named(long_retry, modparam_long_retry, int, 0444); |
85 | MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)"); | 85 | MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)"); |
86 | 86 | ||
87 | static int modparam_noleds; | ||
88 | module_param_named(noleds, modparam_noleds, int, 0444); | ||
89 | MODULE_PARM_DESC(noleds, "Turn off all LED activity"); | ||
90 | |||
91 | static char modparam_fwpostfix[16]; | 87 | static char modparam_fwpostfix[16]; |
92 | module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); | 88 | module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444); |
93 | MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load."); | 89 | MODULE_PARM_DESC(fwpostfix, "Postfix for the .fw files to load."); |
@@ -1391,7 +1387,7 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) | |||
1391 | u32 reason; | 1387 | u32 reason; |
1392 | u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; | 1388 | u32 dma_reason[ARRAY_SIZE(dev->dma_reason)]; |
1393 | u32 merged_dma_reason = 0; | 1389 | u32 merged_dma_reason = 0; |
1394 | int i, activity = 0; | 1390 | int i; |
1395 | unsigned long flags; | 1391 | unsigned long flags; |
1396 | 1392 | ||
1397 | spin_lock_irqsave(&dev->wl->irq_lock, flags); | 1393 | spin_lock_irqsave(&dev->wl->irq_lock, flags); |
@@ -1444,8 +1440,9 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) | |||
1444 | handle_irq_beacon(dev); | 1440 | handle_irq_beacon(dev); |
1445 | if (reason & B43_IRQ_PMQ) | 1441 | if (reason & B43_IRQ_PMQ) |
1446 | handle_irq_pmq(dev); | 1442 | handle_irq_pmq(dev); |
1447 | if (reason & B43_IRQ_TXFIFO_FLUSH_OK) ; | 1443 | if (reason & B43_IRQ_TXFIFO_FLUSH_OK) |
1448 | /*TODO*/ if (reason & B43_IRQ_NOISESAMPLE_OK) | 1444 | ;/* TODO */ |
1445 | if (reason & B43_IRQ_NOISESAMPLE_OK) | ||
1449 | handle_irq_noise(dev); | 1446 | handle_irq_noise(dev); |
1450 | 1447 | ||
1451 | /* Check the DMA reason registers for received data. */ | 1448 | /* Check the DMA reason registers for received data. */ |
@@ -1454,7 +1451,6 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) | |||
1454 | b43_pio_rx(dev->pio.queue0); | 1451 | b43_pio_rx(dev->pio.queue0); |
1455 | else | 1452 | else |
1456 | b43_dma_rx(dev->dma.rx_ring0); | 1453 | b43_dma_rx(dev->dma.rx_ring0); |
1457 | /* We intentionally don't set "activity" to 1, here. */ | ||
1458 | } | 1454 | } |
1459 | B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE); | 1455 | B43_WARN_ON(dma_reason[1] & B43_DMAIRQ_RX_DONE); |
1460 | B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE); | 1456 | B43_WARN_ON(dma_reason[2] & B43_DMAIRQ_RX_DONE); |
@@ -1463,19 +1459,13 @@ static void b43_interrupt_tasklet(struct b43_wldev *dev) | |||
1463 | b43_pio_rx(dev->pio.queue3); | 1459 | b43_pio_rx(dev->pio.queue3); |
1464 | else | 1460 | else |
1465 | b43_dma_rx(dev->dma.rx_ring3); | 1461 | b43_dma_rx(dev->dma.rx_ring3); |
1466 | activity = 1; | ||
1467 | } | 1462 | } |
1468 | B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE); | 1463 | B43_WARN_ON(dma_reason[4] & B43_DMAIRQ_RX_DONE); |
1469 | B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE); | 1464 | B43_WARN_ON(dma_reason[5] & B43_DMAIRQ_RX_DONE); |
1470 | 1465 | ||
1471 | if (reason & B43_IRQ_TX_OK) { | 1466 | if (reason & B43_IRQ_TX_OK) |
1472 | handle_irq_transmit_status(dev); | 1467 | handle_irq_transmit_status(dev); |
1473 | activity = 1; | ||
1474 | //TODO: In AP mode, this also causes sending of powersave responses. | ||
1475 | } | ||
1476 | 1468 | ||
1477 | if (!modparam_noleds) | ||
1478 | b43_leds_update(dev, activity); | ||
1479 | b43_interrupt_enable(dev, dev->irq_savedstate); | 1469 | b43_interrupt_enable(dev, dev->irq_savedstate); |
1480 | mmiowb(); | 1470 | mmiowb(); |
1481 | spin_unlock_irqrestore(&dev->wl->irq_lock, flags); | 1471 | spin_unlock_irqrestore(&dev->wl->irq_lock, flags); |
@@ -1927,7 +1917,6 @@ static int b43_gpio_init(struct b43_wldev *dev) | |||
1927 | b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) | 1917 | b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL) |
1928 | & ~B43_MACCTL_GPOUTSMSK); | 1918 | & ~B43_MACCTL_GPOUTSMSK); |
1929 | 1919 | ||
1930 | b43_leds_switch_all(dev, 0); | ||
1931 | b43_write16(dev, B43_MMIO_GPIO_MASK, b43_read16(dev, B43_MMIO_GPIO_MASK) | 1920 | b43_write16(dev, B43_MMIO_GPIO_MASK, b43_read16(dev, B43_MMIO_GPIO_MASK) |
1932 | | 0x000F); | 1921 | | 0x000F); |
1933 | 1922 | ||
@@ -2173,8 +2162,7 @@ static bool b43_is_hw_radio_enabled(struct b43_wldev *dev) | |||
2173 | static void b43_chip_exit(struct b43_wldev *dev) | 2162 | static void b43_chip_exit(struct b43_wldev *dev) |
2174 | { | 2163 | { |
2175 | b43_radio_turn_off(dev); | 2164 | b43_radio_turn_off(dev); |
2176 | if (!modparam_noleds) | 2165 | b43_leds_exit(dev); |
2177 | b43_leds_exit(dev); | ||
2178 | b43_gpio_cleanup(dev); | 2166 | b43_gpio_cleanup(dev); |
2179 | /* firmware is released later */ | 2167 | /* firmware is released later */ |
2180 | } | 2168 | } |
@@ -2202,9 +2190,11 @@ static int b43_chip_init(struct b43_wldev *dev) | |||
2202 | err = b43_gpio_init(dev); | 2190 | err = b43_gpio_init(dev); |
2203 | if (err) | 2191 | if (err) |
2204 | goto out; /* firmware is released later */ | 2192 | goto out; /* firmware is released later */ |
2193 | b43_leds_init(dev); | ||
2194 | |||
2205 | err = b43_upload_initvals(dev); | 2195 | err = b43_upload_initvals(dev); |
2206 | if (err) | 2196 | if (err) |
2207 | goto err_gpio_cleanup; | 2197 | goto err_leds_exit; |
2208 | b43_radio_turn_on(dev); | 2198 | b43_radio_turn_on(dev); |
2209 | 2199 | ||
2210 | b43_write16(dev, 0x03E6, 0x0000); | 2200 | b43_write16(dev, 0x03E6, 0x0000); |
@@ -2275,14 +2265,15 @@ static int b43_chip_init(struct b43_wldev *dev) | |||
2275 | 2265 | ||
2276 | err = 0; | 2266 | err = 0; |
2277 | b43dbg(dev->wl, "Chip initialized\n"); | 2267 | b43dbg(dev->wl, "Chip initialized\n"); |
2278 | out: | 2268 | out: |
2279 | return err; | 2269 | return err; |
2280 | 2270 | ||
2281 | err_radio_off: | 2271 | err_radio_off: |
2282 | b43_radio_turn_off(dev); | 2272 | b43_radio_turn_off(dev); |
2283 | err_gpio_cleanup: | 2273 | err_leds_exit: |
2274 | b43_leds_exit(dev); | ||
2284 | b43_gpio_cleanup(dev); | 2275 | b43_gpio_cleanup(dev); |
2285 | goto out; | 2276 | return err; |
2286 | } | 2277 | } |
2287 | 2278 | ||
2288 | static void b43_periodic_every120sec(struct b43_wldev *dev) | 2279 | static void b43_periodic_every120sec(struct b43_wldev *dev) |
@@ -2369,7 +2360,6 @@ static void b43_periodic_every1sec(struct b43_wldev *dev) | |||
2369 | dev->radio_hw_enable = radio_hw_enable; | 2360 | dev->radio_hw_enable = radio_hw_enable; |
2370 | b43info(dev->wl, "Radio hardware status changed to %s\n", | 2361 | b43info(dev->wl, "Radio hardware status changed to %s\n", |
2371 | radio_hw_enable ? "ENABLED" : "DISABLED"); | 2362 | radio_hw_enable ? "ENABLED" : "DISABLED"); |
2372 | b43_leds_update(dev, 0); | ||
2373 | } | 2363 | } |
2374 | } | 2364 | } |
2375 | 2365 | ||
@@ -3767,18 +3757,13 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) | |||
3767 | } else | 3757 | } else |
3768 | have_bphy = 1; | 3758 | have_bphy = 1; |
3769 | 3759 | ||
3770 | /* Initialize LEDs structs. */ | ||
3771 | err = b43_leds_init(dev); | ||
3772 | if (err) | ||
3773 | goto err_powerdown; | ||
3774 | |||
3775 | dev->phy.gmode = (have_gphy || have_bphy); | 3760 | dev->phy.gmode = (have_gphy || have_bphy); |
3776 | tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0; | 3761 | tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0; |
3777 | b43_wireless_core_reset(dev, tmp); | 3762 | b43_wireless_core_reset(dev, tmp); |
3778 | 3763 | ||
3779 | err = b43_phy_versioning(dev); | 3764 | err = b43_phy_versioning(dev); |
3780 | if (err) | 3765 | if (err) |
3781 | goto err_leds_exit; | 3766 | goto err_powerdown; |
3782 | /* Check if this device supports multiband. */ | 3767 | /* Check if this device supports multiband. */ |
3783 | if (!pdev || | 3768 | if (!pdev || |
3784 | (pdev->device != 0x4312 && | 3769 | (pdev->device != 0x4312 && |
@@ -3807,10 +3792,10 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) | |||
3807 | 3792 | ||
3808 | err = b43_validate_chipaccess(dev); | 3793 | err = b43_validate_chipaccess(dev); |
3809 | if (err) | 3794 | if (err) |
3810 | goto err_leds_exit; | 3795 | goto err_powerdown; |
3811 | err = b43_setup_modes(dev, have_aphy, have_bphy, have_gphy); | 3796 | err = b43_setup_modes(dev, have_aphy, have_bphy, have_gphy); |
3812 | if (err) | 3797 | if (err) |
3813 | goto err_leds_exit; | 3798 | goto err_powerdown; |
3814 | 3799 | ||
3815 | /* Now set some default "current_dev" */ | 3800 | /* Now set some default "current_dev" */ |
3816 | if (!wl->current_dev) | 3801 | if (!wl->current_dev) |
@@ -3825,8 +3810,6 @@ static int b43_wireless_core_attach(struct b43_wldev *dev) | |||
3825 | out: | 3810 | out: |
3826 | return err; | 3811 | return err; |
3827 | 3812 | ||
3828 | err_leds_exit: | ||
3829 | b43_leds_exit(dev); | ||
3830 | err_powerdown: | 3813 | err_powerdown: |
3831 | ssb_bus_may_powerdown(bus); | 3814 | ssb_bus_may_powerdown(bus); |
3832 | return err; | 3815 | return err; |