~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/net/mac80211/led.c

Version: ~ [ linux-5.2-rc4 ] ~ [ linux-5.1.9 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.50 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.125 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.181 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.181 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.68 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.39.4 ] ~ [ linux-2.6.38.8 ] ~ [ linux-2.6.37.6 ] ~ [ linux-2.6.36.4 ] ~ [ linux-2.6.35.14 ] ~ [ linux-2.6.34.15 ] ~ [ linux-2.6.33.20 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  * Copyright 2006, Johannes Berg <johannes@sipsolutions.net>
  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 <linux/export.h>
 13 #include "led.h"
 14 
 15 void ieee80211_led_assoc(struct ieee80211_local *local, bool associated)
 16 {
 17         if (!atomic_read(&local->assoc_led_active))
 18                 return;
 19         if (associated)
 20                 led_trigger_event(&local->assoc_led, LED_FULL);
 21         else
 22                 led_trigger_event(&local->assoc_led, LED_OFF);
 23 }
 24 
 25 void ieee80211_led_radio(struct ieee80211_local *local, bool enabled)
 26 {
 27         if (!atomic_read(&local->radio_led_active))
 28                 return;
 29         if (enabled)
 30                 led_trigger_event(&local->radio_led, LED_FULL);
 31         else
 32                 led_trigger_event(&local->radio_led, LED_OFF);
 33 }
 34 
 35 void ieee80211_alloc_led_names(struct ieee80211_local *local)
 36 {
 37         local->rx_led.name = kasprintf(GFP_KERNEL, "%srx",
 38                                        wiphy_name(local->hw.wiphy));
 39         local->tx_led.name = kasprintf(GFP_KERNEL, "%stx",
 40                                        wiphy_name(local->hw.wiphy));
 41         local->assoc_led.name = kasprintf(GFP_KERNEL, "%sassoc",
 42                                           wiphy_name(local->hw.wiphy));
 43         local->radio_led.name = kasprintf(GFP_KERNEL, "%sradio",
 44                                           wiphy_name(local->hw.wiphy));
 45 }
 46 
 47 void ieee80211_free_led_names(struct ieee80211_local *local)
 48 {
 49         kfree(local->rx_led.name);
 50         kfree(local->tx_led.name);
 51         kfree(local->assoc_led.name);
 52         kfree(local->radio_led.name);
 53 }
 54 
 55 static void ieee80211_tx_led_activate(struct led_classdev *led_cdev)
 56 {
 57         struct ieee80211_local *local = container_of(led_cdev->trigger,
 58                                                      struct ieee80211_local,
 59                                                      tx_led);
 60 
 61         atomic_inc(&local->tx_led_active);
 62 }
 63 
 64 static void ieee80211_tx_led_deactivate(struct led_classdev *led_cdev)
 65 {
 66         struct ieee80211_local *local = container_of(led_cdev->trigger,
 67                                                      struct ieee80211_local,
 68                                                      tx_led);
 69 
 70         atomic_dec(&local->tx_led_active);
 71 }
 72 
 73 static void ieee80211_rx_led_activate(struct led_classdev *led_cdev)
 74 {
 75         struct ieee80211_local *local = container_of(led_cdev->trigger,
 76                                                      struct ieee80211_local,
 77                                                      rx_led);
 78 
 79         atomic_inc(&local->rx_led_active);
 80 }
 81 
 82 static void ieee80211_rx_led_deactivate(struct led_classdev *led_cdev)
 83 {
 84         struct ieee80211_local *local = container_of(led_cdev->trigger,
 85                                                      struct ieee80211_local,
 86                                                      rx_led);
 87 
 88         atomic_dec(&local->rx_led_active);
 89 }
 90 
 91 static void ieee80211_assoc_led_activate(struct led_classdev *led_cdev)
 92 {
 93         struct ieee80211_local *local = container_of(led_cdev->trigger,
 94                                                      struct ieee80211_local,
 95                                                      assoc_led);
 96 
 97         atomic_inc(&local->assoc_led_active);
 98 }
 99 
100 static void ieee80211_assoc_led_deactivate(struct led_classdev *led_cdev)
101 {
102         struct ieee80211_local *local = container_of(led_cdev->trigger,
103                                                      struct ieee80211_local,
104                                                      assoc_led);
105 
106         atomic_dec(&local->assoc_led_active);
107 }
108 
109 static void ieee80211_radio_led_activate(struct led_classdev *led_cdev)
110 {
111         struct ieee80211_local *local = container_of(led_cdev->trigger,
112                                                      struct ieee80211_local,
113                                                      radio_led);
114 
115         atomic_inc(&local->radio_led_active);
116 }
117 
118 static void ieee80211_radio_led_deactivate(struct led_classdev *led_cdev)
119 {
120         struct ieee80211_local *local = container_of(led_cdev->trigger,
121                                                      struct ieee80211_local,
122                                                      radio_led);
123 
124         atomic_dec(&local->radio_led_active);
125 }
126 
127 static void ieee80211_tpt_led_activate(struct led_classdev *led_cdev)
128 {
129         struct ieee80211_local *local = container_of(led_cdev->trigger,
130                                                      struct ieee80211_local,
131                                                      tpt_led);
132 
133         atomic_inc(&local->tpt_led_active);
134 }
135 
136 static void ieee80211_tpt_led_deactivate(struct led_classdev *led_cdev)
137 {
138         struct ieee80211_local *local = container_of(led_cdev->trigger,
139                                                      struct ieee80211_local,
140                                                      tpt_led);
141 
142         atomic_dec(&local->tpt_led_active);
143 }
144 
145 void ieee80211_led_init(struct ieee80211_local *local)
146 {
147         atomic_set(&local->rx_led_active, 0);
148         local->rx_led.activate = ieee80211_rx_led_activate;
149         local->rx_led.deactivate = ieee80211_rx_led_deactivate;
150         if (local->rx_led.name && led_trigger_register(&local->rx_led)) {
151                 kfree(local->rx_led.name);
152                 local->rx_led.name = NULL;
153         }
154 
155         atomic_set(&local->tx_led_active, 0);
156         local->tx_led.activate = ieee80211_tx_led_activate;
157         local->tx_led.deactivate = ieee80211_tx_led_deactivate;
158         if (local->tx_led.name && led_trigger_register(&local->tx_led)) {
159                 kfree(local->tx_led.name);
160                 local->tx_led.name = NULL;
161         }
162 
163         atomic_set(&local->assoc_led_active, 0);
164         local->assoc_led.activate = ieee80211_assoc_led_activate;
165         local->assoc_led.deactivate = ieee80211_assoc_led_deactivate;
166         if (local->assoc_led.name && led_trigger_register(&local->assoc_led)) {
167                 kfree(local->assoc_led.name);
168                 local->assoc_led.name = NULL;
169         }
170 
171         atomic_set(&local->radio_led_active, 0);
172         local->radio_led.activate = ieee80211_radio_led_activate;
173         local->radio_led.deactivate = ieee80211_radio_led_deactivate;
174         if (local->radio_led.name && led_trigger_register(&local->radio_led)) {
175                 kfree(local->radio_led.name);
176                 local->radio_led.name = NULL;
177         }
178 
179         atomic_set(&local->tpt_led_active, 0);
180         if (local->tpt_led_trigger) {
181                 local->tpt_led.activate = ieee80211_tpt_led_activate;
182                 local->tpt_led.deactivate = ieee80211_tpt_led_deactivate;
183                 if (led_trigger_register(&local->tpt_led)) {
184                         kfree(local->tpt_led_trigger);
185                         local->tpt_led_trigger = NULL;
186                 }
187         }
188 }
189 
190 void ieee80211_led_exit(struct ieee80211_local *local)
191 {
192         if (local->radio_led.name)
193                 led_trigger_unregister(&local->radio_led);
194         if (local->assoc_led.name)
195                 led_trigger_unregister(&local->assoc_led);
196         if (local->tx_led.name)
197                 led_trigger_unregister(&local->tx_led);
198         if (local->rx_led.name)
199                 led_trigger_unregister(&local->rx_led);
200 
201         if (local->tpt_led_trigger) {
202                 led_trigger_unregister(&local->tpt_led);
203                 kfree(local->tpt_led_trigger);
204         }
205 }
206 
207 const char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
208 {
209         struct ieee80211_local *local = hw_to_local(hw);
210 
211         return local->radio_led.name;
212 }
213 EXPORT_SYMBOL(__ieee80211_get_radio_led_name);
214 
215 const char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
216 {
217         struct ieee80211_local *local = hw_to_local(hw);
218 
219         return local->assoc_led.name;
220 }
221 EXPORT_SYMBOL(__ieee80211_get_assoc_led_name);
222 
223 const char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
224 {
225         struct ieee80211_local *local = hw_to_local(hw);
226 
227         return local->tx_led.name;
228 }
229 EXPORT_SYMBOL(__ieee80211_get_tx_led_name);
230 
231 const char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
232 {
233         struct ieee80211_local *local = hw_to_local(hw);
234 
235         return local->rx_led.name;
236 }
237 EXPORT_SYMBOL(__ieee80211_get_rx_led_name);
238 
239 static unsigned long tpt_trig_traffic(struct ieee80211_local *local,
240                                       struct tpt_led_trigger *tpt_trig)
241 {
242         unsigned long traffic, delta;
243 
244         traffic = tpt_trig->tx_bytes + tpt_trig->rx_bytes;
245 
246         delta = traffic - tpt_trig->prev_traffic;
247         tpt_trig->prev_traffic = traffic;
248         return DIV_ROUND_UP(delta, 1024 / 8);
249 }
250 
251 static void tpt_trig_timer(unsigned long data)
252 {
253         struct ieee80211_local *local = (void *)data;
254         struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
255         struct led_classdev *led_cdev;
256         unsigned long on, off, tpt;
257         int i;
258 
259         if (!tpt_trig->running)
260                 return;
261 
262         mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ));
263 
264         tpt = tpt_trig_traffic(local, tpt_trig);
265 
266         /* default to just solid on */
267         on = 1;
268         off = 0;
269 
270         for (i = tpt_trig->blink_table_len - 1; i >= 0; i--) {
271                 if (tpt_trig->blink_table[i].throughput < 0 ||
272                     tpt > tpt_trig->blink_table[i].throughput) {
273                         off = tpt_trig->blink_table[i].blink_time / 2;
274                         on = tpt_trig->blink_table[i].blink_time - off;
275                         break;
276                 }
277         }
278 
279         read_lock(&local->tpt_led.leddev_list_lock);
280         list_for_each_entry(led_cdev, &local->tpt_led.led_cdevs, trig_list)
281                 led_blink_set(led_cdev, &on, &off);
282         read_unlock(&local->tpt_led.leddev_list_lock);
283 }
284 
285 const char *
286 __ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
287                                    unsigned int flags,
288                                    const struct ieee80211_tpt_blink *blink_table,
289                                    unsigned int blink_table_len)
290 {
291         struct ieee80211_local *local = hw_to_local(hw);
292         struct tpt_led_trigger *tpt_trig;
293 
294         if (WARN_ON(local->tpt_led_trigger))
295                 return NULL;
296 
297         tpt_trig = kzalloc(sizeof(struct tpt_led_trigger), GFP_KERNEL);
298         if (!tpt_trig)
299                 return NULL;
300 
301         snprintf(tpt_trig->name, sizeof(tpt_trig->name),
302                  "%stpt", wiphy_name(local->hw.wiphy));
303 
304         local->tpt_led.name = tpt_trig->name;
305 
306         tpt_trig->blink_table = blink_table;
307         tpt_trig->blink_table_len = blink_table_len;
308         tpt_trig->want = flags;
309 
310         setup_timer(&tpt_trig->timer, tpt_trig_timer, (unsigned long)local);
311 
312         local->tpt_led_trigger = tpt_trig;
313 
314         return tpt_trig->name;
315 }
316 EXPORT_SYMBOL(__ieee80211_create_tpt_led_trigger);
317 
318 static void ieee80211_start_tpt_led_trig(struct ieee80211_local *local)
319 {
320         struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
321 
322         if (tpt_trig->running)
323                 return;
324 
325         /* reset traffic */
326         tpt_trig_traffic(local, tpt_trig);
327         tpt_trig->running = true;
328 
329         tpt_trig_timer((unsigned long)local);
330         mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ));
331 }
332 
333 static void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local)
334 {
335         struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
336         struct led_classdev *led_cdev;
337 
338         if (!tpt_trig->running)
339                 return;
340 
341         tpt_trig->running = false;
342         del_timer_sync(&tpt_trig->timer);
343 
344         read_lock(&local->tpt_led.leddev_list_lock);
345         list_for_each_entry(led_cdev, &local->tpt_led.led_cdevs, trig_list)
346                 led_set_brightness(led_cdev, LED_OFF);
347         read_unlock(&local->tpt_led.leddev_list_lock);
348 }
349 
350 void ieee80211_mod_tpt_led_trig(struct ieee80211_local *local,
351                                 unsigned int types_on, unsigned int types_off)
352 {
353         struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
354         bool allowed;
355 
356         WARN_ON(types_on & types_off);
357 
358         if (!tpt_trig)
359                 return;
360 
361         tpt_trig->active &= ~types_off;
362         tpt_trig->active |= types_on;
363 
364         /*
365          * Regardless of wanted state, we shouldn't blink when
366          * the radio is disabled -- this can happen due to some
367          * code ordering issues with __ieee80211_recalc_idle()
368          * being called before the radio is started.
369          */
370         allowed = tpt_trig->active & IEEE80211_TPT_LEDTRIG_FL_RADIO;
371 
372         if (!allowed || !(tpt_trig->active & tpt_trig->want))
373                 ieee80211_stop_tpt_led_trig(local);
374         else
375                 ieee80211_start_tpt_led_trig(local);
376 }
377 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp