leds.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299
  1. /*
  2. Broadcom B43 wireless driver
  3. Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
  4. Stefano Brivio <st3@riseup.net>
  5. Michael Buesch <mb@bu3sch.de>
  6. Danny van Dyk <kugelfang@gentoo.org>
  7. Andreas Jaggi <andreas.jaggi@waterwave.ch>
  8. This program is free software; you can redistribute it and/or modify
  9. it under the terms of the GNU General Public License as published by
  10. the Free Software Foundation; either version 2 of the License, or
  11. (at your option) any later version.
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. GNU General Public License for more details.
  16. You should have received a copy of the GNU General Public License
  17. along with this program; see the file COPYING. If not, write to
  18. the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
  19. Boston, MA 02110-1301, USA.
  20. */
  21. #include "b43.h"
  22. #include "leds.h"
  23. #include "main.h"
  24. static void b43_led_changestate(struct b43_led *led)
  25. {
  26. struct b43_wldev *dev = led->dev;
  27. const int index = led->index;
  28. u16 ledctl;
  29. B43_WARN_ON(!(index >= 0 && index < B43_NR_LEDS));
  30. B43_WARN_ON(!led->blink_interval);
  31. ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
  32. ledctl ^= (1 << index);
  33. b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl);
  34. }
  35. static void b43_led_blink(unsigned long d)
  36. {
  37. struct b43_led *led = (struct b43_led *)d;
  38. struct b43_wldev *dev = led->dev;
  39. unsigned long flags;
  40. spin_lock_irqsave(&dev->wl->leds_lock, flags);
  41. if (led->blink_interval) {
  42. b43_led_changestate(led);
  43. mod_timer(&led->blink_timer, jiffies + led->blink_interval);
  44. }
  45. spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
  46. }
  47. static void b43_led_blink_start(struct b43_led *led, unsigned long interval)
  48. {
  49. if (led->blink_interval)
  50. return;
  51. led->blink_interval = interval;
  52. b43_led_changestate(led);
  53. led->blink_timer.expires = jiffies + interval;
  54. add_timer(&led->blink_timer);
  55. }
  56. static void b43_led_blink_stop(struct b43_led *led, int sync)
  57. {
  58. struct b43_wldev *dev = led->dev;
  59. const int index = led->index;
  60. u16 ledctl;
  61. if (!led->blink_interval)
  62. return;
  63. if (unlikely(sync))
  64. del_timer_sync(&led->blink_timer);
  65. else
  66. del_timer(&led->blink_timer);
  67. led->blink_interval = 0;
  68. /* Make sure the LED is turned off. */
  69. B43_WARN_ON(!(index >= 0 && index < B43_NR_LEDS));
  70. ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
  71. if (led->activelow)
  72. ledctl |= (1 << index);
  73. else
  74. ledctl &= ~(1 << index);
  75. b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl);
  76. }
  77. static void b43_led_init_hardcoded(struct b43_wldev *dev,
  78. struct b43_led *led, int led_index)
  79. {
  80. struct ssb_bus *bus = dev->dev->bus;
  81. /* This function is called, if the behaviour (and activelow)
  82. * information for a LED is missing in the SPROM.
  83. * We hardcode the behaviour values for various devices here.
  84. * Note that the B43_LED_TEST_XXX behaviour values can
  85. * be used to figure out which led is mapped to which index.
  86. */
  87. switch (led_index) {
  88. case 0:
  89. led->behaviour = B43_LED_ACTIVITY;
  90. led->activelow = 1;
  91. if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ)
  92. led->behaviour = B43_LED_RADIO_ALL;
  93. break;
  94. case 1:
  95. led->behaviour = B43_LED_RADIO_B;
  96. if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK)
  97. led->behaviour = B43_LED_ASSOC;
  98. break;
  99. case 2:
  100. led->behaviour = B43_LED_RADIO_A;
  101. break;
  102. case 3:
  103. led->behaviour = B43_LED_OFF;
  104. break;
  105. default:
  106. B43_WARN_ON(1);
  107. }
  108. }
  109. int b43_leds_init(struct b43_wldev *dev)
  110. {
  111. struct b43_led *led;
  112. u8 sprom[4];
  113. int i;
  114. sprom[0] = dev->dev->bus->sprom.r1.gpio0;
  115. sprom[1] = dev->dev->bus->sprom.r1.gpio1;
  116. sprom[2] = dev->dev->bus->sprom.r1.gpio2;
  117. sprom[3] = dev->dev->bus->sprom.r1.gpio3;
  118. for (i = 0; i < B43_NR_LEDS; i++) {
  119. led = &(dev->leds[i]);
  120. led->index = i;
  121. led->dev = dev;
  122. setup_timer(&led->blink_timer,
  123. b43_led_blink, (unsigned long)led);
  124. if (sprom[i] == 0xFF) {
  125. b43_led_init_hardcoded(dev, led, i);
  126. } else {
  127. led->behaviour = sprom[i] & B43_LED_BEHAVIOUR;
  128. led->activelow = !!(sprom[i] & B43_LED_ACTIVELOW);
  129. }
  130. }
  131. return 0;
  132. }
  133. void b43_leds_exit(struct b43_wldev *dev)
  134. {
  135. struct b43_led *led;
  136. int i;
  137. for (i = 0; i < B43_NR_LEDS; i++) {
  138. led = &(dev->leds[i]);
  139. b43_led_blink_stop(led, 1);
  140. }
  141. b43_leds_switch_all(dev, 0);
  142. }
  143. void b43_leds_update(struct b43_wldev *dev, int activity)
  144. {
  145. struct b43_led *led;
  146. struct b43_phy *phy = &dev->phy;
  147. const int transferring =
  148. (jiffies - dev->stats.last_tx) < B43_LED_XFER_THRES;
  149. int i, turn_on;
  150. unsigned long interval = 0;
  151. u16 ledctl;
  152. unsigned long flags;
  153. spin_lock_irqsave(&dev->wl->leds_lock, flags);
  154. ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
  155. for (i = 0; i < B43_NR_LEDS; i++) {
  156. led = &(dev->leds[i]);
  157. turn_on = 0;
  158. switch (led->behaviour) {
  159. case B43_LED_INACTIVE:
  160. continue;
  161. case B43_LED_OFF:
  162. break;
  163. case B43_LED_ON:
  164. turn_on = 1;
  165. break;
  166. case B43_LED_ACTIVITY:
  167. turn_on = activity;
  168. break;
  169. case B43_LED_RADIO_ALL:
  170. turn_on = phy->radio_on && b43_is_hw_radio_enabled(dev);
  171. break;
  172. case B43_LED_RADIO_A:
  173. turn_on = (phy->radio_on && b43_is_hw_radio_enabled(dev)
  174. && phy->type == B43_PHYTYPE_A);
  175. break;
  176. case B43_LED_RADIO_B:
  177. turn_on = (phy->radio_on && b43_is_hw_radio_enabled(dev)
  178. && (phy->type == B43_PHYTYPE_B
  179. || phy->type == B43_PHYTYPE_G));
  180. break;
  181. case B43_LED_MODE_BG:
  182. if (phy->type == B43_PHYTYPE_G
  183. && b43_is_hw_radio_enabled(dev)
  184. && 1 /*FIXME: using G rates. */ )
  185. turn_on = 1;
  186. break;
  187. case B43_LED_TRANSFER:
  188. if (transferring)
  189. b43_led_blink_start(led, B43_LEDBLINK_MEDIUM);
  190. else
  191. b43_led_blink_stop(led, 0);
  192. continue;
  193. case B43_LED_APTRANSFER:
  194. if (b43_is_mode(dev->wl, IEEE80211_IF_TYPE_AP)) {
  195. if (transferring) {
  196. interval = B43_LEDBLINK_FAST;
  197. turn_on = 1;
  198. }
  199. } else {
  200. turn_on = 1;
  201. if (0 /*TODO: not assoc */ )
  202. interval = B43_LEDBLINK_SLOW;
  203. else if (transferring)
  204. interval = B43_LEDBLINK_FAST;
  205. else
  206. turn_on = 0;
  207. }
  208. if (turn_on)
  209. b43_led_blink_start(led, interval);
  210. else
  211. b43_led_blink_stop(led, 0);
  212. continue;
  213. case B43_LED_WEIRD:
  214. //TODO
  215. break;
  216. case B43_LED_ASSOC:
  217. if (1 /*dev->softmac->associated */ )
  218. turn_on = 1;
  219. break;
  220. #ifdef CONFIG_B43_DEBUG
  221. case B43_LED_TEST_BLINKSLOW:
  222. b43_led_blink_start(led, B43_LEDBLINK_SLOW);
  223. continue;
  224. case B43_LED_TEST_BLINKMEDIUM:
  225. b43_led_blink_start(led, B43_LEDBLINK_MEDIUM);
  226. continue;
  227. case B43_LED_TEST_BLINKFAST:
  228. b43_led_blink_start(led, B43_LEDBLINK_FAST);
  229. continue;
  230. #endif /* CONFIG_B43_DEBUG */
  231. default:
  232. B43_WARN_ON(1);
  233. };
  234. if (led->activelow)
  235. turn_on = !turn_on;
  236. if (turn_on)
  237. ledctl |= (1 << i);
  238. else
  239. ledctl &= ~(1 << i);
  240. }
  241. b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl);
  242. spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
  243. }
  244. void b43_leds_switch_all(struct b43_wldev *dev, int on)
  245. {
  246. struct b43_led *led;
  247. u16 ledctl;
  248. int i;
  249. int bit_on;
  250. unsigned long flags;
  251. spin_lock_irqsave(&dev->wl->leds_lock, flags);
  252. ledctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
  253. for (i = 0; i < B43_NR_LEDS; i++) {
  254. led = &(dev->leds[i]);
  255. if (led->behaviour == B43_LED_INACTIVE)
  256. continue;
  257. if (on)
  258. bit_on = led->activelow ? 0 : 1;
  259. else
  260. bit_on = led->activelow ? 1 : 0;
  261. if (bit_on)
  262. ledctl |= (1 << i);
  263. else
  264. ledctl &= ~(1 << i);
  265. }
  266. b43_write16(dev, B43_MMIO_GPIO_CONTROL, ledctl);
  267. spin_unlock_irqrestore(&dev->wl->leds_lock, flags);
  268. }