Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  1 /*
  2 
  3   Broadcom BCM43xx wireless driver
  4 
  5   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
  6                      Stefano Brivio <st3@riseup.net>
  7                      Michael Buesch <mbuesch@freenet.de>
  8                      Danny van Dyk <kugelfang@gentoo.org>
  9                      Andreas Jaggi <andreas.jaggi@waterwave.ch>
 10 
 11   This program is free software; you can redistribute it and/or modify
 12   it under the terms of the GNU General Public License as published by
 13   the Free Software Foundation; either version 2 of the License, or
 14   (at your option) any later version.
 15 
 16   This program is distributed in the hope that it will be useful,
 17   but WITHOUT ANY WARRANTY; without even the implied warranty of
 18   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 19   GNU General Public License for more details.
 20 
 21   You should have received a copy of the GNU General Public License
 22   along with this program; see the file COPYING.  If not, write to
 23   the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
 24   Boston, MA 02110-1301, USA.
 25 
 26 */
 27 
 28 #include "bcm43xx_leds.h"
 29 #include "bcm43xx_radio.h"
 30 #include "bcm43xx.h"
 31 
 32 #include <linux/bitops.h>
 33 
 34 
 35 static void bcm43xx_led_changestate(struct bcm43xx_led *led)
 36 {
 37         struct bcm43xx_private *bcm = led->bcm;
 38         const int index = bcm43xx_led_index(led);
 39         const u16 mask = (1 << index);
 40         u16 ledctl;
 41 
 42         assert(index >= 0 && index < BCM43xx_NR_LEDS);
 43         assert(led->blink_interval);
 44         ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
 45         ledctl = (ledctl & mask) ? (ledctl & ~mask) : (ledctl | mask);
 46         bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
 47 }
 48 
 49 static void bcm43xx_led_blink(unsigned long d)
 50 {
 51         struct bcm43xx_led *led = (struct bcm43xx_led *)d;
 52         struct bcm43xx_private *bcm = led->bcm;
 53         unsigned long flags;
 54 
 55         spin_lock_irqsave(&bcm->leds_lock, flags);
 56         if (led->blink_interval) {
 57                 bcm43xx_led_changestate(led);
 58                 mod_timer(&led->blink_timer, jiffies + led->blink_interval);
 59         }
 60         spin_unlock_irqrestore(&bcm->leds_lock, flags);
 61 }
 62 
 63 static void bcm43xx_led_blink_start(struct bcm43xx_led *led,
 64                                     unsigned long interval)
 65 {
 66         if (led->blink_interval)
 67                 return;
 68         led->blink_interval = interval;
 69         bcm43xx_led_changestate(led);
 70         led->blink_timer.expires = jiffies + interval;
 71         add_timer(&led->blink_timer);
 72 }
 73 
 74 static void bcm43xx_led_blink_stop(struct bcm43xx_led *led, int sync)
 75 {
 76         struct bcm43xx_private *bcm = led->bcm;
 77         const int index = bcm43xx_led_index(led);
 78         u16 ledctl;
 79 
 80         if (!led->blink_interval)
 81                 return;
 82         if (unlikely(sync))
 83                 del_timer_sync(&led->blink_timer);
 84         else
 85                 del_timer(&led->blink_timer);
 86         led->blink_interval = 0;
 87 
 88         /* Make sure the LED is turned off. */
 89         assert(index >= 0 && index < BCM43xx_NR_LEDS);
 90         ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
 91         if (led->activelow)
 92                 ledctl |= (1 << index);
 93         else
 94                 ledctl &= ~(1 << index);
 95         bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
 96 }
 97 
 98 static void bcm43xx_led_init_hardcoded(struct bcm43xx_private *bcm,
 99                                        struct bcm43xx_led *led,
100                                        int led_index)
101 {
102         /* This function is called, if the behaviour (and activelow)
103          * information for a LED is missing in the SPROM.
104          * We hardcode the behaviour values for various devices here.
105          * Note that the BCM43xx_LED_TEST_XXX behaviour values can
106          * be used to figure out which led is mapped to which index.
107          */
108 
109         switch (led_index) {
110         case 0:
111                 led->behaviour = BCM43xx_LED_ACTIVITY;
112                 led->activelow = 1;
113                 if (bcm->board_vendor == PCI_VENDOR_ID_COMPAQ)
114                         led->behaviour = BCM43xx_LED_RADIO_ALL;
115                 break;
116         case 1:
117                 led->behaviour = BCM43xx_LED_RADIO_B;
118                 if (bcm->board_vendor == PCI_VENDOR_ID_ASUSTEK)
119                         led->behaviour = BCM43xx_LED_ASSOC;
120                 break;
121         case 2:
122                 led->behaviour = BCM43xx_LED_RADIO_A;
123                 break;
124         case 3:
125                 led->behaviour = BCM43xx_LED_OFF;
126                 break;
127         default:
128                 assert(0);
129         }
130 }
131 
132 int bcm43xx_leds_init(struct bcm43xx_private *bcm)
133 {
134         struct bcm43xx_led *led;
135         u8 sprom[4];
136         int i;
137 
138         sprom[0] = bcm->sprom.wl0gpio0;
139         sprom[1] = bcm->sprom.wl0gpio1;
140         sprom[2] = bcm->sprom.wl0gpio2;
141         sprom[3] = bcm->sprom.wl0gpio3;
142 
143         for (i = 0; i < BCM43xx_NR_LEDS; i++) {
144                 led = &(bcm->leds[i]);
145                 led->bcm = bcm;
146                 setup_timer(&led->blink_timer,
147                             bcm43xx_led_blink,
148                             (unsigned long)led);
149 
150                 if (sprom[i] == 0xFF) {
151                         bcm43xx_led_init_hardcoded(bcm, led, i);
152                 } else {
153                         led->behaviour = sprom[i] & BCM43xx_LED_BEHAVIOUR;
154                         led->activelow = !!(sprom[i] & BCM43xx_LED_ACTIVELOW);
155                 }
156         }
157 
158         return 0;
159 }
160 
161 void bcm43xx_leds_exit(struct bcm43xx_private *bcm)
162 {
163         struct bcm43xx_led *led;
164         int i;
165 
166         for (i = 0; i < BCM43xx_NR_LEDS; i++) {
167                 led = &(bcm->leds[i]);
168                 bcm43xx_led_blink_stop(led, 1);
169         }
170         bcm43xx_leds_switch_all(bcm, 0);
171 }
172 
173 void bcm43xx_leds_update(struct bcm43xx_private *bcm, int activity)
174 {
175         struct bcm43xx_led *led;
176         struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
177         struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
178         const int transferring = (jiffies - bcm->stats.last_tx) < BCM43xx_LED_XFER_THRES;
179         int i, turn_on;
180         unsigned long interval = 0;
181         u16 ledctl;
182         unsigned long flags;
183 
184         spin_lock_irqsave(&bcm->leds_lock, flags);
185         ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
186         for (i = 0; i < BCM43xx_NR_LEDS; i++) {
187                 led = &(bcm->leds[i]);
188 
189                 turn_on = 0;
190                 switch (led->behaviour) {
191                 case BCM43xx_LED_INACTIVE:
192                         continue;
193                 case BCM43xx_LED_OFF:
194                 case BCM43xx_LED_BCM4303_3:
195                         break;
196                 case BCM43xx_LED_ON:
197                         turn_on = 1;
198                         break;
199                 case BCM43xx_LED_ACTIVITY:
200                 case BCM43xx_LED_BCM4303_0:
201                         turn_on = activity;
202                         break;
203                 case BCM43xx_LED_RADIO_ALL:
204                         turn_on = radio->enabled && bcm43xx_is_hw_radio_enabled(bcm);
205                         break;
206                 case BCM43xx_LED_RADIO_A:
207                 case BCM43xx_LED_BCM4303_2:
208                         turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
209                                    phy->type == BCM43xx_PHYTYPE_A);
210                         break;
211                 case BCM43xx_LED_RADIO_B:
212                 case BCM43xx_LED_BCM4303_1:
213                         turn_on = (radio->enabled && bcm43xx_is_hw_radio_enabled(bcm) &&
214                                    (phy->type == BCM43xx_PHYTYPE_B ||
215                                     phy->type == BCM43xx_PHYTYPE_G));
216                         break;
217                 case BCM43xx_LED_MODE_BG:
218                         if (phy->type == BCM43xx_PHYTYPE_G && bcm43xx_is_hw_radio_enabled(bcm) &&
219                             1/*FIXME: using G rates.*/)
220                                 turn_on = 1;
221                         break;
222                 case BCM43xx_LED_TRANSFER:
223                         if (transferring)
224                                 bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM);
225                         else
226                                 bcm43xx_led_blink_stop(led, 0);
227                         continue;
228                 case BCM43xx_LED_APTRANSFER:
229                         if (bcm->ieee->iw_mode == IW_MODE_MASTER) {
230                                 if (transferring) {
231                                         interval = BCM43xx_LEDBLINK_FAST;
232                                         turn_on = 1;
233                                 }
234                         } else {
235                                 turn_on = 1;
236                                 if (0/*TODO: not assoc*/)
237                                         interval = BCM43xx_LEDBLINK_SLOW;
238                                 else if (transferring)
239                                         interval = BCM43xx_LEDBLINK_FAST;
240                                 else
241                                         turn_on = 0;
242                         }
243                         if (turn_on)
244                                 bcm43xx_led_blink_start(led, interval);
245                         else
246                                 bcm43xx_led_blink_stop(led, 0);
247                         continue;
248                 case BCM43xx_LED_WEIRD:
249                         //TODO
250                         break;
251                 case BCM43xx_LED_ASSOC:
252                         if (bcm->softmac->associnfo.associated)
253                                 turn_on = 1;
254                         break;
255 #ifdef CONFIG_BCM43XX_DEBUG
256                 case BCM43xx_LED_TEST_BLINKSLOW:
257                         bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_SLOW);
258                         continue;
259                 case BCM43xx_LED_TEST_BLINKMEDIUM:
260                         bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_MEDIUM);
261                         continue;
262                 case BCM43xx_LED_TEST_BLINKFAST:
263                         bcm43xx_led_blink_start(led, BCM43xx_LEDBLINK_FAST);
264                         continue;
265 #endif /* CONFIG_BCM43XX_DEBUG */
266                 default:
267                         dprintkl(KERN_INFO PFX "Bad value in leds_update,"
268                                 " led->behaviour: 0x%x\n", led->behaviour);
269                 };
270 
271                 if (led->activelow)
272                         turn_on = !turn_on;
273                 if (turn_on)
274                         ledctl |= (1 << i);
275                 else
276                         ledctl &= ~(1 << i);
277         }
278         bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
279         spin_unlock_irqrestore(&bcm->leds_lock, flags);
280 }
281 
282 void bcm43xx_leds_switch_all(struct bcm43xx_private *bcm, int on)
283 {
284         struct bcm43xx_led *led;
285         u16 ledctl;
286         int i;
287         int bit_on;
288         unsigned long flags;
289 
290         spin_lock_irqsave(&bcm->leds_lock, flags);
291         ledctl = bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL);
292         for (i = 0; i < BCM43xx_NR_LEDS; i++) {
293                 led = &(bcm->leds[i]);
294                 if (led->behaviour == BCM43xx_LED_INACTIVE)
295                         continue;
296                 if (on)
297                         bit_on = led->activelow ? 0 : 1;
298                 else
299                         bit_on = led->activelow ? 1 : 0;
300                 if (bit_on)
301                         ledctl |= (1 << i);
302                 else
303                         ledctl &= ~(1 << i);
304         }
305         bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, ledctl);
306         spin_unlock_irqrestore(&bcm->leds_lock, flags);
307 }
308 
  This page was automatically generated by the LXR engine.