rt2x00leds.c 6.4 KB

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