1 /* 2 Copyright (C) 2004 - 2009 Ivo van Doorn <IvDoorn@gmail.com> 3 <http://rt2x00.serialmonkey.com> 4 5 This program is free software; you can redistribute it and/or modify 6 it under the terms of the GNU General Public License as published by 7 the Free Software Foundation; either version 2 of the License, or 8 (at your option) any later version. 9 10 This program is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 GNU General Public License for more details. 14 15 You should have received a copy of the GNU General Public License 16 along with this program; if not, see <http://www.gnu.org/licenses/>. 17 */ 18 19 /* 20 Module: rt2x00lib 21 Abstract: rt2x00 led specific routines. 22 */ 23 24 #include <linux/kernel.h> 25 #include <linux/module.h> 26 27 #include "rt2x00.h" 28 #include "rt2x00lib.h" 29 30 void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, int rssi) 31 { 32 struct rt2x00_led *led = &rt2x00dev->led_qual; 33 unsigned int brightness; 34 35 if ((led->type != LED_TYPE_QUALITY) || !(led->flags & LED_REGISTERED)) 36 return; 37 38 /* 39 * Led handling requires a positive value for the rssi, 40 * to do that correctly we need to add the correction. 41 */ 42 rssi += rt2x00dev->rssi_offset; 43 44 /* 45 * Get the rssi level, this is used to convert the rssi 46 * to a LED value inside the range LED_OFF - LED_FULL. 47 */ 48 if (rssi <= 30) 49 rssi = 0; 50 else if (rssi <= 39) 51 rssi = 1; 52 else if (rssi <= 49) 53 rssi = 2; 54 else if (rssi <= 53) 55 rssi = 3; 56 else if (rssi <= 63) 57 rssi = 4; 58 else 59 rssi = 5; 60 61 /* 62 * Note that we must _not_ send LED_OFF since the driver 63 * is going to calculate the value and might use it in a 64 * division. 65 */ 66 brightness = ((LED_FULL / 6) * rssi) + 1; 67 if (brightness != led->led_dev.brightness) { 68 led->led_dev.brightness_set(&led->led_dev, brightness); 69 led->led_dev.brightness = brightness; 70 } 71 } 72 73 static void rt2x00led_led_simple(struct rt2x00_led *led, bool enabled) 74 { 75 unsigned int brightness = enabled ? LED_FULL : LED_OFF; 76 77 if (!(led->flags & LED_REGISTERED)) 78 return; 79 80 led->led_dev.brightness_set(&led->led_dev, brightness); 81 led->led_dev.brightness = brightness; 82 } 83 84 void rt2x00led_led_activity(struct rt2x00_dev *rt2x00dev, bool enabled) 85 { 86 if (rt2x00dev->led_qual.type == LED_TYPE_ACTIVITY) 87 rt2x00led_led_simple(&rt2x00dev->led_qual, enabled); 88 } 89 90 void rt2x00leds_led_assoc(struct rt2x00_dev *rt2x00dev, bool enabled) 91 { 92 if (rt2x00dev->led_assoc.type == LED_TYPE_ASSOC) 93 rt2x00led_led_simple(&rt2x00dev->led_assoc, enabled); 94 } 95 96 void rt2x00leds_led_radio(struct rt2x00_dev *rt2x00dev, bool enabled) 97 { 98 if (rt2x00dev->led_radio.type == LED_TYPE_RADIO) 99 rt2x00led_led_simple(&rt2x00dev->led_radio, enabled); 100 } 101 102 static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev, 103 struct rt2x00_led *led, 104 const char *name) 105 { 106 struct device *device = wiphy_dev(rt2x00dev->hw->wiphy); 107 int retval; 108 109 led->led_dev.name = name; 110 led->led_dev.brightness = LED_OFF; 111 112 retval = led_classdev_register(device, &led->led_dev); 113 if (retval) { 114 rt2x00_err(rt2x00dev, "Failed to register led handler\n"); 115 return retval; 116 } 117 118 led->flags |= LED_REGISTERED; 119 120 return 0; 121 } 122 123 void rt2x00leds_register(struct rt2x00_dev *rt2x00dev) 124 { 125 char name[36]; 126 int retval; 127 unsigned long on_period; 128 unsigned long off_period; 129 const char *phy_name = wiphy_name(rt2x00dev->hw->wiphy); 130 131 if (rt2x00dev->led_radio.flags & LED_INITIALIZED) { 132 snprintf(name, sizeof(name), "%s-%s::radio", 133 rt2x00dev->ops->name, phy_name); 134 135 retval = rt2x00leds_register_led(rt2x00dev, 136 &rt2x00dev->led_radio, 137 name); 138 if (retval) 139 goto exit_fail; 140 } 141 142 if (rt2x00dev->led_assoc.flags & LED_INITIALIZED) { 143 snprintf(name, sizeof(name), "%s-%s::assoc", 144 rt2x00dev->ops->name, phy_name); 145 146 retval = rt2x00leds_register_led(rt2x00dev, 147 &rt2x00dev->led_assoc, 148 name); 149 if (retval) 150 goto exit_fail; 151 } 152 153 if (rt2x00dev->led_qual.flags & LED_INITIALIZED) { 154 snprintf(name, sizeof(name), "%s-%s::quality", 155 rt2x00dev->ops->name, phy_name); 156 157 retval = rt2x00leds_register_led(rt2x00dev, 158 &rt2x00dev->led_qual, 159 name); 160 if (retval) 161 goto exit_fail; 162 } 163 164 /* 165 * Initialize blink time to default value: 166 * On period: 70ms 167 * Off period: 30ms 168 */ 169 if (rt2x00dev->led_radio.led_dev.blink_set) { 170 on_period = 70; 171 off_period = 30; 172 rt2x00dev->led_radio.led_dev.blink_set( 173 &rt2x00dev->led_radio.led_dev, &on_period, &off_period); 174 } 175 176 return; 177 178 exit_fail: 179 rt2x00leds_unregister(rt2x00dev); 180 } 181 182 static void rt2x00leds_unregister_led(struct rt2x00_led *led) 183 { 184 led_classdev_unregister(&led->led_dev); 185 186 /* 187 * This might look weird, but when we are unregistering while 188 * suspended the led is already off, and since we haven't 189 * fully resumed yet, access to the device might not be 190 * possible yet. 191 */ 192 if (!(led->led_dev.flags & LED_SUSPENDED)) 193 led->led_dev.brightness_set(&led->led_dev, LED_OFF); 194 195 led->flags &= ~LED_REGISTERED; 196 } 197 198 void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev) 199 { 200 if (rt2x00dev->led_qual.flags & LED_REGISTERED) 201 rt2x00leds_unregister_led(&rt2x00dev->led_qual); 202 if (rt2x00dev->led_assoc.flags & LED_REGISTERED) 203 rt2x00leds_unregister_led(&rt2x00dev->led_assoc); 204 if (rt2x00dev->led_radio.flags & LED_REGISTERED) 205 rt2x00leds_unregister_led(&rt2x00dev->led_radio); 206 } 207 208 static inline void rt2x00leds_suspend_led(struct rt2x00_led *led) 209 { 210 led_classdev_suspend(&led->led_dev); 211 212 /* This shouldn't be needed, but just to be safe */ 213 led->led_dev.brightness_set(&led->led_dev, LED_OFF); 214 led->led_dev.brightness = LED_OFF; 215 } 216 217 void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev) 218 { 219 if (rt2x00dev->led_qual.flags & LED_REGISTERED) 220 rt2x00leds_suspend_led(&rt2x00dev->led_qual); 221 if (rt2x00dev->led_assoc.flags & LED_REGISTERED) 222 rt2x00leds_suspend_led(&rt2x00dev->led_assoc); 223 if (rt2x00dev->led_radio.flags & LED_REGISTERED) 224 rt2x00leds_suspend_led(&rt2x00dev->led_radio); 225 } 226 227 static inline void rt2x00leds_resume_led(struct rt2x00_led *led) 228 { 229 led_classdev_resume(&led->led_dev); 230 231 /* Device might have enabled the LEDS during resume */ 232 led->led_dev.brightness_set(&led->led_dev, LED_OFF); 233 led->led_dev.brightness = LED_OFF; 234 } 235 236 void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev) 237 { 238 if (rt2x00dev->led_radio.flags & LED_REGISTERED) 239 rt2x00leds_resume_led(&rt2x00dev->led_radio); 240 if (rt2x00dev->led_assoc.flags & LED_REGISTERED) 241 rt2x00leds_resume_led(&rt2x00dev->led_assoc); 242 if (rt2x00dev->led_qual.flags & LED_REGISTERED) 243 rt2x00leds_resume_led(&rt2x00dev->led_qual); 244 } 245