0001
0002
0003
0004
0005
0006
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
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
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
0366
0367
0368
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 }