Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright 2006, Johannes Berg <johannes@sipsolutions.net>
0004  */
0005 
0006 /* just for IFNAMSIZ */
0007 #include <linux/if.h>
0008 #include <linux/slab.h>
0009 #include <linux/export.h>
0010 #include "led.h"
0011 
0012 void ieee80211_led_assoc(struct ieee80211_local *local, bool associated)
0013 {
0014     if (!atomic_read(&local->assoc_led_active))
0015         return;
0016     if (associated)
0017         led_trigger_event(&local->assoc_led, LED_FULL);
0018     else
0019         led_trigger_event(&local->assoc_led, LED_OFF);
0020 }
0021 
0022 void ieee80211_led_radio(struct ieee80211_local *local, bool enabled)
0023 {
0024     if (!atomic_read(&local->radio_led_active))
0025         return;
0026     if (enabled)
0027         led_trigger_event(&local->radio_led, LED_FULL);
0028     else
0029         led_trigger_event(&local->radio_led, LED_OFF);
0030 }
0031 
0032 void ieee80211_alloc_led_names(struct ieee80211_local *local)
0033 {
0034     local->rx_led.name = kasprintf(GFP_KERNEL, "%srx",
0035                        wiphy_name(local->hw.wiphy));
0036     local->tx_led.name = kasprintf(GFP_KERNEL, "%stx",
0037                        wiphy_name(local->hw.wiphy));
0038     local->assoc_led.name = kasprintf(GFP_KERNEL, "%sassoc",
0039                       wiphy_name(local->hw.wiphy));
0040     local->radio_led.name = kasprintf(GFP_KERNEL, "%sradio",
0041                       wiphy_name(local->hw.wiphy));
0042 }
0043 
0044 void ieee80211_free_led_names(struct ieee80211_local *local)
0045 {
0046     kfree(local->rx_led.name);
0047     kfree(local->tx_led.name);
0048     kfree(local->assoc_led.name);
0049     kfree(local->radio_led.name);
0050 }
0051 
0052 static int ieee80211_tx_led_activate(struct led_classdev *led_cdev)
0053 {
0054     struct ieee80211_local *local = container_of(led_cdev->trigger,
0055                              struct ieee80211_local,
0056                              tx_led);
0057 
0058     atomic_inc(&local->tx_led_active);
0059 
0060     return 0;
0061 }
0062 
0063 static void ieee80211_tx_led_deactivate(struct led_classdev *led_cdev)
0064 {
0065     struct ieee80211_local *local = container_of(led_cdev->trigger,
0066                              struct ieee80211_local,
0067                              tx_led);
0068 
0069     atomic_dec(&local->tx_led_active);
0070 }
0071 
0072 static int ieee80211_rx_led_activate(struct led_classdev *led_cdev)
0073 {
0074     struct ieee80211_local *local = container_of(led_cdev->trigger,
0075                              struct ieee80211_local,
0076                              rx_led);
0077 
0078     atomic_inc(&local->rx_led_active);
0079 
0080     return 0;
0081 }
0082 
0083 static void ieee80211_rx_led_deactivate(struct led_classdev *led_cdev)
0084 {
0085     struct ieee80211_local *local = container_of(led_cdev->trigger,
0086                              struct ieee80211_local,
0087                              rx_led);
0088 
0089     atomic_dec(&local->rx_led_active);
0090 }
0091 
0092 static int ieee80211_assoc_led_activate(struct led_classdev *led_cdev)
0093 {
0094     struct ieee80211_local *local = container_of(led_cdev->trigger,
0095                              struct ieee80211_local,
0096                              assoc_led);
0097 
0098     atomic_inc(&local->assoc_led_active);
0099 
0100     return 0;
0101 }
0102 
0103 static void ieee80211_assoc_led_deactivate(struct led_classdev *led_cdev)
0104 {
0105     struct ieee80211_local *local = container_of(led_cdev->trigger,
0106                              struct ieee80211_local,
0107                              assoc_led);
0108 
0109     atomic_dec(&local->assoc_led_active);
0110 }
0111 
0112 static int ieee80211_radio_led_activate(struct led_classdev *led_cdev)
0113 {
0114     struct ieee80211_local *local = container_of(led_cdev->trigger,
0115                              struct ieee80211_local,
0116                              radio_led);
0117 
0118     atomic_inc(&local->radio_led_active);
0119 
0120     return 0;
0121 }
0122 
0123 static void ieee80211_radio_led_deactivate(struct led_classdev *led_cdev)
0124 {
0125     struct ieee80211_local *local = container_of(led_cdev->trigger,
0126                              struct ieee80211_local,
0127                              radio_led);
0128 
0129     atomic_dec(&local->radio_led_active);
0130 }
0131 
0132 static int ieee80211_tpt_led_activate(struct led_classdev *led_cdev)
0133 {
0134     struct ieee80211_local *local = container_of(led_cdev->trigger,
0135                              struct ieee80211_local,
0136                              tpt_led);
0137 
0138     atomic_inc(&local->tpt_led_active);
0139 
0140     return 0;
0141 }
0142 
0143 static void ieee80211_tpt_led_deactivate(struct led_classdev *led_cdev)
0144 {
0145     struct ieee80211_local *local = container_of(led_cdev->trigger,
0146                              struct ieee80211_local,
0147                              tpt_led);
0148 
0149     atomic_dec(&local->tpt_led_active);
0150 }
0151 
0152 void ieee80211_led_init(struct ieee80211_local *local)
0153 {
0154     atomic_set(&local->rx_led_active, 0);
0155     local->rx_led.activate = ieee80211_rx_led_activate;
0156     local->rx_led.deactivate = ieee80211_rx_led_deactivate;
0157     if (local->rx_led.name && led_trigger_register(&local->rx_led)) {
0158         kfree(local->rx_led.name);
0159         local->rx_led.name = NULL;
0160     }
0161 
0162     atomic_set(&local->tx_led_active, 0);
0163     local->tx_led.activate = ieee80211_tx_led_activate;
0164     local->tx_led.deactivate = ieee80211_tx_led_deactivate;
0165     if (local->tx_led.name && led_trigger_register(&local->tx_led)) {
0166         kfree(local->tx_led.name);
0167         local->tx_led.name = NULL;
0168     }
0169 
0170     atomic_set(&local->assoc_led_active, 0);
0171     local->assoc_led.activate = ieee80211_assoc_led_activate;
0172     local->assoc_led.deactivate = ieee80211_assoc_led_deactivate;
0173     if (local->assoc_led.name && led_trigger_register(&local->assoc_led)) {
0174         kfree(local->assoc_led.name);
0175         local->assoc_led.name = NULL;
0176     }
0177 
0178     atomic_set(&local->radio_led_active, 0);
0179     local->radio_led.activate = ieee80211_radio_led_activate;
0180     local->radio_led.deactivate = ieee80211_radio_led_deactivate;
0181     if (local->radio_led.name && led_trigger_register(&local->radio_led)) {
0182         kfree(local->radio_led.name);
0183         local->radio_led.name = NULL;
0184     }
0185 
0186     atomic_set(&local->tpt_led_active, 0);
0187     if (local->tpt_led_trigger) {
0188         local->tpt_led.activate = ieee80211_tpt_led_activate;
0189         local->tpt_led.deactivate = ieee80211_tpt_led_deactivate;
0190         if (led_trigger_register(&local->tpt_led)) {
0191             kfree(local->tpt_led_trigger);
0192             local->tpt_led_trigger = NULL;
0193         }
0194     }
0195 }
0196 
0197 void ieee80211_led_exit(struct ieee80211_local *local)
0198 {
0199     if (local->radio_led.name)
0200         led_trigger_unregister(&local->radio_led);
0201     if (local->assoc_led.name)
0202         led_trigger_unregister(&local->assoc_led);
0203     if (local->tx_led.name)
0204         led_trigger_unregister(&local->tx_led);
0205     if (local->rx_led.name)
0206         led_trigger_unregister(&local->rx_led);
0207 
0208     if (local->tpt_led_trigger) {
0209         led_trigger_unregister(&local->tpt_led);
0210         kfree(local->tpt_led_trigger);
0211     }
0212 }
0213 
0214 const char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
0215 {
0216     struct ieee80211_local *local = hw_to_local(hw);
0217 
0218     return local->radio_led.name;
0219 }
0220 EXPORT_SYMBOL(__ieee80211_get_radio_led_name);
0221 
0222 const char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
0223 {
0224     struct ieee80211_local *local = hw_to_local(hw);
0225 
0226     return local->assoc_led.name;
0227 }
0228 EXPORT_SYMBOL(__ieee80211_get_assoc_led_name);
0229 
0230 const char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
0231 {
0232     struct ieee80211_local *local = hw_to_local(hw);
0233 
0234     return local->tx_led.name;
0235 }
0236 EXPORT_SYMBOL(__ieee80211_get_tx_led_name);
0237 
0238 const char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
0239 {
0240     struct ieee80211_local *local = hw_to_local(hw);
0241 
0242     return local->rx_led.name;
0243 }
0244 EXPORT_SYMBOL(__ieee80211_get_rx_led_name);
0245 
0246 static unsigned long tpt_trig_traffic(struct ieee80211_local *local,
0247                       struct tpt_led_trigger *tpt_trig)
0248 {
0249     unsigned long traffic, delta;
0250 
0251     traffic = tpt_trig->tx_bytes + tpt_trig->rx_bytes;
0252 
0253     delta = traffic - tpt_trig->prev_traffic;
0254     tpt_trig->prev_traffic = traffic;
0255     return DIV_ROUND_UP(delta, 1024 / 8);
0256 }
0257 
0258 static void tpt_trig_timer(struct timer_list *t)
0259 {
0260     struct tpt_led_trigger *tpt_trig = from_timer(tpt_trig, t, timer);
0261     struct ieee80211_local *local = tpt_trig->local;
0262     unsigned long on, off, tpt;
0263     int i;
0264 
0265     if (!tpt_trig->running)
0266         return;
0267 
0268     mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ));
0269 
0270     tpt = tpt_trig_traffic(local, tpt_trig);
0271 
0272     /* default to just solid on */
0273     on = 1;
0274     off = 0;
0275 
0276     for (i = tpt_trig->blink_table_len - 1; i >= 0; i--) {
0277         if (tpt_trig->blink_table[i].throughput < 0 ||
0278             tpt > tpt_trig->blink_table[i].throughput) {
0279             off = tpt_trig->blink_table[i].blink_time / 2;
0280             on = tpt_trig->blink_table[i].blink_time - off;
0281             break;
0282         }
0283     }
0284 
0285     led_trigger_blink(&local->tpt_led, &on, &off);
0286 }
0287 
0288 const char *
0289 __ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
0290                    unsigned int flags,
0291                    const struct ieee80211_tpt_blink *blink_table,
0292                    unsigned int blink_table_len)
0293 {
0294     struct ieee80211_local *local = hw_to_local(hw);
0295     struct tpt_led_trigger *tpt_trig;
0296 
0297     if (WARN_ON(local->tpt_led_trigger))
0298         return NULL;
0299 
0300     tpt_trig = kzalloc(sizeof(struct tpt_led_trigger), GFP_KERNEL);
0301     if (!tpt_trig)
0302         return NULL;
0303 
0304     snprintf(tpt_trig->name, sizeof(tpt_trig->name),
0305          "%stpt", wiphy_name(local->hw.wiphy));
0306 
0307     local->tpt_led.name = tpt_trig->name;
0308 
0309     tpt_trig->blink_table = blink_table;
0310     tpt_trig->blink_table_len = blink_table_len;
0311     tpt_trig->want = flags;
0312     tpt_trig->local = local;
0313 
0314     timer_setup(&tpt_trig->timer, tpt_trig_timer, 0);
0315 
0316     local->tpt_led_trigger = tpt_trig;
0317 
0318     return tpt_trig->name;
0319 }
0320 EXPORT_SYMBOL(__ieee80211_create_tpt_led_trigger);
0321 
0322 static void ieee80211_start_tpt_led_trig(struct ieee80211_local *local)
0323 {
0324     struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
0325 
0326     if (tpt_trig->running)
0327         return;
0328 
0329     /* reset traffic */
0330     tpt_trig_traffic(local, tpt_trig);
0331     tpt_trig->running = true;
0332 
0333     tpt_trig_timer(&tpt_trig->timer);
0334     mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ));
0335 }
0336 
0337 static void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local)
0338 {
0339     struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
0340 
0341     if (!tpt_trig->running)
0342         return;
0343 
0344     tpt_trig->running = false;
0345     del_timer_sync(&tpt_trig->timer);
0346 
0347     led_trigger_event(&local->tpt_led, LED_OFF);
0348 }
0349 
0350 void ieee80211_mod_tpt_led_trig(struct ieee80211_local *local,
0351                 unsigned int types_on, unsigned int types_off)
0352 {
0353     struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
0354     bool allowed;
0355 
0356     WARN_ON(types_on & types_off);
0357 
0358     if (!tpt_trig)
0359         return;
0360 
0361     tpt_trig->active &= ~types_off;
0362     tpt_trig->active |= types_on;
0363 
0364     /*
0365      * Regardless of wanted state, we shouldn't blink when
0366      * the radio is disabled -- this can happen due to some
0367      * code ordering issues with __ieee80211_recalc_idle()
0368      * being called before the radio is started.
0369      */
0370     allowed = tpt_trig->active & IEEE80211_TPT_LEDTRIG_FL_RADIO;
0371 
0372     if (!allowed || !(tpt_trig->active & tpt_trig->want))
0373         ieee80211_stop_tpt_led_trig(local);
0374     else
0375         ieee80211_start_tpt_led_trig(local);
0376 }