Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/linville/wireles...
[linux-2.6] / drivers / net / wireless / rt2x00 / rt2x00leds.c
1 /*
2         Copyright (C) 2004 - 2008 rt2x00 SourceForge Project
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, write to the
17         Free Software Foundation, Inc.,
18         59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  */
20
21 /*
22         Module: rt2x00lib
23         Abstract: rt2x00 led specific routines.
24  */
25
26 #include <linux/kernel.h>
27 #include <linux/module.h>
28
29 #include "rt2x00.h"
30 #include "rt2x00lib.h"
31
32 void rt2x00leds_led_quality(struct rt2x00_dev *rt2x00dev, int rssi)
33 {
34         if (!rt2x00dev->trigger_qual.registered)
35                 return;
36
37         /*
38          * Led handling requires a positive value for the rssi,
39          * to do that correctly we need to add the correction.
40          */
41         rssi += rt2x00dev->rssi_offset;
42
43         /*
44          * Get the rssi level, this is used to convert the rssi
45          * to a LED value inside the range LED_OFF - LED_FULL.
46          */
47         if (rssi <= 30)
48                 rssi = 0;
49         else if (rssi <= 39)
50                 rssi = 1;
51         else if (rssi <= 49)
52                 rssi = 2;
53         else if (rssi <= 53)
54                 rssi = 3;
55         else if (rssi <= 63)
56                 rssi = 4;
57         else
58                 rssi = 5;
59
60         /*
61          * Note that we must _not_ send LED_OFF since the driver
62          * is going to calculate the value and might use it in a
63          * division.
64          */
65         led_trigger_event(&rt2x00dev->trigger_qual.trigger,
66                           ((LED_FULL / 6) * rssi) + 1);
67 }
68
69 static int rt2x00leds_register_trigger(struct rt2x00_dev *rt2x00dev,
70                                        struct rt2x00_trigger *trigger,
71                                        const char *name)
72 {
73         int retval;
74
75         trigger->trigger.name = name;
76         retval = led_trigger_register(&trigger->trigger);
77         if (retval) {
78                 ERROR(rt2x00dev, "Failed to register led trigger.\n");
79                 return retval;
80         }
81
82         trigger->registered = 1;
83
84         return 0;
85 }
86
87 static int rt2x00leds_register_led(struct rt2x00_dev *rt2x00dev,
88                                    struct rt2x00_led *led,
89                                    enum led_type type,
90                                    const char *name, char *trigger)
91 {
92         struct device *device = wiphy_dev(rt2x00dev->hw->wiphy);
93         int retval;
94
95         led->led_dev.name = name;
96         led->led_dev.brightness_set = rt2x00dev->ops->lib->led_brightness;
97         led->led_dev.default_trigger = trigger;
98
99         retval = led_classdev_register(device, &led->led_dev);
100         if (retval) {
101                 ERROR(rt2x00dev, "Failed to register led handler.\n");
102                 return retval;
103         }
104
105         led->rt2x00dev = rt2x00dev;
106         led->type = type;
107         led->registered = 1;
108
109         return 0;
110 }
111
112 int rt2x00leds_register(struct rt2x00_dev *rt2x00dev)
113 {
114         char *trigger;
115         char dev_name[16];
116         char name[32];
117         int retval;
118
119         if (!rt2x00dev->ops->lib->led_brightness)
120                 return 0;
121
122         snprintf(dev_name, sizeof(dev_name), "%s-%s",
123                  rt2x00dev->ops->name, wiphy_name(rt2x00dev->hw->wiphy));
124
125         if (rt2x00dev->led_flags & LED_SUPPORT_RADIO) {
126                 trigger = ieee80211_get_radio_led_name(rt2x00dev->hw);
127                 snprintf(name, sizeof(name), "%s:radio", dev_name);
128
129                 retval = rt2x00leds_register_led(rt2x00dev,
130                                                  &rt2x00dev->led_radio,
131                                                  LED_TYPE_RADIO,
132                                                  name, trigger);
133                 if (retval)
134                         goto exit_fail;
135         }
136
137         if (rt2x00dev->led_flags & LED_SUPPORT_ASSOC) {
138                 trigger = ieee80211_get_assoc_led_name(rt2x00dev->hw);
139                 snprintf(name, sizeof(name), "%s:assoc", dev_name);
140
141                 retval = rt2x00leds_register_led(rt2x00dev,
142                                                  &rt2x00dev->led_assoc,
143                                                  LED_TYPE_ASSOC,
144                                                  name, trigger);
145                 if (retval)
146                         goto exit_fail;
147         }
148
149         if (rt2x00dev->led_flags & LED_SUPPORT_QUALITY) {
150                 snprintf(name, sizeof(name), "%s:quality", dev_name);
151
152                 retval = rt2x00leds_register_trigger(rt2x00dev,
153                                                      &rt2x00dev->trigger_qual,
154                                                      name);
155
156                 retval = rt2x00leds_register_led(rt2x00dev,
157                                                  &rt2x00dev->led_qual,
158                                                  LED_TYPE_QUALITY,
159                                                  name, name);
160                 if (retval)
161                         goto exit_fail;
162         }
163
164         return 0;
165
166 exit_fail:
167         rt2x00leds_unregister(rt2x00dev);
168         return retval;
169 }
170
171 static void rt2x00leds_unregister_trigger(struct rt2x00_trigger *trigger)
172 {
173         if (!trigger->registered)
174                 return;
175
176         led_trigger_unregister(&trigger->trigger);
177         trigger->registered = 0;
178 }
179
180 static void rt2x00leds_unregister_led(struct rt2x00_led *led)
181 {
182         if (!led->registered)
183                 return;
184
185         led_classdev_unregister(&led->led_dev);
186
187         led->led_dev.brightness_set(&led->led_dev, LED_OFF);
188         led->registered = 0;
189 }
190
191 void rt2x00leds_unregister(struct rt2x00_dev *rt2x00dev)
192 {
193         rt2x00leds_unregister_trigger(&rt2x00dev->trigger_qual);
194         rt2x00leds_unregister_led(&rt2x00dev->led_qual);
195         rt2x00leds_unregister_led(&rt2x00dev->led_assoc);
196         rt2x00leds_unregister_led(&rt2x00dev->led_radio);
197 }
198
199 void rt2x00leds_suspend(struct rt2x00_dev *rt2x00dev)
200 {
201         if (rt2x00dev->led_qual.registered)
202                 led_classdev_suspend(&rt2x00dev->led_qual.led_dev);
203         if (rt2x00dev->led_assoc.registered)
204                 led_classdev_suspend(&rt2x00dev->led_assoc.led_dev);
205         if (rt2x00dev->led_radio.registered)
206                 led_classdev_suspend(&rt2x00dev->led_radio.led_dev);
207 }
208
209 void rt2x00leds_resume(struct rt2x00_dev *rt2x00dev)
210 {
211         if (rt2x00dev->led_radio.registered)
212                 led_classdev_resume(&rt2x00dev->led_radio.led_dev);
213         if (rt2x00dev->led_assoc.registered)
214                 led_classdev_resume(&rt2x00dev->led_assoc.led_dev);
215         if (rt2x00dev->led_qual.registered)
216                 led_classdev_resume(&rt2x00dev->led_qual.led_dev);
217 }