Commit d0b45aef authored by Christian Lamparter's avatar Christian Lamparter Committed by John W. Linville

p54: initial SoftLED support

This patch adds SoftLED support for all p54 devices.
Signed-off-by: default avatarChristian Lamparter <chunkeey@web.de>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent efeada2c
...@@ -14,6 +14,10 @@ ...@@ -14,6 +14,10 @@
* published by the Free Software Foundation. * published by the Free Software Foundation.
*/ */
#ifdef CONFIG_MAC80211_LEDS
#include <linux/leds.h>
#endif /* CONFIG_MAC80211_LEDS */
enum p54_control_frame_types { enum p54_control_frame_types {
P54_CONTROL_TYPE_SETUP = 0, P54_CONTROL_TYPE_SETUP = 0,
P54_CONTROL_TYPE_SCAN, P54_CONTROL_TYPE_SCAN,
...@@ -112,6 +116,21 @@ enum fw_state { ...@@ -112,6 +116,21 @@ enum fw_state {
FW_STATE_RESETTING, FW_STATE_RESETTING,
}; };
#ifdef CONFIG_MAC80211_LEDS
#define P54_LED_MAX_NAME_LEN 31
struct p54_led_dev {
struct ieee80211_hw *hw_dev;
struct led_classdev led_dev;
char name[P54_LED_MAX_NAME_LEN + 1];
unsigned int index;
unsigned int registered;
};
#endif /* CONFIG_MAC80211_LEDS */
struct p54_common { struct p54_common {
struct ieee80211_hw *hw; struct ieee80211_hw *hw;
u32 rx_start; u32 rx_start;
...@@ -157,6 +176,12 @@ struct p54_common { ...@@ -157,6 +176,12 @@ struct p54_common {
struct completion eeprom_comp; struct completion eeprom_comp;
u8 privacy_caps; u8 privacy_caps;
u8 rx_keycache_size; u8 rx_keycache_size;
/* LED management */
#ifdef CONFIG_MAC80211_LEDS
struct p54_led_dev assoc_led;
struct p54_led_dev tx_led;
#endif /* CONFIG_MAC80211_LEDS */
u16 softled_state; /* bit field of glowing LEDs */
}; };
int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb); int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
......
...@@ -21,6 +21,9 @@ ...@@ -21,6 +21,9 @@
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <net/mac80211.h> #include <net/mac80211.h>
#ifdef CONFIG_MAC80211_LEDS
#include <linux/leds.h>
#endif /* CONFIG_MAC80211_LEDS */
#include "p54.h" #include "p54.h"
#include "p54common.h" #include "p54common.h"
...@@ -1871,7 +1874,7 @@ static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell) ...@@ -1871,7 +1874,7 @@ static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell)
return -EINVAL; return -EINVAL;
} }
static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act) static int p54_set_leds(struct ieee80211_hw *dev)
{ {
struct p54_common *priv = dev->priv; struct p54_common *priv = dev->priv;
struct sk_buff *skb; struct sk_buff *skb;
...@@ -1882,11 +1885,11 @@ static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act) ...@@ -1882,11 +1885,11 @@ static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act)
if (!skb) if (!skb)
return -ENOMEM; return -ENOMEM;
led = (struct p54_led *)skb_put(skb, sizeof(*led)); led = (struct p54_led *) skb_put(skb, sizeof(*led));
led->mode = cpu_to_le16(mode); led->flags = cpu_to_le16(0x0003);
led->led_permanent = cpu_to_le16(link); led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state);
led->led_temporary = cpu_to_le16(act); led->delay[0] = cpu_to_le16(1);
led->duration = cpu_to_le16(1000); led->delay[1] = cpu_to_le16(0);
priv->tx(dev, skb); priv->tx(dev, skb);
return 0; return 0;
} }
...@@ -2070,6 +2073,9 @@ static int p54_start(struct ieee80211_hw *dev) ...@@ -2070,6 +2073,9 @@ static int p54_start(struct ieee80211_hw *dev)
queue_delayed_work(dev->workqueue, &priv->work, 0); queue_delayed_work(dev->workqueue, &priv->work, 0);
priv->softled_state = 0;
err = p54_set_leds(dev);
out: out:
mutex_unlock(&priv->conf_mutex); mutex_unlock(&priv->conf_mutex);
return err; return err;
...@@ -2082,6 +2088,9 @@ static void p54_stop(struct ieee80211_hw *dev) ...@@ -2082,6 +2088,9 @@ static void p54_stop(struct ieee80211_hw *dev)
mutex_lock(&priv->conf_mutex); mutex_lock(&priv->conf_mutex);
priv->mode = NL80211_IFTYPE_UNSPECIFIED; priv->mode = NL80211_IFTYPE_UNSPECIFIED;
priv->softled_state = 0;
p54_set_leds(dev);
cancel_delayed_work_sync(&priv->work); cancel_delayed_work_sync(&priv->work);
if (priv->cached_beacon) if (priv->cached_beacon)
p54_tx_cancel(dev, priv->cached_beacon); p54_tx_cancel(dev, priv->cached_beacon);
...@@ -2119,7 +2128,6 @@ static int p54_add_interface(struct ieee80211_hw *dev, ...@@ -2119,7 +2128,6 @@ static int p54_add_interface(struct ieee80211_hw *dev,
memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN); memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
p54_setup_mac(dev); p54_setup_mac(dev);
p54_set_leds(dev, 1, 0, 0);
mutex_unlock(&priv->conf_mutex); mutex_unlock(&priv->conf_mutex);
return 0; return 0;
} }
...@@ -2199,8 +2207,6 @@ static int p54_config_interface(struct ieee80211_hw *dev, ...@@ -2199,8 +2207,6 @@ static int p54_config_interface(struct ieee80211_hw *dev,
goto out; goto out;
} }
ret = p54_set_leds(dev, 1, !is_multicast_ether_addr(priv->bssid), 0);
out: out:
mutex_unlock(&priv->conf_mutex); mutex_unlock(&priv->conf_mutex);
return ret; return ret;
...@@ -2419,6 +2425,96 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd, ...@@ -2419,6 +2425,96 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
return 0; return 0;
} }
#ifdef CONFIG_MAC80211_LEDS
static void p54_led_brightness_set(struct led_classdev *led_dev,
enum led_brightness brightness)
{
struct p54_led_dev *led = container_of(led_dev, struct p54_led_dev,
led_dev);
struct ieee80211_hw *dev = led->hw_dev;
struct p54_common *priv = dev->priv;
int err;
/* Don't toggle the LED, when the device is down. */
if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
return ;
if (brightness != LED_OFF)
priv->softled_state |= BIT(led->index);
else
priv->softled_state &= ~BIT(led->index);
err = p54_set_leds(dev);
if (err && net_ratelimit())
printk(KERN_ERR "%s: failed to update %s LED.\n",
wiphy_name(dev->wiphy), led_dev->name);
}
static int p54_register_led(struct ieee80211_hw *dev,
struct p54_led_dev *led,
unsigned int led_index,
char *name, char *trigger)
{
int err;
if (led->registered)
return -EEXIST;
snprintf(led->name, sizeof(led->name), "p54-%s::%s",
wiphy_name(dev->wiphy), name);
led->hw_dev = dev;
led->index = led_index;
led->led_dev.name = led->name;
led->led_dev.default_trigger = trigger;
led->led_dev.brightness_set = p54_led_brightness_set;
err = led_classdev_register(wiphy_dev(dev->wiphy), &led->led_dev);
if (err)
printk(KERN_ERR "%s: Failed to register %s LED.\n",
wiphy_name(dev->wiphy), name);
else
led->registered = 1;
return err;
}
static int p54_init_leds(struct ieee80211_hw *dev)
{
struct p54_common *priv = dev->priv;
int err;
/*
* TODO:
* Figure out if the EEPROM contains some hints about the number
* of available/programmable LEDs of the device.
* But for now, we can assume that we have two programmable LEDs.
*/
err = p54_register_led(dev, &priv->assoc_led, 0, "assoc",
ieee80211_get_assoc_led_name(dev));
if (err)
return err;
err = p54_register_led(dev, &priv->tx_led, 1, "tx",
ieee80211_get_tx_led_name(dev));
if (err)
return err;
err = p54_set_leds(dev);
return err;
}
static void p54_unregister_leds(struct ieee80211_hw *dev)
{
struct p54_common *priv = dev->priv;
if (priv->tx_led.registered)
led_classdev_unregister(&priv->tx_led.led_dev);
if (priv->assoc_led.registered)
led_classdev_unregister(&priv->assoc_led.led_dev);
}
#endif /* CONFIG_MAC80211_LEDS */
static const struct ieee80211_ops p54_ops = { static const struct ieee80211_ops p54_ops = {
.tx = p54_tx, .tx = p54_tx,
.start = p54_start, .start = p54_start,
...@@ -2499,6 +2595,12 @@ int p54_register_common(struct ieee80211_hw *dev, struct device *pdev) ...@@ -2499,6 +2595,12 @@ int p54_register_common(struct ieee80211_hw *dev, struct device *pdev)
return err; return err;
} }
#ifdef CONFIG_MAC80211_LEDS
err = p54_init_leds(dev);
if (err)
return err;
#endif /* CONFIG_MAC80211_LEDS */
dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy)); dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy));
return 0; return 0;
} }
...@@ -2510,6 +2612,10 @@ void p54_free_common(struct ieee80211_hw *dev) ...@@ -2510,6 +2612,10 @@ void p54_free_common(struct ieee80211_hw *dev)
kfree(priv->iq_autocal); kfree(priv->iq_autocal);
kfree(priv->output_limit); kfree(priv->output_limit);
kfree(priv->curve_data); kfree(priv->curve_data);
#ifdef CONFIG_MAC80211_LEDS
p54_unregister_leds(dev);
#endif /* CONFIG_MAC80211_LEDS */
} }
EXPORT_SYMBOL_GPL(p54_free_common); EXPORT_SYMBOL_GPL(p54_free_common);
......
...@@ -515,10 +515,9 @@ struct p54_scan_tail_rate { ...@@ -515,10 +515,9 @@ struct p54_scan_tail_rate {
} __attribute__ ((packed)); } __attribute__ ((packed));
struct p54_led { struct p54_led {
__le16 mode; __le16 flags;
__le16 led_temporary; __le16 mask[2];
__le16 led_permanent; __le16 delay[2];
__le16 duration;
} __attribute__ ((packed)); } __attribute__ ((packed));
struct p54_edcf { struct p54_edcf {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment