aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
diff options
context:
space:
mode:
authorMohamed Abbas <mabbas@linux.intel.com>2008-03-25 19:33:36 -0400
committerJohn W. Linville <linville@tuxdriver.com>2008-03-27 16:03:16 -0400
commitab53d8af6772b22d4d68b1bcd74f7a5dba693983 (patch)
tree599c6682d75e15b30af9bf994595e7d5eed5c3ac /drivers/net/wireless/iwlwifi
parente0e0a67e44ce13e34f553b6ab6377560fa9813f1 (diff)
iwlwifi: Add led support
This patch add LEDS support to 3965 and 4965 drivers. It is based on led trigger and class. For our drivers we needed to avoid two things. 1- We receive led trigger on/off on each Rx\Tx frame. In our driver we can not call led command like that. In this driver once driver receive a start of traffic it call the led command to start blinking then we count all bytes of Tx and Rx frame, after two second we count the blink rate of last two second then id blink rate changed we call the led commands 2- Since we can call led command very often, we make sure we call the led command after we receive the statistics notification so we don't need to wake up the ucode id it is in sleep state. This patch was tested with 4965 and 3945. Signed-off-by: Mohamed Abbas <mabbas@linux.intel.com> Signed-off-by: Ian Schram<ischram@telenet.be> Signed-off-by: Tomas Winkler <tomas.winkler@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r--drivers/net/wireless/iwlwifi/Kconfig20
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-led.c433
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945-led.h73
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-3945.h13
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.c6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-4965.h12
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-csr.h6
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.c446
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-led.h82
-rw-r--r--drivers/net/wireless/iwlwifi/iwl3945-base.c9
-rw-r--r--drivers/net/wireless/iwlwifi/iwl4965-base.c7
13 files changed, 1107 insertions, 16 deletions
diff --git a/drivers/net/wireless/iwlwifi/Kconfig b/drivers/net/wireless/iwlwifi/Kconfig
index 1ab14ed33f58..4bdb75ecb170 100644
--- a/drivers/net/wireless/iwlwifi/Kconfig
+++ b/drivers/net/wireless/iwlwifi/Kconfig
@@ -2,6 +2,13 @@ config IWLCORE
2 tristate "Intel Wireless Wifi Core" 2 tristate "Intel Wireless Wifi Core"
3 depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL 3 depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
4 4
5config IWLWIFI_LEDS
6 bool "Enable LEDS features in iwlwifi driver"
7 depends on IWLCORE && MAC80211_LEDS && LEDS_CLASS
8 ---help---
9 This option enables LEDS for the iwlwifi drivers
10
11
5config IWL4965 12config IWL4965
6 tristate "Intel Wireless WiFi 4965AGN" 13 tristate "Intel Wireless WiFi 4965AGN"
7 depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL 14 depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
@@ -37,6 +44,13 @@ config IWL4965_HT
37 This option enables IEEE 802.11n High Throughput features 44 This option enables IEEE 802.11n High Throughput features
38 for the iwl4965 driver. 45 for the iwl4965 driver.
39 46
47config IWL4965_LEDS
48 bool "Enable LEDS features in iwl4965 driver"
49 depends on IWL4965 && IWLWIFI_LEDS
50 ---help---
51 This option enables LEDS for the iwlwifi drivers
52
53
40config IWL4965_SPECTRUM_MEASUREMENT 54config IWL4965_SPECTRUM_MEASUREMENT
41 bool "Enable Spectrum Measurement in iwl4965 driver" 55 bool "Enable Spectrum Measurement in iwl4965 driver"
42 depends on IWL4965 56 depends on IWL4965
@@ -114,6 +128,12 @@ config IWL3945_SPECTRUM_MEASUREMENT
114 ---help--- 128 ---help---
115 This option will enable spectrum measurement for the iwl3945 driver. 129 This option will enable spectrum measurement for the iwl3945 driver.
116 130
131config IWL3945_LEDS
132 bool "Enable LEDS features in iwl3945 driver"
133 depends on IWL3945 && MAC80211_LEDS && LEDS_CLASS
134 ---help---
135 This option enables LEDS for the iwl3945 driver.
136
117config IWL3945_DEBUG 137config IWL3945_DEBUG
118 bool "Enable full debugging output in iwl3945 driver" 138 bool "Enable full debugging output in iwl3945 driver"
119 depends on IWL3945 139 depends on IWL3945
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index 6be8012a1743..64fca4d9ac76 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -5,8 +5,18 @@ ifeq ($(CONFIG_IWLWIFI_DEBUGFS),y)
5 iwlcore-objs += iwl-debugfs.o 5 iwlcore-objs += iwl-debugfs.o
6endif 6endif
7 7
8ifeq ($(CONFIG_IWLWIFI_LEDS),y)
9 iwlcore-objs += iwl-led.o
10endif
11
8obj-$(CONFIG_IWL3945) += iwl3945.o 12obj-$(CONFIG_IWL3945) += iwl3945.o
9iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o 13iwl3945-objs = iwl3945-base.o iwl-3945.o iwl-3945-rs.o
10 14
15ifeq ($(CONFIG_IWL3945_LEDS),y)
16 iwl3945-objs += iwl-3945-led.o
17endif
18
19
11obj-$(CONFIG_IWL4965) += iwl4965.o 20obj-$(CONFIG_IWL4965) += iwl4965.o
12iwl4965-objs = iwl4965-base.o iwl-4965.o iwl-4965-rs.o 21iwl4965-objs = iwl4965-base.o iwl-4965.o iwl-4965-rs.o
22
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.c b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
new file mode 100644
index 000000000000..d200d08fb086
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.c
@@ -0,0 +1,433 @@
1/******************************************************************************
2 *
3 * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17 *
18 * The full GNU General Public License is included in this distribution in the
19 * file called LICENSE.
20 *
21 * Contact Information:
22 * James P. Ketrenos <ipw2100-admin@linux.intel.com>
23 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
24 *
25 *****************************************************************************/
26
27
28#include <linux/kernel.h>
29#include <linux/module.h>
30#include <linux/version.h>
31#include <linux/init.h>
32#include <linux/pci.h>
33#include <linux/dma-mapping.h>
34#include <linux/delay.h>
35#include <linux/skbuff.h>
36#include <linux/netdevice.h>
37#include <linux/wireless.h>
38#include <net/mac80211.h>
39#include <linux/etherdevice.h>
40#include <asm/unaligned.h>
41
42#include "iwl-3945.h"
43#include "iwl-helpers.h"
44
45#define IWL_1MB_RATE (128 * 1024)
46#define IWL_LED_THRESHOLD (16)
47#define IWL_MAX_BLINK_TBL (10)
48
49static const struct {
50 u16 brightness;
51 u8 on_time;
52 u8 of_time;
53} blink_tbl[] =
54{
55 {300, 25, 25},
56 {200, 40, 40},
57 {100, 55, 55},
58 {70, 65, 65},
59 {50, 75, 75},
60 {20, 85, 85},
61 {15, 95, 95 },
62 {10, 110, 110},
63 {5, 130, 130},
64 {0, 167, 167}
65};
66
67static int iwl3945_led_cmd_callback(struct iwl3945_priv *priv,
68 struct iwl3945_cmd *cmd,
69 struct sk_buff *skb)
70{
71 return 1;
72}
73
74
75/* Send led command */
76static int iwl_send_led_cmd(struct iwl3945_priv *priv,
77 struct iwl3945_led_cmd *led_cmd)
78{
79 struct iwl3945_host_cmd cmd = {
80 .id = REPLY_LEDS_CMD,
81 .len = sizeof(struct iwl3945_led_cmd),
82 .data = led_cmd,
83 .meta.flags = CMD_ASYNC,
84 .meta.u.callback = iwl3945_led_cmd_callback
85 };
86
87 return iwl3945_send_cmd(priv, &cmd);
88}
89
90
91/* Set led on command */
92static int iwl3945_led_on(struct iwl3945_priv *priv, int led_id)
93{
94 struct iwl3945_led_cmd led_cmd = {
95 .id = led_id,
96 .on = IWL_LED_SOLID,
97 .off = 0,
98 .interval = IWL_DEF_LED_INTRVL
99 };
100 return iwl_send_led_cmd(priv, &led_cmd);
101}
102
103/* Set led on command */
104static int iwl3945_led_pattern(struct iwl3945_priv *priv, int led_id,
105 enum led_brightness brightness)
106{
107 struct iwl3945_led_cmd led_cmd = {
108 .id = led_id,
109 .on = brightness,
110 .off = brightness,
111 .interval = IWL_DEF_LED_INTRVL
112 };
113 if (brightness == LED_FULL) {
114 led_cmd.on = IWL_LED_SOLID;
115 led_cmd.off = 0;
116 }
117 return iwl_send_led_cmd(priv, &led_cmd);
118}
119
120/* Set led register off */
121static int iwl3945_led_on_reg(struct iwl3945_priv *priv, int led_id)
122{
123 IWL_DEBUG_LED("led on %d\n", led_id);
124 return iwl3945_led_on(priv, led_id);
125}
126
127/* Set led off command */
128static int iwl3945_led_off(struct iwl3945_priv *priv, int led_id)
129{
130 struct iwl3945_led_cmd led_cmd = {
131 .id = led_id,
132 .on = 0,
133 .off = 0,
134 .interval = IWL_DEF_LED_INTRVL
135 };
136 IWL_DEBUG_LED("led off %d\n", led_id);
137 return iwl_send_led_cmd(priv, &led_cmd);
138}
139
140/* Set led register off */
141static int iwl3945_led_off_reg(struct iwl3945_priv *priv, int led_id)
142{
143 iwl3945_led_off(priv, led_id);
144 return 0;
145}
146
147/* Set led blink command */
148static int iwl3945_led_not_solid(struct iwl3945_priv *priv, int led_id,
149 u8 brightness)
150{
151 struct iwl3945_led_cmd led_cmd = {
152 .id = led_id,
153 .on = brightness,
154 .off = brightness,
155 .interval = IWL_DEF_LED_INTRVL
156 };
157
158 return iwl_send_led_cmd(priv, &led_cmd);
159}
160
161
162/*
163 * brightness call back function for Tx/Rx LED
164 */
165static int iwl3945_led_associated(struct iwl3945_priv *priv, int led_id)
166{
167 if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
168 !test_bit(STATUS_READY, &priv->status))
169 return 0;
170
171
172 /* start counting Tx/Rx bytes */
173 if (!priv->last_blink_time && priv->allow_blinking)
174 priv->last_blink_time = jiffies;
175 return 0;
176}
177
178/*
179 * brightness call back for association and radio
180 */
181static void iwl3945_led_brightness_set(struct led_classdev *led_cdev,
182 enum led_brightness brightness)
183{
184 struct iwl3945_led *led = container_of(led_cdev,
185 struct iwl3945_led, led_dev);
186 struct iwl3945_priv *priv = led->priv;
187
188 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
189 return;
190
191 switch (brightness) {
192 case LED_FULL:
193 if (led->type == IWL_LED_TRG_ASSOC) {
194 priv->allow_blinking = 1;
195 IWL_DEBUG_LED("MAC is associated\n");
196 }
197 if (led->led_on)
198 led->led_on(priv, IWL_LED_LINK);
199 break;
200 case LED_OFF:
201 if (led->type == IWL_LED_TRG_ASSOC) {
202 priv->allow_blinking = 0;
203 IWL_DEBUG_LED("MAC is disassociated\n");
204 }
205 if (led->led_off)
206 led->led_off(priv, IWL_LED_LINK);
207 break;
208 default:
209 if (led->led_pattern)
210 led->led_pattern(priv, IWL_LED_LINK, brightness);
211 break;
212 }
213}
214
215
216
217/*
218 * Register led class with the system
219 */
220static int iwl3945_led_register_led(struct iwl3945_priv *priv,
221 struct iwl3945_led *led,
222 enum led_type type, u8 set_led,
223 const char *name, char *trigger)
224{
225 struct device *device = wiphy_dev(priv->hw->wiphy);
226 int ret;
227
228 led->led_dev.name = name;
229 led->led_dev.brightness_set = iwl3945_led_brightness_set;
230 led->led_dev.default_trigger = trigger;
231
232 ret = led_classdev_register(device, &led->led_dev);
233 if (ret) {
234 IWL_ERROR("Error: failed to register led handler.\n");
235 return ret;
236 }
237
238 led->priv = priv;
239 led->type = type;
240 led->registered = 1;
241
242 if (set_led && led->led_on)
243 led->led_on(priv, IWL_LED_LINK);
244 return 0;
245}
246
247
248/*
249 * calculate blink rate according to last 2 sec Tx/Rx activities
250 */
251static inline u8 get_blink_rate(struct iwl3945_priv *priv)
252{
253 int index;
254 u8 blink_rate;
255
256 if (priv->rxtxpackets < IWL_LED_THRESHOLD)
257 index = 10;
258 else {
259 for (index = 0; index < IWL_MAX_BLINK_TBL; index++) {
260 if (priv->rxtxpackets > (blink_tbl[index].brightness *
261 IWL_1MB_RATE))
262 break;
263 }
264 }
265 /* if 0 frame is transfered */
266 if ((index == IWL_MAX_BLINK_TBL) || !priv->allow_blinking)
267 blink_rate = IWL_LED_SOLID;
268 else
269 blink_rate = blink_tbl[index].on_time;
270
271 return blink_rate;
272}
273
274static inline int is_rf_kill(struct iwl3945_priv *priv)
275{
276 return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
277 test_bit(STATUS_RF_KILL_SW, &priv->status);
278}
279
280/*
281 * this function called from handler. Since setting Led command can
282 * happen very frequent we postpone led command to be called from
283 * REPLY handler so we know ucode is up
284 */
285void iwl3945_led_background(struct iwl3945_priv *priv)
286{
287 u8 blink_rate;
288
289 if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
290 priv->last_blink_time = 0;
291 return;
292 }
293 if (is_rf_kill(priv)) {
294 priv->last_blink_time = 0;
295 return;
296 }
297
298 if (!priv->allow_blinking) {
299 priv->last_blink_time = 0;
300 if (priv->last_blink_rate != IWL_LED_SOLID) {
301 priv->last_blink_rate = IWL_LED_SOLID;
302 iwl3945_led_on(priv, IWL_LED_LINK);
303 }
304 return;
305 }
306 if (!priv->last_blink_time ||
307 !time_after(jiffies, priv->last_blink_time +
308 msecs_to_jiffies(1000)))
309 return;
310
311 blink_rate = get_blink_rate(priv);
312
313 /* call only if blink rate change */
314 if (blink_rate != priv->last_blink_rate) {
315 if (blink_rate != IWL_LED_SOLID) {
316 priv->last_blink_time = jiffies +
317 msecs_to_jiffies(1000);
318 iwl3945_led_not_solid(priv, IWL_LED_LINK, blink_rate);
319 } else {
320 priv->last_blink_time = 0;
321 iwl3945_led_on(priv, IWL_LED_LINK);
322 }
323 }
324
325 priv->last_blink_rate = blink_rate;
326 priv->rxtxpackets = 0;
327}
328
329
330/* Register all led handler */
331int iwl3945_led_register(struct iwl3945_priv *priv)
332{
333 char *trigger;
334 char name[32];
335 int ret;
336
337 priv->last_blink_rate = 0;
338 priv->rxtxpackets = 0;
339 priv->last_blink_time = 0;
340 priv->allow_blinking = 0;
341
342 trigger = ieee80211_get_radio_led_name(priv->hw);
343 snprintf(name, sizeof(name), "iwl-%s:radio",
344 wiphy_name(priv->hw->wiphy));
345
346 priv->led[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on_reg;
347 priv->led[IWL_LED_TRG_RADIO].led_off = iwl3945_led_off_reg;
348 priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
349
350 ret = iwl3945_led_register_led(priv,
351 &priv->led[IWL_LED_TRG_RADIO],
352 IWL_LED_TRG_RADIO, 1,
353 name, trigger);
354 if (ret)
355 goto exit_fail;
356
357 trigger = ieee80211_get_assoc_led_name(priv->hw);
358 snprintf(name, sizeof(name), "iwl-%s:assoc",
359 wiphy_name(priv->hw->wiphy));
360
361 ret = iwl3945_led_register_led(priv,
362 &priv->led[IWL_LED_TRG_ASSOC],
363 IWL_LED_TRG_ASSOC, 0,
364 name, trigger);
365 /* for assoc always turn led on */
366 priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_on_reg;
367 priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_on_reg;
368 priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL;
369
370 if (ret)
371 goto exit_fail;
372
373 trigger = ieee80211_get_rx_led_name(priv->hw);
374 snprintf(name, sizeof(name), "iwl-%s:RX",
375 wiphy_name(priv->hw->wiphy));
376
377
378 ret = iwl3945_led_register_led(priv,
379 &priv->led[IWL_LED_TRG_RX],
380 IWL_LED_TRG_RX, 0,
381 name, trigger);
382
383 priv->led[IWL_LED_TRG_RX].led_on = iwl3945_led_associated;
384 priv->led[IWL_LED_TRG_RX].led_off = iwl3945_led_associated;
385 priv->led[IWL_LED_TRG_RX].led_pattern = iwl3945_led_pattern;
386
387 if (ret)
388 goto exit_fail;
389
390 trigger = ieee80211_get_tx_led_name(priv->hw);
391 snprintf(name, sizeof(name), "iwl-%s:TX",
392 wiphy_name(priv->hw->wiphy));
393 ret = iwl3945_led_register_led(priv,
394 &priv->led[IWL_LED_TRG_TX],
395 IWL_LED_TRG_TX, 0,
396 name, trigger);
397 priv->led[IWL_LED_TRG_TX].led_on = iwl3945_led_associated;
398 priv->led[IWL_LED_TRG_TX].led_off = iwl3945_led_associated;
399 priv->led[IWL_LED_TRG_TX].led_pattern = iwl3945_led_pattern;
400
401 if (ret)
402 goto exit_fail;
403
404 return 0;
405
406exit_fail:
407 iwl3945_led_unregister(priv);
408 return ret;
409}
410
411
412/* unregister led class */
413static void iwl3945_led_unregister_led(struct iwl3945_led *led, u8 set_led)
414{
415 if (!led->registered)
416 return;
417
418 led_classdev_unregister(&led->led_dev);
419
420 if (set_led)
421 led->led_dev.brightness_set(&led->led_dev, LED_OFF);
422 led->registered = 0;
423}
424
425/* Unregister all led handlers */
426void iwl3945_led_unregister(struct iwl3945_priv *priv)
427{
428 iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_ASSOC], 0);
429 iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_RX], 0);
430 iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_TX], 0);
431 iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_RADIO], 1);
432}
433
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945-led.h b/drivers/net/wireless/iwlwifi/iwl-3945-led.h
new file mode 100644
index 000000000000..b1d2f6b8b259
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-3945-led.h
@@ -0,0 +1,73 @@
1/******************************************************************************
2 *
3 * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17 *
18 * The full GNU General Public License is included in this distribution in the
19 * file called LICENSE.
20 *
21 * Contact Information:
22 * James P. Ketrenos <ipw2100-admin@linux.intel.com>
23 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
24 *
25 *****************************************************************************/
26
27#ifndef IWL3945_LEDS_H
28#define IWL3945_LEDS_H
29
30struct iwl3945_priv;
31
32#ifdef CONFIG_IWL3945_LEDS
33#define IWL_LED_SOLID 11
34#define IWL_LED_NAME_LEN 31
35#define IWL_DEF_LED_INTRVL __constant_cpu_to_le32(1000)
36
37#define IWL_LED_ACTIVITY (0<<1)
38#define IWL_LED_LINK (1<<1)
39
40enum led_type {
41 IWL_LED_TRG_TX,
42 IWL_LED_TRG_RX,
43 IWL_LED_TRG_ASSOC,
44 IWL_LED_TRG_RADIO,
45 IWL_LED_TRG_MAX,
46};
47
48#include <linux/leds.h>
49
50struct iwl3945_led {
51 struct iwl3945_priv *priv;
52 struct led_classdev led_dev;
53
54 int (*led_on) (struct iwl3945_priv *priv, int led_id);
55 int (*led_off) (struct iwl3945_priv *priv, int led_id);
56 int (*led_pattern) (struct iwl3945_priv *priv, int led_id,
57 enum led_brightness brightness);
58
59 enum led_type type;
60 unsigned int registered;
61};
62
63extern int iwl3945_led_register(struct iwl3945_priv *priv);
64extern void iwl3945_led_unregister(struct iwl3945_priv *priv);
65extern void iwl3945_led_background(struct iwl3945_priv *priv);
66
67#else
68static inline int iwl3945_led_register(struct iwl3945_priv *priv) { return 0; }
69static inline void iwl3945_led_unregister(struct iwl3945_priv *priv) {}
70static inline void iwl3945_led_background(struct iwl3945_priv *priv) {}
71#endif /* CONFIG_IWL3945_LEDS */
72
73#endif /* IWL3945_LEDS_H */
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.c b/drivers/net/wireless/iwlwifi/iwl-3945.c
index e116ed77c5ad..eb30819cddc4 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.c
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.c
@@ -358,6 +358,8 @@ void iwl3945_hw_rx_statistics(struct iwl3945_priv *priv, struct iwl3945_rx_mem_b
358 358
359 memcpy(&priv->statistics, pkt->u.raw, sizeof(priv->statistics)); 359 memcpy(&priv->statistics, pkt->u.raw, sizeof(priv->statistics));
360 360
361 iwl3945_led_background(priv);
362
361 priv->last_statistics_time = jiffies; 363 priv->last_statistics_time = jiffies;
362} 364}
363 365
@@ -640,6 +642,10 @@ static void iwl3945_handle_data_packet(struct iwl3945_priv *priv, int is_data,
640 if (priv->add_radiotap) 642 if (priv->add_radiotap)
641 iwl3945_add_radiotap(priv, rxb->skb, rx_hdr, stats); 643 iwl3945_add_radiotap(priv, rxb->skb, rx_hdr, stats);
642 644
645#ifdef CONFIG_IWL3945_LEDS
646 if (is_data)
647 priv->rxtxpackets += len;
648#endif
643 ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); 649 ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
644 rxb->skb = NULL; 650 rxb->skb = NULL;
645} 651}
diff --git a/drivers/net/wireless/iwlwifi/iwl-3945.h b/drivers/net/wireless/iwlwifi/iwl-3945.h
index 931c465f9e5e..e0655b988f44 100644
--- a/drivers/net/wireless/iwlwifi/iwl-3945.h
+++ b/drivers/net/wireless/iwlwifi/iwl-3945.h
@@ -44,6 +44,7 @@ extern struct pci_device_id iwl3945_hw_card_ids[];
44#include "iwl-prph.h" 44#include "iwl-prph.h"
45#include "iwl-3945-hw.h" 45#include "iwl-3945-hw.h"
46#include "iwl-3945-debug.h" 46#include "iwl-3945-debug.h"
47#include "iwl-3945-led.h"
47 48
48/* Change firmware file name, using "-" and incrementing number, 49/* Change firmware file name, using "-" and incrementing number,
49 * *only* when uCode interface or architecture changes so that it 50 * *only* when uCode interface or architecture changes so that it
@@ -777,13 +778,15 @@ struct iwl3945_priv {
777 struct iwl3945_init_alive_resp card_alive_init; 778 struct iwl3945_init_alive_resp card_alive_init;
778 struct iwl3945_alive_resp card_alive; 779 struct iwl3945_alive_resp card_alive;
779 780
780#ifdef LED 781#ifdef CONFIG_IWL4965_LEDS
781 /* LED related variables */ 782 struct iwl3945_led led[IWL_LED_TRG_MAX];
782 struct iwl3945_activity_blink activity; 783 unsigned long last_blink_time;
783 unsigned long led_packets; 784 u8 last_blink_rate;
784 int led_state; 785 u8 allow_blinking;
786 unsigned int rxtxpackets;
785#endif 787#endif
786 788
789
787 u16 active_rate; 790 u16 active_rate;
788 u16 active_rate_basic; 791 u16 active_rate_basic;
789 792
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.c b/drivers/net/wireless/iwlwifi/iwl-4965.c
index 1db873b02f1e..8b5cacb14618 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.c
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.c
@@ -3258,6 +3258,8 @@ void iwl4965_hw_rx_statistics(struct iwl_priv *priv, struct iwl4965_rx_mem_buffe
3258#endif 3258#endif
3259 } 3259 }
3260 3260
3261 iwl_leds_background(priv);
3262
3261 /* If the hardware hasn't reported a change in 3263 /* If the hardware hasn't reported a change in
3262 * temperature then don't bother computing a 3264 * temperature then don't bother computing a
3263 * calibrated temperature value */ 3265 * calibrated temperature value */
@@ -3539,10 +3541,6 @@ static void iwl4965_handle_data_packet(struct iwl_priv *priv, int is_data,
3539 ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats); 3541 ieee80211_rx_irqsafe(priv->hw, rxb->skb, stats);
3540 priv->alloc_rxb_skb--; 3542 priv->alloc_rxb_skb--;
3541 rxb->skb = NULL; 3543 rxb->skb = NULL;
3542#ifdef LED
3543 priv->led_packets += len;
3544 iwl4965_setup_activity_timer(priv);
3545#endif
3546} 3544}
3547 3545
3548/* Calc max signal level (dBm) among 3 possible receivers */ 3546/* Calc max signal level (dBm) among 3 possible receivers */
diff --git a/drivers/net/wireless/iwlwifi/iwl-4965.h b/drivers/net/wireless/iwlwifi/iwl-4965.h
index 960b53b20df8..32c21d266f98 100644
--- a/drivers/net/wireless/iwlwifi/iwl-4965.h
+++ b/drivers/net/wireless/iwlwifi/iwl-4965.h
@@ -45,6 +45,7 @@ extern struct pci_device_id iwl4965_hw_card_ids[];
45#include "iwl-csr.h" 45#include "iwl-csr.h"
46#include "iwl-prph.h" 46#include "iwl-prph.h"
47#include "iwl-debug.h" 47#include "iwl-debug.h"
48#include "iwl-led.h"
48 49
49/* Change firmware file name, using "-" and incrementing number, 50/* Change firmware file name, using "-" and incrementing number,
50 * *only* when uCode interface or architecture changes so that it 51 * *only* when uCode interface or architecture changes so that it
@@ -1050,11 +1051,12 @@ struct iwl_priv {
1050 struct iwl4965_init_alive_resp card_alive_init; 1051 struct iwl4965_init_alive_resp card_alive_init;
1051 struct iwl4965_alive_resp card_alive; 1052 struct iwl4965_alive_resp card_alive;
1052 1053
1053#ifdef LED 1054#ifdef CONFIG_IWL4965_LEDS
1054 /* LED related variables */ 1055 struct iwl4965_led led[IWL_LED_TRG_MAX];
1055 struct iwl4965_activity_blink activity; 1056 unsigned long last_blink_time;
1056 unsigned long led_packets; 1057 u8 last_blink_rate;
1057 int led_state; 1058 u8 allow_blinking;
1059 u64 led_tpt;
1058#endif 1060#endif
1059 1061
1060 u16 active_rate; 1062 u16 active_rate;
diff --git a/drivers/net/wireless/iwlwifi/iwl-csr.h b/drivers/net/wireless/iwlwifi/iwl-csr.h
index f0a2c8d180f0..12725796ea5f 100644
--- a/drivers/net/wireless/iwlwifi/iwl-csr.h
+++ b/drivers/net/wireless/iwlwifi/iwl-csr.h
@@ -93,6 +93,7 @@
93#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c) 93#define CSR_UCODE_DRV_GP1_CLR (CSR_BASE+0x05c)
94#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060) 94#define CSR_UCODE_DRV_GP2 (CSR_BASE+0x060)
95#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100) 95#define CSR_GIO_CHICKEN_BITS (CSR_BASE+0x100)
96#define CSR_LED_REG (CSR_BASE+0x094)
96 97
97/* Analog phase-lock-loop configuration (3945 only) 98/* Analog phase-lock-loop configuration (3945 only)
98 * Set bit 24. */ 99 * Set bit 24. */
@@ -214,6 +215,11 @@
214#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000) 215#define CSR_GIO_CHICKEN_BITS_REG_BIT_L1A_NO_L0S_RX (0x00800000)
215#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000) 216#define CSR_GIO_CHICKEN_BITS_REG_BIT_DIS_L0S_EXIT_TIMER (0x20000000)
216 217
218/* LED */
219#define CSR_LED_BSM_CTRL_MSK (0xFFFFFFDF)
220#define CSR_LED_REG_TRUN_ON (0x78)
221#define CSR_LED_REG_TRUN_OFF (0x38)
222
217/*=== HBUS (Host-side Bus) ===*/ 223/*=== HBUS (Host-side Bus) ===*/
218#define HBUS_BASE (0x400) 224#define HBUS_BASE (0x400)
219/* 225/*
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c
new file mode 100644
index 000000000000..6f5424bd365b
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-led.c
@@ -0,0 +1,446 @@
1/******************************************************************************
2 *
3 * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17 *
18 * The full GNU General Public License is included in this distribution in the
19 * file called LICENSE.
20 *
21 * Contact Information:
22 * James P. Ketrenos <ipw2100-admin@linux.intel.com>
23 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
24 *
25 *****************************************************************************/
26
27
28#include <linux/kernel.h>
29#include <linux/module.h>
30#include <linux/version.h>
31#include <linux/init.h>
32#include <linux/pci.h>
33#include <linux/dma-mapping.h>
34#include <linux/delay.h>
35#include <linux/skbuff.h>
36#include <linux/netdevice.h>
37#include <linux/wireless.h>
38#include <net/mac80211.h>
39#include <linux/etherdevice.h>
40#include <asm/unaligned.h>
41
42#include "iwl-4965.h"
43#include "iwl-core.h"
44#include "iwl-helpers.h"
45
46#define IWL_1MB_RATE (128 * 1024)
47#define IWL_LED_THRESHOLD (16)
48#define IWL_MAX_BLINK_TBL (10)
49
50static const struct {
51 u16 tpt;
52 u8 on_time;
53 u8 of_time;
54} blink_tbl[] =
55{
56 {300, 25, 25},
57 {200, 40, 40},
58 {100, 55, 55},
59 {70, 65, 65},
60 {50, 75, 75},
61 {20, 85, 85},
62 {15, 95, 95 },
63 {10, 110, 110},
64 {5, 130, 130},
65 {0, 167, 167}
66};
67
68static int iwl_led_cmd_callback(struct iwl_priv *priv,
69 struct iwl_cmd *cmd, struct sk_buff *skb)
70{
71 return 1;
72}
73
74
75/* Send led command */
76static int iwl_send_led_cmd(struct iwl_priv *priv,
77 struct iwl4965_led_cmd *led_cmd)
78{
79 struct iwl_host_cmd cmd = {
80 .id = REPLY_LEDS_CMD,
81 .len = sizeof(struct iwl4965_led_cmd),
82 .data = led_cmd,
83 .meta.flags = CMD_ASYNC,
84 .meta.u.callback = iwl_led_cmd_callback
85 };
86 u32 reg;
87
88 reg = iwl4965_read32(priv, CSR_LED_REG);
89 if (reg != (reg & CSR_LED_BSM_CTRL_MSK))
90 iwl4965_write32(priv, CSR_LED_REG, reg & CSR_LED_BSM_CTRL_MSK);
91
92 return iwl_send_cmd(priv, &cmd);
93}
94
95
96/* Set led on command */
97static int iwl4965_led_on(struct iwl_priv *priv, int led_id)
98{
99 struct iwl4965_led_cmd led_cmd = {
100 .id = led_id,
101 .on = IWL_LED_SOLID,
102 .off = 0,
103 .interval = IWL_DEF_LED_INTRVL
104 };
105 return iwl_send_led_cmd(priv, &led_cmd);
106}
107
108/* Set led on command */
109static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id,
110 enum led_brightness brightness)
111{
112 struct iwl4965_led_cmd led_cmd = {
113 .id = led_id,
114 .on = brightness,
115 .off = brightness,
116 .interval = IWL_DEF_LED_INTRVL
117 };
118 if (brightness == LED_FULL) {
119 led_cmd.on = IWL_LED_SOLID;
120 led_cmd.off = 0;
121 }
122 return iwl_send_led_cmd(priv, &led_cmd);
123}
124
125/* Set led register off */
126static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id)
127{
128 IWL_DEBUG_LED("led on %d\n", led_id);
129 iwl4965_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_ON);
130 return 0;
131}
132
133#if 0
134/* Set led off command */
135int iwl4965_led_off(struct iwl_priv *priv, int led_id)
136{
137 struct iwl4965_led_cmd led_cmd = {
138 .id = led_id,
139 .on = 0,
140 .off = 0,
141 .interval = IWL_DEF_LED_INTRVL
142 };
143 IWL_DEBUG_LED("led off %d\n", led_id);
144 return iwl_send_led_cmd(priv, &led_cmd);
145}
146#endif
147
148
149/* Set led register off */
150static int iwl4965_led_off_reg(struct iwl_priv *priv, int led_id)
151{
152 IWL_DEBUG_LED("radio off\n");
153 iwl4965_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF);
154 return 0;
155}
156
157/* Set led blink command */
158static int iwl4965_led_not_solid(struct iwl_priv *priv, int led_id,
159 u8 brightness)
160{
161 struct iwl4965_led_cmd led_cmd = {
162 .id = led_id,
163 .on = brightness,
164 .off = brightness,
165 .interval = IWL_DEF_LED_INTRVL
166 };
167
168 return iwl_send_led_cmd(priv, &led_cmd);
169}
170
171
172/*
173 * brightness call back function for Tx/Rx LED
174 */
175static int iwl4965_led_associated(struct iwl_priv *priv, int led_id)
176{
177 if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
178 !test_bit(STATUS_READY, &priv->status))
179 return 0;
180
181
182 /* start counting Tx/Rx bytes */
183 if (!priv->last_blink_time && priv->allow_blinking)
184 priv->last_blink_time = jiffies;
185 return 0;
186}
187
188/*
189 * brightness call back for association and radio
190 */
191static void iwl4965_led_brightness_set(struct led_classdev *led_cdev,
192 enum led_brightness brightness)
193{
194 struct iwl4965_led *led = container_of(led_cdev,
195 struct iwl4965_led, led_dev);
196 struct iwl_priv *priv = led->priv;
197
198 if (test_bit(STATUS_EXIT_PENDING, &priv->status))
199 return;
200
201 switch (brightness) {
202 case LED_FULL:
203 if (led->type == IWL_LED_TRG_ASSOC)
204 priv->allow_blinking = 1;
205
206 if (led->led_on)
207 led->led_on(priv, IWL_LED_LINK);
208 break;
209 case LED_OFF:
210 if (led->type == IWL_LED_TRG_ASSOC)
211 priv->allow_blinking = 0;
212
213 if (led->led_off)
214 led->led_off(priv, IWL_LED_LINK);
215 break;
216 default:
217 if (led->led_pattern)
218 led->led_pattern(priv, IWL_LED_LINK, brightness);
219 break;
220 }
221}
222
223
224
225/*
226 * Register led class with the system
227 */
228static int iwl_leds_register_led(struct iwl_priv *priv,
229 struct iwl4965_led *led,
230 enum led_type type, u8 set_led,
231 const char *name, char *trigger)
232{
233 struct device *device = wiphy_dev(priv->hw->wiphy);
234 int ret;
235
236 led->led_dev.name = name;
237 led->led_dev.brightness_set = iwl4965_led_brightness_set;
238 led->led_dev.default_trigger = trigger;
239
240 ret = led_classdev_register(device, &led->led_dev);
241 if (ret) {
242 IWL_ERROR("Error: failed to register led handler.\n");
243 return ret;
244 }
245
246 led->priv = priv;
247 led->type = type;
248 led->registered = 1;
249
250 if (set_led && led->led_on)
251 led->led_on(priv, IWL_LED_LINK);
252 return 0;
253}
254
255
256/*
257 * calculate blink rate according to last 2 sec Tx/Rx activities
258 */
259static inline u8 get_blink_rate(struct iwl_priv *priv)
260{
261 int i;
262 u8 blink_rate;
263 u64 current_tpt = priv->tx_stats[2].bytes + priv->rx_stats[2].bytes;
264 s64 tpt = current_tpt - priv->led_tpt;
265
266 if (tpt < 0) /* wrapparound */
267 tpt = -tpt;
268
269 priv->led_tpt = current_tpt;
270
271 if (tpt < IWL_LED_THRESHOLD) {
272 i = IWL_MAX_BLINK_TBL;
273 } else {
274 for (i = 0; i < IWL_MAX_BLINK_TBL; i++)
275 if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE))
276 break;
277 }
278 /* if 0 frame is transfered */
279 if ((i == IWL_MAX_BLINK_TBL) || !priv->allow_blinking)
280 blink_rate = IWL_LED_SOLID;
281 else
282 blink_rate = blink_tbl[i].on_time;
283
284 return blink_rate;
285}
286
287static inline int is_rf_kill(struct iwl_priv *priv)
288{
289 return test_bit(STATUS_RF_KILL_HW, &priv->status) ||
290 test_bit(STATUS_RF_KILL_SW, &priv->status);
291}
292
293/*
294 * this function called from handler. Since setting Led command can
295 * happen very frequent we postpone led command to be called from
296 * REPLY handler so we know ucode is up
297 */
298void iwl_leds_background(struct iwl_priv *priv)
299{
300 u8 blink_rate;
301
302 if (test_bit(STATUS_EXIT_PENDING, &priv->status)) {
303 priv->last_blink_time = 0;
304 return;
305 }
306 if (is_rf_kill(priv)) {
307 priv->last_blink_time = 0;
308 return;
309 }
310
311 if (!priv->allow_blinking) {
312 priv->last_blink_time = 0;
313 if (priv->last_blink_rate != IWL_LED_SOLID) {
314 priv->last_blink_rate = IWL_LED_SOLID;
315 iwl4965_led_on(priv, IWL_LED_LINK);
316 }
317 return;
318 }
319 if (!priv->last_blink_time ||
320 !time_after(jiffies, priv->last_blink_time +
321 msecs_to_jiffies(1000)))
322 return;
323
324 blink_rate = get_blink_rate(priv);
325
326 /* call only if blink rate change */
327 if (blink_rate != priv->last_blink_rate) {
328 if (blink_rate != IWL_LED_SOLID) {
329 priv->last_blink_time = jiffies +
330 msecs_to_jiffies(1000);
331 iwl4965_led_not_solid(priv, IWL_LED_LINK, blink_rate);
332 } else {
333 priv->last_blink_time = 0;
334 iwl4965_led_on(priv, IWL_LED_LINK);
335 }
336 }
337
338 priv->last_blink_rate = blink_rate;
339}
340EXPORT_SYMBOL(iwl_leds_background);
341
342/* Register all led handler */
343int iwl_leds_register(struct iwl_priv *priv)
344{
345 char *trigger;
346 char name[32];
347 int ret;
348
349 priv->last_blink_rate = 0;
350 priv->led_tpt = 0;
351 priv->last_blink_time = 0;
352 priv->allow_blinking = 0;
353
354 trigger = ieee80211_get_radio_led_name(priv->hw);
355 snprintf(name, sizeof(name), "iwl-%s:radio",
356 wiphy_name(priv->hw->wiphy));
357
358 priv->led[IWL_LED_TRG_RADIO].led_on = iwl4965_led_on_reg;
359 priv->led[IWL_LED_TRG_RADIO].led_off = iwl4965_led_off_reg;
360 priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
361
362 ret = iwl_leds_register_led(priv,
363 &priv->led[IWL_LED_TRG_RADIO],
364 IWL_LED_TRG_RADIO, 1,
365 name, trigger);
366 if (ret)
367 goto exit_fail;
368
369 trigger = ieee80211_get_assoc_led_name(priv->hw);
370 snprintf(name, sizeof(name), "iwl-%s:assoc",
371 wiphy_name(priv->hw->wiphy));
372
373 ret = iwl_leds_register_led(priv,
374 &priv->led[IWL_LED_TRG_ASSOC],
375 IWL_LED_TRG_ASSOC, 0,
376 name, trigger);
377 /* for assoc always turn led on */
378 priv->led[IWL_LED_TRG_ASSOC].led_on = iwl4965_led_on_reg;
379 priv->led[IWL_LED_TRG_ASSOC].led_off = iwl4965_led_on_reg;
380 priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL;
381
382 if (ret)
383 goto exit_fail;
384
385 trigger = ieee80211_get_rx_led_name(priv->hw);
386 snprintf(name, sizeof(name), "iwl-%s:RX",
387 wiphy_name(priv->hw->wiphy));
388
389
390 ret = iwl_leds_register_led(priv,
391 &priv->led[IWL_LED_TRG_RX],
392 IWL_LED_TRG_RX, 0,
393 name, trigger);
394
395 priv->led[IWL_LED_TRG_RX].led_on = iwl4965_led_associated;
396 priv->led[IWL_LED_TRG_RX].led_off = iwl4965_led_associated;
397 priv->led[IWL_LED_TRG_RX].led_pattern = iwl4965_led_pattern;
398
399 if (ret)
400 goto exit_fail;
401
402 trigger = ieee80211_get_tx_led_name(priv->hw);
403 snprintf(name, sizeof(name), "iwl-%s:TX",
404 wiphy_name(priv->hw->wiphy));
405 ret = iwl_leds_register_led(priv,
406 &priv->led[IWL_LED_TRG_TX],
407 IWL_LED_TRG_TX, 0,
408 name, trigger);
409 priv->led[IWL_LED_TRG_TX].led_on = iwl4965_led_associated;
410 priv->led[IWL_LED_TRG_TX].led_off = iwl4965_led_associated;
411 priv->led[IWL_LED_TRG_TX].led_pattern = iwl4965_led_pattern;
412
413 if (ret)
414 goto exit_fail;
415
416 return 0;
417
418exit_fail:
419 iwl_leds_unregister(priv);
420 return ret;
421}
422EXPORT_SYMBOL(iwl_leds_register);
423
424/* unregister led class */
425static void iwl_leds_unregister_led(struct iwl4965_led *led, u8 set_led)
426{
427 if (!led->registered)
428 return;
429
430 led_classdev_unregister(&led->led_dev);
431
432 if (set_led)
433 led->led_dev.brightness_set(&led->led_dev, LED_OFF);
434 led->registered = 0;
435}
436
437/* Unregister all led handlers */
438void iwl_leds_unregister(struct iwl_priv *priv)
439{
440 iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_ASSOC], 0);
441 iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_RX], 0);
442 iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_TX], 0);
443 iwl_leds_unregister_led(&priv->led[IWL_LED_TRG_RADIO], 1);
444}
445EXPORT_SYMBOL(iwl_leds_unregister);
446
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.h b/drivers/net/wireless/iwlwifi/iwl-led.h
new file mode 100644
index 000000000000..5bb04128cd65
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-led.h
@@ -0,0 +1,82 @@
1/******************************************************************************
2 *
3 * Copyright(c) 2003 - 2008 Intel Corporation. All rights reserved.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along with
15 * this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
17 *
18 * The full GNU General Public License is included in this distribution in the
19 * file called LICENSE.
20 *
21 * Contact Information:
22 * James P. Ketrenos <ipw2100-admin@linux.intel.com>
23 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
24 *
25 *****************************************************************************/
26
27#ifndef __iwl_leds_h__
28#define __iwl_leds_h__
29
30
31struct iwl_priv;
32
33#ifdef CONFIG_IWLWIFI_LEDS
34#include <linux/leds.h>
35
36#define IWL_LED_SOLID 11
37#define IWL_LED_NAME_LEN 31
38#define IWL_DEF_LED_INTRVL __constant_cpu_to_le32(1000)
39
40#define IWL_LED_ACTIVITY (0<<1)
41#define IWL_LED_LINK (1<<1)
42
43enum led_type {
44 IWL_LED_TRG_TX,
45 IWL_LED_TRG_RX,
46 IWL_LED_TRG_ASSOC,
47 IWL_LED_TRG_RADIO,
48 IWL_LED_TRG_MAX,
49};
50
51
52struct iwl4965_led {
53 struct iwl_priv *priv;
54 struct led_classdev led_dev;
55
56 int (*led_on) (struct iwl_priv *priv, int led_id);
57 int (*led_off) (struct iwl_priv *priv, int led_id);
58 int (*led_pattern) (struct iwl_priv *priv, int led_id,
59 enum led_brightness brightness);
60
61 enum led_type type;
62 unsigned int registered;
63};
64
65int iwl_leds_register(struct iwl_priv *priv);
66void iwl_leds_unregister(struct iwl_priv *priv);
67void iwl_leds_background(struct iwl_priv *priv);
68
69#else
70static inline int iwl_leds_register(struct iwl_priv *priv)
71{
72 return 0;
73}
74static inline void iwl_leds_unregister(struct iwl_priv *priv)
75{
76}
77static inline void iwl_leds_background(struct iwl_priv *priv)
78{
79}
80
81#endif /* CONFIG_IWLWIFI_LEDS */
82#endif /* __iwl_leds_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c
index 4ba959153cb1..470a9abf12c3 100644
--- a/drivers/net/wireless/iwlwifi/iwl3945-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c
@@ -2481,8 +2481,12 @@ static void iwl3945_build_tx_cmd_basic(struct iwl3945_priv *priv,
2481 cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3); 2481 cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3);
2482 else 2482 else
2483 cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2); 2483 cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2);
2484 } else 2484 } else {
2485 cmd->cmd.tx.timeout.pm_frame_timeout = 0; 2485 cmd->cmd.tx.timeout.pm_frame_timeout = 0;
2486#ifdef CONFIG_IWL3945_LEDS
2487 priv->rxtxpackets += le16_to_cpu(cmd->cmd.tx.len);
2488#endif
2489 }
2486 2490
2487 cmd->cmd.tx.driver_txop = 0; 2491 cmd->cmd.tx.driver_txop = 0;
2488 cmd->cmd.tx.tx_flags = tx_flags; 2492 cmd->cmd.tx.tx_flags = tx_flags;
@@ -5855,6 +5859,8 @@ static void iwl3945_alive_start(struct iwl3945_priv *priv)
5855 IWL_DEBUG_INFO("ALIVE processing complete.\n"); 5859 IWL_DEBUG_INFO("ALIVE processing complete.\n");
5856 wake_up_interruptible(&priv->wait_command_queue); 5860 wake_up_interruptible(&priv->wait_command_queue);
5857 5861
5862 iwl3945_led_register(priv);
5863
5858 if (priv->error_recovering) 5864 if (priv->error_recovering)
5859 iwl3945_error_recovery(priv); 5865 iwl3945_error_recovery(priv);
5860 5866
@@ -5879,6 +5885,7 @@ static void __iwl3945_down(struct iwl3945_priv *priv)
5879 if (!exit_pending) 5885 if (!exit_pending)
5880 set_bit(STATUS_EXIT_PENDING, &priv->status); 5886 set_bit(STATUS_EXIT_PENDING, &priv->status);
5881 5887
5888 iwl3945_led_unregister(priv);
5882 iwl3945_clear_stations_table(priv); 5889 iwl3945_clear_stations_table(priv);
5883 5890
5884 /* Unblock any waiting calls */ 5891 /* Unblock any waiting calls */
diff --git a/drivers/net/wireless/iwlwifi/iwl4965-base.c b/drivers/net/wireless/iwlwifi/iwl4965-base.c
index 9ae3d2981df5..a04127a8acf7 100644
--- a/drivers/net/wireless/iwlwifi/iwl4965-base.c
+++ b/drivers/net/wireless/iwlwifi/iwl4965-base.c
@@ -2238,8 +2238,9 @@ static void iwl4965_build_tx_cmd_basic(struct iwl_priv *priv,
2238 cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3); 2238 cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(3);
2239 else 2239 else
2240 cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2); 2240 cmd->cmd.tx.timeout.pm_frame_timeout = cpu_to_le16(2);
2241 } else 2241 } else {
2242 cmd->cmd.tx.timeout.pm_frame_timeout = 0; 2242 cmd->cmd.tx.timeout.pm_frame_timeout = 0;
2243 }
2243 2244
2244 cmd->cmd.tx.driver_txop = 0; 2245 cmd->cmd.tx.driver_txop = 0;
2245 cmd->cmd.tx.tx_flags = tx_flags; 2246 cmd->cmd.tx.tx_flags = tx_flags;
@@ -5712,6 +5713,8 @@ static void iwl4965_alive_start(struct iwl_priv *priv)
5712 IWL_DEBUG_INFO("ALIVE processing complete.\n"); 5713 IWL_DEBUG_INFO("ALIVE processing complete.\n");
5713 wake_up_interruptible(&priv->wait_command_queue); 5714 wake_up_interruptible(&priv->wait_command_queue);
5714 5715
5716 iwl_leds_register(priv);
5717
5715 if (priv->error_recovering) 5718 if (priv->error_recovering)
5716 iwl4965_error_recovery(priv); 5719 iwl4965_error_recovery(priv);
5717 5720
@@ -5736,6 +5739,8 @@ static void __iwl4965_down(struct iwl_priv *priv)
5736 if (!exit_pending) 5739 if (!exit_pending)
5737 set_bit(STATUS_EXIT_PENDING, &priv->status); 5740 set_bit(STATUS_EXIT_PENDING, &priv->status);
5738 5741
5742 iwl_leds_unregister(priv);
5743
5739 iwlcore_clear_stations_table(priv); 5744 iwlcore_clear_stations_table(priv);
5740 5745
5741 /* Unblock any waiting calls */ 5746 /* Unblock any waiting calls */