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 #define MAC80211_BLINK_DELAY 50 /* ms */
17 void ieee80211_led_rx(struct ieee80211_local
*local
)
19 unsigned long led_delay
= MAC80211_BLINK_DELAY
;
20 if (unlikely(!local
->rx_led
))
22 led_trigger_blink_oneshot(local
->rx_led
, &led_delay
, &led_delay
, 0);
25 void ieee80211_led_tx(struct ieee80211_local
*local
)
27 unsigned long led_delay
= MAC80211_BLINK_DELAY
;
28 if (unlikely(!local
->tx_led
))
30 led_trigger_blink_oneshot(local
->tx_led
, &led_delay
, &led_delay
, 0);
33 void ieee80211_led_assoc(struct ieee80211_local
*local
, bool associated
)
35 if (unlikely(!local
->assoc_led
))
38 led_trigger_event(local
->assoc_led
, LED_FULL
);
40 led_trigger_event(local
->assoc_led
, LED_OFF
);
43 void ieee80211_led_radio(struct ieee80211_local
*local
, bool enabled
)
45 if (unlikely(!local
->radio_led
))
48 led_trigger_event(local
->radio_led
, LED_FULL
);
50 led_trigger_event(local
->radio_led
, LED_OFF
);
53 void ieee80211_led_names(struct ieee80211_local
*local
)
55 snprintf(local
->rx_led_name
, sizeof(local
->rx_led_name
),
56 "%srx", wiphy_name(local
->hw
.wiphy
));
57 snprintf(local
->tx_led_name
, sizeof(local
->tx_led_name
),
58 "%stx", wiphy_name(local
->hw
.wiphy
));
59 snprintf(local
->assoc_led_name
, sizeof(local
->assoc_led_name
),
60 "%sassoc", wiphy_name(local
->hw
.wiphy
));
61 snprintf(local
->radio_led_name
, sizeof(local
->radio_led_name
),
62 "%sradio", wiphy_name(local
->hw
.wiphy
));
65 void ieee80211_led_init(struct ieee80211_local
*local
)
67 local
->rx_led
= kzalloc(sizeof(struct led_trigger
), GFP_KERNEL
);
69 local
->rx_led
->name
= local
->rx_led_name
;
70 if (led_trigger_register(local
->rx_led
)) {
76 local
->tx_led
= kzalloc(sizeof(struct led_trigger
), GFP_KERNEL
);
78 local
->tx_led
->name
= local
->tx_led_name
;
79 if (led_trigger_register(local
->tx_led
)) {
85 local
->assoc_led
= kzalloc(sizeof(struct led_trigger
), GFP_KERNEL
);
86 if (local
->assoc_led
) {
87 local
->assoc_led
->name
= local
->assoc_led_name
;
88 if (led_trigger_register(local
->assoc_led
)) {
89 kfree(local
->assoc_led
);
90 local
->assoc_led
= NULL
;
94 local
->radio_led
= kzalloc(sizeof(struct led_trigger
), GFP_KERNEL
);
95 if (local
->radio_led
) {
96 local
->radio_led
->name
= local
->radio_led_name
;
97 if (led_trigger_register(local
->radio_led
)) {
98 kfree(local
->radio_led
);
99 local
->radio_led
= NULL
;
103 if (local
->tpt_led_trigger
) {
104 if (led_trigger_register(&local
->tpt_led_trigger
->trig
)) {
105 kfree(local
->tpt_led_trigger
);
106 local
->tpt_led_trigger
= NULL
;
111 void ieee80211_led_exit(struct ieee80211_local
*local
)
113 if (local
->radio_led
) {
114 led_trigger_unregister(local
->radio_led
);
115 kfree(local
->radio_led
);
117 if (local
->assoc_led
) {
118 led_trigger_unregister(local
->assoc_led
);
119 kfree(local
->assoc_led
);
122 led_trigger_unregister(local
->tx_led
);
123 kfree(local
->tx_led
);
126 led_trigger_unregister(local
->rx_led
);
127 kfree(local
->rx_led
);
130 if (local
->tpt_led_trigger
) {
131 led_trigger_unregister(&local
->tpt_led_trigger
->trig
);
132 kfree(local
->tpt_led_trigger
);
136 char *__ieee80211_get_radio_led_name(struct ieee80211_hw
*hw
)
138 struct ieee80211_local
*local
= hw_to_local(hw
);
140 return local
->radio_led_name
;
142 EXPORT_SYMBOL(__ieee80211_get_radio_led_name
);
144 char *__ieee80211_get_assoc_led_name(struct ieee80211_hw
*hw
)
146 struct ieee80211_local
*local
= hw_to_local(hw
);
148 return local
->assoc_led_name
;
150 EXPORT_SYMBOL(__ieee80211_get_assoc_led_name
);
152 char *__ieee80211_get_tx_led_name(struct ieee80211_hw
*hw
)
154 struct ieee80211_local
*local
= hw_to_local(hw
);
156 return local
->tx_led_name
;
158 EXPORT_SYMBOL(__ieee80211_get_tx_led_name
);
160 char *__ieee80211_get_rx_led_name(struct ieee80211_hw
*hw
)
162 struct ieee80211_local
*local
= hw_to_local(hw
);
164 return local
->rx_led_name
;
166 EXPORT_SYMBOL(__ieee80211_get_rx_led_name
);
168 static unsigned long tpt_trig_traffic(struct ieee80211_local
*local
,
169 struct tpt_led_trigger
*tpt_trig
)
171 unsigned long traffic
, delta
;
173 traffic
= tpt_trig
->tx_bytes
+ tpt_trig
->rx_bytes
;
175 delta
= traffic
- tpt_trig
->prev_traffic
;
176 tpt_trig
->prev_traffic
= traffic
;
177 return DIV_ROUND_UP(delta
, 1024 / 8);
180 static void tpt_trig_timer(unsigned long data
)
182 struct ieee80211_local
*local
= (void *)data
;
183 struct tpt_led_trigger
*tpt_trig
= local
->tpt_led_trigger
;
184 struct led_classdev
*led_cdev
;
185 unsigned long on
, off
, tpt
;
188 if (!tpt_trig
->running
)
191 mod_timer(&tpt_trig
->timer
, round_jiffies(jiffies
+ HZ
));
193 tpt
= tpt_trig_traffic(local
, tpt_trig
);
195 /* default to just solid on */
199 for (i
= tpt_trig
->blink_table_len
- 1; i
>= 0; i
--) {
200 if (tpt_trig
->blink_table
[i
].throughput
< 0 ||
201 tpt
> tpt_trig
->blink_table
[i
].throughput
) {
202 off
= tpt_trig
->blink_table
[i
].blink_time
/ 2;
203 on
= tpt_trig
->blink_table
[i
].blink_time
- off
;
208 read_lock(&tpt_trig
->trig
.leddev_list_lock
);
209 list_for_each_entry(led_cdev
, &tpt_trig
->trig
.led_cdevs
, trig_list
)
210 led_blink_set(led_cdev
, &on
, &off
);
211 read_unlock(&tpt_trig
->trig
.leddev_list_lock
);
214 char *__ieee80211_create_tpt_led_trigger(struct ieee80211_hw
*hw
,
216 const struct ieee80211_tpt_blink
*blink_table
,
217 unsigned int blink_table_len
)
219 struct ieee80211_local
*local
= hw_to_local(hw
);
220 struct tpt_led_trigger
*tpt_trig
;
222 if (WARN_ON(local
->tpt_led_trigger
))
225 tpt_trig
= kzalloc(sizeof(struct tpt_led_trigger
), GFP_KERNEL
);
229 snprintf(tpt_trig
->name
, sizeof(tpt_trig
->name
),
230 "%stpt", wiphy_name(local
->hw
.wiphy
));
232 tpt_trig
->trig
.name
= tpt_trig
->name
;
234 tpt_trig
->blink_table
= blink_table
;
235 tpt_trig
->blink_table_len
= blink_table_len
;
236 tpt_trig
->want
= flags
;
238 setup_timer(&tpt_trig
->timer
, tpt_trig_timer
, (unsigned long)local
);
240 local
->tpt_led_trigger
= tpt_trig
;
242 return tpt_trig
->name
;
244 EXPORT_SYMBOL(__ieee80211_create_tpt_led_trigger
);
246 static void ieee80211_start_tpt_led_trig(struct ieee80211_local
*local
)
248 struct tpt_led_trigger
*tpt_trig
= local
->tpt_led_trigger
;
250 if (tpt_trig
->running
)
254 tpt_trig_traffic(local
, tpt_trig
);
255 tpt_trig
->running
= true;
257 tpt_trig_timer((unsigned long)local
);
258 mod_timer(&tpt_trig
->timer
, round_jiffies(jiffies
+ HZ
));
261 static void ieee80211_stop_tpt_led_trig(struct ieee80211_local
*local
)
263 struct tpt_led_trigger
*tpt_trig
= local
->tpt_led_trigger
;
264 struct led_classdev
*led_cdev
;
266 if (!tpt_trig
->running
)
269 tpt_trig
->running
= false;
270 del_timer_sync(&tpt_trig
->timer
);
272 read_lock(&tpt_trig
->trig
.leddev_list_lock
);
273 list_for_each_entry(led_cdev
, &tpt_trig
->trig
.led_cdevs
, trig_list
)
274 led_set_brightness(led_cdev
, LED_OFF
);
275 read_unlock(&tpt_trig
->trig
.leddev_list_lock
);
278 void ieee80211_mod_tpt_led_trig(struct ieee80211_local
*local
,
279 unsigned int types_on
, unsigned int types_off
)
281 struct tpt_led_trigger
*tpt_trig
= local
->tpt_led_trigger
;
284 WARN_ON(types_on
& types_off
);
289 tpt_trig
->active
&= ~types_off
;
290 tpt_trig
->active
|= types_on
;
293 * Regardless of wanted state, we shouldn't blink when
294 * the radio is disabled -- this can happen due to some
295 * code ordering issues with __ieee80211_recalc_idle()
296 * being called before the radio is started.
298 allowed
= tpt_trig
->active
& IEEE80211_TPT_LEDTRIG_FL_RADIO
;
300 if (!allowed
|| !(tpt_trig
->active
& tpt_trig
->want
))
301 ieee80211_stop_tpt_led_trig(local
);
303 ieee80211_start_tpt_led_trig(local
);