diff options
Diffstat (limited to 'net/mac80211/led.c')
-rw-r--r-- | net/mac80211/led.c | 186 |
1 files changed, 166 insertions, 20 deletions
diff --git a/net/mac80211/led.c b/net/mac80211/led.c index 063aad944246..4905eb8af572 100644 --- a/net/mac80211/led.c +++ b/net/mac80211/led.c | |||
@@ -54,12 +54,22 @@ void ieee80211_led_radio(struct ieee80211_local *local, bool enabled) | |||
54 | led_trigger_event(local->radio_led, LED_OFF); | 54 | led_trigger_event(local->radio_led, LED_OFF); |
55 | } | 55 | } |
56 | 56 | ||
57 | void ieee80211_led_names(struct ieee80211_local *local) | ||
58 | { | ||
59 | snprintf(local->rx_led_name, sizeof(local->rx_led_name), | ||
60 | "%srx", wiphy_name(local->hw.wiphy)); | ||
61 | snprintf(local->tx_led_name, sizeof(local->tx_led_name), | ||
62 | "%stx", wiphy_name(local->hw.wiphy)); | ||
63 | snprintf(local->assoc_led_name, sizeof(local->assoc_led_name), | ||
64 | "%sassoc", wiphy_name(local->hw.wiphy)); | ||
65 | snprintf(local->radio_led_name, sizeof(local->radio_led_name), | ||
66 | "%sradio", wiphy_name(local->hw.wiphy)); | ||
67 | } | ||
68 | |||
57 | void ieee80211_led_init(struct ieee80211_local *local) | 69 | void ieee80211_led_init(struct ieee80211_local *local) |
58 | { | 70 | { |
59 | local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); | 71 | local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); |
60 | if (local->rx_led) { | 72 | if (local->rx_led) { |
61 | snprintf(local->rx_led_name, sizeof(local->rx_led_name), | ||
62 | "%srx", wiphy_name(local->hw.wiphy)); | ||
63 | local->rx_led->name = local->rx_led_name; | 73 | local->rx_led->name = local->rx_led_name; |
64 | if (led_trigger_register(local->rx_led)) { | 74 | if (led_trigger_register(local->rx_led)) { |
65 | kfree(local->rx_led); | 75 | kfree(local->rx_led); |
@@ -69,8 +79,6 @@ void ieee80211_led_init(struct ieee80211_local *local) | |||
69 | 79 | ||
70 | local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); | 80 | local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); |
71 | if (local->tx_led) { | 81 | if (local->tx_led) { |
72 | snprintf(local->tx_led_name, sizeof(local->tx_led_name), | ||
73 | "%stx", wiphy_name(local->hw.wiphy)); | ||
74 | local->tx_led->name = local->tx_led_name; | 82 | local->tx_led->name = local->tx_led_name; |
75 | if (led_trigger_register(local->tx_led)) { | 83 | if (led_trigger_register(local->tx_led)) { |
76 | kfree(local->tx_led); | 84 | kfree(local->tx_led); |
@@ -80,8 +88,6 @@ void ieee80211_led_init(struct ieee80211_local *local) | |||
80 | 88 | ||
81 | local->assoc_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); | 89 | local->assoc_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); |
82 | if (local->assoc_led) { | 90 | if (local->assoc_led) { |
83 | snprintf(local->assoc_led_name, sizeof(local->assoc_led_name), | ||
84 | "%sassoc", wiphy_name(local->hw.wiphy)); | ||
85 | local->assoc_led->name = local->assoc_led_name; | 91 | local->assoc_led->name = local->assoc_led_name; |
86 | if (led_trigger_register(local->assoc_led)) { | 92 | if (led_trigger_register(local->assoc_led)) { |
87 | kfree(local->assoc_led); | 93 | kfree(local->assoc_led); |
@@ -91,14 +97,19 @@ void ieee80211_led_init(struct ieee80211_local *local) | |||
91 | 97 | ||
92 | local->radio_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); | 98 | local->radio_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL); |
93 | if (local->radio_led) { | 99 | if (local->radio_led) { |
94 | snprintf(local->radio_led_name, sizeof(local->radio_led_name), | ||
95 | "%sradio", wiphy_name(local->hw.wiphy)); | ||
96 | local->radio_led->name = local->radio_led_name; | 100 | local->radio_led->name = local->radio_led_name; |
97 | if (led_trigger_register(local->radio_led)) { | 101 | if (led_trigger_register(local->radio_led)) { |
98 | kfree(local->radio_led); | 102 | kfree(local->radio_led); |
99 | local->radio_led = NULL; | 103 | local->radio_led = NULL; |
100 | } | 104 | } |
101 | } | 105 | } |
106 | |||
107 | if (local->tpt_led_trigger) { | ||
108 | if (led_trigger_register(&local->tpt_led_trigger->trig)) { | ||
109 | kfree(local->tpt_led_trigger); | ||
110 | local->tpt_led_trigger = NULL; | ||
111 | } | ||
112 | } | ||
102 | } | 113 | } |
103 | 114 | ||
104 | void ieee80211_led_exit(struct ieee80211_local *local) | 115 | void ieee80211_led_exit(struct ieee80211_local *local) |
@@ -119,15 +130,18 @@ void ieee80211_led_exit(struct ieee80211_local *local) | |||
119 | led_trigger_unregister(local->rx_led); | 130 | led_trigger_unregister(local->rx_led); |
120 | kfree(local->rx_led); | 131 | kfree(local->rx_led); |
121 | } | 132 | } |
133 | |||
134 | if (local->tpt_led_trigger) { | ||
135 | led_trigger_unregister(&local->tpt_led_trigger->trig); | ||
136 | kfree(local->tpt_led_trigger); | ||
137 | } | ||
122 | } | 138 | } |
123 | 139 | ||
124 | char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw) | 140 | char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw) |
125 | { | 141 | { |
126 | struct ieee80211_local *local = hw_to_local(hw); | 142 | struct ieee80211_local *local = hw_to_local(hw); |
127 | 143 | ||
128 | if (local->radio_led) | 144 | return local->radio_led_name; |
129 | return local->radio_led_name; | ||
130 | return NULL; | ||
131 | } | 145 | } |
132 | EXPORT_SYMBOL(__ieee80211_get_radio_led_name); | 146 | EXPORT_SYMBOL(__ieee80211_get_radio_led_name); |
133 | 147 | ||
@@ -135,9 +149,7 @@ char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw) | |||
135 | { | 149 | { |
136 | struct ieee80211_local *local = hw_to_local(hw); | 150 | struct ieee80211_local *local = hw_to_local(hw); |
137 | 151 | ||
138 | if (local->assoc_led) | 152 | return local->assoc_led_name; |
139 | return local->assoc_led_name; | ||
140 | return NULL; | ||
141 | } | 153 | } |
142 | EXPORT_SYMBOL(__ieee80211_get_assoc_led_name); | 154 | EXPORT_SYMBOL(__ieee80211_get_assoc_led_name); |
143 | 155 | ||
@@ -145,9 +157,7 @@ char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw) | |||
145 | { | 157 | { |
146 | struct ieee80211_local *local = hw_to_local(hw); | 158 | struct ieee80211_local *local = hw_to_local(hw); |
147 | 159 | ||
148 | if (local->tx_led) | 160 | return local->tx_led_name; |
149 | return local->tx_led_name; | ||
150 | return NULL; | ||
151 | } | 161 | } |
152 | EXPORT_SYMBOL(__ieee80211_get_tx_led_name); | 162 | EXPORT_SYMBOL(__ieee80211_get_tx_led_name); |
153 | 163 | ||
@@ -155,8 +165,144 @@ char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw) | |||
155 | { | 165 | { |
156 | struct ieee80211_local *local = hw_to_local(hw); | 166 | struct ieee80211_local *local = hw_to_local(hw); |
157 | 167 | ||
158 | if (local->rx_led) | 168 | return local->rx_led_name; |
159 | return local->rx_led_name; | ||
160 | return NULL; | ||
161 | } | 169 | } |
162 | EXPORT_SYMBOL(__ieee80211_get_rx_led_name); | 170 | EXPORT_SYMBOL(__ieee80211_get_rx_led_name); |
171 | |||
172 | static unsigned long tpt_trig_traffic(struct ieee80211_local *local, | ||
173 | struct tpt_led_trigger *tpt_trig) | ||
174 | { | ||
175 | unsigned long traffic, delta; | ||
176 | |||
177 | traffic = tpt_trig->tx_bytes + tpt_trig->rx_bytes; | ||
178 | |||
179 | delta = traffic - tpt_trig->prev_traffic; | ||
180 | tpt_trig->prev_traffic = traffic; | ||
181 | return DIV_ROUND_UP(delta, 1024 / 8); | ||
182 | } | ||
183 | |||
184 | static void tpt_trig_timer(unsigned long data) | ||
185 | { | ||
186 | struct ieee80211_local *local = (void *)data; | ||
187 | struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger; | ||
188 | struct led_classdev *led_cdev; | ||
189 | unsigned long on, off, tpt; | ||
190 | int i; | ||
191 | |||
192 | if (!tpt_trig->running) | ||
193 | return; | ||
194 | |||
195 | mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ)); | ||
196 | |||
197 | tpt = tpt_trig_traffic(local, tpt_trig); | ||
198 | |||
199 | /* default to just solid on */ | ||
200 | on = 1; | ||
201 | off = 0; | ||
202 | |||
203 | for (i = tpt_trig->blink_table_len - 1; i >= 0; i--) { | ||
204 | if (tpt_trig->blink_table[i].throughput < 0 || | ||
205 | tpt > tpt_trig->blink_table[i].throughput) { | ||
206 | off = tpt_trig->blink_table[i].blink_time / 2; | ||
207 | on = tpt_trig->blink_table[i].blink_time - off; | ||
208 | break; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | read_lock(&tpt_trig->trig.leddev_list_lock); | ||
213 | list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list) | ||
214 | led_blink_set(led_cdev, &on, &off); | ||
215 | read_unlock(&tpt_trig->trig.leddev_list_lock); | ||
216 | } | ||
217 | |||
218 | extern char *__ieee80211_create_tpt_led_trigger( | ||
219 | struct ieee80211_hw *hw, unsigned int flags, | ||
220 | const struct ieee80211_tpt_blink *blink_table, | ||
221 | unsigned int blink_table_len) | ||
222 | { | ||
223 | struct ieee80211_local *local = hw_to_local(hw); | ||
224 | struct tpt_led_trigger *tpt_trig; | ||
225 | |||
226 | if (WARN_ON(local->tpt_led_trigger)) | ||
227 | return NULL; | ||
228 | |||
229 | tpt_trig = kzalloc(sizeof(struct tpt_led_trigger), GFP_KERNEL); | ||
230 | if (!tpt_trig) | ||
231 | return NULL; | ||
232 | |||
233 | snprintf(tpt_trig->name, sizeof(tpt_trig->name), | ||
234 | "%stpt", wiphy_name(local->hw.wiphy)); | ||
235 | |||
236 | tpt_trig->trig.name = tpt_trig->name; | ||
237 | |||
238 | tpt_trig->blink_table = blink_table; | ||
239 | tpt_trig->blink_table_len = blink_table_len; | ||
240 | tpt_trig->want = flags; | ||
241 | |||
242 | setup_timer(&tpt_trig->timer, tpt_trig_timer, (unsigned long)local); | ||
243 | |||
244 | local->tpt_led_trigger = tpt_trig; | ||
245 | |||
246 | return tpt_trig->name; | ||
247 | } | ||
248 | EXPORT_SYMBOL(__ieee80211_create_tpt_led_trigger); | ||
249 | |||
250 | static void ieee80211_start_tpt_led_trig(struct ieee80211_local *local) | ||
251 | { | ||
252 | struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger; | ||
253 | |||
254 | if (tpt_trig->running) | ||
255 | return; | ||
256 | |||
257 | /* reset traffic */ | ||
258 | tpt_trig_traffic(local, tpt_trig); | ||
259 | tpt_trig->running = true; | ||
260 | |||
261 | tpt_trig_timer((unsigned long)local); | ||
262 | mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ)); | ||
263 | } | ||
264 | |||
265 | static void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local) | ||
266 | { | ||
267 | struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger; | ||
268 | struct led_classdev *led_cdev; | ||
269 | |||
270 | if (!tpt_trig->running) | ||
271 | return; | ||
272 | |||
273 | tpt_trig->running = false; | ||
274 | del_timer_sync(&tpt_trig->timer); | ||
275 | |||
276 | read_lock(&tpt_trig->trig.leddev_list_lock); | ||
277 | list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list) | ||
278 | led_brightness_set(led_cdev, LED_OFF); | ||
279 | read_unlock(&tpt_trig->trig.leddev_list_lock); | ||
280 | } | ||
281 | |||
282 | void ieee80211_mod_tpt_led_trig(struct ieee80211_local *local, | ||
283 | unsigned int types_on, unsigned int types_off) | ||
284 | { | ||
285 | struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger; | ||
286 | bool allowed; | ||
287 | |||
288 | WARN_ON(types_on & types_off); | ||
289 | |||
290 | if (!tpt_trig) | ||
291 | return; | ||
292 | |||
293 | tpt_trig->active &= ~types_off; | ||
294 | tpt_trig->active |= types_on; | ||
295 | |||
296 | /* | ||
297 | * Regardless of wanted state, we shouldn't blink when | ||
298 | * the radio is disabled -- this can happen due to some | ||
299 | * code ordering issues with __ieee80211_recalc_idle() | ||
300 | * being called before the radio is started. | ||
301 | */ | ||
302 | allowed = tpt_trig->active & IEEE80211_TPT_LEDTRIG_FL_RADIO; | ||
303 | |||
304 | if (!allowed || !(tpt_trig->active & tpt_trig->want)) | ||
305 | ieee80211_stop_tpt_led_trig(local); | ||
306 | else | ||
307 | ieee80211_start_tpt_led_trig(local); | ||
308 | } | ||