3   Broadcom B43 wireless driver
 
   6   Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,
 
   7   Copyright (c) 2005 Stefano Brivio <stefano.brivio@polimi.it>
 
   8   Copyright (c) 2005-2007 Michael Buesch <mb@bu3sch.de>
 
   9   Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
 
  10   Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
 
  12   This program is free software; you can redistribute it and/or modify
 
  13   it under the terms of the GNU General Public License as published by
 
  14   the Free Software Foundation; either version 2 of the License, or
 
  15   (at your option) any later version.
 
  17   This program is distributed in the hope that it will be useful,
 
  18   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  19   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  20   GNU General Public License for more details.
 
  22   You should have received a copy of the GNU General Public License
 
  23   along with this program; see the file COPYING.  If not, write to
 
  24   the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
 
  25   Boston, MA 02110-1301, USA.
 
  33 static void b43_led_turn_on(struct b43_wldev *dev, u8 led_index,
 
  36         struct b43_wl *wl = dev->wl;
 
  40         spin_lock_irqsave(&wl->leds_lock, flags);
 
  41         ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
 
  43                 ctl &= ~(1 << led_index);
 
  45                 ctl |= (1 << led_index);
 
  46         b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl);
 
  47         spin_unlock_irqrestore(&wl->leds_lock, flags);
 
  50 static void b43_led_turn_off(struct b43_wldev *dev, u8 led_index,
 
  53         struct b43_wl *wl = dev->wl;
 
  57         spin_lock_irqsave(&wl->leds_lock, flags);
 
  58         ctl = b43_read16(dev, B43_MMIO_GPIO_CONTROL);
 
  60                 ctl |= (1 << led_index);
 
  62                 ctl &= ~(1 << led_index);
 
  63         b43_write16(dev, B43_MMIO_GPIO_CONTROL, ctl);
 
  64         spin_unlock_irqrestore(&wl->leds_lock, flags);
 
  67 /* Callback from the LED subsystem. */
 
  68 static void b43_led_brightness_set(struct led_classdev *led_dev,
 
  69                                    enum led_brightness brightness)
 
  71         struct b43_led *led = container_of(led_dev, struct b43_led, led_dev);
 
  72         struct b43_wldev *dev = led->dev;
 
  75         if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED))
 
  78         /* Checking the radio-enabled status here is slightly racy,
 
  79          * but we want to avoid the locking overhead and we don't care
 
  80          * whether the LED has the wrong state for a second. */
 
  81         radio_enabled = (dev->phy.radio_on && dev->radio_hw_enable);
 
  83         if (brightness == LED_OFF || !radio_enabled)
 
  84                 b43_led_turn_off(dev, led->index, led->activelow);
 
  86                 b43_led_turn_on(dev, led->index, led->activelow);
 
  89 static int b43_register_led(struct b43_wldev *dev, struct b43_led *led,
 
  90                             const char *name, char *default_trigger,
 
  91                             u8 led_index, bool activelow)
 
  95         b43_led_turn_off(dev, led_index, activelow);
 
 101         led->index = led_index;
 
 102         led->activelow = activelow;
 
 103         strncpy(led->name, name, sizeof(led->name));
 
 105         led->led_dev.name = led->name;
 
 106         led->led_dev.default_trigger = default_trigger;
 
 107         led->led_dev.brightness_set = b43_led_brightness_set;
 
 109         err = led_classdev_register(dev->dev->dev, &led->led_dev);
 
 111                 b43warn(dev->wl, "LEDs: Failed to register %s\n", name);
 
 118 static void b43_unregister_led(struct b43_led *led)
 
 122         led_classdev_unregister(&led->led_dev);
 
 123         b43_led_turn_off(led->dev, led->index, led->activelow);
 
 127 static void b43_map_led(struct b43_wldev *dev,
 
 129                         enum b43_led_behaviour behaviour,
 
 132         struct ieee80211_hw *hw = dev->wl->hw;
 
 133         char name[B43_LED_MAX_NAME_LEN + 1];
 
 135         /* Map the b43 specific LED behaviour value to the
 
 136          * generic LED triggers. */
 
 138         case B43_LED_INACTIVE:
 
 141                 b43_led_turn_off(dev, led_index, activelow);
 
 144                 b43_led_turn_on(dev, led_index, activelow);
 
 146         case B43_LED_ACTIVITY:
 
 147         case B43_LED_TRANSFER:
 
 148         case B43_LED_APTRANSFER:
 
 149                 snprintf(name, sizeof(name),
 
 150                          "b43-%s::tx", wiphy_name(hw->wiphy));
 
 151                 b43_register_led(dev, &dev->led_tx, name,
 
 152                                  ieee80211_get_tx_led_name(hw),
 
 153                                  led_index, activelow);
 
 154                 snprintf(name, sizeof(name),
 
 155                          "b43-%s::rx", wiphy_name(hw->wiphy));
 
 156                 b43_register_led(dev, &dev->led_rx, name,
 
 157                                  ieee80211_get_rx_led_name(hw),
 
 158                                  led_index, activelow);
 
 160         case B43_LED_RADIO_ALL:
 
 161         case B43_LED_RADIO_A:
 
 162         case B43_LED_RADIO_B:
 
 163         case B43_LED_MODE_BG:
 
 164                 snprintf(name, sizeof(name),
 
 165                          "b43-%s::radio", wiphy_name(hw->wiphy));
 
 166                 b43_register_led(dev, &dev->led_radio, name,
 
 167                                  b43_rfkill_led_name(dev),
 
 168                                  led_index, activelow);
 
 169                 /* Sync the RF-kill LED state with the switch state. */
 
 170                 if (dev->radio_hw_enable)
 
 171                         b43_led_turn_on(dev, led_index, activelow);
 
 175                 snprintf(name, sizeof(name),
 
 176                          "b43-%s::assoc", wiphy_name(hw->wiphy));
 
 177                 b43_register_led(dev, &dev->led_assoc, name,
 
 178                                  ieee80211_get_assoc_led_name(hw),
 
 179                                  led_index, activelow);
 
 182                 b43warn(dev->wl, "LEDs: Unknown behaviour 0x%02X\n",
 
 188 void b43_leds_init(struct b43_wldev *dev)
 
 190         struct ssb_bus *bus = dev->dev->bus;
 
 193         enum b43_led_behaviour behaviour;
 
 196         sprom[0] = bus->sprom.gpio0;
 
 197         sprom[1] = bus->sprom.gpio1;
 
 198         sprom[2] = bus->sprom.gpio2;
 
 199         sprom[3] = bus->sprom.gpio3;
 
 201         for (i = 0; i < 4; i++) {
 
 202                 if (sprom[i] == 0xFF) {
 
 203                         /* There is no LED information in the SPROM
 
 204                          * for this LED. Hardcode it here. */
 
 208                                 behaviour = B43_LED_ACTIVITY;
 
 210                                 if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ)
 
 211                                         behaviour = B43_LED_RADIO_ALL;
 
 214                                 behaviour = B43_LED_RADIO_B;
 
 215                                 if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK)
 
 216                                         behaviour = B43_LED_ASSOC;
 
 219                                 behaviour = B43_LED_RADIO_A;
 
 222                                 behaviour = B43_LED_OFF;
 
 229                         behaviour = sprom[i] & B43_LED_BEHAVIOUR;
 
 230                         activelow = !!(sprom[i] & B43_LED_ACTIVELOW);
 
 232                 b43_map_led(dev, i, behaviour, activelow);
 
 236 void b43_leds_exit(struct b43_wldev *dev)
 
 238         b43_unregister_led(&dev->led_tx);
 
 239         b43_unregister_led(&dev->led_rx);
 
 240         b43_unregister_led(&dev->led_assoc);
 
 241         b43_unregister_led(&dev->led_radio);