00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <linux/if.h>
00011 #include <linux/slab.h>
00012 #include <linux/export.h>
00013 #include "led.h"
00014
00015 void ieee80211_led_rx(struct ieee80211_local *local)
00016 {
00017 if (unlikely(!local->rx_led))
00018 return;
00019 if (local->rx_led_counter++ % 2 == 0)
00020 led_trigger_event(local->rx_led, LED_OFF);
00021 else
00022 led_trigger_event(local->rx_led, LED_FULL);
00023 }
00024
00025
00026 void ieee80211_led_tx(struct ieee80211_local *local, int q)
00027 {
00028 if (unlikely(!local->tx_led))
00029 return;
00030
00031 local->tx_led_counter += 2*q-1;
00032 if (local->tx_led_counter % 2 == 0)
00033 led_trigger_event(local->tx_led, LED_OFF);
00034 else
00035 led_trigger_event(local->tx_led, LED_FULL);
00036 }
00037
00038 void ieee80211_led_assoc(struct ieee80211_local *local, bool associated)
00039 {
00040 if (unlikely(!local->assoc_led))
00041 return;
00042 if (associated)
00043 led_trigger_event(local->assoc_led, LED_FULL);
00044 else
00045 led_trigger_event(local->assoc_led, LED_OFF);
00046 }
00047
00048 void ieee80211_led_radio(struct ieee80211_local *local, bool enabled)
00049 {
00050 if (unlikely(!local->radio_led))
00051 return;
00052 if (enabled)
00053 led_trigger_event(local->radio_led, LED_FULL);
00054 else
00055 led_trigger_event(local->radio_led, LED_OFF);
00056 }
00057
00058 void ieee80211_led_names(struct ieee80211_local *local)
00059 {
00060 snprintf(local->rx_led_name, sizeof(local->rx_led_name),
00061 "%srx", wiphy_name(local->hw.wiphy));
00062 snprintf(local->tx_led_name, sizeof(local->tx_led_name),
00063 "%stx", wiphy_name(local->hw.wiphy));
00064 snprintf(local->assoc_led_name, sizeof(local->assoc_led_name),
00065 "%sassoc", wiphy_name(local->hw.wiphy));
00066 snprintf(local->radio_led_name, sizeof(local->radio_led_name),
00067 "%sradio", wiphy_name(local->hw.wiphy));
00068 }
00069
00070 void ieee80211_led_init(struct ieee80211_local *local)
00071 {
00072 local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
00073 if (local->rx_led) {
00074 local->rx_led->name = local->rx_led_name;
00075 if (led_trigger_register(local->rx_led)) {
00076 kfree(local->rx_led);
00077 local->rx_led = NULL;
00078 }
00079 }
00080
00081 local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
00082 if (local->tx_led) {
00083 local->tx_led->name = local->tx_led_name;
00084 if (led_trigger_register(local->tx_led)) {
00085 kfree(local->tx_led);
00086 local->tx_led = NULL;
00087 }
00088 }
00089
00090 local->assoc_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
00091 if (local->assoc_led) {
00092 local->assoc_led->name = local->assoc_led_name;
00093 if (led_trigger_register(local->assoc_led)) {
00094 kfree(local->assoc_led);
00095 local->assoc_led = NULL;
00096 }
00097 }
00098
00099 local->radio_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
00100 if (local->radio_led) {
00101 local->radio_led->name = local->radio_led_name;
00102 if (led_trigger_register(local->radio_led)) {
00103 kfree(local->radio_led);
00104 local->radio_led = NULL;
00105 }
00106 }
00107
00108 if (local->tpt_led_trigger) {
00109 if (led_trigger_register(&local->tpt_led_trigger->trig)) {
00110 kfree(local->tpt_led_trigger);
00111 local->tpt_led_trigger = NULL;
00112 }
00113 }
00114 }
00115
00116 void ieee80211_led_exit(struct ieee80211_local *local)
00117 {
00118 if (local->radio_led) {
00119 led_trigger_unregister(local->radio_led);
00120 kfree(local->radio_led);
00121 }
00122 if (local->assoc_led) {
00123 led_trigger_unregister(local->assoc_led);
00124 kfree(local->assoc_led);
00125 }
00126 if (local->tx_led) {
00127 led_trigger_unregister(local->tx_led);
00128 kfree(local->tx_led);
00129 }
00130 if (local->rx_led) {
00131 led_trigger_unregister(local->rx_led);
00132 kfree(local->rx_led);
00133 }
00134
00135 if (local->tpt_led_trigger) {
00136 led_trigger_unregister(&local->tpt_led_trigger->trig);
00137 kfree(local->tpt_led_trigger);
00138 }
00139 }
00140
00141 char *__ieee80211_get_radio_led_name(struct ieee80211_hw *hw)
00142 {
00143 struct ieee80211_local *local = hw_to_local(hw);
00144
00145 return local->radio_led_name;
00146 }
00147 EXPORT_SYMBOL(__ieee80211_get_radio_led_name);
00148
00149 char *__ieee80211_get_assoc_led_name(struct ieee80211_hw *hw)
00150 {
00151 struct ieee80211_local *local = hw_to_local(hw);
00152
00153 return local->assoc_led_name;
00154 }
00155 EXPORT_SYMBOL(__ieee80211_get_assoc_led_name);
00156
00157 char *__ieee80211_get_tx_led_name(struct ieee80211_hw *hw)
00158 {
00159 struct ieee80211_local *local = hw_to_local(hw);
00160
00161 return local->tx_led_name;
00162 }
00163 EXPORT_SYMBOL(__ieee80211_get_tx_led_name);
00164
00165 char *__ieee80211_get_rx_led_name(struct ieee80211_hw *hw)
00166 {
00167 struct ieee80211_local *local = hw_to_local(hw);
00168
00169 return local->rx_led_name;
00170 }
00171 EXPORT_SYMBOL(__ieee80211_get_rx_led_name);
00172
00173 static unsigned long tpt_trig_traffic(struct ieee80211_local *local,
00174 struct tpt_led_trigger *tpt_trig)
00175 {
00176 unsigned long traffic, delta;
00177
00178 traffic = tpt_trig->tx_bytes + tpt_trig->rx_bytes;
00179
00180 delta = traffic - tpt_trig->prev_traffic;
00181 tpt_trig->prev_traffic = traffic;
00182 return DIV_ROUND_UP(delta, 1024 / 8);
00183 }
00184
00185 static void tpt_trig_timer(unsigned long data)
00186 {
00187 struct ieee80211_local *local = (void *)data;
00188 struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
00189 struct led_classdev *led_cdev;
00190 unsigned long on, off, tpt;
00191 int i;
00192
00193 if (!tpt_trig->running)
00194 return;
00195
00196 mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ));
00197
00198 tpt = tpt_trig_traffic(local, tpt_trig);
00199
00200
00201 on = 1;
00202 off = 0;
00203
00204 for (i = tpt_trig->blink_table_len - 1; i >= 0; i--) {
00205 if (tpt_trig->blink_table[i].throughput < 0 ||
00206 tpt > tpt_trig->blink_table[i].throughput) {
00207 off = tpt_trig->blink_table[i].blink_time / 2;
00208 on = tpt_trig->blink_table[i].blink_time - off;
00209 break;
00210 }
00211 }
00212
00213 read_lock(&tpt_trig->trig.leddev_list_lock);
00214 list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list)
00215 led_blink_set(led_cdev, &on, &off);
00216 read_unlock(&tpt_trig->trig.leddev_list_lock);
00217 }
00218
00219 char *__ieee80211_create_tpt_led_trigger(struct ieee80211_hw *hw,
00220 unsigned int flags,
00221 const struct ieee80211_tpt_blink *blink_table,
00222 unsigned int blink_table_len)
00223 {
00224 struct ieee80211_local *local = hw_to_local(hw);
00225 struct tpt_led_trigger *tpt_trig;
00226
00227 if (WARN_ON(local->tpt_led_trigger))
00228 return NULL;
00229
00230 tpt_trig = kzalloc(sizeof(struct tpt_led_trigger), GFP_KERNEL);
00231 if (!tpt_trig)
00232 return NULL;
00233
00234 snprintf(tpt_trig->name, sizeof(tpt_trig->name),
00235 "%stpt", wiphy_name(local->hw.wiphy));
00236
00237 tpt_trig->trig.name = tpt_trig->name;
00238
00239 tpt_trig->blink_table = blink_table;
00240 tpt_trig->blink_table_len = blink_table_len;
00241 tpt_trig->want = flags;
00242
00243 setup_timer(&tpt_trig->timer, tpt_trig_timer, (unsigned long)local);
00244
00245 local->tpt_led_trigger = tpt_trig;
00246
00247 return tpt_trig->name;
00248 }
00249 EXPORT_SYMBOL(__ieee80211_create_tpt_led_trigger);
00250
00251 static void ieee80211_start_tpt_led_trig(struct ieee80211_local *local)
00252 {
00253 struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
00254
00255 if (tpt_trig->running)
00256 return;
00257
00258
00259 tpt_trig_traffic(local, tpt_trig);
00260 tpt_trig->running = true;
00261
00262 tpt_trig_timer((unsigned long)local);
00263 mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ));
00264 }
00265
00266 static void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local)
00267 {
00268 struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
00269 struct led_classdev *led_cdev;
00270
00271 if (!tpt_trig->running)
00272 return;
00273
00274 tpt_trig->running = false;
00275 del_timer_sync(&tpt_trig->timer);
00276
00277 read_lock(&tpt_trig->trig.leddev_list_lock);
00278 list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list)
00279 led_brightness_set(led_cdev, LED_OFF);
00280 read_unlock(&tpt_trig->trig.leddev_list_lock);
00281 }
00282
00283 void ieee80211_mod_tpt_led_trig(struct ieee80211_local *local,
00284 unsigned int types_on, unsigned int types_off)
00285 {
00286 struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
00287 bool allowed;
00288
00289 WARN_ON(types_on & types_off);
00290
00291 if (!tpt_trig)
00292 return;
00293
00294 tpt_trig->active &= ~types_off;
00295 tpt_trig->active |= types_on;
00296
00297
00298
00299
00300
00301
00302
00303 allowed = tpt_trig->active & IEEE80211_TPT_LEDTRIG_FL_RADIO;
00304
00305 if (!allowed || !(tpt_trig->active & tpt_trig->want))
00306 ieee80211_stop_tpt_led_trig(local);
00307 else
00308 ieee80211_start_tpt_led_trig(local);
00309 }