Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/net/mac80211/led.c
15109 views
1
/*
2
* Copyright 2006, Johannes Berg <[email protected]>
3
*
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.
7
*/
8
9
/* just for IFNAMSIZ */
10
#include <linux/if.h>
11
#include <linux/slab.h>
12
#include "led.h"
13
14
void ieee80211_led_rx(struct ieee80211_local *local)
15
{
16
if (unlikely(!local->rx_led))
17
return;
18
if (local->rx_led_counter++ % 2 == 0)
19
led_trigger_event(local->rx_led, LED_OFF);
20
else
21
led_trigger_event(local->rx_led, LED_FULL);
22
}
23
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)
26
{
27
if (unlikely(!local->tx_led))
28
return;
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);
33
else
34
led_trigger_event(local->tx_led, LED_FULL);
35
}
36
37
void ieee80211_led_assoc(struct ieee80211_local *local, bool associated)
38
{
39
if (unlikely(!local->assoc_led))
40
return;
41
if (associated)
42
led_trigger_event(local->assoc_led, LED_FULL);
43
else
44
led_trigger_event(local->assoc_led, LED_OFF);
45
}
46
47
void ieee80211_led_radio(struct ieee80211_local *local, bool enabled)
48
{
49
if (unlikely(!local->radio_led))
50
return;
51
if (enabled)
52
led_trigger_event(local->radio_led, LED_FULL);
53
else
54
led_trigger_event(local->radio_led, LED_OFF);
55
}
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
69
void ieee80211_led_init(struct ieee80211_local *local)
70
{
71
local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
72
if (local->rx_led) {
73
local->rx_led->name = local->rx_led_name;
74
if (led_trigger_register(local->rx_led)) {
75
kfree(local->rx_led);
76
local->rx_led = NULL;
77
}
78
}
79
80
local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
81
if (local->tx_led) {
82
local->tx_led->name = local->tx_led_name;
83
if (led_trigger_register(local->tx_led)) {
84
kfree(local->tx_led);
85
local->tx_led = NULL;
86
}
87
}
88
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;
95
}
96
}
97
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;
104
}
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
}
113
}
114
115
void ieee80211_led_exit(struct ieee80211_local *local)
116
{
117
if (local->radio_led) {
118
led_trigger_unregister(local->radio_led);
119
kfree(local->radio_led);
120
}
121
if (local->assoc_led) {
122
led_trigger_unregister(local->assoc_led);
123
kfree(local->assoc_led);
124
}
125
if (local->tx_led) {
126
led_trigger_unregister(local->tx_led);
127
kfree(local->tx_led);
128
}
129
if (local->rx_led) {
130
led_trigger_unregister(local->rx_led);
131
kfree(local->rx_led);
132
}
133
134
if (local->tpt_led_trigger) {
135
led_trigger_unregister(&local->tpt_led_trigger->trig);
136
kfree(local->tpt_led_trigger);
137
}
138
}
139
140
char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
141
{
142
struct ieee80211_local *local = hw_to_local(hw);
143
144
return local->radio_led_name;
145
}
146
EXPORT_SYMBOL(__ieee80211_get_radio_led_name);
147
148
char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
149
{
150
struct ieee80211_local *local = hw_to_local(hw);
151
152
return local->assoc_led_name;
153
}
154
EXPORT_SYMBOL(__ieee80211_get_assoc_led_name);
155
156
char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
157
{
158
struct ieee80211_local *local = hw_to_local(hw);
159
160
return local->tx_led_name;
161
}
162
EXPORT_SYMBOL(__ieee80211_get_tx_led_name);
163
164
char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
165
{
166
struct ieee80211_local *local = hw_to_local(hw);
167
168
return local->rx_led_name;
169
}
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
char *__ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
219
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
}
309
310