Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
led.c
Go to the documentation of this file.
1 /*
2  * Copyright 2006, Johannes Berg <[email protected]>
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_rx(struct ieee80211_local *local)
16 {
17  if (unlikely(!local->rx_led))
18  return;
19  if (local->rx_led_counter++ % 2 == 0)
20  led_trigger_event(local->rx_led, LED_OFF);
21  else
22  led_trigger_event(local->rx_led, LED_FULL);
23 }
24 
25 /* q is 1 if a packet was enqueued, 0 if it has been transmitted */
26 void ieee80211_led_tx(struct ieee80211_local *local, int q)
27 {
28  if (unlikely(!local->tx_led))
29  return;
30  /* not sure how this is supposed to work ... */
31  local->tx_led_counter += 2*q-1;
32  if (local->tx_led_counter % 2 == 0)
33  led_trigger_event(local->tx_led, LED_OFF);
34  else
35  led_trigger_event(local->tx_led, LED_FULL);
36 }
37 
38 void ieee80211_led_assoc(struct ieee80211_local *local, bool associated)
39 {
40  if (unlikely(!local->assoc_led))
41  return;
42  if (associated)
43  led_trigger_event(local->assoc_led, LED_FULL);
44  else
45  led_trigger_event(local->assoc_led, LED_OFF);
46 }
47 
48 void ieee80211_led_radio(struct ieee80211_local *local, bool enabled)
49 {
50  if (unlikely(!local->radio_led))
51  return;
52  if (enabled)
53  led_trigger_event(local->radio_led, LED_FULL);
54  else
55  led_trigger_event(local->radio_led, LED_OFF);
56 }
57 
59 {
60  snprintf(local->rx_led_name, sizeof(local->rx_led_name),
61  "%srx", wiphy_name(local->hw.wiphy));
62  snprintf(local->tx_led_name, sizeof(local->tx_led_name),
63  "%stx", wiphy_name(local->hw.wiphy));
64  snprintf(local->assoc_led_name, sizeof(local->assoc_led_name),
65  "%sassoc", wiphy_name(local->hw.wiphy));
66  snprintf(local->radio_led_name, sizeof(local->radio_led_name),
67  "%sradio", wiphy_name(local->hw.wiphy));
68 }
69 
71 {
72  local->rx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
73  if (local->rx_led) {
74  local->rx_led->name = local->rx_led_name;
75  if (led_trigger_register(local->rx_led)) {
76  kfree(local->rx_led);
77  local->rx_led = NULL;
78  }
79  }
80 
81  local->tx_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
82  if (local->tx_led) {
83  local->tx_led->name = local->tx_led_name;
84  if (led_trigger_register(local->tx_led)) {
85  kfree(local->tx_led);
86  local->tx_led = NULL;
87  }
88  }
89 
90  local->assoc_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
91  if (local->assoc_led) {
92  local->assoc_led->name = local->assoc_led_name;
93  if (led_trigger_register(local->assoc_led)) {
94  kfree(local->assoc_led);
95  local->assoc_led = NULL;
96  }
97  }
98 
99  local->radio_led = kzalloc(sizeof(struct led_trigger), GFP_KERNEL);
100  if (local->radio_led) {
101  local->radio_led->name = local->radio_led_name;
102  if (led_trigger_register(local->radio_led)) {
103  kfree(local->radio_led);
104  local->radio_led = NULL;
105  }
106  }
107 
108  if (local->tpt_led_trigger) {
109  if (led_trigger_register(&local->tpt_led_trigger->trig)) {
110  kfree(local->tpt_led_trigger);
111  local->tpt_led_trigger = NULL;
112  }
113  }
114 }
115 
117 {
118  if (local->radio_led) {
119  led_trigger_unregister(local->radio_led);
120  kfree(local->radio_led);
121  }
122  if (local->assoc_led) {
123  led_trigger_unregister(local->assoc_led);
124  kfree(local->assoc_led);
125  }
126  if (local->tx_led) {
127  led_trigger_unregister(local->tx_led);
128  kfree(local->tx_led);
129  }
130  if (local->rx_led) {
131  led_trigger_unregister(local->rx_led);
132  kfree(local->rx_led);
133  }
134 
135  if (local->tpt_led_trigger) {
136  led_trigger_unregister(&local->tpt_led_trigger->trig);
137  kfree(local->tpt_led_trigger);
138  }
139 }
140 
142 {
143  struct ieee80211_local *local = hw_to_local(hw);
144 
145  return local->radio_led_name;
146 }
148 
150 {
151  struct ieee80211_local *local = hw_to_local(hw);
152 
153  return local->assoc_led_name;
154 }
156 
158 {
159  struct ieee80211_local *local = hw_to_local(hw);
160 
161  return local->tx_led_name;
162 }
164 
166 {
167  struct ieee80211_local *local = hw_to_local(hw);
168 
169  return local->rx_led_name;
170 }
172 
173 static unsigned long tpt_trig_traffic(struct ieee80211_local *local,
174  struct tpt_led_trigger *tpt_trig)
175 {
176  unsigned long traffic, delta;
177 
178  traffic = tpt_trig->tx_bytes + tpt_trig->rx_bytes;
179 
180  delta = traffic - tpt_trig->prev_traffic;
181  tpt_trig->prev_traffic = traffic;
182  return DIV_ROUND_UP(delta, 1024 / 8);
183 }
184 
185 static void tpt_trig_timer(unsigned long data)
186 {
187  struct ieee80211_local *local = (void *)data;
188  struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
189  struct led_classdev *led_cdev;
190  unsigned long on, off, tpt;
191  int i;
192 
193  if (!tpt_trig->running)
194  return;
195 
196  mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ));
197 
198  tpt = tpt_trig_traffic(local, tpt_trig);
199 
200  /* default to just solid on */
201  on = 1;
202  off = 0;
203 
204  for (i = tpt_trig->blink_table_len - 1; i >= 0; i--) {
205  if (tpt_trig->blink_table[i].throughput < 0 ||
206  tpt > tpt_trig->blink_table[i].throughput) {
207  off = tpt_trig->blink_table[i].blink_time / 2;
208  on = tpt_trig->blink_table[i].blink_time - off;
209  break;
210  }
211  }
212 
213  read_lock(&tpt_trig->trig.leddev_list_lock);
214  list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list)
215  led_blink_set(led_cdev, &on, &off);
216  read_unlock(&tpt_trig->trig.leddev_list_lock);
217 }
218 
220  unsigned int flags,
221  const struct ieee80211_tpt_blink *blink_table,
222  unsigned int blink_table_len)
223 {
224  struct ieee80211_local *local = hw_to_local(hw);
225  struct tpt_led_trigger *tpt_trig;
226 
227  if (WARN_ON(local->tpt_led_trigger))
228  return NULL;
229 
230  tpt_trig = kzalloc(sizeof(struct tpt_led_trigger), GFP_KERNEL);
231  if (!tpt_trig)
232  return NULL;
233 
234  snprintf(tpt_trig->name, sizeof(tpt_trig->name),
235  "%stpt", wiphy_name(local->hw.wiphy));
236 
237  tpt_trig->trig.name = tpt_trig->name;
238 
239  tpt_trig->blink_table = blink_table;
240  tpt_trig->blink_table_len = blink_table_len;
241  tpt_trig->want = flags;
242 
243  setup_timer(&tpt_trig->timer, tpt_trig_timer, (unsigned long)local);
244 
245  local->tpt_led_trigger = tpt_trig;
246 
247  return tpt_trig->name;
248 }
250 
251 static void ieee80211_start_tpt_led_trig(struct ieee80211_local *local)
252 {
253  struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
254 
255  if (tpt_trig->running)
256  return;
257 
258  /* reset traffic */
259  tpt_trig_traffic(local, tpt_trig);
260  tpt_trig->running = true;
261 
262  tpt_trig_timer((unsigned long)local);
263  mod_timer(&tpt_trig->timer, round_jiffies(jiffies + HZ));
264 }
265 
266 static void ieee80211_stop_tpt_led_trig(struct ieee80211_local *local)
267 {
268  struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
269  struct led_classdev *led_cdev;
270 
271  if (!tpt_trig->running)
272  return;
273 
274  tpt_trig->running = false;
275  del_timer_sync(&tpt_trig->timer);
276 
277  read_lock(&tpt_trig->trig.leddev_list_lock);
278  list_for_each_entry(led_cdev, &tpt_trig->trig.led_cdevs, trig_list)
279  led_set_brightness(led_cdev, LED_OFF);
280  read_unlock(&tpt_trig->trig.leddev_list_lock);
281 }
282 
284  unsigned int types_on, unsigned int types_off)
285 {
286  struct tpt_led_trigger *tpt_trig = local->tpt_led_trigger;
287  bool allowed;
288 
289  WARN_ON(types_on & types_off);
290 
291  if (!tpt_trig)
292  return;
293 
294  tpt_trig->active &= ~types_off;
295  tpt_trig->active |= types_on;
296 
297  /*
298  * Regardless of wanted state, we shouldn't blink when
299  * the radio is disabled -- this can happen due to some
300  * code ordering issues with __ieee80211_recalc_idle()
301  * being called before the radio is started.
302  */
303  allowed = tpt_trig->active & IEEE80211_TPT_LEDTRIG_FL_RADIO;
304 
305  if (!allowed || !(tpt_trig->active & tpt_trig->want))
306  ieee80211_stop_tpt_led_trig(local);
307  else
308  ieee80211_start_tpt_led_trig(local);
309 }