diff options
Diffstat (limited to 'drivers/net/wireless/iwlwifi/iwl-led.c')
-rw-r--r-- | drivers/net/wireless/iwlwifi/iwl-led.c | 257 |
1 files changed, 126 insertions, 131 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-led.c b/drivers/net/wireless/iwlwifi/iwl-led.c index 03fdf5b434a1..4eee1b163cd2 100644 --- a/drivers/net/wireless/iwlwifi/iwl-led.c +++ b/drivers/net/wireless/iwlwifi/iwl-led.c @@ -27,7 +27,6 @@ #include <linux/kernel.h> #include <linux/module.h> -#include <linux/version.h> #include <linux/init.h> #include <linux/pci.h> #include <linux/dma-mapping.h> @@ -39,19 +38,26 @@ #include <linux/etherdevice.h> #include <asm/unaligned.h> -#include "iwl-4965.h" +#include "iwl-dev.h" #include "iwl-core.h" #include "iwl-io.h" #include "iwl-helpers.h" -#define IWL_1MB_RATE (128 * 1024) -#define IWL_LED_THRESHOLD (16) -#define IWL_MAX_BLINK_TBL (10) +#ifdef CONFIG_IWLWIFI_DEBUG +static const char *led_type_str[] = { + __stringify(IWL_LED_TRG_TX), + __stringify(IWL_LED_TRG_RX), + __stringify(IWL_LED_TRG_ASSOC), + __stringify(IWL_LED_TRG_RADIO), + NULL +}; +#endif /* CONFIG_IWLWIFI_DEBUG */ + static const struct { u16 tpt; u8 on_time; - u8 of_time; + u8 off_time; } blink_tbl[] = { {300, 25, 25}, @@ -63,26 +69,31 @@ static const struct { {15, 95, 95 }, {10, 110, 110}, {5, 130, 130}, - {0, 167, 167} + {0, 167, 167}, +/* SOLID_ON */ + {-1, IWL_LED_SOLID, 0} }; -static int iwl_led_cmd_callback(struct iwl_priv *priv, - struct iwl_cmd *cmd, struct sk_buff *skb) +#define IWL_1MB_RATE (128 * 1024) +#define IWL_LED_THRESHOLD (16) +#define IWL_MAX_BLINK_TBL (ARRAY_SIZE(blink_tbl) - 1) /* exclude SOLID_ON */ +#define IWL_SOLID_BLINK_IDX (ARRAY_SIZE(blink_tbl) - 1) + +/* [0-256] -> [0..8] FIXME: we need [0..10] */ +static inline int iwl_brightness_to_idx(enum led_brightness brightness) { - return 1; + return fls(0x000000FF & (u32)brightness); } - /* Send led command */ -static int iwl_send_led_cmd(struct iwl_priv *priv, - struct iwl4965_led_cmd *led_cmd) +static int iwl_send_led_cmd(struct iwl_priv *priv, struct iwl_led_cmd *led_cmd) { struct iwl_host_cmd cmd = { .id = REPLY_LEDS_CMD, - .len = sizeof(struct iwl4965_led_cmd), + .len = sizeof(struct iwl_led_cmd), .data = led_cmd, .meta.flags = CMD_ASYNC, - .meta.u.callback = iwl_led_cmd_callback + .meta.u.callback = NULL, }; u32 reg; @@ -93,33 +104,20 @@ static int iwl_send_led_cmd(struct iwl_priv *priv, return iwl_send_cmd(priv, &cmd); } - -/* Set led on command */ -static int iwl4965_led_on(struct iwl_priv *priv, int led_id) -{ - struct iwl4965_led_cmd led_cmd = { - .id = led_id, - .on = IWL_LED_SOLID, - .off = 0, - .interval = IWL_DEF_LED_INTRVL - }; - return iwl_send_led_cmd(priv, &led_cmd); -} - -/* Set led on command */ +/* Set led pattern command */ static int iwl4965_led_pattern(struct iwl_priv *priv, int led_id, - enum led_brightness brightness) + unsigned int idx) { - struct iwl4965_led_cmd led_cmd = { + struct iwl_led_cmd led_cmd = { .id = led_id, - .on = brightness, - .off = brightness, .interval = IWL_DEF_LED_INTRVL }; - if (brightness == LED_FULL) { - led_cmd.on = IWL_LED_SOLID; - led_cmd.off = 0; - } + + BUG_ON(idx > IWL_MAX_BLINK_TBL); + + led_cmd.on = blink_tbl[idx].on_time; + led_cmd.off = blink_tbl[idx].off_time; + return iwl_send_led_cmd(priv, &led_cmd); } @@ -132,10 +130,22 @@ static int iwl4965_led_on_reg(struct iwl_priv *priv, int led_id) } #if 0 +/* Set led on command */ +static int iwl4965_led_on(struct iwl_priv *priv, int led_id) +{ + struct iwl_led_cmd led_cmd = { + .id = led_id, + .on = IWL_LED_SOLID, + .off = 0, + .interval = IWL_DEF_LED_INTRVL + }; + return iwl_send_led_cmd(priv, &led_cmd); +} + /* Set led off command */ int iwl4965_led_off(struct iwl_priv *priv, int led_id) { - struct iwl4965_led_cmd led_cmd = { + struct iwl_led_cmd led_cmd = { .id = led_id, .on = 0, .off = 0, @@ -150,30 +160,35 @@ int iwl4965_led_off(struct iwl_priv *priv, int led_id) /* Set led register off */ static int iwl4965_led_off_reg(struct iwl_priv *priv, int led_id) { - IWL_DEBUG_LED("radio off\n"); + IWL_DEBUG_LED("LED Reg off\n"); iwl_write32(priv, CSR_LED_REG, CSR_LED_REG_TRUN_OFF); return 0; } -/* Set led blink command */ -static int iwl4965_led_not_solid(struct iwl_priv *priv, int led_id, - u8 brightness) +/* + * Set led register in case of disassociation according to rfkill state + */ +static int iwl_led_associate(struct iwl_priv *priv, int led_id) { - struct iwl4965_led_cmd led_cmd = { - .id = led_id, - .on = brightness, - .off = brightness, - .interval = IWL_DEF_LED_INTRVL - }; - - return iwl_send_led_cmd(priv, &led_cmd); + IWL_DEBUG_LED("Associated\n"); + priv->allow_blinking = 1; + return iwl4965_led_on_reg(priv, led_id); } +static int iwl_led_disassociate(struct iwl_priv *priv, int led_id) +{ + priv->allow_blinking = 0; + if (iwl_is_rfkill(priv)) + iwl4965_led_off_reg(priv, led_id); + else + iwl4965_led_on_reg(priv, led_id); + return 0; +} /* * brightness call back function for Tx/Rx LED */ -static int iwl4965_led_associated(struct iwl_priv *priv, int led_id) +static int iwl_led_associated(struct iwl_priv *priv, int led_id) { if (test_bit(STATUS_EXIT_PENDING, &priv->status) || !test_bit(STATUS_READY, &priv->status)) @@ -189,34 +204,32 @@ static int iwl4965_led_associated(struct iwl_priv *priv, int led_id) /* * brightness call back for association and radio */ -static void iwl4965_led_brightness_set(struct led_classdev *led_cdev, +static void iwl_led_brightness_set(struct led_classdev *led_cdev, enum led_brightness brightness) { - struct iwl4965_led *led = container_of(led_cdev, - struct iwl4965_led, led_dev); + struct iwl_led *led = container_of(led_cdev, struct iwl_led, led_dev); struct iwl_priv *priv = led->priv; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) return; + + IWL_DEBUG_LED("Led type = %s brightness = %d\n", + led_type_str[led->type], brightness); switch (brightness) { case LED_FULL: - if (led->type == IWL_LED_TRG_ASSOC) - priv->allow_blinking = 1; - if (led->led_on) led->led_on(priv, IWL_LED_LINK); break; case LED_OFF: - if (led->type == IWL_LED_TRG_ASSOC) - priv->allow_blinking = 0; - if (led->led_off) led->led_off(priv, IWL_LED_LINK); break; default: - if (led->led_pattern) - led->led_pattern(priv, IWL_LED_LINK, brightness); + if (led->led_pattern) { + int idx = iwl_brightness_to_idx(brightness); + led->led_pattern(priv, IWL_LED_LINK, idx); + } break; } } @@ -226,16 +239,15 @@ static void iwl4965_led_brightness_set(struct led_classdev *led_cdev, /* * Register led class with the system */ -static int iwl_leds_register_led(struct iwl_priv *priv, - struct iwl4965_led *led, +static int iwl_leds_register_led(struct iwl_priv *priv, struct iwl_led *led, enum led_type type, u8 set_led, - const char *name, char *trigger) + char *trigger) { struct device *device = wiphy_dev(priv->hw->wiphy); int ret; - led->led_dev.name = name; - led->led_dev.brightness_set = iwl4965_led_brightness_set; + led->led_dev.name = led->name; + led->led_dev.brightness_set = iwl_led_brightness_set; led->led_dev.default_trigger = trigger; led->priv = priv; @@ -259,38 +271,30 @@ static int iwl_leds_register_led(struct iwl_priv *priv, /* * calculate blink rate according to last 2 sec Tx/Rx activities */ -static inline u8 get_blink_rate(struct iwl_priv *priv) +static int iwl_get_blink_rate(struct iwl_priv *priv) { int i; - u8 blink_rate; - u64 current_tpt = priv->tx_stats[2].bytes + priv->rx_stats[2].bytes; + u64 current_tpt = priv->tx_stats[2].bytes; + /* FIXME: + priv->rx_stats[2].bytes; */ s64 tpt = current_tpt - priv->led_tpt; if (tpt < 0) /* wrapparound */ tpt = -tpt; + IWL_DEBUG_LED("tpt %lld current_tpt %llu\n", + (long long)tpt, + (unsigned long long)current_tpt); priv->led_tpt = current_tpt; - if (tpt < IWL_LED_THRESHOLD) { + if (!priv->allow_blinking) i = IWL_MAX_BLINK_TBL; - } else { + else for (i = 0; i < IWL_MAX_BLINK_TBL; i++) if (tpt > (blink_tbl[i].tpt * IWL_1MB_RATE)) break; - } - /* if 0 frame is transfered */ - if ((i == IWL_MAX_BLINK_TBL) || !priv->allow_blinking) - blink_rate = IWL_LED_SOLID; - else - blink_rate = blink_tbl[i].on_time; - - return blink_rate; -} -static inline int is_rf_kill(struct iwl_priv *priv) -{ - return test_bit(STATUS_RF_KILL_HW, &priv->status) || - test_bit(STATUS_RF_KILL_SW, &priv->status); + IWL_DEBUG_LED("LED BLINK IDX=%d", i); + return i; } /* @@ -300,22 +304,23 @@ static inline int is_rf_kill(struct iwl_priv *priv) */ void iwl_leds_background(struct iwl_priv *priv) { - u8 blink_rate; + u8 blink_idx; if (test_bit(STATUS_EXIT_PENDING, &priv->status)) { priv->last_blink_time = 0; return; } - if (is_rf_kill(priv)) { + if (iwl_is_rfkill(priv)) { priv->last_blink_time = 0; return; } if (!priv->allow_blinking) { priv->last_blink_time = 0; - if (priv->last_blink_rate != IWL_LED_SOLID) { - priv->last_blink_rate = IWL_LED_SOLID; - iwl4965_led_on(priv, IWL_LED_LINK); + if (priv->last_blink_rate != IWL_SOLID_BLINK_IDX) { + priv->last_blink_rate = IWL_SOLID_BLINK_IDX; + iwl4965_led_pattern(priv, IWL_LED_LINK, + IWL_SOLID_BLINK_IDX); } return; } @@ -324,21 +329,14 @@ void iwl_leds_background(struct iwl_priv *priv) msecs_to_jiffies(1000))) return; - blink_rate = get_blink_rate(priv); + blink_idx = iwl_get_blink_rate(priv); /* call only if blink rate change */ - if (blink_rate != priv->last_blink_rate) { - if (blink_rate != IWL_LED_SOLID) { - priv->last_blink_time = jiffies + - msecs_to_jiffies(1000); - iwl4965_led_not_solid(priv, IWL_LED_LINK, blink_rate); - } else { - priv->last_blink_time = 0; - iwl4965_led_on(priv, IWL_LED_LINK); - } - } + if (blink_idx != priv->last_blink_rate) + iwl4965_led_pattern(priv, IWL_LED_LINK, blink_idx); - priv->last_blink_rate = blink_rate; + priv->last_blink_time = jiffies; + priv->last_blink_rate = blink_idx; } EXPORT_SYMBOL(iwl_leds_background); @@ -346,7 +344,6 @@ EXPORT_SYMBOL(iwl_leds_background); int iwl_leds_register(struct iwl_priv *priv) { char *trigger; - char name[32]; int ret; priv->last_blink_rate = 0; @@ -355,62 +352,60 @@ int iwl_leds_register(struct iwl_priv *priv) priv->allow_blinking = 0; trigger = ieee80211_get_radio_led_name(priv->hw); - snprintf(name, sizeof(name), "iwl-%s:radio", + snprintf(priv->led[IWL_LED_TRG_RADIO].name, + sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s:radio", wiphy_name(priv->hw->wiphy)); priv->led[IWL_LED_TRG_RADIO].led_on = iwl4965_led_on_reg; priv->led[IWL_LED_TRG_RADIO].led_off = iwl4965_led_off_reg; priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL; - ret = iwl_leds_register_led(priv, - &priv->led[IWL_LED_TRG_RADIO], - IWL_LED_TRG_RADIO, 1, - name, trigger); + ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RADIO], + IWL_LED_TRG_RADIO, 1, trigger); if (ret) goto exit_fail; trigger = ieee80211_get_assoc_led_name(priv->hw); - snprintf(name, sizeof(name), "iwl-%s:assoc", + snprintf(priv->led[IWL_LED_TRG_ASSOC].name, + sizeof(priv->led[IWL_LED_TRG_ASSOC].name), "iwl-%s:assoc", wiphy_name(priv->hw->wiphy)); - ret = iwl_leds_register_led(priv, - &priv->led[IWL_LED_TRG_ASSOC], - IWL_LED_TRG_ASSOC, 0, - name, trigger); + ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_ASSOC], + IWL_LED_TRG_ASSOC, 0, trigger); + /* for assoc always turn led on */ - priv->led[IWL_LED_TRG_ASSOC].led_on = iwl4965_led_on_reg; - priv->led[IWL_LED_TRG_ASSOC].led_off = iwl4965_led_on_reg; + priv->led[IWL_LED_TRG_ASSOC].led_on = iwl_led_associate; + priv->led[IWL_LED_TRG_ASSOC].led_off = iwl_led_disassociate; priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL; if (ret) goto exit_fail; trigger = ieee80211_get_rx_led_name(priv->hw); - snprintf(name, sizeof(name), "iwl-%s:RX", + snprintf(priv->led[IWL_LED_TRG_RX].name, + sizeof(priv->led[IWL_LED_TRG_RX].name), "iwl-%s:RX", wiphy_name(priv->hw->wiphy)); + ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_RX], + IWL_LED_TRG_RX, 0, trigger); - ret = iwl_leds_register_led(priv, - &priv->led[IWL_LED_TRG_RX], - IWL_LED_TRG_RX, 0, - name, trigger); - - priv->led[IWL_LED_TRG_RX].led_on = iwl4965_led_associated; - priv->led[IWL_LED_TRG_RX].led_off = iwl4965_led_associated; + priv->led[IWL_LED_TRG_RX].led_on = iwl_led_associated; + priv->led[IWL_LED_TRG_RX].led_off = iwl_led_associated; priv->led[IWL_LED_TRG_RX].led_pattern = iwl4965_led_pattern; if (ret) goto exit_fail; trigger = ieee80211_get_tx_led_name(priv->hw); - snprintf(name, sizeof(name), "iwl-%s:TX", + snprintf(priv->led[IWL_LED_TRG_TX].name, + sizeof(priv->led[IWL_LED_TRG_TX].name), "iwl-%s:TX", wiphy_name(priv->hw->wiphy)); - ret = iwl_leds_register_led(priv, - &priv->led[IWL_LED_TRG_TX], - IWL_LED_TRG_TX, 0, - name, trigger); - priv->led[IWL_LED_TRG_TX].led_on = iwl4965_led_associated; - priv->led[IWL_LED_TRG_TX].led_off = iwl4965_led_associated; + + ret = iwl_leds_register_led(priv, &priv->led[IWL_LED_TRG_TX], + IWL_LED_TRG_TX, 0, trigger); + + priv->led[IWL_LED_TRG_TX].led_on = iwl_led_associated; + priv->led[IWL_LED_TRG_TX].led_off = iwl_led_associated; priv->led[IWL_LED_TRG_TX].led_pattern = iwl4965_led_pattern; if (ret) @@ -425,7 +420,7 @@ exit_fail: EXPORT_SYMBOL(iwl_leds_register); /* unregister led class */ -static void iwl_leds_unregister_led(struct iwl4965_led *led, u8 set_led) +static void iwl_leds_unregister_led(struct iwl_led *led, u8 set_led) { if (!led->registered) return; |