Blame view

net/mac80211/led.c 7.93 KB
f0706e828   Jiri Benc   [MAC80211]: Add m...
1
2
3
4
5
6
7
8
9
10
  /*
   * Copyright 2006, Johannes Berg <johannes@sipsolutions.net>
   *
   * This program is free software; you can redistribute it and/or modify
   * it under the terms of the GNU General Public License version 2 as
   * published by the Free Software Foundation.
   */
  
  /* just for IFNAMSIZ */
  #include <linux/if.h>
5a0e3ad6a   Tejun Heo   include cleanup: ...
11
  #include <linux/slab.h>
bc3b2d7fb   Paul Gortmaker   net: Add export.h...
12
  #include <linux/export.h>
2c8dccc77   Johannes Berg   mac80211: rename ...
13
  #include "led.h"
f0706e828   Jiri Benc   [MAC80211]: Add m...
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
  
  void ieee80211_led_rx(struct ieee80211_local *local)
  {
  	if (unlikely(!local->rx_led))
  		return;
  	if (local->rx_led_counter++ % 2 == 0)
  		led_trigger_event(local->rx_led, LED_OFF);
  	else
  		led_trigger_event(local->rx_led, LED_FULL);
  }
  
  /* q is 1 if a packet was enqueued, 0 if it has been transmitted */
  void ieee80211_led_tx(struct ieee80211_local *local, int q)
  {
  	if (unlikely(!local->tx_led))
  		return;
  	/* not sure how this is supposed to work ... */
  	local->tx_led_counter += 2*q-1;
  	if (local->tx_led_counter % 2 == 0)
  		led_trigger_event(local->tx_led, LED_OFF);
  	else
  		led_trigger_event(local->tx_led, LED_FULL);
  }
47f0c5022   Michael Buesch   [MAC80211]: Add a...
37
38
39
40
41
42
43
44
45
  void ieee80211_led_assoc(struct ieee80211_local *local, bool associated)
  {
  	if (unlikely(!local->assoc_led))
  		return;
  	if (associated)
  		led_trigger_event(local->assoc_led, LED_FULL);
  	else
  		led_trigger_event(local->assoc_led, LED_OFF);
  }
cdcb006fb   Ivo van Doorn   mac80211: Add rad...
46
47
48
49
50
51
52
53
54
  void ieee80211_led_radio(struct ieee80211_local *local, bool enabled)
  {
  	if (unlikely(!local->radio_led))
  		return;
  	if (enabled)
  		led_trigger_event(local->radio_led, LED_FULL);
  	else
  		led_trigger_event(local->radio_led, LED_OFF);
  }
fe67c913f   Johannes Berg   mac80211: make LE...
55
56
57
58
59
60
61
62
63
64
65
  void ieee80211_led_names(struct ieee80211_local *local)
  {
  	snprintf(local->rx_led_name, sizeof(local->rx_led_name),
  		 "%srx", wiphy_name(local->hw.wiphy));
  	snprintf(local->tx_led_name, sizeof(local->tx_led_name),
  		 "%stx", wiphy_name(local->hw.wiphy));
  	snprintf(local->assoc_led_name, sizeof(local->assoc_led_name),
  		 "%sassoc", wiphy_name(local->hw.wiphy));
  	snprintf(local->radio_led_name, sizeof(local->radio_led_name),
  		 "%sradio", wiphy_name(local->hw.wiphy));
  }
f0706e828   Jiri Benc   [MAC80211]: Add m...
66
67
68
  void ieee80211_led_init(struct ieee80211_local *local)
  {
  	local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
47f0c5022   Michael Buesch   [MAC80211]: Add a...
69
  	if (local->rx_led) {
47f0c5022   Michael Buesch   [MAC80211]: Add a...
70
71
72
73
74
  		local->rx_led->name = local->rx_led_name;
  		if (led_trigger_register(local->rx_led)) {
  			kfree(local->rx_led);
  			local->rx_led = NULL;
  		}
f0706e828   Jiri Benc   [MAC80211]: Add m...
75
76
77
  	}
  
  	local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
47f0c5022   Michael Buesch   [MAC80211]: Add a...
78
  	if (local->tx_led) {
47f0c5022   Michael Buesch   [MAC80211]: Add a...
79
80
81
82
83
84
85
86
87
  		local->tx_led->name = local->tx_led_name;
  		if (led_trigger_register(local->tx_led)) {
  			kfree(local->tx_led);
  			local->tx_led = NULL;
  		}
  	}
  
  	local->assoc_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
  	if (local->assoc_led) {
47f0c5022   Michael Buesch   [MAC80211]: Add a...
88
89
90
91
92
  		local->assoc_led->name = local->assoc_led_name;
  		if (led_trigger_register(local->assoc_led)) {
  			kfree(local->assoc_led);
  			local->assoc_led = NULL;
  		}
f0706e828   Jiri Benc   [MAC80211]: Add m...
93
  	}
cdcb006fb   Ivo van Doorn   mac80211: Add rad...
94
95
96
  
  	local->radio_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
  	if (local->radio_led) {
cdcb006fb   Ivo van Doorn   mac80211: Add rad...
97
98
99
100
101
102
  		local->radio_led->name = local->radio_led_name;
  		if (led_trigger_register(local->radio_led)) {
  			kfree(local->radio_led);
  			local->radio_led = NULL;
  		}
  	}
e1e540685   Johannes Berg   mac80211: add thr...
103
104
105
106
107
108
109
  
  	if (local->tpt_led_trigger) {
  		if (led_trigger_register(&local->tpt_led_trigger->trig)) {
  			kfree(local->tpt_led_trigger);
  			local->tpt_led_trigger = NULL;
  		}
  	}
f0706e828   Jiri Benc   [MAC80211]: Add m...
110
111
112
113
  }
  
  void ieee80211_led_exit(struct ieee80211_local *local)
  {
cdcb006fb   Ivo van Doorn   mac80211: Add rad...
114
115
116
117
  	if (local->radio_led) {
  		led_trigger_unregister(local->radio_led);
  		kfree(local->radio_led);
  	}
47f0c5022   Michael Buesch   [MAC80211]: Add a...
118
119
120
121
  	if (local->assoc_led) {
  		led_trigger_unregister(local->assoc_led);
  		kfree(local->assoc_led);
  	}
f0706e828   Jiri Benc   [MAC80211]: Add m...
122
123
124
125
126
127
128
129
  	if (local->tx_led) {
  		led_trigger_unregister(local->tx_led);
  		kfree(local->tx_led);
  	}
  	if (local->rx_led) {
  		led_trigger_unregister(local->rx_led);
  		kfree(local->rx_led);
  	}
e1e540685   Johannes Berg   mac80211: add thr...
130
131
132
133
134
  
  	if (local->tpt_led_trigger) {
  		led_trigger_unregister(&local->tpt_led_trigger->trig);
  		kfree(local->tpt_led_trigger);
  	}
f0706e828   Jiri Benc   [MAC80211]: Add m...
135
  }
cdcb006fb   Ivo van Doorn   mac80211: Add rad...
136
137
138
  char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
  {
  	struct ieee80211_local *local = hw_to_local(hw);
fe67c913f   Johannes Berg   mac80211: make LE...
139
  	return local->radio_led_name;
cdcb006fb   Ivo van Doorn   mac80211: Add rad...
140
141
  }
  EXPORT_SYMBOL(__ieee80211_get_radio_led_name);
47f0c5022   Michael Buesch   [MAC80211]: Add a...
142
143
144
  char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
  {
  	struct ieee80211_local *local = hw_to_local(hw);
fe67c913f   Johannes Berg   mac80211: make LE...
145
  	return local->assoc_led_name;
47f0c5022   Michael Buesch   [MAC80211]: Add a...
146
147
  }
  EXPORT_SYMBOL(__ieee80211_get_assoc_led_name);
f0706e828   Jiri Benc   [MAC80211]: Add m...
148
149
150
  char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
  {
  	struct ieee80211_local *local = hw_to_local(hw);
fe67c913f   Johannes Berg   mac80211: make LE...
151
  	return local->tx_led_name;
f0706e828   Jiri Benc   [MAC80211]: Add m...
152
153
154
155
156
157
  }
  EXPORT_SYMBOL(__ieee80211_get_tx_led_name);
  
  char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
  {
  	struct ieee80211_local *local = hw_to_local(hw);
fe67c913f   Johannes Berg   mac80211: make LE...
158
  	return local->rx_led_name;
f0706e828   Jiri Benc   [MAC80211]: Add m...
159
160
  }
  EXPORT_SYMBOL(__ieee80211_get_rx_led_name);
e1e540685   Johannes Berg   mac80211: add thr...
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
  
  static unsigned long tpt_trig_traffic(struct ieee80211_local *local,
  				      struct tpt_led_trigger *tpt_trig)
  {
  	unsigned long traffic, delta;
  
  	traffic = tpt_trig->tx_bytes + tpt_trig->rx_bytes;
  
  	delta = traffic - tpt_trig->prev_traffic;
  	tpt_trig->prev_traffic = traffic;
  	return DIV_ROUND_UP(delta, 1024 / 8);
  }
  
  static void tpt_trig_timer(unsigned long data)
  {
  	struct ieee80211_local *local = (void *)data;
  	struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
  	struct led_classdev *led_cdev;
  	unsigned long on, off, tpt;
  	int i;
  
  	if (!tpt_trig->running)
  		return;
  
  	mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ));
  
  	tpt = tpt_trig_traffic(local, tpt_trig);
  
  	/* default to just solid on */
  	on = 1;
  	off = 0;
  
  	for (i = tpt_trig->blink_table_len - 1; i >= 0; i--) {
  		if (tpt_trig->blink_table[i].throughput < 0 ||
  		    tpt > tpt_trig->blink_table[i].throughput) {
  			off = tpt_trig->blink_table[i].blink_time / 2;
  			on = tpt_trig->blink_table[i].blink_time - off;
  			break;
  		}
  	}
  
  	read_lock(&tpt_trig->trig.leddev_list_lock);
  	list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list)
  		led_blink_set(led_cdev, &on, &off);
  	read_unlock(&tpt_trig->trig.leddev_list_lock);
  }
06778b1c3   Johannes Berg   mac80211: remove ...
207
208
  char *__ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
  				unsigned int flags,
e1e540685   Johannes Berg   mac80211: add thr...
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
  				const struct ieee80211_tpt_blink *blink_table,
  				unsigned int blink_table_len)
  {
  	struct ieee80211_local *local = hw_to_local(hw);
  	struct tpt_led_trigger *tpt_trig;
  
  	if (WARN_ON(local->tpt_led_trigger))
  		return NULL;
  
  	tpt_trig = kzalloc(sizeof(struct tpt_led_trigger), GFP_KERNEL);
  	if (!tpt_trig)
  		return NULL;
  
  	snprintf(tpt_trig->name, sizeof(tpt_trig->name),
  		 "%stpt", wiphy_name(local->hw.wiphy));
  
  	tpt_trig->trig.name = tpt_trig->name;
  
  	tpt_trig->blink_table = blink_table;
  	tpt_trig->blink_table_len = blink_table_len;
67408c8c7   Johannes Berg   mac80211: selecti...
229
  	tpt_trig->want = flags;
e1e540685   Johannes Berg   mac80211: add thr...
230
231
232
233
234
235
236
237
  
  	setup_timer(&tpt_trig->timer, tpt_trig_timer, (unsigned long)local);
  
  	local->tpt_led_trigger = tpt_trig;
  
  	return tpt_trig->name;
  }
  EXPORT_SYMBOL(__ieee80211_create_tpt_led_trigger);
67408c8c7   Johannes Berg   mac80211: selecti...
238
  static void ieee80211_start_tpt_led_trig(struct ieee80211_local *local)
e1e540685   Johannes Berg   mac80211: add thr...
239
240
  {
  	struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
67408c8c7   Johannes Berg   mac80211: selecti...
241
  	if (tpt_trig->running)
e1e540685   Johannes Berg   mac80211: add thr...
242
243
244
245
246
247
248
249
250
  		return;
  
  	/* reset traffic */
  	tpt_trig_traffic(local, tpt_trig);
  	tpt_trig->running = true;
  
  	tpt_trig_timer((unsigned long)local);
  	mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ));
  }
67408c8c7   Johannes Berg   mac80211: selecti...
251
  static void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local)
e1e540685   Johannes Berg   mac80211: add thr...
252
253
254
  {
  	struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
  	struct led_classdev *led_cdev;
67408c8c7   Johannes Berg   mac80211: selecti...
255
  	if (!tpt_trig->running)
e1e540685   Johannes Berg   mac80211: add thr...
256
257
258
259
260
261
262
  		return;
  
  	tpt_trig->running = false;
  	del_timer_sync(&tpt_trig->timer);
  
  	read_lock(&tpt_trig->trig.leddev_list_lock);
  	list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list)
19cd67e2d   Shuah Khan   leds: Rename led_...
263
  		led_set_brightness(led_cdev, LED_OFF);
e1e540685   Johannes Berg   mac80211: add thr...
264
265
  	read_unlock(&tpt_trig->trig.leddev_list_lock);
  }
67408c8c7   Johannes Berg   mac80211: selecti...
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
  
  void ieee80211_mod_tpt_led_trig(struct ieee80211_local *local,
  				unsigned int types_on, unsigned int types_off)
  {
  	struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
  	bool allowed;
  
  	WARN_ON(types_on & types_off);
  
  	if (!tpt_trig)
  		return;
  
  	tpt_trig->active &= ~types_off;
  	tpt_trig->active |= types_on;
  
  	/*
  	 * Regardless of wanted state, we shouldn't blink when
  	 * the radio is disabled -- this can happen due to some
  	 * code ordering issues with __ieee80211_recalc_idle()
  	 * being called before the radio is started.
  	 */
  	allowed = tpt_trig->active & IEEE80211_TPT_LEDTRIG_FL_RADIO;
  
  	if (!allowed || !(tpt_trig->active & tpt_trig->want))
  		ieee80211_stop_tpt_led_trig(local);
  	else
  		ieee80211_start_tpt_led_trig(local);
  }