|
@@ -21,6 +21,9 @@
|
|
|
#include <linux/etherdevice.h>
|
|
|
|
|
|
#include <net/mac80211.h>
|
|
|
+#ifdef CONFIG_MAC80211_LEDS
|
|
|
+#include <linux/leds.h>
|
|
|
+#endif /* CONFIG_MAC80211_LEDS */
|
|
|
|
|
|
#include "p54.h"
|
|
|
#include "p54common.h"
|
|
@@ -1871,7 +1874,7 @@ static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell)
|
|
|
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 sk_buff *skb;
|
|
@@ -1882,11 +1885,11 @@ static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act)
|
|
|
if (!skb)
|
|
|
return -ENOMEM;
|
|
|
|
|
|
- led = (struct p54_led *)skb_put(skb, sizeof(*led));
|
|
|
- led->mode = cpu_to_le16(mode);
|
|
|
- led->led_permanent = cpu_to_le16(link);
|
|
|
- led->led_temporary = cpu_to_le16(act);
|
|
|
- led->duration = cpu_to_le16(1000);
|
|
|
+ led = (struct p54_led *) skb_put(skb, sizeof(*led));
|
|
|
+ led->flags = cpu_to_le16(0x0003);
|
|
|
+ led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state);
|
|
|
+ led->delay[0] = cpu_to_le16(1);
|
|
|
+ led->delay[1] = cpu_to_le16(0);
|
|
|
priv->tx(dev, skb);
|
|
|
return 0;
|
|
|
}
|
|
@@ -2070,6 +2073,9 @@ static int p54_start(struct ieee80211_hw *dev)
|
|
|
|
|
|
queue_delayed_work(dev->workqueue, &priv->work, 0);
|
|
|
|
|
|
+ priv->softled_state = 0;
|
|
|
+ err = p54_set_leds(dev);
|
|
|
+
|
|
|
out:
|
|
|
mutex_unlock(&priv->conf_mutex);
|
|
|
return err;
|
|
@@ -2082,6 +2088,9 @@ static void p54_stop(struct ieee80211_hw *dev)
|
|
|
|
|
|
mutex_lock(&priv->conf_mutex);
|
|
|
priv->mode = NL80211_IFTYPE_UNSPECIFIED;
|
|
|
+ priv->softled_state = 0;
|
|
|
+ p54_set_leds(dev);
|
|
|
+
|
|
|
cancel_delayed_work_sync(&priv->work);
|
|
|
if (priv->cached_beacon)
|
|
|
p54_tx_cancel(dev, priv->cached_beacon);
|
|
@@ -2119,7 +2128,6 @@ static int p54_add_interface(struct ieee80211_hw *dev,
|
|
|
|
|
|
memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
|
|
|
p54_setup_mac(dev);
|
|
|
- p54_set_leds(dev, 1, 0, 0);
|
|
|
mutex_unlock(&priv->conf_mutex);
|
|
|
return 0;
|
|
|
}
|
|
@@ -2199,8 +2207,6 @@ static int p54_config_interface(struct ieee80211_hw *dev,
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
- ret = p54_set_leds(dev, 1, !is_multicast_ether_addr(priv->bssid), 0);
|
|
|
-
|
|
|
out:
|
|
|
mutex_unlock(&priv->conf_mutex);
|
|
|
return ret;
|
|
@@ -2419,6 +2425,96 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
|
|
|
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 = {
|
|
|
.tx = p54_tx,
|
|
|
.start = p54_start,
|
|
@@ -2499,6 +2595,12 @@ int p54_register_common(struct ieee80211_hw *dev, struct device *pdev)
|
|
|
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));
|
|
|
return 0;
|
|
|
}
|
|
@@ -2510,6 +2612,10 @@ void p54_free_common(struct ieee80211_hw *dev)
|
|
|
kfree(priv->iq_autocal);
|
|
|
kfree(priv->output_limit);
|
|
|
kfree(priv->curve_data);
|
|
|
+
|
|
|
+ #ifdef CONFIG_MAC80211_LEDS
|
|
|
+ p54_unregister_leds(dev);
|
|
|
+ #endif /* CONFIG_MAC80211_LEDS */
|
|
|
}
|
|
|
EXPORT_SYMBOL_GPL(p54_free_common);
|
|
|
|