1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright 2006, Johannes Berg <johannes@sipsolutions.net>
6 /* just for IFNAMSIZ */
8 #include <linux/slab.h>
9 #include <linux/export.h>
12 void ieee80211_led_assoc(struct ieee80211_local
*local
, bool associated
)
14 if (!atomic_read(&local
->assoc_led_active
))
17 led_trigger_event(&local
->assoc_led
, LED_FULL
);
19 led_trigger_event(&local
->assoc_led
, LED_OFF
);
22 void ieee80211_led_radio(struct ieee80211_local
*local
, bool enabled
)
24 if (!atomic_read(&local
->radio_led_active
))
27 led_trigger_event(&local
->radio_led
, LED_FULL
);
29 led_trigger_event(&local
->radio_led
, LED_OFF
);
32 void ieee80211_alloc_led_names(struct ieee80211_local
*local
)
34 local
->rx_led
.name
= kasprintf(GFP_KERNEL
, "%srx",
35 wiphy_name(local
->hw
.wiphy
));
36 local
->tx_led
.name
= kasprintf(GFP_KERNEL
, "%stx",
37 wiphy_name(local
->hw
.wiphy
));
38 local
->assoc_led
.name
= kasprintf(GFP_KERNEL
, "%sassoc",
39 wiphy_name(local
->hw
.wiphy
));
40 local
->radio_led
.name
= kasprintf(GFP_KERNEL
, "%sradio",
41 wiphy_name(local
->hw
.wiphy
));
44 void ieee80211_free_led_names(struct ieee80211_local
*local
)
46 kfree(local
->rx_led
.name
);
47 kfree(local
->tx_led
.name
);
48 kfree(local
->assoc_led
.name
);
49 kfree(local
->radio_led
.name
);
52 static int ieee80211_tx_led_activate(struct led_classdev
*led_cdev
)
54 struct ieee80211_local
*local
= container_of(led_cdev
->trigger
,
55 struct ieee80211_local
,
58 atomic_inc(&local
->tx_led_active
);
63 static void ieee80211_tx_led_deactivate(struct led_classdev
*led_cdev
)
65 struct ieee80211_local
*local
= container_of(led_cdev
->trigger
,
66 struct ieee80211_local
,
69 atomic_dec(&local
->tx_led_active
);
72 static int ieee80211_rx_led_activate(struct led_classdev
*led_cdev
)
74 struct ieee80211_local
*local
= container_of(led_cdev
->trigger
,
75 struct ieee80211_local
,
78 atomic_inc(&local
->rx_led_active
);
83 static void ieee80211_rx_led_deactivate(struct led_classdev
*led_cdev
)
85 struct ieee80211_local
*local
= container_of(led_cdev
->trigger
,
86 struct ieee80211_local
,
89 atomic_dec(&local
->rx_led_active
);
92 static int ieee80211_assoc_led_activate(struct led_classdev
*led_cdev
)
94 struct ieee80211_local
*local
= container_of(led_cdev
->trigger
,
95 struct ieee80211_local
,
98 atomic_inc(&local
->assoc_led_active
);
103 static void ieee80211_assoc_led_deactivate(struct led_classdev
*led_cdev
)
105 struct ieee80211_local
*local
= container_of(led_cdev
->trigger
,
106 struct ieee80211_local
,
109 atomic_dec(&local
->assoc_led_active
);
112 static int ieee80211_radio_led_activate(struct led_classdev
*led_cdev
)
114 struct ieee80211_local
*local
= container_of(led_cdev
->trigger
,
115 struct ieee80211_local
,
118 atomic_inc(&local
->radio_led_active
);
123 static void ieee80211_radio_led_deactivate(struct led_classdev
*led_cdev
)
125 struct ieee80211_local
*local
= container_of(led_cdev
->trigger
,
126 struct ieee80211_local
,
129 atomic_dec(&local
->radio_led_active
);
132 static int ieee80211_tpt_led_activate(struct led_classdev
*led_cdev
)
134 struct ieee80211_local
*local
= container_of(led_cdev
->trigger
,
135 struct ieee80211_local
,
138 atomic_inc(&local
->tpt_led_active
);
143 static void ieee80211_tpt_led_deactivate(struct led_classdev
*led_cdev
)
145 struct ieee80211_local
*local
= container_of(led_cdev
->trigger
,
146 struct ieee80211_local
,
149 atomic_dec(&local
->tpt_led_active
);
152 void ieee80211_led_init(struct ieee80211_local
*local
)
154 atomic_set(&local
->rx_led_active
, 0);
155 local
->rx_led
.activate
= ieee80211_rx_led_activate
;
156 local
->rx_led
.deactivate
= ieee80211_rx_led_deactivate
;
157 if (local
->rx_led
.name
&& led_trigger_register(&local
->rx_led
)) {
158 kfree(local
->rx_led
.name
);
159 local
->rx_led
.name
= NULL
;
162 atomic_set(&local
->tx_led_active
, 0);
163 local
->tx_led
.activate
= ieee80211_tx_led_activate
;
164 local
->tx_led
.deactivate
= ieee80211_tx_led_deactivate
;
165 if (local
->tx_led
.name
&& led_trigger_register(&local
->tx_led
)) {
166 kfree(local
->tx_led
.name
);
167 local
->tx_led
.name
= NULL
;
170 atomic_set(&local
->assoc_led_active
, 0);
171 local
->assoc_led
.activate
= ieee80211_assoc_led_activate
;
172 local
->assoc_led
.deactivate
= ieee80211_assoc_led_deactivate
;
173 if (local
->assoc_led
.name
&& led_trigger_register(&local
->assoc_led
)) {
174 kfree(local
->assoc_led
.name
);
175 local
->assoc_led
.name
= NULL
;
178 atomic_set(&local
->radio_led_active
, 0);
179 local
->radio_led
.activate
= ieee80211_radio_led_activate
;
180 local
->radio_led
.deactivate
= ieee80211_radio_led_deactivate
;
181 if (local
->radio_led
.name
&& led_trigger_register(&local
->radio_led
)) {
182 kfree(local
->radio_led
.name
);
183 local
->radio_led
.name
= NULL
;
186 atomic_set(&local
->tpt_led_active
, 0);
187 if (local
->tpt_led_trigger
) {
188 local
->tpt_led
.activate
= ieee80211_tpt_led_activate
;
189 local
->tpt_led
.deactivate
= ieee80211_tpt_led_deactivate
;
190 if (led_trigger_register(&local
->tpt_led
)) {
191 kfree(local
->tpt_led_trigger
);
192 local
->tpt_led_trigger
= NULL
;
197 void ieee80211_led_exit(struct ieee80211_local
*local
)
199 if (local
->radio_led
.name
)
200 led_trigger_unregister(&local
->radio_led
);
201 if (local
->assoc_led
.name
)
202 led_trigger_unregister(&local
->assoc_led
);
203 if (local
->tx_led
.name
)
204 led_trigger_unregister(&local
->tx_led
);
205 if (local
->rx_led
.name
)
206 led_trigger_unregister(&local
->rx_led
);
208 if (local
->tpt_led_trigger
) {
209 led_trigger_unregister(&local
->tpt_led
);
210 kfree(local
->tpt_led_trigger
);
214 const char *__ieee80211_get_radio_led_name(struct ieee80211_hw
*hw
)
216 struct ieee80211_local
*local
= hw_to_local(hw
);
218 return local
->radio_led
.name
;
220 EXPORT_SYMBOL(__ieee80211_get_radio_led_name
);
222 const char *__ieee80211_get_assoc_led_name(struct ieee80211_hw
*hw
)
224 struct ieee80211_local
*local
= hw_to_local(hw
);
226 return local
->assoc_led
.name
;
228 EXPORT_SYMBOL(__ieee80211_get_assoc_led_name
);
230 const char *__ieee80211_get_tx_led_name(struct ieee80211_hw
*hw
)
232 struct ieee80211_local
*local
= hw_to_local(hw
);
234 return local
->tx_led
.name
;
236 EXPORT_SYMBOL(__ieee80211_get_tx_led_name
);
238 const char *__ieee80211_get_rx_led_name(struct ieee80211_hw
*hw
)
240 struct ieee80211_local
*local
= hw_to_local(hw
);
242 return local
->rx_led
.name
;
244 EXPORT_SYMBOL(__ieee80211_get_rx_led_name
);
246 static unsigned long tpt_trig_traffic(struct ieee80211_local
*local
,
247 struct tpt_led_trigger
*tpt_trig
)
249 unsigned long traffic
, delta
;
251 traffic
= tpt_trig
->tx_bytes
+ tpt_trig
->rx_bytes
;
253 delta
= traffic
- tpt_trig
->prev_traffic
;
254 tpt_trig
->prev_traffic
= traffic
;
255 return DIV_ROUND_UP(delta
, 1024 / 8);
258 static void tpt_trig_timer(struct timer_list
*t
)
260 struct tpt_led_trigger
*tpt_trig
= from_timer(tpt_trig
, t
, timer
);
261 struct ieee80211_local
*local
= tpt_trig
->local
;
262 struct led_classdev
*led_cdev
;
263 unsigned long on
, off
, tpt
;
266 if (!tpt_trig
->running
)
269 mod_timer(&tpt_trig
->timer
, round_jiffies(jiffies
+ HZ
));
271 tpt
= tpt_trig_traffic(local
, tpt_trig
);
273 /* default to just solid on */
277 for (i
= tpt_trig
->blink_table_len
- 1; i
>= 0; i
--) {
278 if (tpt_trig
->blink_table
[i
].throughput
< 0 ||
279 tpt
> tpt_trig
->blink_table
[i
].throughput
) {
280 off
= tpt_trig
->blink_table
[i
].blink_time
/ 2;
281 on
= tpt_trig
->blink_table
[i
].blink_time
- off
;
286 read_lock(&local
->tpt_led
.leddev_list_lock
);
287 list_for_each_entry(led_cdev
, &local
->tpt_led
.led_cdevs
, trig_list
)
288 led_blink_set(led_cdev
, &on
, &off
);
289 read_unlock(&local
->tpt_led
.leddev_list_lock
);
293 __ieee80211_create_tpt_led_trigger(struct ieee80211_hw
*hw
,
295 const struct ieee80211_tpt_blink
*blink_table
,
296 unsigned int blink_table_len
)
298 struct ieee80211_local
*local
= hw_to_local(hw
);
299 struct tpt_led_trigger
*tpt_trig
;
301 if (WARN_ON(local
->tpt_led_trigger
))
304 tpt_trig
= kzalloc(sizeof(struct tpt_led_trigger
), GFP_KERNEL
);
308 snprintf(tpt_trig
->name
, sizeof(tpt_trig
->name
),
309 "%stpt", wiphy_name(local
->hw
.wiphy
));
311 local
->tpt_led
.name
= tpt_trig
->name
;
313 tpt_trig
->blink_table
= blink_table
;
314 tpt_trig
->blink_table_len
= blink_table_len
;
315 tpt_trig
->want
= flags
;
316 tpt_trig
->local
= local
;
318 timer_setup(&tpt_trig
->timer
, tpt_trig_timer
, 0);
320 local
->tpt_led_trigger
= tpt_trig
;
322 return tpt_trig
->name
;
324 EXPORT_SYMBOL(__ieee80211_create_tpt_led_trigger
);
326 static void ieee80211_start_tpt_led_trig(struct ieee80211_local
*local
)
328 struct tpt_led_trigger
*tpt_trig
= local
->tpt_led_trigger
;
330 if (tpt_trig
->running
)
334 tpt_trig_traffic(local
, tpt_trig
);
335 tpt_trig
->running
= true;
337 tpt_trig_timer(&tpt_trig
->timer
);
338 mod_timer(&tpt_trig
->timer
, round_jiffies(jiffies
+ HZ
));
341 static void ieee80211_stop_tpt_led_trig(struct ieee80211_local
*local
)
343 struct tpt_led_trigger
*tpt_trig
= local
->tpt_led_trigger
;
344 struct led_classdev
*led_cdev
;
346 if (!tpt_trig
->running
)
349 tpt_trig
->running
= false;
350 del_timer_sync(&tpt_trig
->timer
);
352 read_lock(&local
->tpt_led
.leddev_list_lock
);
353 list_for_each_entry(led_cdev
, &local
->tpt_led
.led_cdevs
, trig_list
)
354 led_set_brightness(led_cdev
, LED_OFF
);
355 read_unlock(&local
->tpt_led
.leddev_list_lock
);
358 void ieee80211_mod_tpt_led_trig(struct ieee80211_local
*local
,
359 unsigned int types_on
, unsigned int types_off
)
361 struct tpt_led_trigger
*tpt_trig
= local
->tpt_led_trigger
;
364 WARN_ON(types_on
& types_off
);
369 tpt_trig
->active
&= ~types_off
;
370 tpt_trig
->active
|= types_on
;
373 * Regardless of wanted state, we shouldn't blink when
374 * the radio is disabled -- this can happen due to some
375 * code ordering issues with __ieee80211_recalc_idle()
376 * being called before the radio is started.
378 allowed
= tpt_trig
->active
& IEEE80211_TPT_LEDTRIG_FL_RADIO
;
380 if (!allowed
|| !(tpt_trig
->active
& tpt_trig
->want
))
381 ieee80211_stop_tpt_led_trig(local
);
383 ieee80211_start_tpt_led_trig(local
);