Skip to content

Commit

Permalink
rt2x00: Enable LED class support for rt2500usb/rt73usb
Browse files Browse the repository at this point in the history
Add kerneldoc for vendor request functions in rt2x00usb.
Add asynchroneous vendor request function in rt2x00usb.

With the availability of the asynchroneuous vendor request
we can now enable LED class support for rt2500usb and rt73usb.
Since LED handling is not important, it doesn't really matter
if a register call fails (This solution is better then no
LED class support at all).

Signed-off-by: Ivo van Doorn <IvDoorn@gmail.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
  • Loading branch information
Ivo van Doorn authored and John W. Linville committed Feb 29, 2008
1 parent a9450b7 commit 3b640f2
Show file tree
Hide file tree
Showing 7 changed files with 463 additions and 53 deletions.
14 changes: 14 additions & 0 deletions drivers/net/wireless/rt2x00/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,13 @@ config RT2500USB

When compiled as a module, this driver will be called "rt2500usb.ko".

config RT2500USB_LEDS
bool "RT2500 leds support"
depends on RT2500USB
select RT2X00_LIB_LEDS
---help---
This adds support for led triggers provided my mac80211.

config RT73USB
tristate "Ralink rt73 usb support"
depends on RT2X00 && USB
Expand All @@ -143,6 +150,13 @@ config RT73USB

When compiled as a module, this driver will be called "rt73usb.ko".

config RT73USB_LEDS
bool "RT73 leds support"
depends on RT73USB
select RT2X00_LIB_LEDS
---help---
This adds support for led triggers provided my mac80211.

config RT2X00_LIB_DEBUGFS
bool "Ralink debugfs support"
depends on RT2X00_LIB && MAC80211_DEBUGFS
Expand Down
20 changes: 13 additions & 7 deletions drivers/net/wireless/rt2x00/rt2500usb.c
Original file line number Diff line number Diff line change
Expand Up @@ -291,17 +291,16 @@ static void rt2500usb_led_brightness(struct led_classdev *led_cdev,
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);
rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg,
MAC_CSR20_LINK, enabled);
rt2x00_set_field16(&led->rt2x00dev->led_mcu_reg,
MAC_CSR20_ACTIVITY, enabled && activity);
}

rt2500usb_register_write(led->rt2x00dev, MAC_CSR20, reg);
rt2x00usb_vendor_request_async(led->rt2x00dev, USB_SINGLE_WRITE,
MAC_CSR20, led->rt2x00dev->led_mcu_reg);
}
#else
#define rt2500usb_led_brightness NULL
Expand Down Expand Up @@ -1377,6 +1376,13 @@ static int rt2500usb_init_eeprom(struct rt2x00_dev *rt2x00dev)
rt2x00dev->led_flags = LED_SUPPORT_RADIO;
break;
}

/*
* Store the current led register value, we need it later
* in set_brightness but that is called in irq context which
* means we can't use rt2500usb_register_read() at that time.
*/
rt2500usb_register_read(rt2x00dev, MAC_CSR20, &rt2x00dev->led_mcu_reg);
#endif /* CONFIG_RT2500USB_LEDS */

/*
Expand Down
217 changes: 217 additions & 0 deletions drivers/net/wireless/rt2x00/rt2x00leds.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
/*
Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

/*
Module: rt2x00lib
Abstract: rt2x00 led specific routines.
*/

#include <linux/kernel.h>
#include <linux/module.h>

#include "rt2x00.h"
#include "rt2x00lib.h"

void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, int rssi)
{
if (!rt2x00dev->trigger_qual.registered)
return;

/*
* Led handling requires a positive value for the rssi,
* to do that correctly we need to add the correction.
*/
rssi += rt2x00dev->rssi_offset;

/*
* Get the rssi level, this is used to convert the rssi
* to a LED value inside the range LED_OFF - LED_FULL.
*/
if (rssi <= 30)
rssi = 0;
else if (rssi <= 39)
rssi = 1;
else if (rssi <= 49)
rssi = 2;
else if (rssi <= 53)
rssi = 3;
else if (rssi <= 63)
rssi = 4;
else
rssi = 5;

/*
* Note that we must _not_ send LED_OFF since the driver
* is going to calculate the value and might use it in a
* division.
*/
led_trigger_event(&rt2x00dev->trigger_qual.trigger,
((LED_FULL / 6) * rssi) + 1);
}

static int rt2x00leds_register_trigger(struct rt2x00_dev *rt2x00dev,
struct rt2x00_trigger *trigger,
const char *name)
{
int retval;

trigger->trigger.name = name;
retval = led_trigger_register(&trigger->trigger);
if (retval) {
ERROR(rt2x00dev, "Failed to register led trigger.\n");
return retval;
}

trigger->registered = 1;

return 0;
}

static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev,
struct rt2x00_led *led,
enum led_type type,
const char *name, char *trigger)
{
struct device *device = wiphy_dev(rt2x00dev->hw->wiphy);
int retval;

led->led_dev.name = name;
led->led_dev.brightness_set = rt2x00dev->ops->lib->led_brightness;
led->led_dev.default_trigger = trigger;

retval = led_classdev_register(device, &led->led_dev);
if (retval) {
ERROR(rt2x00dev, "Failed to register led handler.\n");
return retval;
}

led->rt2x00dev = rt2x00dev;
led->type = type;
led->registered = 1;

return 0;
}

int rt2x00leds_register(struct rt2x00_dev *rt2x00dev)
{
char *trigger;
char dev_name[16];
char name[32];
int retval;

if (!rt2x00dev->ops->lib->led_brightness)
return 0;

snprintf(dev_name, sizeof(dev_name), "%s-%s",
rt2x00dev->ops->name, wiphy_name(rt2x00dev->hw->wiphy));

if (rt2x00dev->led_flags & LED_SUPPORT_RADIO) {
trigger = ieee80211_get_radio_led_name(rt2x00dev->hw);
snprintf(name, sizeof(name), "%s:radio", dev_name);

retval = rt2x00leds_register_led(rt2x00dev,
&rt2x00dev->led_radio,
LED_TYPE_RADIO,
name, trigger);
if (retval)
goto exit_fail;
}

if (rt2x00dev->led_flags & LED_SUPPORT_ASSOC) {
trigger = ieee80211_get_assoc_led_name(rt2x00dev->hw);
snprintf(name, sizeof(name), "%s:assoc", dev_name);

retval = rt2x00leds_register_led(rt2x00dev,
&rt2x00dev->led_assoc,
LED_TYPE_ASSOC,
name, trigger);
if (retval)
goto exit_fail;
}

if (rt2x00dev->led_flags & LED_SUPPORT_QUALITY) {
snprintf(name, sizeof(name), "%s:quality", dev_name);

retval = rt2x00leds_register_trigger(rt2x00dev,
&rt2x00dev->trigger_qual,
name);

retval = rt2x00leds_register_led(rt2x00dev,
&rt2x00dev->led_qual,
LED_TYPE_QUALITY,
name, name);
if (retval)
goto exit_fail;
}

return 0;

exit_fail:
rt2x00leds_unregister(rt2x00dev);
return retval;
}

static void rt2x00leds_unregister_trigger(struct rt2x00_trigger *trigger)
{
if (!trigger->registered)
return;

led_trigger_unregister(&trigger->trigger);
trigger->registered = 0;
}

static void rt2x00leds_unregister_led(struct rt2x00_led *led)
{
if (!led->registered)
return;

led_classdev_unregister(&led->led_dev);

led->led_dev.brightness_set(&led->led_dev, LED_OFF);
led->registered = 0;
}

void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev)
{
rt2x00leds_unregister_trigger(&rt2x00dev->trigger_qual);
rt2x00leds_unregister_led(&rt2x00dev->led_qual);
rt2x00leds_unregister_led(&rt2x00dev->led_assoc);
rt2x00leds_unregister_led(&rt2x00dev->led_radio);
}

void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev)
{
if (rt2x00dev->led_qual.registered)
led_classdev_suspend(&rt2x00dev->led_qual.led_dev);
if (rt2x00dev->led_assoc.registered)
led_classdev_suspend(&rt2x00dev->led_assoc.led_dev);
if (rt2x00dev->led_radio.registered)
led_classdev_suspend(&rt2x00dev->led_radio.led_dev);
}

void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev)
{
if (rt2x00dev->led_radio.registered)
led_classdev_resume(&rt2x00dev->led_radio.led_dev);
if (rt2x00dev->led_assoc.registered)
led_classdev_resume(&rt2x00dev->led_assoc.led_dev);
if (rt2x00dev->led_qual.registered)
led_classdev_resume(&rt2x00dev->led_qual.led_dev);
}
63 changes: 63 additions & 0 deletions drivers/net/wireless/rt2x00/rt2x00leds.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/*
Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
<http://rt2x00.serialmonkey.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the
Free Software Foundation, Inc.,
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/

/*
Module: rt2x00lib
Abstract: rt2x00 led datastructures and routines
*/

#ifndef RT2X00LEDS_H
#define RT2X00LEDS_H

/*
* Flags used by driver to indicate which
* which led types are supported.
*/
#define LED_SUPPORT_RADIO 0x000001
#define LED_SUPPORT_ASSOC 0x000002
#define LED_SUPPORT_ACTIVITY 0x000004
#define LED_SUPPORT_QUALITY 0x000008

enum led_type {
LED_TYPE_RADIO,
LED_TYPE_ASSOC,
LED_TYPE_QUALITY,
};

#ifdef CONFIG_RT2X00_LIB_LEDS

struct rt2x00_led {
struct rt2x00_dev *rt2x00dev;
struct led_classdev led_dev;

enum led_type type;
unsigned int registered;
};

struct rt2x00_trigger {
struct led_trigger trigger;

enum led_type type;
unsigned int registered;
};

#endif /* CONFIG_RT2X00_LIB_LEDS */

#endif /* RT2X00LEDS_H */
Loading

0 comments on commit 3b640f2

Please sign in to comment.