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>
14 void ieee80211_led_rx(struct ieee80211_local
*local
)
16 if (unlikely(!local
->rx_led
))
18 if (local
->rx_led_counter
++ % 2 == 0)
19 led_trigger_event(local
->rx_led
, LED_OFF
);
21 led_trigger_event(local
->rx_led
, LED_FULL
);
24 /* q is 1 if a packet was enqueued, 0 if it has been transmitted */
25 void ieee80211_led_tx(struct ieee80211_local
*local
, int q
)
27 if (unlikely(!local
->tx_led
))
29 /* not sure how this is supposed to work ... */
30 local
->tx_led_counter
+= 2*q
-1;
31 if (local
->tx_led_counter
% 2 == 0)
32 led_trigger_event(local
->tx_led
, LED_OFF
);
34 led_trigger_event(local
->tx_led
, LED_FULL
);
37 void ieee80211_led_assoc(struct ieee80211_local
*local
, bool associated
)
39 if (unlikely(!local
->assoc_led
))
42 led_trigger_event(local
->assoc_led
, LED_FULL
);
44 led_trigger_event(local
->assoc_led
, LED_OFF
);
47 void ieee80211_led_radio(struct ieee80211_local
*local
, bool enabled
)
49 if (unlikely(!local
->radio_led
))
52 led_trigger_event(local
->radio_led
, LED_FULL
);
54 led_trigger_event(local
->radio_led
, LED_OFF
);
57 void ieee80211_led_names(struct ieee80211_local
*local
)
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
));
69 void ieee80211_led_init(struct ieee80211_local
*local
)
71 local
->rx_led
= kzalloc(sizeof(struct led_trigger
), GFP_KERNEL
);
73 local
->rx_led
->name
= local
->rx_led_name
;
74 if (led_trigger_register(local
->rx_led
)) {
80 local
->tx_led
= kzalloc(sizeof(struct led_trigger
), GFP_KERNEL
);
82 local
->tx_led
->name
= local
->tx_led_name
;
83 if (led_trigger_register(local
->tx_led
)) {
89 local
->assoc_led
= kzalloc(sizeof(struct led_trigger
), GFP_KERNEL
);
90 if (local
->assoc_led
) {
91 local
->assoc_led
->name
= local
->assoc_led_name
;
92 if (led_trigger_register(local
->assoc_led
)) {
93 kfree(local
->assoc_led
);
94 local
->assoc_led
= NULL
;
98 local
->radio_led
= kzalloc(sizeof(struct led_trigger
), GFP_KERNEL
);
99 if (local
->radio_led
) {
100 local
->radio_led
->name
= local
->radio_led_name
;
101 if (led_trigger_register(local
->radio_led
)) {
102 kfree(local
->radio_led
);
103 local
->radio_led
= NULL
;
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
;
115 void ieee80211_led_exit(struct ieee80211_local
*local
)
117 if (local
->radio_led
) {
118 led_trigger_unregister(local
->radio_led
);
119 kfree(local
->radio_led
);
121 if (local
->assoc_led
) {
122 led_trigger_unregister(local
->assoc_led
);
123 kfree(local
->assoc_led
);
126 led_trigger_unregister(local
->tx_led
);
127 kfree(local
->tx_led
);
130 led_trigger_unregister(local
->rx_led
);
131 kfree(local
->rx_led
);
134 if (local
->tpt_led_trigger
) {
135 led_trigger_unregister(&local
->tpt_led_trigger
->trig
);
136 kfree(local
->tpt_led_trigger
);
140 char *__ieee80211_get_radio_led_name(struct ieee80211_hw
*hw
)
142 struct ieee80211_local
*local
= hw_to_local(hw
);
144 return local
->radio_led_name
;
146 EXPORT_SYMBOL(__ieee80211_get_radio_led_name
);
148 char *__ieee80211_get_assoc_led_name(struct ieee80211_hw
*hw
)
150 struct ieee80211_local
*local
= hw_to_local(hw
);
152 return local
->assoc_led_name
;
154 EXPORT_SYMBOL(__ieee80211_get_assoc_led_name
);
156 char *__ieee80211_get_tx_led_name(struct ieee80211_hw
*hw
)
158 struct ieee80211_local
*local
= hw_to_local(hw
);
160 return local
->tx_led_name
;
162 EXPORT_SYMBOL(__ieee80211_get_tx_led_name
);
164 char *__ieee80211_get_rx_led_name(struct ieee80211_hw
*hw
)
166 struct ieee80211_local
*local
= hw_to_local(hw
);
168 return local
->rx_led_name
;
170 EXPORT_SYMBOL(__ieee80211_get_rx_led_name
);
172 static unsigned long tpt_trig_traffic(struct ieee80211_local
*local
,
173 struct tpt_led_trigger
*tpt_trig
)
175 unsigned long traffic
, delta
;
177 traffic
= tpt_trig
->tx_bytes
+ tpt_trig
->rx_bytes
;
179 delta
= traffic
- tpt_trig
->prev_traffic
;
180 tpt_trig
->prev_traffic
= traffic
;
181 return DIV_ROUND_UP(delta
, 1024 / 8);
184 static void tpt_trig_timer(unsigned long data
)
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
;
192 if (!tpt_trig
->running
)
195 mod_timer(&tpt_trig
->timer
, round_jiffies(jiffies
+ HZ
));
197 tpt
= tpt_trig_traffic(local
, tpt_trig
);
199 /* default to just solid on */
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
;
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
);
218 char *__ieee80211_create_tpt_led_trigger(struct ieee80211_hw
*hw
,
220 const struct ieee80211_tpt_blink
*blink_table
,
221 unsigned int blink_table_len
)
223 struct ieee80211_local
*local
= hw_to_local(hw
);
224 struct tpt_led_trigger
*tpt_trig
;
226 if (WARN_ON(local
->tpt_led_trigger
))
229 tpt_trig
= kzalloc(sizeof(struct tpt_led_trigger
), GFP_KERNEL
);
233 snprintf(tpt_trig
->name
, sizeof(tpt_trig
->name
),
234 "%stpt", wiphy_name(local
->hw
.wiphy
));
236 tpt_trig
->trig
.name
= tpt_trig
->name
;
238 tpt_trig
->blink_table
= blink_table
;
239 tpt_trig
->blink_table_len
= blink_table_len
;
240 tpt_trig
->want
= flags
;
242 setup_timer(&tpt_trig
->timer
, tpt_trig_timer
, (unsigned long)local
);
244 local
->tpt_led_trigger
= tpt_trig
;
246 return tpt_trig
->name
;
248 EXPORT_SYMBOL(__ieee80211_create_tpt_led_trigger
);
250 static void ieee80211_start_tpt_led_trig(struct ieee80211_local
*local
)
252 struct tpt_led_trigger
*tpt_trig
= local
->tpt_led_trigger
;
254 if (tpt_trig
->running
)
258 tpt_trig_traffic(local
, tpt_trig
);
259 tpt_trig
->running
= true;
261 tpt_trig_timer((unsigned long)local
);
262 mod_timer(&tpt_trig
->timer
, round_jiffies(jiffies
+ HZ
));
265 static void ieee80211_stop_tpt_led_trig(struct ieee80211_local
*local
)
267 struct tpt_led_trigger
*tpt_trig
= local
->tpt_led_trigger
;
268 struct led_classdev
*led_cdev
;
270 if (!tpt_trig
->running
)
273 tpt_trig
->running
= false;
274 del_timer_sync(&tpt_trig
->timer
);
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
);
282 void ieee80211_mod_tpt_led_trig(struct ieee80211_local
*local
,
283 unsigned int types_on
, unsigned int types_off
)
285 struct tpt_led_trigger
*tpt_trig
= local
->tpt_led_trigger
;
288 WARN_ON(types_on
& types_off
);
293 tpt_trig
->active
&= ~types_off
;
294 tpt_trig
->active
|= types_on
;
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.
302 allowed
= tpt_trig
->active
& IEEE80211_TPT_LEDTRIG_FL_RADIO
;
304 if (!allowed
|| !(tpt_trig
->active
& tpt_trig
->want
))
305 ieee80211_stop_tpt_led_trig(local
);
307 ieee80211_start_tpt_led_trig(local
);