1
linux/drivers/net/wireless/rt2x00/rt2x00leds.c
Ivo van Doorn 3b640f21af rt2x00: Enable LED class support for rt2500usb/rt73usb
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>
2008-02-29 15:37:00 -05:00

218 lines
5.3 KiB
C

/*
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);
}