--- ./drivers/net/wireless/iwlwifi/Kconfig.orig 2007-12-04 07:57:24.000000000 +0100 +++ ./drivers/net/wireless/iwlwifi/Kconfig 2007-12-04 13:04:52.000000000 +0100 @@ -126,3 +126,9 @@ inserted in and remvoed from the running kernel whenever you want), say M here and read . The module will be called iwl3945.ko. +config IWLWIFI_LEDS + bool "IWLWIFI leds" + depends on IWLWIFI && MAC80211_LEDS + default y + ---help--- + This options enables the wireless led. --- ./drivers/net/wireless/iwlwifi/iwl-priv.h.orig 2007-12-04 07:57:24.000000000 +0100 +++ ./drivers/net/wireless/iwlwifi/iwl-priv.h 2007-12-04 13:04:52.000000000 +0100 @@ -127,11 +127,14 @@ struct iwl_init_alive_resp card_alive_init; struct iwl_alive_resp card_alive; -#ifdef LED - /* LED related variables */ - struct iwl_activity_blink activity; - unsigned long led_packets; - int led_state; + +#ifdef CONFIG_IWLWIFI_LEDS + u8 led_state; + unsigned int rxtxpackets; + atomic_t ledtimer; + struct iwl_led tx_led; + struct iwl_led rx_led; + struct iwl_led assoc_led; #endif u16 active_rate; @@ -274,6 +277,7 @@ struct delayed_work gather_stats; struct delayed_work scan_check; struct delayed_work post_associate; + struct delayed_work update_led; #define IWL_DEFAULT_TX_POWER 0x0F s8 user_txpower_limit; --- ./drivers/net/wireless/iwlwifi/iwlwifi.h.orig 2007-12-04 07:57:24.000000000 +0100 +++ ./drivers/net/wireless/iwlwifi/iwlwifi.h 2007-12-04 13:04:52.000000000 +0100 @@ -50,6 +50,9 @@ #include "iwl-prph.h" +#ifdef CONFIG_IWLWIFI_LEDS +#include "iwl-leds.h" +#endif /* * Driver implementation data structures, constants, inline * functions --- ./drivers/net/wireless/iwlwifi/iwl-leds.h.orig 2007-12-04 13:04:52.000000000 +0100 +++ ./drivers/net/wireless/iwlwifi/iwl-leds.h 2007-12-04 13:04:52.000000000 +0100 @@ -0,0 +1,20 @@ +#ifndef __iwl_leds_h__ +#define __iwl_leds_h__ + + +#include + + +#define IWL_LED_ACTIVITY (0<<1) +#define IWL_LED_LINK (1<<1) +#define IWL_LED_INTERVAL __constant_cpu_to_le32(1000) +#define IWL_LED_ACTIVITY_PERIOD msecs_to_jiffies(500) +#define IWL_LED_MAX_NAME_LEN 31 + +struct iwl_led { + char name[IWL_LED_MAX_NAME_LEN + 1]; + struct led_classdev cdev; +}; + + +#endif --- ./drivers/net/wireless/iwlwifi/iwl3945-base.c.orig 2007-12-04 07:57:24.000000000 +0100 +++ ./drivers/net/wireless/iwlwifi/iwl3945-base.c 2007-12-04 13:06:17.000000000 +0100 @@ -6086,6 +6086,173 @@ queue_work(priv->workqueue, &priv->restart); } +#ifdef CONFIG_IWLWIFI_LEDS +static int iwl_led_cmd_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) +{ + return 1; +} + +static void iwl_bg_led_update(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, update_led.work); + struct iwl_led_cmd led_cmd = { + .id = IWL_LED_ACTIVITY, + .interval = IWL_LED_INTERVAL, + }; + struct iwl_host_cmd cmd = { + .id = REPLY_LEDS_CMD, + .len = sizeof(struct iwl_led_cmd), + .data = &led_cmd, + .meta.flags = CMD_ASYNC, + .meta.u.callback = iwl_led_cmd_callback, + }; + u8 on; + unsigned long flags; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status) || + !test_bit(STATUS_READY, &priv->status)) + return; + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->rxtxpackets) { + on = 25 + 230 / (1 + (priv->rxtxpackets >> 2)); + priv->rxtxpackets = 0; + queue_delayed_work(priv->workqueue, &priv->update_led, + IWL_LED_ACTIVITY_PERIOD); + + if (on == priv->led_state) + goto exit_unlock; + + led_cmd.on = led_cmd.off = on; + priv->led_state = on; + + } + else { + atomic_set(&priv->ledtimer, 0); + led_cmd.on = led_cmd.off = 0; + priv->led_state = 0; + } + + spin_unlock_irqrestore(&priv->lock, flags); + iwl_send_cmd(priv, &cmd); + + return; + +exit_unlock: + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void iwl_led_set_rx(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, + rx_led.cdev); + unsigned long flags; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status) || + !test_bit(STATUS_READY, &priv->status)) + return; + + spin_lock_irqsave(&priv->lock, flags); + priv->rxtxpackets += 2; + if (!atomic_xchg(&priv->ledtimer, 1)) + queue_delayed_work(priv->workqueue, &priv->update_led, + IWL_LED_ACTIVITY_PERIOD); + spin_unlock_irqrestore(&priv->lock, flags); + +} + +static void iwl_led_set_tx(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, + tx_led.cdev); + unsigned long flags; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status) || + !test_bit(STATUS_READY, &priv->status)) + return; + + spin_lock_irqsave(&priv->lock, flags); + priv->rxtxpackets++; + if (!atomic_xchg(&priv->ledtimer, 1)) + queue_delayed_work(priv->workqueue, &priv->update_led, + IWL_LED_ACTIVITY_PERIOD); + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void iwl_led_set_assoc(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, + assoc_led.cdev); + struct iwl_led_cmd led_cmd = { + .id = IWL_LED_LINK, + .interval = IWL_LED_INTERVAL, + }; + struct iwl_host_cmd cmd = { + .id = REPLY_LEDS_CMD, + .len = sizeof(struct iwl_led_cmd), + .data = &led_cmd, + .meta.flags = CMD_ASYNC, + .meta.u.callback = iwl_led_cmd_callback + }; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status) || + !test_bit(STATUS_READY, &priv->status)) + return; + + switch(value) + { + case LED_OFF: + led_cmd.off = 0; + led_cmd.on = 0; + break; + case LED_HALF: + case LED_FULL: + led_cmd.off = 0; + led_cmd.on = 40; + } + iwl_send_cmd(priv, &cmd); +} + + +static int iwl_register_led(struct iwl_priv *priv, struct iwl_led *led, char *ledname, + char *triggername, void (*callback) + (struct led_classdev *, enum led_brightness)) +{ + snprintf(led->name, sizeof(led->name), ledname, + wiphy_name(priv->hw->wiphy)); + led->cdev.name = led->name; + led->cdev.brightness_set = callback; + led->cdev.default_trigger = triggername; + + return led_classdev_register(&priv->pci_dev->dev, &led->cdev); +} + +static void iwl_register_leds(struct iwl_priv *priv) +{ + iwl_register_led(priv, &priv->tx_led, "iwl-%s:tx", + ieee80211_get_tx_led_name(priv->hw), + iwl_led_set_tx); + iwl_register_led(priv, &priv->rx_led, "iwl-%s:rx", + ieee80211_get_rx_led_name(priv->hw), + iwl_led_set_rx); + iwl_register_led(priv, &priv->assoc_led, "iwl-%s:asoc", + ieee80211_get_assoc_led_name(priv->hw), + iwl_led_set_assoc); +} + +static void iwl_unregister_leds(struct iwl_priv *priv) +{ + led_classdev_unregister(&priv->tx_led.cdev); + led_classdev_unregister(&priv->rx_led.cdev); + led_classdev_unregister(&priv->assoc_led.cdev); +} +#endif /** * iwl_alive_start - called after REPLY_ALIVE notification received @@ -6161,6 +6328,9 @@ if (iwl_is_rfkill(priv)) return; +#ifdef CONFIG_IWLWIFI_LEDS + atomic_set(&priv->ledtimer, 0); +#endif if (!priv->mac80211_registered) { /* Unlock so any user space entry points can call back into * the driver without a deadlock... */ @@ -6179,6 +6349,9 @@ priv->mac80211_registered = 1; iwl_reset_channel_flag(priv); +#ifdef CONFIG_IWLWIFI_LEDS + iwl_register_leds(priv); +#endif } else ieee80211_start_queues(priv->hw); @@ -8266,7 +8439,9 @@ INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check); - +#ifdef CONFIG_IWLWIFI_LEDS + INIT_DELAYED_WORK(&priv->update_led, iwl_bg_led_update); +#endif iwl_hw_setup_deferred_work(priv); tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) @@ -8278,6 +8453,9 @@ iwl_hw_cancel_deferred_work(priv); cancel_delayed_work_sync(&priv->init_alive_start); +#ifdef CONFIG_IWLWIFI_LEDS + cancel_delayed_work(&priv->update_led); +#endif cancel_delayed_work(&priv->scan_check); cancel_delayed_work(&priv->alive_start); cancel_delayed_work(&priv->post_associate); @@ -8602,6 +8780,9 @@ iwl_clear_stations_table(priv); if (priv->mac80211_registered) { +#ifdef CONFIG_IWLWIFI_LEDS + iwl_unregister_leds(priv); +#endif ieee80211_unregister_hw(priv->hw); iwl_rate_control_unregister(priv->hw); } --- ./drivers/net/wireless/iwlwifi/iwl4965-base.c.orig 2007-12-04 07:57:24.000000000 +0100 +++ ./drivers/net/wireless/iwlwifi/iwl4965-base.c 2007-12-04 13:06:54.000000000 +0100 @@ -6462,6 +6462,174 @@ queue_work(priv->workqueue, &priv->restart); } +#ifdef CONFIG_IWLWIFI_LEDS +static int iwl_led_cmd_callback(struct iwl_priv *priv, + struct iwl_cmd *cmd, struct sk_buff *skb) +{ + return 1; +} + +static void iwl_bg_led_update(struct work_struct *data) +{ + struct iwl_priv *priv = + container_of(data, struct iwl_priv, update_led.work); + struct iwl_led_cmd led_cmd = { + .id = IWL_LED_ACTIVITY, + .interval = IWL_LED_INTERVAL, + }; + struct iwl_host_cmd cmd = { + .id = REPLY_LEDS_CMD, + .len = sizeof(struct iwl_led_cmd), + .data = &led_cmd, + .meta.flags = CMD_ASYNC, + .meta.u.callback = iwl_led_cmd_callback, + }; + u8 on; + unsigned long flags; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status) || + !test_bit(STATUS_READY, &priv->status)) + return; + + spin_lock_irqsave(&priv->lock, flags); + + if (priv->rxtxpackets) { + on = 25 + 230 / (1 + (priv->rxtxpackets >> 2)); + priv->rxtxpackets = 0; + queue_delayed_work(priv->workqueue, &priv->update_led, + IWL_LED_ACTIVITY_PERIOD); + + if (on == priv->led_state) + goto exit_unlock; + + led_cmd.on = led_cmd.off = on; + priv->led_state = on; + + } + else { + atomic_set(&priv->ledtimer, 0); + led_cmd.on = led_cmd.off = 0; + priv->led_state = 0; + } + + spin_unlock_irqrestore(&priv->lock, flags); + iwl_send_cmd(priv, &cmd); + + return; + +exit_unlock: + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void iwl_led_set_rx(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, + rx_led.cdev); + unsigned long flags; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status) || + !test_bit(STATUS_READY, &priv->status)) + return; + + spin_lock_irqsave(&priv->lock, flags); + priv->rxtxpackets += 2; + if (!atomic_xchg(&priv->ledtimer, 1)) + queue_delayed_work(priv->workqueue, &priv->update_led, + IWL_LED_ACTIVITY_PERIOD); + spin_unlock_irqrestore(&priv->lock, flags); + +} + +static void iwl_led_set_tx(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, + tx_led.cdev); + unsigned long flags; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status) || + !test_bit(STATUS_READY, &priv->status)) + return; + + spin_lock_irqsave(&priv->lock, flags); + priv->rxtxpackets++; + if (!atomic_xchg(&priv->ledtimer, 1)) + queue_delayed_work(priv->workqueue, &priv->update_led, + IWL_LED_ACTIVITY_PERIOD); + spin_unlock_irqrestore(&priv->lock, flags); +} + +static void iwl_led_set_assoc(struct led_classdev *led_cdev, + enum led_brightness value) +{ + struct iwl_priv *priv = container_of(led_cdev, struct iwl_priv, + assoc_led.cdev); + struct iwl_led_cmd led_cmd = { + .id = IWL_LED_LINK, + .interval = IWL_LED_INTERVAL, + }; + struct iwl_host_cmd cmd = { + .id = REPLY_LEDS_CMD, + .len = sizeof(struct iwl_led_cmd), + .data = &led_cmd, + .meta.flags = CMD_ASYNC, + .meta.u.callback = iwl_led_cmd_callback + }; + + if (test_bit(STATUS_EXIT_PENDING, &priv->status) || + !test_bit(STATUS_READY, &priv->status)) + return; + + switch(value) + { + case LED_OFF: + led_cmd.off = 0; + led_cmd.on = 0; + break; + case LED_HALF: + case LED_FULL: + led_cmd.off = 0; + led_cmd.on = 40; + } + iwl_send_cmd(priv, &cmd); +} + + +static int iwl_register_led(struct iwl_priv *priv, struct iwl_led *led, char *ledname, + char *triggername, void (*callback) + (struct led_classdev *, enum led_brightness)) +{ + snprintf(led->name, sizeof(led->name), ledname, + wiphy_name(priv->hw->wiphy)); + led->cdev.name = led->name; + led->cdev.brightness_set = callback; + led->cdev.default_trigger = triggername; + + return led_classdev_register(&priv->pci_dev->dev, &led->cdev); +} + +static void iwl_register_leds(struct iwl_priv *priv) +{ + iwl_register_led(priv, &priv->tx_led, "iwl-%s:tx", + ieee80211_get_tx_led_name(priv->hw), + iwl_led_set_tx); + iwl_register_led(priv, &priv->rx_led, "iwl-%s:rx", + ieee80211_get_rx_led_name(priv->hw), + iwl_led_set_rx); + iwl_register_led(priv, &priv->assoc_led, "iwl-%s:asoc", + ieee80211_get_assoc_led_name(priv->hw), + iwl_led_set_assoc); +} + +static void iwl_unregister_leds(struct iwl_priv *priv) +{ + led_classdev_unregister(&priv->tx_led.cdev); + led_classdev_unregister(&priv->rx_led.cdev); + led_classdev_unregister(&priv->assoc_led.cdev); +} +#endif + /** * iwl_alive_start - called after REPLY_ALIVE notification received @@ -6517,6 +6685,9 @@ if (iwl_is_rfkill(priv)) return; +#ifdef CONFIG_IWLWIFI_LEDS + atomic_set(&priv->ledtimer, 0); +#endif if (!priv->mac80211_registered) { /* Unlock so any user space entry points can call back into * the driver without a deadlock... */ @@ -6535,6 +6706,9 @@ priv->mac80211_registered = 1; iwl_reset_channel_flag(priv); +#ifdef CONFIG_IWLWIFI_LEDS + iwl_register_leds(priv); +#endif } else ieee80211_start_queues(priv->hw); @@ -8859,7 +9033,9 @@ INIT_DELAYED_WORK(&priv->init_alive_start, iwl_bg_init_alive_start); INIT_DELAYED_WORK(&priv->alive_start, iwl_bg_alive_start); INIT_DELAYED_WORK(&priv->scan_check, iwl_bg_scan_check); - +#ifdef CONFIG_IWLWIFI_LEDS + INIT_DELAYED_WORK(&priv->update_led, iwl_bg_led_update); +#endif iwl_hw_setup_deferred_work(priv); tasklet_init(&priv->irq_tasklet, (void (*)(unsigned long)) @@ -8871,6 +9047,9 @@ iwl_hw_cancel_deferred_work(priv); cancel_delayed_work_sync(&priv->init_alive_start); +#ifdef CONFIG_IWLWIFI_LEDS + cancel_delayed_work(&priv->update_led); +#endif cancel_delayed_work(&priv->scan_check); cancel_delayed_work(&priv->alive_start); cancel_delayed_work(&priv->post_associate); @@ -9196,6 +9375,9 @@ iwl_clear_stations_table(priv); if (priv->mac80211_registered) { +#ifdef CONFIG_IWLWIFI_LEDS + iwl_unregister_leds(priv); +#endif ieee80211_unregister_hw(priv->hw); iwl_rate_control_unregister(priv->hw); }