root/net/mac80211/led.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ieee80211_led_assoc
  2. ieee80211_led_radio
  3. ieee80211_alloc_led_names
  4. ieee80211_free_led_names
  5. ieee80211_tx_led_activate
  6. ieee80211_tx_led_deactivate
  7. ieee80211_rx_led_activate
  8. ieee80211_rx_led_deactivate
  9. ieee80211_assoc_led_activate
  10. ieee80211_assoc_led_deactivate
  11. ieee80211_radio_led_activate
  12. ieee80211_radio_led_deactivate
  13. ieee80211_tpt_led_activate
  14. ieee80211_tpt_led_deactivate
  15. ieee80211_led_init
  16. ieee80211_led_exit
  17. __ieee80211_get_radio_led_name
  18. __ieee80211_get_assoc_led_name
  19. __ieee80211_get_tx_led_name
  20. __ieee80211_get_rx_led_name
  21. tpt_trig_traffic
  22. tpt_trig_timer
  23. __ieee80211_create_tpt_led_trigger
  24. ieee80211_start_tpt_led_trig
  25. ieee80211_stop_tpt_led_trig
  26. ieee80211_mod_tpt_led_trig

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

/* [<][>][^][v][top][bottom][index][help] */