2 * Copyright 2006, Johannes Berg <johannes@sipsolutions.net>
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License version 2 as
6 * published by the Free Software Foundation.
9 /* just for IFNAMSIZ */
11 #include <linux/slab.h>
12 #include <linux/export.h>
15 void ieee80211_led_assoc(struct ieee80211_local
*local
, bool associated
)
17 if (!atomic_read(&local
->assoc_led_active
))
20 led_trigger_event(&local
->assoc_led
, LED_FULL
);
22 led_trigger_event(&local
->assoc_led
, LED_OFF
);
25 void ieee80211_led_radio(struct ieee80211_local
*local
, bool enabled
)
27 if (!atomic_read(&local
->radio_led_active
))
30 led_trigger_event(&local
->radio_led
, LED_FULL
);
32 led_trigger_event(&local
->radio_led
, LED_OFF
);
35 void ieee80211_alloc_led_names(struct ieee80211_local
*local
)
37 local
->rx_led
.name
= kasprintf(GFP_KERNEL
, "%srx",
38 wiphy_name(local
->hw
.wiphy
));
39 local
->tx_led
.name
= kasprintf(GFP_KERNEL
, "%stx",
40 wiphy_name(local
->hw
.wiphy
));
41 local
->assoc_led
.name
= kasprintf(GFP_KERNEL
, "%sassoc",
42 wiphy_name(local
->hw
.wiphy
));
43 local
->radio_led
.name
= kasprintf(GFP_KERNEL
, "%sradio",
44 wiphy_name(local
->hw
.wiphy
));
47 void ieee80211_free_led_names(struct ieee80211_local
*local
)
49 kfree(local
->rx_led
.name
);
50 kfree(local
->tx_led
.name
);
51 kfree(local
->assoc_led
.name
);
52 kfree(local
->radio_led
.name
);
55 static int ieee80211_tx_led_activate(struct led_classdev
*led_cdev
)
57 struct ieee80211_local
*local
= container_of(led_cdev
->trigger
,
58 struct ieee80211_local
,
61 atomic_inc(&local
->tx_led_active
);
66 static void ieee80211_tx_led_deactivate(struct led_classdev
*led_cdev
)
68 struct ieee80211_local
*local
= container_of(led_cdev
->trigger
,
69 struct ieee80211_local
,
72 atomic_dec(&local
->tx_led_active
);
75 static int ieee80211_rx_led_activate(struct led_classdev
*led_cdev
)
77 struct ieee80211_local
*local
= container_of(led_cdev
->trigger
,
78 struct ieee80211_local
,
81 atomic_inc(&local
->rx_led_active
);
86 static void ieee80211_rx_led_deactivate(struct led_classdev
*led_cdev
)
88 struct ieee80211_local
*local
= container_of(led_cdev
->trigger
,
89 struct ieee80211_local
,
92 atomic_dec(&local
->rx_led_active
);
95 static int ieee80211_assoc_led_activate(struct led_classdev
*led_cdev
)
97 struct ieee80211_local
*local
= container_of(led_cdev
->trigger
,
98 struct ieee80211_local
,
101 atomic_inc(&local
->assoc_led_active
);
106 static void ieee80211_assoc_led_deactivate(struct led_classdev
*led_cdev
)
108 struct ieee80211_local
*local
= container_of(led_cdev
->trigger
,
109 struct ieee80211_local
,
112 atomic_dec(&local
->assoc_led_active
);
115 static int ieee80211_radio_led_activate(struct led_classdev
*led_cdev
)
117 struct ieee80211_local
*local
= container_of(led_cdev
->trigger
,
118 struct ieee80211_local
,
121 atomic_inc(&local
->radio_led_active
);
126 static void ieee80211_radio_led_deactivate(struct led_classdev
*led_cdev
)
128 struct ieee80211_local
*local
= container_of(led_cdev
->trigger
,
129 struct ieee80211_local
,
132 atomic_dec(&local
->radio_led_active
);
135 static int ieee80211_tpt_led_activate(struct led_classdev
*led_cdev
)
137 struct ieee80211_local
*local
= container_of(led_cdev
->trigger
,
138 struct ieee80211_local
,
141 atomic_inc(&local
->tpt_led_active
);
146 static void ieee80211_tpt_led_deactivate(struct led_classdev
*led_cdev
)
148 struct ieee80211_local
*local
= container_of(led_cdev
->trigger
,
149 struct ieee80211_local
,
152 atomic_dec(&local
->tpt_led_active
);
155 void ieee80211_led_init(struct ieee80211_local
*local
)
157 atomic_set(&local
->rx_led_active
, 0);
158 local
->rx_led
.activate
= ieee80211_rx_led_activate
;
159 local
->rx_led
.deactivate
= ieee80211_rx_led_deactivate
;
160 if (local
->rx_led
.name
&& led_trigger_register(&local
->rx_led
)) {
161 kfree(local
->rx_led
.name
);
162 local
->rx_led
.name
= NULL
;
165 atomic_set(&local
->tx_led_active
, 0);
166 local
->tx_led
.activate
= ieee80211_tx_led_activate
;
167 local
->tx_led
.deactivate
= ieee80211_tx_led_deactivate
;
168 if (local
->tx_led
.name
&& led_trigger_register(&local
->tx_led
)) {
169 kfree(local
->tx_led
.name
);
170 local
->tx_led
.name
= NULL
;
173 atomic_set(&local
->assoc_led_active
, 0);
174 local
->assoc_led
.activate
= ieee80211_assoc_led_activate
;
175 local
->assoc_led
.deactivate
= ieee80211_assoc_led_deactivate
;
176 if (local
->assoc_led
.name
&& led_trigger_register(&local
->assoc_led
)) {
177 kfree(local
->assoc_led
.name
);
178 local
->assoc_led
.name
= NULL
;
181 atomic_set(&local
->radio_led_active
, 0);
182 local
->radio_led
.activate
= ieee80211_radio_led_activate
;
183 local
->radio_led
.deactivate
= ieee80211_radio_led_deactivate
;
184 if (local
->radio_led
.name
&& led_trigger_register(&local
->radio_led
)) {
185 kfree(local
->radio_led
.name
);
186 local
->radio_led
.name
= NULL
;
189 atomic_set(&local
->tpt_led_active
, 0);
190 if (local
->tpt_led_trigger
) {
191 local
->tpt_led
.activate
= ieee80211_tpt_led_activate
;
192 local
->tpt_led
.deactivate
= ieee80211_tpt_led_deactivate
;
193 if (led_trigger_register(&local
->tpt_led
)) {
194 kfree(local
->tpt_led_trigger
);
195 local
->tpt_led_trigger
= NULL
;
200 void ieee80211_led_exit(struct ieee80211_local
*local
)
202 if (local
->radio_led
.name
)
203 led_trigger_unregister(&local
->radio_led
);
204 if (local
->assoc_led
.name
)
205 led_trigger_unregister(&local
->assoc_led
);
206 if (local
->tx_led
.name
)
207 led_trigger_unregister(&local
->tx_led
);
208 if (local
->rx_led
.name
)
209 led_trigger_unregister(&local
->rx_led
);
211 if (local
->tpt_led_trigger
) {
212 led_trigger_unregister(&local
->tpt_led
);
213 kfree(local
->tpt_led_trigger
);
217 const char *__ieee80211_get_radio_led_name(struct ieee80211_hw
*hw
)
219 struct ieee80211_local
*local
= hw_to_local(hw
);
221 return local
->radio_led
.name
;
223 EXPORT_SYMBOL(__ieee80211_get_radio_led_name
);
225 const char *__ieee80211_get_assoc_led_name(struct ieee80211_hw
*hw
)
227 struct ieee80211_local
*local
= hw_to_local(hw
);
229 return local
->assoc_led
.name
;
231 EXPORT_SYMBOL(__ieee80211_get_assoc_led_name
);
233 const char *__ieee80211_get_tx_led_name(struct ieee80211_hw
*hw
)
235 struct ieee80211_local
*local
= hw_to_local(hw
);
237 return local
->tx_led
.name
;
239 EXPORT_SYMBOL(__ieee80211_get_tx_led_name
);
241 const char *__ieee80211_get_rx_led_name(struct ieee80211_hw
*hw
)
243 struct ieee80211_local
*local
= hw_to_local(hw
);
245 return local
->rx_led
.name
;
247 EXPORT_SYMBOL(__ieee80211_get_rx_led_name
);
249 static unsigned long tpt_trig_traffic(struct ieee80211_local
*local
,
250 struct tpt_led_trigger
*tpt_trig
)
252 unsigned long traffic
, delta
;
254 traffic
= tpt_trig
->tx_bytes
+ tpt_trig
->rx_bytes
;
256 delta
= traffic
- tpt_trig
->prev_traffic
;
257 tpt_trig
->prev_traffic
= traffic
;
258 return DIV_ROUND_UP(delta
, 1024 / 8);
261 static void tpt_trig_timer(struct timer_list
*t
)
263 struct tpt_led_trigger
*tpt_trig
= from_timer(tpt_trig
, t
, timer
);
264 struct ieee80211_local
*local
= tpt_trig
->local
;
265 struct led_classdev
*led_cdev
;
266 unsigned long on
, off
, tpt
;
269 if (!tpt_trig
->running
)
272 mod_timer(&tpt_trig
->timer
, round_jiffies(jiffies
+ HZ
));
274 tpt
= tpt_trig_traffic(local
, tpt_trig
);
276 /* default to just solid on */
280 for (i
= tpt_trig
->blink_table_len
- 1; i
>= 0; i
--) {
281 if (tpt_trig
->blink_table
[i
].throughput
< 0 ||
282 tpt
> tpt_trig
->blink_table
[i
].throughput
) {
283 off
= tpt_trig
->blink_table
[i
].blink_time
/ 2;
284 on
= tpt_trig
->blink_table
[i
].blink_time
- off
;
289 read_lock(&local
->tpt_led
.leddev_list_lock
);
290 list_for_each_entry(led_cdev
, &local
->tpt_led
.led_cdevs
, trig_list
)
291 led_blink_set(led_cdev
, &on
, &off
);
292 read_unlock(&local
->tpt_led
.leddev_list_lock
);
296 __ieee80211_create_tpt_led_trigger(struct ieee80211_hw
*hw
,
298 const struct ieee80211_tpt_blink
*blink_table
,
299 unsigned int blink_table_len
)
301 struct ieee80211_local
*local
= hw_to_local(hw
);
302 struct tpt_led_trigger
*tpt_trig
;
304 if (WARN_ON(local
->tpt_led_trigger
))
307 tpt_trig
= kzalloc(sizeof(struct tpt_led_trigger
), GFP_KERNEL
);
311 snprintf(tpt_trig
->name
, sizeof(tpt_trig
->name
),
312 "%stpt", wiphy_name(local
->hw
.wiphy
));
314 local
->tpt_led
.name
= tpt_trig
->name
;
316 tpt_trig
->blink_table
= blink_table
;
317 tpt_trig
->blink_table_len
= blink_table_len
;
318 tpt_trig
->want
= flags
;
319 tpt_trig
->local
= local
;
321 timer_setup(&tpt_trig
->timer
, tpt_trig_timer
, 0);
323 local
->tpt_led_trigger
= tpt_trig
;
325 return tpt_trig
->name
;
327 EXPORT_SYMBOL(__ieee80211_create_tpt_led_trigger
);
329 static void ieee80211_start_tpt_led_trig(struct ieee80211_local
*local
)
331 struct tpt_led_trigger
*tpt_trig
= local
->tpt_led_trigger
;
333 if (tpt_trig
->running
)
337 tpt_trig_traffic(local
, tpt_trig
);
338 tpt_trig
->running
= true;
340 tpt_trig_timer(&tpt_trig
->timer
);
341 mod_timer(&tpt_trig
->timer
, round_jiffies(jiffies
+ HZ
));
344 static void ieee80211_stop_tpt_led_trig(struct ieee80211_local
*local
)
346 struct tpt_led_trigger
*tpt_trig
= local
->tpt_led_trigger
;
347 struct led_classdev
*led_cdev
;
349 if (!tpt_trig
->running
)
352 tpt_trig
->running
= false;
353 del_timer_sync(&tpt_trig
->timer
);
355 read_lock(&local
->tpt_led
.leddev_list_lock
);
356 list_for_each_entry(led_cdev
, &local
->tpt_led
.led_cdevs
, trig_list
)
357 led_set_brightness(led_cdev
, LED_OFF
);
358 read_unlock(&local
->tpt_led
.leddev_list_lock
);
361 void ieee80211_mod_tpt_led_trig(struct ieee80211_local
*local
,
362 unsigned int types_on
, unsigned int types_off
)
364 struct tpt_led_trigger
*tpt_trig
= local
->tpt_led_trigger
;
367 WARN_ON(types_on
& types_off
);
372 tpt_trig
->active
&= ~types_off
;
373 tpt_trig
->active
|= types_on
;
376 * Regardless of wanted state, we shouldn't blink when
377 * the radio is disabled -- this can happen due to some
378 * code ordering issues with __ieee80211_recalc_idle()
379 * being called before the radio is started.
381 allowed
= tpt_trig
->active
& IEEE80211_TPT_LEDTRIG_FL_RADIO
;
383 if (!allowed
|| !(tpt_trig
->active
& tpt_trig
->want
))
384 ieee80211_stop_tpt_led_trig(local
);
386 ieee80211_start_tpt_led_trig(local
);