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