Commit a9450b70 authored by Ivo van Doorn's avatar Ivo van Doorn Committed by John W. Linville
Browse files

rt2x00: Make use of MAC80211_LED_TRIGGERS



Make use of the led triggers provided by mac80211 to control
the led status. This can be enabled through a per-driver
configuration option which will automatically enable the
generic handler in rt2x00lib.

This has been enabled for rt2500usb and rt73usb for the moment
since the led class will call set_brightness in irq context which
will not work correctly with the usb drivers who need to sleep.
Signed-off-by: default avatarIvo van Doorn <IvDoorn@gmail.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent f2a3c7f5
......@@ -38,6 +38,13 @@ config RT2X00_LIB_RFKILL
select RFKILL
select INPUT_POLLDEV
config RT2X00_LIB_LEDS
boolean
depends on RT2X00_LIB
select LEDS_CLASS
select LEDS_TRIGGERS
select MAC80211_LEDS
config RT2400PCI
tristate "Ralink rt2400 pci/pcmcia support"
depends on RT2X00 && PCI
......@@ -57,6 +64,13 @@ config RT2400PCI_RFKILL
hardware button to control the radio state.
This feature depends on the RF switch subsystem rfkill.
config RT2400PCI_LEDS
bool "RT2400 leds support"
depends on RT2400PCI
select RT2X00_LIB_LEDS
---help---
This adds support for led triggers provided my mac80211.
config RT2500PCI
tristate "Ralink rt2500 pci/pcmcia support"
depends on RT2X00 && PCI
......@@ -76,6 +90,13 @@ config RT2500PCI_RFKILL
hardware button to control the radio state.
This feature depends on the RF switch subsystem rfkill.
config RT2500PCI_LEDS
bool "RT2500 leds support"
depends on RT2500PCI
select RT2X00_LIB_LEDS
---help---
This adds support for led triggers provided my mac80211.
config RT61PCI
tristate "Ralink rt61 pci/pcmcia support"
depends on RT2X00 && PCI
......@@ -96,6 +117,13 @@ config RT61PCI_RFKILL
hardware button to control the radio state.
This feature depends on the RF switch subsystem rfkill.
config RT61PCI_LEDS
bool "RT61 leds support"
depends on RT61PCI
select RT2X00_LIB_LEDS
---help---
This adds support for led triggers provided my mac80211.
config RT2500USB
tristate "Ralink rt2500 usb support"
depends on RT2X00 && USB
......
......@@ -12,6 +12,10 @@ ifeq ($(CONFIG_RT2X00_LIB_FIRMWARE),y)
rt2x00lib-objs += rt2x00firmware.o
endif
ifeq ($(CONFIG_RT2X00_LIB_LEDS),y)
rt2x00lib-objs += rt2x00leds.o
endif
obj-$(CONFIG_RT2X00_LIB) += rt2x00lib.o
obj-$(CONFIG_RT2X00_LIB_PCI) += rt2x00pci.o
obj-$(CONFIG_RT2X00_LIB_USB) += rt2x00usb.o
......
......@@ -243,6 +243,30 @@ static int rt2400pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
#define rt2400pci_rfkill_poll NULL
#endif /* CONFIG_RT2400PCI_RFKILL */
#ifdef CONFIG_RT2400PCI_LEDS
static void rt2400pci_led_brightness(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct rt2x00_led *led =
container_of(led_cdev, struct rt2x00_led, led_dev);
unsigned int enabled = brightness != LED_OFF;
unsigned int activity =
led->rt2x00dev->led_flags & LED_SUPPORT_ACTIVITY;
u32 reg;
rt2x00pci_register_read(led->rt2x00dev, LEDCSR, &reg);
if (led->type == LED_TYPE_RADIO || led->type == LED_TYPE_ASSOC) {
rt2x00_set_field32(&reg, LEDCSR_LINK, enabled);
rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, enabled && activity);
}
rt2x00pci_register_write(led->rt2x00dev, LEDCSR, reg);
}
#else
#define rt2400pci_led_brightness NULL
#endif /* CONFIG_RT2400PCI_LEDS */
/*
* Configuration handlers.
*/
......@@ -510,34 +534,6 @@ static void rt2400pci_config_cw(struct rt2x00_dev *rt2x00dev,
rt2x00pci_register_write(rt2x00dev, CSR11, reg);
}
/*
* LED functions.
*/
static void rt2400pci_enable_led(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
rt2x00pci_register_read(rt2x00dev, LEDCSR, &reg);
rt2x00_set_field32(&reg, LEDCSR_ON_PERIOD, 70);
rt2x00_set_field32(&reg, LEDCSR_OFF_PERIOD, 30);
rt2x00_set_field32(&reg, LEDCSR_LINK,
(rt2x00dev->led_mode != LED_MODE_ASUS));
rt2x00_set_field32(&reg, LEDCSR_ACTIVITY,
(rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY));
rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
}
static void rt2400pci_disable_led(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
rt2x00pci_register_read(rt2x00dev, LEDCSR, &reg);
rt2x00_set_field32(&reg, LEDCSR_LINK, 0);
rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 0);
rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
}
/*
* Link tuning
*/
......@@ -703,6 +699,11 @@ static int rt2400pci_init_registers(struct rt2x00_dev *rt2x00dev)
(rt2x00dev->rx->data_size / 128));
rt2x00pci_register_write(rt2x00dev, CSR9, reg);
rt2x00pci_register_read(rt2x00dev, LEDCSR, &reg);
rt2x00_set_field32(&reg, LEDCSR_ON_PERIOD, 70);
rt2x00_set_field32(&reg, LEDCSR_OFF_PERIOD, 30);
rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
rt2x00pci_register_write(rt2x00dev, CNT3, 0x3f080000);
rt2x00pci_register_read(rt2x00dev, ARCSR0, &reg);
......@@ -872,11 +873,6 @@ static int rt2400pci_enable_radio(struct rt2x00_dev *rt2x00dev)
*/
rt2400pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON);
/*
* Enable LED
*/
rt2400pci_enable_led(rt2x00dev);
return 0;
}
......@@ -884,11 +880,6 @@ static void rt2400pci_disable_radio(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
/*
* Disable LED
*/
rt2400pci_disable_led(rt2x00dev);
rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0);
/*
......@@ -1273,8 +1264,24 @@ static int rt2400pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Store led mode, for correct led behaviour.
*/
rt2x00dev->led_mode =
rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
#ifdef CONFIG_RT2400PCI_LEDS
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
switch (value) {
case LED_MODE_ASUS:
case LED_MODE_ALPHA:
case LED_MODE_DEFAULT:
rt2x00dev->led_flags = LED_SUPPORT_RADIO;
break;
case LED_MODE_TXRX_ACTIVITY:
rt2x00dev->led_flags =
LED_SUPPORT_RADIO | LED_SUPPORT_ACTIVITY;
break;
case LED_MODE_SIGNAL_STRENGTH:
rt2x00dev->led_flags = LED_SUPPORT_RADIO;
break;
}
#endif /* CONFIG_RT2400PCI_LEDS */
/*
* Detect if this device has an hardware controlled radio.
......@@ -1594,6 +1601,7 @@ static const struct rt2x00lib_ops rt2400pci_rt2x00_ops = {
.link_stats = rt2400pci_link_stats,
.reset_tuner = rt2400pci_reset_tuner,
.link_tuner = rt2400pci_link_tuner,
.led_brightness = rt2400pci_led_brightness,
.write_tx_desc = rt2400pci_write_tx_desc,
.write_tx_data = rt2x00pci_write_tx_data,
.kick_tx_queue = rt2400pci_kick_tx_queue,
......
......@@ -243,6 +243,30 @@ static int rt2500pci_rfkill_poll(struct rt2x00_dev *rt2x00dev)
#define rt2500pci_rfkill_poll NULL
#endif /* CONFIG_RT2500PCI_RFKILL */
#ifdef CONFIG_RT2500PCI_LEDS
static void rt2500pci_led_brightness(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct rt2x00_led *led =
container_of(led_cdev, struct rt2x00_led, led_dev);
unsigned int enabled = brightness != LED_OFF;
unsigned int activity =
led->rt2x00dev->led_flags & LED_SUPPORT_ACTIVITY;
u32 reg;
rt2x00pci_register_read(led->rt2x00dev, LEDCSR, &reg);
if (led->type == LED_TYPE_RADIO || led->type == LED_TYPE_ASSOC) {
rt2x00_set_field32(&reg, LEDCSR_LINK, enabled);
rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, enabled && activity);
}
rt2x00pci_register_write(led->rt2x00dev, LEDCSR, reg);
}
#else
#define rt2500pci_led_brightness NULL
#endif /* CONFIG_RT2500PCI_LEDS */
/*
* Configuration handlers.
*/
......@@ -548,34 +572,6 @@ static void rt2500pci_config(struct rt2x00_dev *rt2x00dev,
rt2500pci_config_duration(rt2x00dev, libconf);
}
/*
* LED functions.
*/
static void rt2500pci_enable_led(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
rt2x00pci_register_read(rt2x00dev, LEDCSR, &reg);
rt2x00_set_field32(&reg, LEDCSR_ON_PERIOD, 70);
rt2x00_set_field32(&reg, LEDCSR_OFF_PERIOD, 30);
rt2x00_set_field32(&reg, LEDCSR_LINK,
(rt2x00dev->led_mode != LED_MODE_ASUS));
rt2x00_set_field32(&reg, LEDCSR_ACTIVITY,
(rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY));
rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
}
static void rt2500pci_disable_led(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
rt2x00pci_register_read(rt2x00dev, LEDCSR, &reg);
rt2x00_set_field32(&reg, LEDCSR_LINK, 0);
rt2x00_set_field32(&reg, LEDCSR_ACTIVITY, 0);
rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
}
/*
* Link tuning
*/
......@@ -795,6 +791,11 @@ static int rt2500pci_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field32(&reg, CSR11_CW_SELECT, 0);
rt2x00pci_register_write(rt2x00dev, CSR11, reg);
rt2x00pci_register_read(rt2x00dev, LEDCSR, &reg);
rt2x00_set_field32(&reg, LEDCSR_ON_PERIOD, 70);
rt2x00_set_field32(&reg, LEDCSR_OFF_PERIOD, 30);
rt2x00pci_register_write(rt2x00dev, LEDCSR, reg);
rt2x00pci_register_write(rt2x00dev, CNT3, 0);
rt2x00pci_register_read(rt2x00dev, TXCSR8, &reg);
......@@ -1026,11 +1027,6 @@ static int rt2500pci_enable_radio(struct rt2x00_dev *rt2x00dev)
*/
rt2500pci_toggle_irq(rt2x00dev, STATE_RADIO_IRQ_ON);
/*
* Enable LED
*/
rt2500pci_enable_led(rt2x00dev);
return 0;
}
......@@ -1038,11 +1034,6 @@ static void rt2500pci_disable_radio(struct rt2x00_dev *rt2x00dev)
{
u32 reg;
/*
* Disable LED
*/
rt2500pci_disable_led(rt2x00dev);
rt2x00pci_register_write(rt2x00dev, PWRCSR0, 0);
/*
......@@ -1445,8 +1436,24 @@ static int rt2500pci_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Store led mode, for correct led behaviour.
*/
rt2x00dev->led_mode =
rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
#ifdef CONFIG_RT2500PCI_LEDS
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
switch (value) {
case LED_MODE_ASUS:
case LED_MODE_ALPHA:
case LED_MODE_DEFAULT:
rt2x00dev->led_flags = LED_SUPPORT_RADIO;
break;
case LED_MODE_TXRX_ACTIVITY:
rt2x00dev->led_flags =
LED_SUPPORT_RADIO | LED_SUPPORT_ACTIVITY;
break;
case LED_MODE_SIGNAL_STRENGTH:
rt2x00dev->led_flags = LED_SUPPORT_RADIO;
break;
}
#endif /* CONFIG_RT2500PCI_LEDS */
/*
* Detect if this device has an hardware controlled radio.
......@@ -1906,6 +1913,7 @@ static const struct rt2x00lib_ops rt2500pci_rt2x00_ops = {
.link_stats = rt2500pci_link_stats,
.reset_tuner = rt2500pci_reset_tuner,
.link_tuner = rt2500pci_link_tuner,
.led_brightness = rt2500pci_led_brightness,
.write_tx_desc = rt2500pci_write_tx_desc,
.write_tx_data = rt2x00pci_write_tx_data,
.kick_tx_queue = rt2500pci_kick_tx_queue,
......
......@@ -282,6 +282,31 @@ static const struct rt2x00debug rt2500usb_rt2x00debug = {
};
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
#ifdef CONFIG_RT2500USB_LEDS
static void rt2500usb_led_brightness(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct rt2x00_led *led =
container_of(led_cdev, struct rt2x00_led, led_dev);
unsigned int enabled = brightness != LED_OFF;
unsigned int activity =
led->rt2x00dev->led_flags & LED_SUPPORT_ACTIVITY;
u16 reg;
rt2500usb_register_read(led->rt2x00dev, MAC_CSR20, &reg);
if (led->type == LED_TYPE_RADIO || led->type == LED_TYPE_ASSOC) {
rt2x00_set_field16(&reg, MAC_CSR20_LINK, enabled);
rt2x00_set_field16(&reg, MAC_CSR20_ACTIVITY,
enabled && activity);
}
rt2500usb_register_write(led->rt2x00dev, MAC_CSR20, reg);
}
#else
#define rt2500usb_led_brightness NULL
#endif /* CONFIG_RT2500USB_LEDS */
/*
* Configuration handlers.
*/
......@@ -525,36 +550,6 @@ static void rt2500usb_config(struct rt2x00_dev *rt2x00dev,
rt2500usb_config_duration(rt2x00dev, libconf);
}
/*
* LED functions.
*/
static void rt2500usb_enable_led(struct rt2x00_dev *rt2x00dev)
{
u16 reg;
rt2500usb_register_read(rt2x00dev, MAC_CSR21, &reg);
rt2x00_set_field16(&reg, MAC_CSR21_ON_PERIOD, 70);
rt2x00_set_field16(&reg, MAC_CSR21_OFF_PERIOD, 30);
rt2500usb_register_write(rt2x00dev, MAC_CSR21, reg);
rt2500usb_register_read(rt2x00dev, MAC_CSR20, &reg);
rt2x00_set_field16(&reg, MAC_CSR20_LINK,
(rt2x00dev->led_mode != LED_MODE_ASUS));
rt2x00_set_field16(&reg, MAC_CSR20_ACTIVITY,
(rt2x00dev->led_mode != LED_MODE_TXRX_ACTIVITY));
rt2500usb_register_write(rt2x00dev, MAC_CSR20, reg);
}
static void rt2500usb_disable_led(struct rt2x00_dev *rt2x00dev)
{
u16 reg;
rt2500usb_register_read(rt2x00dev, MAC_CSR20, &reg);
rt2x00_set_field16(&reg, MAC_CSR20_LINK, 0);
rt2x00_set_field16(&reg, MAC_CSR20_ACTIVITY, 0);
rt2500usb_register_write(rt2x00dev, MAC_CSR20, reg);
}
/*
* Link tuning
*/
......@@ -751,6 +746,11 @@ static int rt2500usb_init_registers(struct rt2x00_dev *rt2x00dev)
rt2x00_set_field16(&reg, MAC_CSR1_HOST_READY, 0);
rt2500usb_register_write(rt2x00dev, MAC_CSR1, reg);
rt2500usb_register_read(rt2x00dev, MAC_CSR21, &reg);
rt2x00_set_field16(&reg, MAC_CSR21_ON_PERIOD, 70);
rt2x00_set_field16(&reg, MAC_CSR21_OFF_PERIOD, 30);
rt2500usb_register_write(rt2x00dev, MAC_CSR21, reg);
rt2500usb_register_read(rt2x00dev, TXRX_CSR5, &reg);
rt2x00_set_field16(&reg, TXRX_CSR5_BBP_ID0, 13);
rt2x00_set_field16(&reg, TXRX_CSR5_BBP_ID0_VALID, 1);
......@@ -924,21 +924,11 @@ static int rt2500usb_enable_radio(struct rt2x00_dev *rt2x00dev)
return -EIO;
}
/*
* Enable LED
*/
rt2500usb_enable_led(rt2x00dev);
return 0;
}
static void rt2500usb_disable_radio(struct rt2x00_dev *rt2x00dev)
{
/*
* Disable LED
*/
rt2500usb_disable_led(rt2x00dev);
rt2500usb_register_write(rt2x00dev, MAC_CSR13, 0x2121);
rt2500usb_register_write(rt2x00dev, MAC_CSR14, 0x2121);
......@@ -1370,8 +1360,24 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
/*
* Store led mode, for correct led behaviour.
*/
rt2x00dev->led_mode =
rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
#ifdef CONFIG_RT2500USB_LEDS
value = rt2x00_get_field16(eeprom, EEPROM_ANTENNA_LED_MODE);
switch (value) {
case LED_MODE_ASUS:
case LED_MODE_ALPHA:
case LED_MODE_DEFAULT:
rt2x00dev->led_flags = LED_SUPPORT_RADIO;
break;
case LED_MODE_TXRX_ACTIVITY:
rt2x00dev->led_flags =
LED_SUPPORT_RADIO | LED_SUPPORT_ACTIVITY;
break;
case LED_MODE_SIGNAL_STRENGTH:
rt2x00dev->led_flags = LED_SUPPORT_RADIO;
break;
}
#endif /* CONFIG_RT2500USB_LEDS */
/*
* Check if the BBP tuning should be disabled.
......@@ -1817,6 +1823,7 @@ static const struct rt2x00lib_ops rt2500usb_rt2x00_ops = {
.link_stats = rt2500usb_link_stats,
.reset_tuner = rt2500usb_reset_tuner,
.link_tuner = rt2500usb_link_tuner,
.led_brightness = rt2500usb_led_brightness,
.write_tx_desc = rt2500usb_write_tx_desc,
.write_tx_data = rt2x00usb_write_tx_data,
.get_tx_data_len = rt2500usb_get_tx_data_len,
......
......@@ -30,12 +30,14 @@
#include <linux/skbuff.h>
#include <linux/workqueue.h>
#include <linux/firmware.h>
#include <linux/leds.h>
#include <linux/mutex.h>
#include <linux/etherdevice.h>
#include <net/mac80211.h>
#include "rt2x00debug.h"
#include "rt2x00leds.h"
#include "rt2x00reg.h"
#include "rt2x00queue.h"
......@@ -512,6 +514,8 @@ struct rt2x00lib_ops {
struct link_qual *qual);
void (*reset_tuner) (struct rt2x00_dev *rt2x00dev);
void (*link_tuner) (struct rt2x00_dev *rt2x00dev);
void (*led_brightness) (struct led_classdev *led_cdev,
enum led_brightness brightness);
/*
* TX control handlers
......@@ -664,6 +668,19 @@ struct rt2x00_dev {
struct rt2x00debug_intf *debugfs_intf;
#endif /* CONFIG_RT2X00_LIB_DEBUGFS */
/*
* LED structure for changing the LED status
* by mac8011 or the kernel.
*/
#ifdef CONFIG_RT2X00_LIB_LEDS
unsigned int led_flags;
struct rt2x00_trigger trigger_qual;
struct rt2x00_led led_radio;
struct rt2x00_led led_assoc;
struct rt2x00_led led_qual;
u16 led_mcu_reg;
#endif /* CONFIG_RT2X00_LIB_LEDS */
/*
* Device flags.
* In these flags the current status and some
......@@ -755,16 +772,6 @@ struct rt2x00_dev {
*/
u16 tx_power;
/*
* LED register (for rt61pci & rt73usb).
*/
u16 led_reg;
/*
* Led mode (LED_MODE_*)
*/
u8 led_mode;
/*
* Rssi <-> Dbm offset
*/
......
......@@ -378,6 +378,11 @@ static void rt2x00lib_link_tuner(struct work_struct *work)
*/
rt2x00lib_precalculate_link_signal(&rt2x00dev->link.qual);
/*
* Send a signal to the led to update the led signal strength.
*/
rt2x00leds_led_quality(rt2x00dev, rt2x00dev->link.qual.avg_rssi);
/*
* Evaluate antenna setup, make this the last step since this could
* possibly reset some statistics.
......@@ -1139,6 +1144,11 @@ int rt2x00lib_probe_dev(struct rt2x00_dev *rt2x00dev)
goto exit;
}
/*
* Register LED.
*/
rt2x00leds_register(rt2x00dev);
/*
* Allocatie rfkill.
*/
......@@ -1186,6 +1196,11 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
*/
rt2x00rfkill_free(rt2x00dev);
/*
* Free LED.
*/
rt2x00leds_unregister(rt2x00dev);
/*
* Free ieee80211_hw memory.
*/
......@@ -1227,6 +1242,7 @@ int rt2x00lib_suspend(struct rt2x00_dev *rt2x00dev, pm_message_t state)
*/
rt2x00lib_stop(rt2x00dev);
rt2x00lib_uninitialize(rt2x00dev);
rt2x00leds_suspend(rt2x00dev);
rt2x00debug_deregister(rt2x00dev);
exit:
......@@ -1270,9 +1286,10 @@ int rt2x00lib_resume(struct rt2x00_dev *rt2x00dev)
NOTICE(rt2x00dev, "Waking up.\n");
/*
* Open the debugfs entry.
* Open the debugfs entry and restore led handling.
*/
rt2x00debug_register(rt2x00dev);
rt2x00leds_resume(rt2x00dev);
/*
* Only continue if mac80211 had open interfaces.
......
......@@ -183,4 +183,37 @@ static inline void rt2x00rfkill_free(struct rt2x00_dev *rt2x00dev)
}
#endif /* CONFIG_RT2X00_LIB_RFKILL */
/*
* LED handlers
*/
#ifdef CONFIG_RT2X00_LIB_LEDS
void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, int rssi);
int rt2x00leds_register(struct rt2x00_dev *rt2x00dev);
void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev);
void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev);
void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev);
#else
static inline void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev,
int rssi)
{
}
static inline int rt2x00leds_register(struct rt2x00_dev *rt2x00dev)
{
return 0;
}
static inline void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev)
{
}