bcm43xx_leds.c 8.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /*
  2. Broadcom BCM43xx wireless driver
  3. Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
  4. Stefano Brivio <st3@riseup.net>
  5. Michael Buesch <mbuesch@freenet.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 "bcm43xx_leds.h"
  22. #include "bcm43xx_radio.h"
  23. #include "bcm43xx.h"
  24. #include <asm/bitops.h>
  25. static void bcm43xx_led_changestate(struct bcm43xx_led *led)
  26. {
  27. struct bcm43xx_private *bcm = led->bcm;
  28. const int index = bcm43xx_led_index(led);
  29. const u16 mask = (1 << index);
  30. u16 ledctl;
  31. assert(index >= 0 && index < BCM43xx_NR_LEDS);
  32. assert(led->blink_interval);
  33. ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
  34. ledctl = (ledctl & mask) ? (ledctl & ~mask) : (ledctl | mask);
  35. bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
  36. }
  37. static void bcm43xx_led_blink(unsigned long d)
  38. {
  39. struct bcm43xx_led *led = (struct bcm43xx_led *)d;
  40. struct bcm43xx_private *bcm = led->bcm;
  41. unsigned long flags;
  42. spin_lock_irqsave(&bcm->leds_lock, flags);
  43. if (led->blink_interval) {
  44. bcm43xx_led_changestate(led);
  45. mod_timer(&led->blink_timer, jiffies + led->blink_interval);
  46. }
  47. spin_unlock_irqrestore(&bcm->leds_lock, flags);
  48. }
  49. static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
  50. unsigned long interval)
  51. {
  52. if (led->blink_interval)
  53. return;
  54. led->blink_interval = interval;
  55. bcm43xx_led_changestate(led);
  56. led->blink_timer.expires = jiffies + interval;
  57. add_timer(&led->blink_timer);
  58. }
  59. static void bcm43xx_led_blink_stop(struct bcm43xx_led *led, int sync)
  60. {
  61. struct bcm43xx_private *bcm = led->bcm;
  62. const int index = bcm43xx_led_index(led);
  63. u16 ledctl;
  64. if (!led->blink_interval)
  65. return;
  66. if (unlikely(sync))
  67. del_timer_sync(&led->blink_timer);
  68. else
  69. del_timer(&led->blink_timer);
  70. led->blink_interval = 0;
  71. /* Make sure the LED is turned off. */
  72. assert(index >= 0 && index < BCM43xx_NR_LEDS);
  73. ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
  74. if (led->activelow)
  75. ledctl |= (1 << index);
  76. else
  77. ledctl &= ~(1 << index);
  78. bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
  79. }
  80. static void bcm43xx_led_init_hardcoded(struct bcm43xx_private *bcm,
  81. struct bcm43xx_led *led,
  82. int led_index)
  83. {
  84. /* This function is called, if the behaviour (and activelow)
  85. * information for a LED is missing in the SPROM.
  86. * We hardcode the behaviour values for various devices here.
  87. * Note that the BCM43xx_LED_TEST_XXX behaviour values can
  88. * be used to figure out which led is mapped to which index.
  89. */
  90. switch (led_index) {
  91. case 0:
  92. led->behaviour = BCM43xx_LED_ACTIVITY;
  93. led->activelow = 1;
  94. if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ)
  95. led->behaviour = BCM43xx_LED_RADIO_ALL;
  96. break;
  97. case 1:
  98. led->behaviour = BCM43xx_LED_RADIO_B;
  99. if (bcm->board_vendor == PCI_VENDOR_ID_ASUSTEK)
  100. led->behaviour = BCM43xx_LED_ASSOC;
  101. break;
  102. case 2:
  103. led->behaviour = BCM43xx_LED_RADIO_A;
  104. break;
  105. case 3:
  106. led->behaviour = BCM43xx_LED_OFF;
  107. break;
  108. default:
  109. assert(0);
  110. }
  111. }
  112. int bcm43xx_leds_init(struct bcm43xx_private *bcm)
  113. {
  114. struct bcm43xx_led *led;
  115. u8 sprom[4];
  116. int i;
  117. sprom[0] = bcm->sprom.wl0gpio0;
  118. sprom[1] = bcm->sprom.wl0gpio1;
  119. sprom[2] = bcm->sprom.wl0gpio2;
  120. sprom[3] = bcm->sprom.wl0gpio3;
  121. for (i = 0; i < BCM43xx_NR_LEDS; i++) {
  122. led = &(bcm->leds[i]);
  123. led->bcm = bcm;
  124. setup_timer(&led->blink_timer,
  125. bcm43xx_led_blink,
  126. (unsigned long)led);
  127. if (sprom[i] == 0xFF) {
  128. bcm43xx_led_init_hardcoded(bcm, led, i);
  129. } else {
  130. led->behaviour = sprom[i] & BCM43xx_LED_BEHAVIOUR;
  131. led->activelow = !!(sprom[i] & BCM43xx_LED_ACTIVELOW);
  132. }
  133. }
  134. return 0;
  135. }
  136. void bcm43xx_leds_exit(struct bcm43xx_private *bcm)
  137. {
  138. struct bcm43xx_led *led;
  139. int i;
  140. for (i = 0; i < BCM43xx_NR_LEDS; i++) {
  141. led = &(bcm->leds[i]);
  142. bcm43xx_led_blink_stop(led, 1);
  143. }
  144. bcm43xx_leds_switch_all(bcm, 0);
  145. }
  146. void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
  147. {
  148. struct bcm43xx_led *led;
  149. struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
  150. struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
  151. const int transferring = (jiffies - bcm->stats.last_tx) < BCM43xx_LED_XFER_THRES;
  152. int i, turn_on;
  153. unsigned long interval = 0;
  154. u16 ledctl;
  155. unsigned long flags;
  156. spin_lock_irqsave(&bcm->leds_lock, flags);
  157. ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
  158. for (i = 0; i < BCM43xx_NR_LEDS; i++) {
  159. led = &(bcm->leds[i]);
  160. turn_on = 0;
  161. switch (led->behaviour) {
  162. case BCM43xx_LED_INACTIVE:
  163. continue;
  164. case BCM43xx_LED_OFF:
  165. case BCM43xx_LED_BCM4303_3:
  166. break;
  167. case BCM43xx_LED_ON:
  168. turn_on = 1;
  169. break;
  170. case BCM43xx_LED_ACTIVITY:
  171. case BCM43xx_LED_BCM4303_0:
  172. turn_on = activity;
  173. break;
  174. case BCM43xx_LED_RADIO_ALL:
  175. turn_on = radio->enabled && bcm43xx_is_hw_radio_enabled(bcm);
  176. break;
  177. case BCM43xx_LED_RADIO_A:
  178. case BCM43xx_LED_BCM4303_2:
  179. turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
  180. phy->type == BCM43xx_PHYTYPE_A);
  181. break;
  182. case BCM43xx_LED_RADIO_B:
  183. case BCM43xx_LED_BCM4303_1:
  184. turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
  185. (phy->type == BCM43xx_PHYTYPE_B ||
  186. phy->type == BCM43xx_PHYTYPE_G));
  187. break;
  188. case BCM43xx_LED_MODE_BG:
  189. if (phy->type == BCM43xx_PHYTYPE_G && bcm43xx_is_hw_radio_enabled(bcm) &&
  190. 1/*FIXME: using G rates.*/)
  191. turn_on = 1;
  192. break;
  193. case BCM43xx_LED_TRANSFER:
  194. if (transferring)
  195. bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM);
  196. else
  197. bcm43xx_led_blink_stop(led, 0);
  198. continue;
  199. case BCM43xx_LED_APTRANSFER:
  200. if (bcm->ieee->iw_mode == IW_MODE_MASTER) {
  201. if (transferring) {
  202. interval = BCM43xx_LEDBLINK_FAST;
  203. turn_on = 1;
  204. }
  205. } else {
  206. turn_on = 1;
  207. if (0/*TODO: not assoc*/)
  208. interval = BCM43xx_LEDBLINK_SLOW;
  209. else if (transferring)
  210. interval = BCM43xx_LEDBLINK_FAST;
  211. else
  212. turn_on = 0;
  213. }
  214. if (turn_on)
  215. bcm43xx_led_blink_start(led, interval);
  216. else
  217. bcm43xx_led_blink_stop(led, 0);
  218. continue;
  219. case BCM43xx_LED_WEIRD:
  220. //TODO
  221. break;
  222. case BCM43xx_LED_ASSOC:
  223. if (bcm->softmac->associnfo.associated)
  224. turn_on = 1;
  225. break;
  226. #ifdef CONFIG_BCM43XX_DEBUG
  227. case BCM43xx_LED_TEST_BLINKSLOW:
  228. bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_SLOW);
  229. continue;
  230. case BCM43xx_LED_TEST_BLINKMEDIUM:
  231. bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM);
  232. continue;
  233. case BCM43xx_LED_TEST_BLINKFAST:
  234. bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_FAST);
  235. continue;
  236. #endif /* CONFIG_BCM43XX_DEBUG */
  237. default:
  238. dprintkl(KERN_INFO PFX "Bad value in leds_update,"
  239. " led->behaviour: 0x%x\n", led->behaviour);
  240. };
  241. if (led->activelow)
  242. turn_on = !turn_on;
  243. if (turn_on)
  244. ledctl |= (1 << i);
  245. else
  246. ledctl &= ~(1 << i);
  247. }
  248. bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
  249. spin_unlock_irqrestore(&bcm->leds_lock, flags);
  250. }
  251. void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
  252. {
  253. struct bcm43xx_led *led;
  254. u16 ledctl;
  255. int i;
  256. int bit_on;
  257. unsigned long flags;
  258. spin_lock_irqsave(&bcm->leds_lock, flags);
  259. ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
  260. for (i = 0; i < BCM43xx_NR_LEDS; i++) {
  261. led = &(bcm->leds[i]);
  262. if (led->behaviour == BCM43xx_LED_INACTIVE)
  263. continue;
  264. if (on)
  265. bit_on = led->activelow ? 0 : 1;
  266. else
  267. bit_on = led->activelow ? 1 : 0;
  268. if (bit_on)
  269. ledctl |= (1 << i);
  270. else
  271. ledctl &= ~(1 << i);
  272. }
  273. bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
  274. spin_unlock_irqrestore(&bcm->leds_lock, flags);
  275. }