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

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
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -14,6 +14,10 @@
 * published by the Free Software Foundation.
 */

#ifdef CONFIG_MAC80211_LEDS
#include <linux/leds.h>
#endif /* CONFIG_MAC80211_LEDS */

enum p54_control_frame_types {
	P54_CONTROL_TYPE_SETUP = 0,
	P54_CONTROL_TYPE_SCAN,
@@ -112,6 +116,21 @@ enum fw_state {
	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 ieee80211_hw *hw;
	u32 rx_start;
@@ -157,6 +176,12 @@ struct p54_common {
	struct completion eeprom_comp;
	u8 privacy_caps;
	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);
+115 −9
Original line number Diff line number Diff line
@@ -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;
@@ -1883,10 +1886,10 @@ static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act)
		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->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);

+3 −4
Original line number Diff line number Diff line
@@ -515,10 +515,9 @@ struct p54_scan_tail_rate {
} __attribute__ ((packed));

struct p54_led {
	__le16 mode;
	__le16 led_temporary;
	__le16 led_permanent;
	__le16 duration;
	__le16 flags;
	__le16 mask[2];
	__le16 delay[2];
} __attribute__ ((packed));

struct p54_edcf {