mac80211: pass vif and station to update_tkip_key
[safe/jmp/linux-2.6] / drivers / net / wireless / b43 / main.c
index fca2fe9..c699e46 100644 (file)
@@ -8,6 +8,9 @@
   Copyright (c) 2005 Danny van Dyk <kugelfang@gentoo.org>
   Copyright (c) 2005 Andreas Jaggi <andreas.jaggi@waterwave.ch>
 
+  SDIO support
+  Copyright (c) 2009 Albert Herranz <albert_herranz@yahoo.es>
+
   Some parts of the code in this file are derived from the ipw2200
   driver  Copyright(c) 2003 - 2004 Intel Corporation.
 
@@ -53,6 +56,8 @@
 #include "xmit.h"
 #include "lo.h"
 #include "pcmcia.h"
+#include "sdio.h"
+#include <linux/mmc/sdio_func.h>
 
 MODULE_DESCRIPTION("Broadcom B43 wireless driver");
 MODULE_AUTHOR("Martin Langer");
@@ -62,7 +67,12 @@ MODULE_AUTHOR("Gábor Stefanik");
 MODULE_LICENSE("GPL");
 
 MODULE_FIRMWARE(B43_SUPPORTED_FIRMWARE_ID);
-
+MODULE_FIRMWARE("b43/ucode11.fw");
+MODULE_FIRMWARE("b43/ucode13.fw");
+MODULE_FIRMWARE("b43/ucode14.fw");
+MODULE_FIRMWARE("b43/ucode15.fw");
+MODULE_FIRMWARE("b43/ucode5.fw");
+MODULE_FIRMWARE("b43/ucode9.fw");
 
 static int modparam_bad_frames_preempt;
 module_param_named(bad_frames_preempt, modparam_bad_frames_preempt, int, 0444);
@@ -97,6 +107,9 @@ int b43_modparam_verbose = B43_VERBOSITY_DEFAULT;
 module_param_named(verbose, b43_modparam_verbose, int, 0644);
 MODULE_PARM_DESC(verbose, "Log message verbosity: 0=error, 1=warn, 2=info(default), 3=debug");
 
+static int modparam_pio;
+module_param_named(pio, modparam_pio, int, 0444);
+MODULE_PARM_DESC(pio, "enable(1) / disable(0) PIO mode");
 
 static const struct ssb_device_id b43_ssb_tbl[] = {
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
@@ -105,6 +118,7 @@ static const struct ssb_device_id b43_ssb_tbl[] = {
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 9),
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 10),
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 11),
+       SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 12),
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 13),
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 15),
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 16),
@@ -390,7 +404,7 @@ static inline void b43_shm_control_word(struct b43_wldev *dev,
        b43_write32(dev, B43_MMIO_SHM_CONTROL, control);
 }
 
-u32 __b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
+u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
 {
        u32 ret;
 
@@ -413,20 +427,7 @@ out:
        return ret;
 }
 
-u32 b43_shm_read32(struct b43_wldev *dev, u16 routing, u16 offset)
-{
-       struct b43_wl *wl = dev->wl;
-       unsigned long flags;
-       u32 ret;
-
-       spin_lock_irqsave(&wl->shm_lock, flags);
-       ret = __b43_shm_read32(dev, routing, offset);
-       spin_unlock_irqrestore(&wl->shm_lock, flags);
-
-       return ret;
-}
-
-u16 __b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset)
+u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset)
 {
        u16 ret;
 
@@ -447,20 +448,7 @@ out:
        return ret;
 }
 
-u16 b43_shm_read16(struct b43_wldev *dev, u16 routing, u16 offset)
-{
-       struct b43_wl *wl = dev->wl;
-       unsigned long flags;
-       u16 ret;
-
-       spin_lock_irqsave(&wl->shm_lock, flags);
-       ret = __b43_shm_read16(dev, routing, offset);
-       spin_unlock_irqrestore(&wl->shm_lock, flags);
-
-       return ret;
-}
-
-void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
+void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
 {
        if (routing == B43_SHM_SHARED) {
                B43_WARN_ON(offset & 0x0001);
@@ -480,17 +468,7 @@ void __b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value
        b43_write32(dev, B43_MMIO_SHM_DATA, value);
 }
 
-void b43_shm_write32(struct b43_wldev *dev, u16 routing, u16 offset, u32 value)
-{
-       struct b43_wl *wl = dev->wl;
-       unsigned long flags;
-
-       spin_lock_irqsave(&wl->shm_lock, flags);
-       __b43_shm_write32(dev, routing, offset, value);
-       spin_unlock_irqrestore(&wl->shm_lock, flags);
-}
-
-void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
+void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
 {
        if (routing == B43_SHM_SHARED) {
                B43_WARN_ON(offset & 0x0001);
@@ -506,16 +484,6 @@ void __b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value
        b43_write16(dev, B43_MMIO_SHM_DATA, value);
 }
 
-void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
-{
-       struct b43_wl *wl = dev->wl;
-       unsigned long flags;
-
-       spin_lock_irqsave(&wl->shm_lock, flags);
-       __b43_shm_write16(dev, routing, offset, value);
-       spin_unlock_irqrestore(&wl->shm_lock, flags);
-}
-
 /* Read HostFlags */
 u64 b43_hf_read(struct b43_wldev *dev)
 {
@@ -876,8 +844,10 @@ static void rx_tkip_phase1_write(struct b43_wldev *dev, u8 index, u32 iv32,
 }
 
 static void b43_op_update_tkip_key(struct ieee80211_hw *hw,
-                       struct ieee80211_key_conf *keyconf, const u8 *addr,
-                       u32 iv32, u16 *phase1key)
+                                  struct ieee80211_vif *vif,
+                                  struct ieee80211_key_conf *keyconf,
+                                  struct ieee80211_sta *sta,
+                                  u32 iv32, u16 *phase1key)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev;
@@ -895,7 +865,10 @@ static void b43_op_update_tkip_key(struct ieee80211_hw *hw,
        keymac_write(dev, index, NULL); /* First zero out mac to avoid race */
 
        rx_tkip_phase1_write(dev, index, iv32, phase1key);
-       keymac_write(dev, index, addr);
+       /* only pairwise TKIP keys are supported right now */
+       if (WARN_ON(!sta))
+               goto out_unlock;
+       keymac_write(dev, index, sta->addr);
 
 out_unlock:
        mutex_unlock(&wl->mutex);
@@ -1633,7 +1606,7 @@ static void b43_beacon_update_trigger_work(struct work_struct *work)
        mutex_lock(&wl->mutex);
        dev = wl->current_dev;
        if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) {
-               if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) {
+               if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
                        /* wl->mutex is enough. */
                        b43_do_beacon_update_trigger_work(dev);
                        mmiowb();
@@ -1825,7 +1798,10 @@ static void b43_do_interrupt_thread(struct b43_wldev *dev)
                               dma_reason[0], dma_reason[1],
                               dma_reason[2], dma_reason[3],
                               dma_reason[4], dma_reason[5]);
-                       b43_controller_restart(dev, "DMA error");
+                       b43err(dev->wl, "This device does not support DMA "
+                              "on your system. Please use PIO instead.\n");
+                       b43err(dev->wl, "Unload the b43 module and reload "
+                              "with 'pio=1'\n");
                        return;
                }
                if (merged_dma_reason & B43_DMAIRQ_NONFATALMASK) {
@@ -1871,6 +1847,16 @@ static void b43_do_interrupt_thread(struct b43_wldev *dev)
 
        /* Re-enable interrupts on the device by restoring the current interrupt mask. */
        b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, dev->irq_mask);
+
+#if B43_DEBUG
+       if (b43_debug(dev, B43_DBG_VERBOSESTATS)) {
+               dev->irq_count++;
+               for (i = 0; i < ARRAY_SIZE(dev->irq_bit_count); i++) {
+                       if (reason & (1 << i))
+                               dev->irq_bit_count[i]++;
+               }
+       }
+#endif
 }
 
 /* Interrupt thread handler. Handles device interrupts in thread context. */
@@ -1951,6 +1937,21 @@ static irqreturn_t b43_interrupt_handler(int irq, void *dev_id)
        return ret;
 }
 
+/* SDIO interrupt handler. This runs in process context. */
+static void b43_sdio_interrupt_handler(struct b43_wldev *dev)
+{
+       struct b43_wl *wl = dev->wl;
+       irqreturn_t ret;
+
+       mutex_lock(&wl->mutex);
+
+       ret = b43_do_interrupt(dev);
+       if (ret == IRQ_WAKE_THREAD)
+               b43_do_interrupt_thread(dev);
+
+       mutex_unlock(&wl->mutex);
+}
+
 void b43_do_release_fw(struct b43_firmware_file *fw)
 {
        release_firmware(fw->data);
@@ -2335,11 +2336,7 @@ static int b43_upload_microcode(struct b43_wldev *dev)
                        err = -ENODEV;
                        goto error;
                }
-               msleep_interruptible(50);
-               if (signal_pending(current)) {
-                       err = -EINTR;
-                       goto error;
-               }
+               msleep(50);
        }
        b43_read32(dev, B43_MMIO_GEN_IRQ_REASON);       /* dummy read */
 
@@ -2695,6 +2692,20 @@ static void b43_adjust_opmode(struct b43_wldev *dev)
                        cfp_pretbtt = 50;
        }
        b43_write16(dev, 0x612, cfp_pretbtt);
+
+       /* FIXME: We don't currently implement the PMQ mechanism,
+        *        so always disable it. If we want to implement PMQ,
+        *        we need to enable it here (clear DISCPMQ) in AP mode.
+        */
+       if (0  /* ctl & B43_MACCTL_AP */) {
+               b43_write32(dev, B43_MMIO_MACCTL,
+                           b43_read32(dev, B43_MMIO_MACCTL)
+                           & ~B43_MACCTL_DISCPMQ);
+       } else {
+               b43_write32(dev, B43_MMIO_MACCTL,
+                           b43_read32(dev, B43_MMIO_MACCTL)
+                           | B43_MACCTL_DISCPMQ);
+       }
 }
 
 static void b43_rate_memory_write(struct b43_wldev *dev, u16 rate, int is_ofdm)
@@ -2923,6 +2934,27 @@ static void b43_periodic_every15sec(struct b43_wldev *dev)
 
        atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
        wmb();
+
+#if B43_DEBUG
+       if (b43_debug(dev, B43_DBG_VERBOSESTATS)) {
+               unsigned int i;
+
+               b43dbg(dev->wl, "Stats: %7u IRQs/sec, %7u TX/sec, %7u RX/sec\n",
+                      dev->irq_count / 15,
+                      dev->tx_count / 15,
+                      dev->rx_count / 15);
+               dev->irq_count = 0;
+               dev->tx_count = 0;
+               dev->rx_count = 0;
+               for (i = 0; i < ARRAY_SIZE(dev->irq_bit_count); i++) {
+                       if (dev->irq_bit_count[i]) {
+                               b43dbg(dev->wl, "Stats: %7u IRQ-%02u/sec (0x%08X)\n",
+                                      dev->irq_bit_count[i] / 15, i, (1 << i));
+                               dev->irq_bit_count[i] = 0;
+                       }
+               }
+       }
+#endif
 }
 
 static void do_periodic_work(struct b43_wldev *dev)
@@ -3052,14 +3084,18 @@ static void b43_security_init(struct b43_wldev *dev)
 static int b43_rng_read(struct hwrng *rng, u32 *data)
 {
        struct b43_wl *wl = (struct b43_wl *)rng->priv;
+       struct b43_wldev *dev;
+       int count = -ENODEV;
 
-       /* FIXME: We need to take wl->mutex here to make sure the device
-        * is not going away from under our ass. However it could deadlock
-        * with hwrng internal locking. */
-
-       *data = b43_read16(wl->current_dev, B43_MMIO_RNG);
+       mutex_lock(&wl->mutex);
+       dev = wl->current_dev;
+       if (likely(dev && b43_status(dev) >= B43_STAT_INITIALIZED)) {
+               *data = b43_read16(dev, B43_MMIO_RNG);
+               count = sizeof(u16);
+       }
+       mutex_unlock(&wl->mutex);
 
-       return (sizeof(u16));
+       return count;
 }
 #endif /* CONFIG_B43_HWRNG */
 
@@ -3118,6 +3154,9 @@ static void b43_tx_work(struct work_struct *work)
                        dev_kfree_skb(skb); /* Drop it */
        }
 
+#if B43_DEBUG
+       dev->tx_count++;
+#endif
        mutex_unlock(&wl->mutex);
 }
 
@@ -3139,7 +3178,6 @@ static int b43_op_tx(struct ieee80211_hw *hw,
        return NETDEV_TX_OK;
 }
 
-/* Locking: wl->irq_lock */
 static void b43_qos_params_upload(struct b43_wldev *dev,
                                  const struct ieee80211_tx_queue_params *p,
                                  u16 shm_offset)
@@ -3148,6 +3186,9 @@ static void b43_qos_params_upload(struct b43_wldev *dev,
        int bslots, tmp;
        unsigned int i;
 
+       if (!dev->qos_enabled)
+               return;
+
        bslots = b43_read16(dev, B43_MMIO_RNG) & p->cw_min;
 
        memset(&params, 0, sizeof(params));
@@ -3193,6 +3234,9 @@ static void b43_qos_upload_all(struct b43_wldev *dev)
        struct b43_qos_params *params;
        unsigned int i;
 
+       if (!dev->qos_enabled)
+               return;
+
        BUILD_BUG_ON(ARRAY_SIZE(b43_qos_shm_offsets) !=
                     ARRAY_SIZE(wl->qos_params));
 
@@ -3252,6 +3296,16 @@ static void b43_qos_clear(struct b43_wl *wl)
 /* Initialize the core's QOS capabilities */
 static void b43_qos_init(struct b43_wldev *dev)
 {
+       if (!dev->qos_enabled) {
+               /* Disable QOS support. */
+               b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_EDCF);
+               b43_write16(dev, B43_MMIO_IFSCTL,
+                           b43_read16(dev, B43_MMIO_IFSCTL)
+                           & ~B43_MMIO_IFSCTL_USE_EDCF);
+               b43dbg(dev->wl, "QoS disabled\n");
+               return;
+       }
+
        /* Upload the current QOS parameters. */
        b43_qos_upload_all(dev);
 
@@ -3260,6 +3314,7 @@ static void b43_qos_init(struct b43_wldev *dev)
        b43_write16(dev, B43_MMIO_IFSCTL,
                    b43_read16(dev, B43_MMIO_IFSCTL)
                    | B43_MMIO_IFSCTL_USE_EDCF);
+       b43dbg(dev->wl, "QoS enabled\n");
 }
 
 static int b43_op_conf_tx(struct ieee80211_hw *hw, u16 _queue,
@@ -3535,7 +3590,7 @@ static int b43_op_config(struct ieee80211_hw *hw, u32 changed)
        if (conf->channel->hw_value != phy->channel)
                b43_switch_channel(dev, conf->channel->hw_value);
 
-       dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_RADIOTAP);
+       dev->wl->radiotap_enabled = !!(conf->flags & IEEE80211_CONF_MONITOR);
 
        /* Adjust the desired TX power level. */
        if (conf->power_level != 0) {
@@ -3836,6 +3891,7 @@ static struct b43_wldev * b43_wireless_core_stop(struct b43_wldev *dev)
 {
        struct b43_wl *wl = dev->wl;
        struct b43_wldev *orig_dev;
+       u32 mask;
 
 redo:
        if (!dev || b43_status(dev) < B43_STAT_STARTED)
@@ -3854,7 +3910,7 @@ redo:
 
        /* Disable interrupts on the device. */
        b43_set_status(dev, B43_STAT_INITIALIZED);
-       if (0 /*FIXME dev->dev->bus->bustype == SSB_BUSTYPE_SDIO*/) {
+       if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
                /* wl->mutex is locked. That is enough. */
                b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
                b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */
@@ -3864,10 +3920,15 @@ redo:
                b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */
                spin_unlock_irq(&wl->hardirq_lock);
        }
-       /* Synchronize the interrupt handlers. Unlock to avoid deadlocks. */
+       /* Synchronize and free the interrupt handlers. Unlock to avoid deadlocks. */
        orig_dev = dev;
        mutex_unlock(&wl->mutex);
-       synchronize_irq(dev->dev->irq);
+       if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
+               b43_sdio_free_irq(dev);
+       } else {
+               synchronize_irq(dev->dev->irq);
+               free_irq(dev->dev->irq, dev);
+       }
        mutex_lock(&wl->mutex);
        dev = wl->current_dev;
        if (!dev)
@@ -3877,15 +3938,15 @@ redo:
                        goto redo;
                return dev;
        }
-       B43_WARN_ON(b43_read32(dev, B43_MMIO_GEN_IRQ_MASK));
+       mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
+       B43_WARN_ON(mask != 0xFFFFFFFF && mask);
 
        /* Drain the TX queue */
        while (skb_queue_len(&wl->tx_queue))
                dev_kfree_skb(skb_dequeue(&wl->tx_queue));
 
-       b43_pio_stop(dev);
        b43_mac_suspend(dev);
-       free_irq(dev->dev->irq, dev);
+       b43_leds_exit(dev);
        b43dbg(wl, "Wireless interface stopped\n");
 
        return dev;
@@ -3899,12 +3960,20 @@ static int b43_wireless_core_start(struct b43_wldev *dev)
        B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED);
 
        drain_txstatus_queue(dev);
-       err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler,
-                                  b43_interrupt_thread_handler,
-                                  IRQF_SHARED, KBUILD_MODNAME, dev);
-       if (err) {
-               b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq);
-               goto out;
+       if (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) {
+               err = b43_sdio_request_irq(dev, b43_sdio_interrupt_handler);
+               if (err) {
+                       b43err(dev->wl, "Cannot request SDIO IRQ\n");
+                       goto out;
+               }
+       } else {
+               err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler,
+                                          b43_interrupt_thread_handler,
+                                          IRQF_SHARED, KBUILD_MODNAME, dev);
+               if (err) {
+                       b43err(dev->wl, "Cannot request IRQ-%d\n", dev->dev->irq);
+                       goto out;
+               }
        }
 
        /* We are ready to run. */
@@ -3917,8 +3986,10 @@ static int b43_wireless_core_start(struct b43_wldev *dev)
        /* Start maintainance work */
        b43_periodic_tasks_setup(dev);
 
+       b43_leds_init(dev);
+
        b43dbg(dev->wl, "Wireless interface started\n");
-      out:
+out:
        return err;
 }
 
@@ -4123,16 +4194,20 @@ static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
            bus->pcicore.dev->id.revision <= 5) {
                /* IMCFGLO timeouts workaround. */
                tmp = ssb_read32(dev->dev, SSB_IMCFGLO);
-               tmp &= ~SSB_IMCFGLO_REQTO;
-               tmp &= ~SSB_IMCFGLO_SERTO;
                switch (bus->bustype) {
                case SSB_BUSTYPE_PCI:
                case SSB_BUSTYPE_PCMCIA:
+                       tmp &= ~SSB_IMCFGLO_REQTO;
+                       tmp &= ~SSB_IMCFGLO_SERTO;
                        tmp |= 0x32;
                        break;
                case SSB_BUSTYPE_SSB:
+                       tmp &= ~SSB_IMCFGLO_REQTO;
+                       tmp &= ~SSB_IMCFGLO_SERTO;
                        tmp |= 0x53;
                        break;
+               default:
+                       break;
                }
                ssb_write32(dev->dev, SSB_IMCFGLO, tmp);
        }
@@ -4191,10 +4266,6 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
        macctl |= B43_MACCTL_PSM_JMP0;
        b43_write32(dev, B43_MMIO_MACCTL, macctl);
 
-       if (!dev->suspend_in_progress) {
-               b43_leds_exit(dev);
-               b43_rng_exit(dev->wl);
-       }
        b43_dma_free(dev);
        b43_pio_free(dev);
        b43_chip_exit(dev);
@@ -4211,7 +4282,6 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
 /* Initialize a wireless core */
 static int b43_wireless_core_init(struct b43_wldev *dev)
 {
-       struct b43_wl *wl = dev->wl;
        struct ssb_bus *bus = dev->dev->bus;
        struct ssb_sprom *sprom = &bus->sprom;
        struct b43_phy *phy = &dev->phy;
@@ -4295,7 +4365,9 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        /* Maximum Contention Window */
        b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
 
-       if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) || B43_FORCE_PIO) {
+       if ((dev->dev->bus->bustype == SSB_BUSTYPE_PCMCIA) ||
+           (dev->dev->bus->bustype == SSB_BUSTYPE_SDIO) ||
+           modparam_pio) {
                dev->__using_pio_transfers = 1;
                err = b43_pio_init(dev);
        } else {
@@ -4311,13 +4383,13 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        ssb_bus_powerup(bus, !(sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW));
        b43_upload_card_macaddress(dev);
        b43_security_init(dev);
-       if (!dev->suspend_in_progress)
-               b43_rng_init(wl);
+
+       ieee80211_wake_queues(dev->wl->hw);
+
+       ieee80211_wake_queues(dev->wl->hw);
 
        b43_set_status(dev, B43_STAT_INITIALIZED);
 
-       if (!dev->suspend_in_progress)
-               b43_leds_init(dev);
 out:
        return err;
 
@@ -4330,7 +4402,7 @@ err_busdown:
 }
 
 static int b43_op_add_interface(struct ieee80211_hw *hw,
-                               struct ieee80211_if_init_conf *conf)
+                               struct ieee80211_vif *vif)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev;
@@ -4338,24 +4410,24 @@ static int b43_op_add_interface(struct ieee80211_hw *hw,
 
        /* TODO: allow WDS/AP devices to coexist */
 
-       if (conf->type != NL80211_IFTYPE_AP &&
-           conf->type != NL80211_IFTYPE_MESH_POINT &&
-           conf->type != NL80211_IFTYPE_STATION &&
-           conf->type != NL80211_IFTYPE_WDS &&
-           conf->type != NL80211_IFTYPE_ADHOC)
+       if (vif->type != NL80211_IFTYPE_AP &&
+           vif->type != NL80211_IFTYPE_MESH_POINT &&
+           vif->type != NL80211_IFTYPE_STATION &&
+           vif->type != NL80211_IFTYPE_WDS &&
+           vif->type != NL80211_IFTYPE_ADHOC)
                return -EOPNOTSUPP;
 
        mutex_lock(&wl->mutex);
        if (wl->operating)
                goto out_mutex_unlock;
 
-       b43dbg(wl, "Adding Interface type %d\n", conf->type);
+       b43dbg(wl, "Adding Interface type %d\n", vif->type);
 
        dev = wl->current_dev;
        wl->operating = 1;
-       wl->vif = conf->vif;
-       wl->if_type = conf->type;
-       memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
+       wl->vif = vif;
+       wl->if_type = vif->type;
+       memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
 
        b43_adjust_opmode(dev);
        b43_set_pretbtt(dev);
@@ -4370,17 +4442,17 @@ static int b43_op_add_interface(struct ieee80211_hw *hw,
 }
 
 static void b43_op_remove_interface(struct ieee80211_hw *hw,
-                                   struct ieee80211_if_init_conf *conf)
+                                   struct ieee80211_vif *vif)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
 
-       b43dbg(wl, "Removing Interface type %d\n", conf->type);
+       b43dbg(wl, "Removing Interface type %d\n", vif->type);
 
        mutex_lock(&wl->mutex);
 
        B43_WARN_ON(!wl->operating);
-       B43_WARN_ON(wl->vif != conf->vif);
+       B43_WARN_ON(wl->vif != vif);
        wl->vif = NULL;
 
        wl->operating = 0;
@@ -4466,9 +4538,8 @@ static int b43_op_beacon_set_tim(struct ieee80211_hw *hw,
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
 
-       mutex_lock(&wl->mutex);
+       /* FIXME: add locking */
        b43_update_templates(wl);
-       mutex_unlock(&wl->mutex);
 
        return 0;
 }
@@ -4615,7 +4686,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
 {
        struct b43_wl *wl = dev->wl;
        struct ssb_bus *bus = dev->dev->bus;
-       struct pci_dev *pdev = bus->host_pci;
+       struct pci_dev *pdev = (bus->bustype == SSB_BUSTYPE_PCI) ? bus->host_pci : NULL;
        int err;
        bool have_2ghz_phy = 0, have_5ghz_phy = 0;
        u32 tmp;
@@ -4748,7 +4819,7 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
 
        if (!list_empty(&wl->devlist)) {
                /* We are not the first core on this chip. */
-               pdev = dev->bus->host_pci;
+               pdev = (dev->bus->bustype == SSB_BUSTYPE_PCI) ? dev->bus->host_pci : NULL;
                /* Only special chips support more than one wireless
                 * core, although some of the other chips have more than
                 * one wireless core as well. Check for this and
@@ -4866,8 +4937,6 @@ static int b43_wireless_init(struct ssb_device *dev)
 
        /* Initialize struct b43_wl */
        wl->hw = hw;
-       spin_lock_init(&wl->leds_lock);
-       spin_lock_init(&wl->shm_lock);
        mutex_init(&wl->mutex);
        spin_lock_init(&wl->hardirq_lock);
        INIT_LIST_HEAD(&wl->devlist);
@@ -4908,6 +4977,8 @@ static int b43_probe(struct ssb_device *dev, const struct ssb_device_id *id)
                err = ieee80211_register_hw(wl->hw);
                if (err)
                        goto err_one_core_detach;
+               b43_leds_register(wl->current_dev);
+               b43_rng_init(wl);
        }
 
       out:
@@ -4936,12 +5007,15 @@ static void b43_remove(struct ssb_device *dev)
                 * might have modified it. Restoring is important, so the networking
                 * stack can properly free resources. */
                wl->hw->queues = wl->mac80211_initially_registered_queues;
+               b43_leds_stop(wldev);
                ieee80211_unregister_hw(wl->hw);
        }
 
        b43_one_core_detach(dev);
 
        if (list_empty(&wl->devlist)) {
+               b43_rng_exit(wl);
+               b43_leds_unregister(wl);
                /* Last core on the chip unregistered.
                 * We can destroy common struct b43_wl.
                 */
@@ -4959,80 +5033,17 @@ void b43_controller_restart(struct b43_wldev *dev, const char *reason)
        ieee80211_queue_work(dev->wl->hw, &dev->restart_work);
 }
 
-#ifdef CONFIG_PM
-
-static int b43_suspend(struct ssb_device *dev, pm_message_t state)
-{
-       struct b43_wldev *wldev = ssb_get_drvdata(dev);
-       struct b43_wl *wl = wldev->wl;
-
-       b43dbg(wl, "Suspending...\n");
-
-       mutex_lock(&wl->mutex);
-       wldev->suspend_in_progress = true;
-       wldev->suspend_init_status = b43_status(wldev);
-       if (wldev->suspend_init_status >= B43_STAT_STARTED)
-               wldev = b43_wireless_core_stop(wldev);
-       if (wldev && wldev->suspend_init_status >= B43_STAT_INITIALIZED)
-               b43_wireless_core_exit(wldev);
-       mutex_unlock(&wl->mutex);
-
-       b43dbg(wl, "Device suspended.\n");
-
-       return 0;
-}
-
-static int b43_resume(struct ssb_device *dev)
-{
-       struct b43_wldev *wldev = ssb_get_drvdata(dev);
-       struct b43_wl *wl = wldev->wl;
-       int err = 0;
-
-       b43dbg(wl, "Resuming...\n");
-
-       mutex_lock(&wl->mutex);
-       if (wldev->suspend_init_status >= B43_STAT_INITIALIZED) {
-               err = b43_wireless_core_init(wldev);
-               if (err) {
-                       b43err(wl, "Resume failed at core init\n");
-                       goto out;
-               }
-       }
-       if (wldev->suspend_init_status >= B43_STAT_STARTED) {
-               err = b43_wireless_core_start(wldev);
-               if (err) {
-                       b43_leds_exit(wldev);
-                       b43_rng_exit(wldev->wl);
-                       b43_wireless_core_exit(wldev);
-                       b43err(wl, "Resume failed at core start\n");
-                       goto out;
-               }
-       }
-       b43dbg(wl, "Device resumed.\n");
- out:
-       wldev->suspend_in_progress = false;
-       mutex_unlock(&wl->mutex);
-       return err;
-}
-
-#else /* CONFIG_PM */
-# define b43_suspend   NULL
-# define b43_resume    NULL
-#endif /* CONFIG_PM */
-
 static struct ssb_driver b43_ssb_driver = {
        .name           = KBUILD_MODNAME,
        .id_table       = b43_ssb_tbl,
        .probe          = b43_probe,
        .remove         = b43_remove,
-       .suspend        = b43_suspend,
-       .resume         = b43_resume,
 };
 
 static void b43_print_driverinfo(void)
 {
        const char *feat_pci = "", *feat_pcmcia = "", *feat_nphy = "",
-                  *feat_leds = "";
+                  *feat_leds = "", *feat_sdio = "";
 
 #ifdef CONFIG_B43_PCI_AUTOSELECT
        feat_pci = "P";
@@ -5046,11 +5057,14 @@ static void b43_print_driverinfo(void)
 #ifdef CONFIG_B43_LEDS
        feat_leds = "L";
 #endif
+#ifdef CONFIG_B43_SDIO
+       feat_sdio = "S";
+#endif
        printk(KERN_INFO "Broadcom 43xx driver loaded "
-              "[ Features: %s%s%s%s, Firmware-ID: "
+              "[ Features: %s%s%s%s%s, Firmware-ID: "
               B43_SUPPORTED_FIRMWARE_ID " ]\n",
               feat_pci, feat_pcmcia, feat_nphy,
-              feat_leds);
+              feat_leds, feat_sdio);
 }
 
 static int __init b43_init(void)
@@ -5061,13 +5075,18 @@ static int __init b43_init(void)
        err = b43_pcmcia_init();
        if (err)
                goto err_dfs_exit;
-       err = ssb_driver_register(&b43_ssb_driver);
+       err = b43_sdio_init();
        if (err)
                goto err_pcmcia_exit;
+       err = ssb_driver_register(&b43_ssb_driver);
+       if (err)
+               goto err_sdio_exit;
        b43_print_driverinfo();
 
        return err;
 
+err_sdio_exit:
+       b43_sdio_exit();
 err_pcmcia_exit:
        b43_pcmcia_exit();
 err_dfs_exit:
@@ -5078,6 +5097,7 @@ err_dfs_exit:
 static void __exit b43_exit(void)
 {
        ssb_driver_unregister(&b43_ssb_driver);
+       b43_sdio_exit();
        b43_pcmcia_exit();
        b43_debugfs_exit();
 }