]> err.no Git - linux-2.6/blobdiff - drivers/net/wireless/b43legacy/main.c
b43legacy: LED triggers support
[linux-2.6] / drivers / net / wireless / b43legacy / main.c
index 61b94218094bbb61cbcb18156f089758ebc3cf2b..43edd08297a473b81bfe3d1be06c3aeca0c68693 100644 (file)
@@ -83,22 +83,10 @@ static int modparam_long_retry = B43legacy_DEFAULT_LONG_RETRY_LIMIT;
 module_param_named(long_retry, modparam_long_retry, int, 0444);
 MODULE_PARM_DESC(long_retry, "Long-Retry-Limit (0 - 15)");
 
-static int modparam_noleds;
-module_param_named(noleds, modparam_noleds, int, 0444);
-MODULE_PARM_DESC(noleds, "Turn off all LED activity");
-
 static char modparam_fwpostfix[16];
 module_param_string(fwpostfix, modparam_fwpostfix, 16, 0444);
 MODULE_PARM_DESC(fwpostfix, "Postfix for the firmware files to load.");
 
-static int modparam_mon_keep_bad;
-module_param_named(mon_keep_bad, modparam_mon_keep_bad, int, 0444);
-MODULE_PARM_DESC(mon_keep_bad, "Keep bad frames in monitor mode");
-
-static int modparam_mon_keep_badplcp;
-module_param_named(mon_keep_badplcp, modparam_mon_keep_bad, int, 0444);
-MODULE_PARM_DESC(mon_keep_badplcp, "Keep frames with bad PLCP in monitor mode");
-
 /* The following table supports BCM4301, BCM4303 and BCM4306/2 devices. */
 static const struct ssb_device_id b43legacy_ssb_tbl[] = {
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 2),
@@ -566,12 +554,11 @@ static void b43legacy_write_mac_bssid_templates(struct b43legacy_wldev *dev)
        }
 }
 
-static void b43legacy_upload_card_macaddress(struct b43legacy_wldev *dev,
-                                            const u8 *mac_addr)
+static void b43legacy_upload_card_macaddress(struct b43legacy_wldev *dev)
 {
-       dev->wl->mac_addr = mac_addr;
        b43legacy_write_mac_bssid_templates(dev);
-       b43legacy_macfilter_set(dev, B43legacy_MACFILTER_SELF, mac_addr);
+       b43legacy_macfilter_set(dev, B43legacy_MACFILTER_SELF,
+                               dev->wl->mac_addr);
 }
 
 static void b43legacy_set_slot_time(struct b43legacy_wldev *dev,
@@ -1226,7 +1213,6 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev)
        u32 dma_reason[ARRAY_SIZE(dev->dma_reason)];
        u32 merged_dma_reason = 0;
        int i;
-       int activity = 0;
        unsigned long flags;
 
        spin_lock_irqsave(&dev->wl->irq_lock, flags);
@@ -1290,7 +1276,6 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev)
                        b43legacy_pio_rx(dev->pio.queue0);
                else
                        b43legacy_dma_rx(dev->dma.rx_ring0);
-               /* We intentionally don't set "activity" to 1, here. */
        }
        B43legacy_WARN_ON(dma_reason[1] & B43legacy_DMAIRQ_RX_DONE);
        B43legacy_WARN_ON(dma_reason[2] & B43legacy_DMAIRQ_RX_DONE);
@@ -1299,20 +1284,13 @@ static void b43legacy_interrupt_tasklet(struct b43legacy_wldev *dev)
                        b43legacy_pio_rx(dev->pio.queue3);
                else
                        b43legacy_dma_rx(dev->dma.rx_ring3);
-               activity = 1;
        }
        B43legacy_WARN_ON(dma_reason[4] & B43legacy_DMAIRQ_RX_DONE);
        B43legacy_WARN_ON(dma_reason[5] & B43legacy_DMAIRQ_RX_DONE);
 
-       if (reason & B43legacy_IRQ_TX_OK) {
+       if (reason & B43legacy_IRQ_TX_OK)
                handle_irq_transmit_status(dev);
-               activity = 1;
-               /* TODO: In AP mode, this also causes sending of powersave
-                        responses. */
-       }
 
-       if (!modparam_noleds)
-               b43legacy_leds_update(dev, activity);
        b43legacy_interrupt_enable(dev, dev->irq_savedstate);
        mmiowb();
        spin_unlock_irqrestore(&dev->wl->irq_lock, flags);
@@ -1428,7 +1406,7 @@ static void b43legacy_release_firmware(struct b43legacy_wldev *dev)
 static void b43legacy_print_fw_helptext(struct b43legacy_wl *wl)
 {
        b43legacyerr(wl, "You must go to http://linuxwireless.org/en/users/"
-                    "Drivers/bcm43xx#devicefirmware "
+                    "Drivers/b43#devicefirmware "
                     "and download the correct firmware (version 3).\n");
 }
 
@@ -1764,7 +1742,6 @@ static int b43legacy_gpio_init(struct b43legacy_wldev *dev)
                          B43legacy_MMIO_STATUS_BITFIELD)
                          & 0xFFFF3FFF);
 
-       b43legacy_leds_switch_all(dev, 0);
        b43legacy_write16(dev, B43legacy_MMIO_GPIO_MASK,
                          b43legacy_read16(dev,
                          B43legacy_MMIO_GPIO_MASK)
@@ -1874,34 +1851,25 @@ static void b43legacy_adjust_opmode(struct b43legacy_wldev *dev)
        ctl &= ~B43legacy_MACCTL_KEEP_BADPLCP;
        ctl &= ~B43legacy_MACCTL_KEEP_BAD;
        ctl &= ~B43legacy_MACCTL_PROMISC;
+       ctl &= ~B43legacy_MACCTL_BEACPROMISC;
        ctl |= B43legacy_MACCTL_INFRA;
 
-       if (wl->operating) {
-               switch (wl->if_type) {
-               case IEEE80211_IF_TYPE_AP:
-                       ctl |= B43legacy_MACCTL_AP;
-                       break;
-               case IEEE80211_IF_TYPE_IBSS:
-                       ctl &= ~B43legacy_MACCTL_INFRA;
-                       break;
-               case IEEE80211_IF_TYPE_STA:
-               case IEEE80211_IF_TYPE_MNTR:
-               case IEEE80211_IF_TYPE_WDS:
-                       break;
-               default:
-                       b43legacyerr(wl, "Improper value of %d for"
-                                    " wl->if_type\n", wl->if_type);
-               }
-       }
-       if (wl->monitor) {
+       if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP))
+               ctl |= B43legacy_MACCTL_AP;
+       else if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_IBSS))
+               ctl &= ~B43legacy_MACCTL_INFRA;
+
+       if (wl->filter_flags & FIF_CONTROL)
                ctl |= B43legacy_MACCTL_KEEP_CTL;
-               if (modparam_mon_keep_bad)
-                       ctl |= B43legacy_MACCTL_KEEP_BAD;
-               if (modparam_mon_keep_badplcp)
-                       ctl |= B43legacy_MACCTL_KEEP_BADPLCP;
-       }
-       if (wl->promisc)
+       if (wl->filter_flags & FIF_FCSFAIL)
+               ctl |= B43legacy_MACCTL_KEEP_BAD;
+       if (wl->filter_flags & FIF_PLCPFAIL)
+               ctl |= B43legacy_MACCTL_KEEP_BADPLCP;
+       if (wl->filter_flags & FIF_PROMISC_IN_BSS)
                ctl |= B43legacy_MACCTL_PROMISC;
+       if (wl->filter_flags & FIF_BCN_PRBRESP_PROMISC)
+               ctl |= B43legacy_MACCTL_BEACPROMISC;
+
        /* Workaround: On old hardware the HW-MAC-address-filter
         * doesn't work properly, so always run promisc in filter
         * it in software. */
@@ -2007,12 +1975,26 @@ static void b43legacy_mgmtframe_txantenna(struct b43legacy_wldev *dev,
                              B43legacy_SHM_SH_PRPHYCTL, tmp);
 }
 
+/* Returns TRUE, if the radio is enabled in hardware. */
+static bool b43legacy_is_hw_radio_enabled(struct b43legacy_wldev *dev)
+{
+       if (dev->phy.rev >= 3) {
+               if (!(b43legacy_read32(dev, B43legacy_MMIO_RADIO_HWENABLED_HI)
+                     & B43legacy_MMIO_RADIO_HWENABLED_HI_MASK))
+                       return 1;
+       } else {
+               if (b43legacy_read16(dev, B43legacy_MMIO_RADIO_HWENABLED_LO)
+                   & B43legacy_MMIO_RADIO_HWENABLED_LO_MASK)
+                       return 1;
+       }
+       return 0;
+}
+
 /* This is the opposite of b43legacy_chip_init() */
 static void b43legacy_chip_exit(struct b43legacy_wldev *dev)
 {
        b43legacy_radio_turn_off(dev);
-       if (!modparam_noleds)
-               b43legacy_leds_exit(dev);
+       b43legacy_leds_exit(dev);
        b43legacy_gpio_cleanup(dev);
        /* firmware is released later */
 }
@@ -2042,13 +2024,12 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev)
        err = b43legacy_gpio_init(dev);
        if (err)
                goto out; /* firmware is released later */
+       b43legacy_leds_init(dev);
+
        err = b43legacy_upload_initvals(dev);
        if (err)
-               goto err_gpio_cleanup;
+               goto err_leds_exit;
        b43legacy_radio_turn_on(dev);
-       dev->radio_hw_enable = b43legacy_is_hw_radio_enabled(dev);
-       b43legacyinfo(dev->wl, "Radio %s by hardware\n",
-              (dev->radio_hw_enable == 0) ? "disabled" : "enabled");
 
        b43legacy_write16(dev, 0x03E6, 0x0000);
        err = b43legacy_phy_init(dev);
@@ -2079,10 +2060,6 @@ static int b43legacy_chip_init(struct b43legacy_wldev *dev)
        value32 |= B43legacy_SBF_MODE_NOTADHOC;
        b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32);
 
-       value32 = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);
-       value32 |= 0x100000;
-       b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, value32);
-
        if (b43legacy_using_pio(dev)) {
                b43legacy_write32(dev, 0x0210, 0x00000100);
                b43legacy_write32(dev, 0x0230, 0x00000100);
@@ -2130,7 +2107,8 @@ out:
 
 err_radio_off:
        b43legacy_radio_turn_off(dev);
-err_gpio_cleanup:
+err_leds_exit:
+       b43legacy_leds_exit(dev);
        b43legacy_gpio_cleanup(dev);
        goto out;
 }
@@ -2170,15 +2148,14 @@ static void b43legacy_periodic_every15sec(struct b43legacy_wldev *dev)
 
 static void b43legacy_periodic_every1sec(struct b43legacy_wldev *dev)
 {
-       int radio_hw_enable;
+       bool radio_hw_enable;
 
        /* check if radio hardware enabled status changed */
        radio_hw_enable = b43legacy_is_hw_radio_enabled(dev);
        if (unlikely(dev->radio_hw_enable != radio_hw_enable)) {
                dev->radio_hw_enable = radio_hw_enable;
                b43legacyinfo(dev->wl, "Radio hardware status changed to %s\n",
-                      (radio_hw_enable == 0) ? "disabled" : "enabled");
-               b43legacy_leds_update(dev, 0);
+                      (radio_hw_enable) ? "enabled" : "disabled");
        }
 }
 
@@ -2270,7 +2247,7 @@ out_requeue:
        if (b43legacy_debug(dev, B43legacy_DBG_PWORK_FAST))
                delay = msecs_to_jiffies(50);
        else
-               delay = round_jiffies(HZ);
+               delay = round_jiffies_relative(HZ);
        queue_delayed_work(dev->wl->hw->workqueue,
                           &dev->periodic_work, delay);
 out:
@@ -2660,6 +2637,22 @@ static int b43legacy_dev_config(struct ieee80211_hw *hw,
                b43legacy_set_beacon_int(dev, conf->beacon_int);
 
 
+       if (!!conf->radio_enabled != phy->radio_on) {
+               if (conf->radio_enabled) {
+                       b43legacy_radio_turn_on(dev);
+                       b43legacyinfo(dev->wl, "Radio turned on by software\n");
+                       if (!dev->radio_hw_enable)
+                               b43legacyinfo(dev->wl, "The hardware RF-kill"
+                                             " button still turns the radio"
+                                             " physically off. Press the"
+                                             " button to turn it on.\n");
+               } else {
+                       b43legacy_radio_turn_off(dev);
+                       b43legacyinfo(dev->wl, "Radio turned off by"
+                                     " software\n");
+               }
+       }
+
        spin_lock_irqsave(&wl->irq_lock, flags);
        b43legacy_interrupt_enable(dev, savedirqs);
        mmiowb();
@@ -2671,7 +2664,7 @@ out_unlock_mutex:
 }
 
 static int b43legacy_dev_set_key(struct ieee80211_hw *hw,
-                                set_key_cmd cmd,
+                                enum set_key_cmd cmd,
                                 const u8 *local_addr, const u8 *addr,
                                 struct ieee80211_key_conf *key)
 {
@@ -2696,22 +2689,42 @@ static int b43legacy_dev_set_key(struct ieee80211_hw *hw,
        return err;
 }
 
-static void b43legacy_set_multicast_list(struct ieee80211_hw *hw,
-                                        unsigned short netflags,
-                                        int mc_count)
+static void b43legacy_configure_filter(struct ieee80211_hw *hw,
+                                      unsigned int changed,
+                                      unsigned int *fflags,
+                                      int mc_count,
+                                      struct dev_addr_list *mc_list)
 {
        struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
        struct b43legacy_wldev *dev = wl->current_dev;
        unsigned long flags;
 
-       if (!dev)
+       if (!dev) {
+               *fflags = 0;
                return;
-       spin_lock_irqsave(&wl->irq_lock, flags);
-       if (wl->promisc != !!(netflags & IFF_PROMISC)) {
-               wl->promisc = !!(netflags & IFF_PROMISC);
-               if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED)
-                       b43legacy_adjust_opmode(dev);
        }
+
+       spin_lock_irqsave(&wl->irq_lock, flags);
+       *fflags &= FIF_PROMISC_IN_BSS |
+                 FIF_ALLMULTI |
+                 FIF_FCSFAIL |
+                 FIF_PLCPFAIL |
+                 FIF_CONTROL |
+                 FIF_OTHER_BSS |
+                 FIF_BCN_PRBRESP_PROMISC;
+
+       changed &= FIF_PROMISC_IN_BSS |
+                  FIF_ALLMULTI |
+                  FIF_FCSFAIL |
+                  FIF_PLCPFAIL |
+                  FIF_CONTROL |
+                  FIF_OTHER_BSS |
+                  FIF_BCN_PRBRESP_PROMISC;
+
+       wl->filter_flags = *fflags;
+
+       if (changed && b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED)
+               b43legacy_adjust_opmode(dev);
        spin_unlock_irqrestore(&wl->irq_lock, flags);
 }
 
@@ -2727,21 +2740,19 @@ static int b43legacy_config_interface(struct ieee80211_hw *hw,
                return -ENODEV;
        mutex_lock(&wl->mutex);
        spin_lock_irqsave(&wl->irq_lock, flags);
-       if (conf->type != IEEE80211_IF_TYPE_MNTR) {
-               B43legacy_WARN_ON(wl->if_id != if_id);
-               wl->bssid = conf->bssid;
-               if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
-                       if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
-                               B43legacy_WARN_ON(conf->type !=
-                                                 IEEE80211_IF_TYPE_AP);
-                               b43legacy_set_ssid(dev, conf->ssid,
-                                                  conf->ssid_len);
-                               if (conf->beacon)
-                                       b43legacy_refresh_templates(dev,
-                                                                conf->beacon);
-                       }
-                       b43legacy_write_mac_bssid_templates(dev);
+       B43legacy_WARN_ON(wl->if_id != if_id);
+       if (conf->bssid)
+               memcpy(wl->bssid, conf->bssid, ETH_ALEN);
+       else
+               memset(wl->bssid, 0, ETH_ALEN);
+       if (b43legacy_status(dev) >= B43legacy_STAT_INITIALIZED) {
+               if (b43legacy_is_mode(wl, IEEE80211_IF_TYPE_AP)) {
+                       B43legacy_WARN_ON(conf->type != IEEE80211_IF_TYPE_AP);
+                       b43legacy_set_ssid(dev, conf->ssid, conf->ssid_len);
+                       if (conf->beacon)
+                               b43legacy_refresh_templates(dev, conf->beacon);
                }
+               b43legacy_write_mac_bssid_templates(dev);
        }
        spin_unlock_irqrestore(&wl->irq_lock, flags);
        mutex_unlock(&wl->mutex);
@@ -2757,6 +2768,17 @@ static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev)
 
        if (b43legacy_status(dev) < B43legacy_STAT_STARTED)
                return;
+
+       /* Disable and sync interrupts. We must do this before than
+        * setting the status to INITIALIZED, as the interrupt handler
+        * won't care about IRQs then. */
+       spin_lock_irqsave(&wl->irq_lock, flags);
+       dev->irq_savedstate = b43legacy_interrupt_disable(dev,
+                                                         B43legacy_IRQ_ALL);
+       b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); /* flush */
+       spin_unlock_irqrestore(&wl->irq_lock, flags);
+       b43legacy_synchronize_irq(dev);
+
        b43legacy_set_status(dev, B43legacy_STAT_INITIALIZED);
 
        mutex_unlock(&wl->mutex);
@@ -2767,14 +2789,6 @@ static void b43legacy_wireless_core_stop(struct b43legacy_wldev *dev)
 
        ieee80211_stop_queues(wl->hw); /* FIXME this could cause a deadlock */
 
-       /* Disable and sync interrupts. */
-       spin_lock_irqsave(&wl->irq_lock, flags);
-       dev->irq_savedstate = b43legacy_interrupt_disable(dev,
-                                                         B43legacy_IRQ_ALL);
-       b43legacy_read32(dev, B43legacy_MMIO_GEN_IRQ_MASK); /* flush */
-       spin_unlock_irqrestore(&wl->irq_lock, flags);
-       b43legacy_synchronize_irq(dev);
-
        b43legacy_mac_suspend(dev);
        free_irq(dev->dev->irq, dev);
        b43legacydbg(wl, "Wireless interface stopped\n");
@@ -2917,6 +2931,9 @@ static void setup_struct_phy_for_init(struct b43legacy_wldev *dev,
 
        /* Flags */
        phy->locked = 0;
+       /* Assume the radio is enabled. If it's not enabled, the state will
+        * immediately get fixed on the first periodic work run. */
+       dev->radio_hw_enable = 1;
 
        phy->savedpctlreg = 0xFFFF;
        phy->aci_enable = 0;
@@ -3185,8 +3202,9 @@ static int b43legacy_wireless_core_init(struct b43legacy_wldev *dev)
        b43legacy_shm_write16(dev, B43legacy_SHM_SHARED, 0x0414, 0x01F4);
 
        ssb_bus_powerup(bus, 1); /* Enable dynamic PCTL */
-       wl->bssid = NULL;
-       b43legacy_upload_card_macaddress(dev, NULL);
+       memset(wl->bssid, 0, ETH_ALEN);
+       memset(wl->mac_addr, 0, ETH_ALEN);
+       b43legacy_upload_card_macaddress(dev);
        b43legacy_security_init(dev);
        b43legacy_rng_init(wl);
 
@@ -3215,22 +3233,80 @@ static int b43legacy_add_interface(struct ieee80211_hw *hw,
        struct b43legacy_wldev *dev;
        unsigned long flags;
        int err = -EOPNOTSUPP;
-       int did_init = 0;
+
+       /* TODO: allow WDS/AP devices to coexist */
+
+       if (conf->type != IEEE80211_IF_TYPE_AP &&
+           conf->type != IEEE80211_IF_TYPE_STA &&
+           conf->type != IEEE80211_IF_TYPE_WDS &&
+           conf->type != IEEE80211_IF_TYPE_IBSS)
+               return -EOPNOTSUPP;
 
        mutex_lock(&wl->mutex);
-       if ((conf->type != IEEE80211_IF_TYPE_MNTR) &&
-           wl->operating)
+       if (wl->operating)
                goto out_mutex_unlock;
 
        b43legacydbg(wl, "Adding Interface type %d\n", conf->type);
 
        dev = wl->current_dev;
+       wl->operating = 1;
+       wl->if_id = conf->if_id;
+       wl->if_type = conf->type;
+       memcpy(wl->mac_addr, conf->mac_addr, ETH_ALEN);
+
+       spin_lock_irqsave(&wl->irq_lock, flags);
+       b43legacy_adjust_opmode(dev);
+       b43legacy_upload_card_macaddress(dev);
+       spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+       err = 0;
+ out_mutex_unlock:
+       mutex_unlock(&wl->mutex);
+
+       return err;
+}
+
+static void b43legacy_remove_interface(struct ieee80211_hw *hw,
+                                      struct ieee80211_if_init_conf *conf)
+{
+       struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+       struct b43legacy_wldev *dev = wl->current_dev;
+       unsigned long flags;
+
+       b43legacydbg(wl, "Removing Interface type %d\n", conf->type);
+
+       mutex_lock(&wl->mutex);
+
+       B43legacy_WARN_ON(!wl->operating);
+       B43legacy_WARN_ON(wl->if_id != conf->if_id);
+
+       wl->operating = 0;
+
+       spin_lock_irqsave(&wl->irq_lock, flags);
+       b43legacy_adjust_opmode(dev);
+       memset(wl->mac_addr, 0, ETH_ALEN);
+       b43legacy_upload_card_macaddress(dev);
+       spin_unlock_irqrestore(&wl->irq_lock, flags);
+
+       mutex_unlock(&wl->mutex);
+}
+
+static int b43legacy_start(struct ieee80211_hw *hw)
+{
+       struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
+       struct b43legacy_wldev *dev = wl->current_dev;
+       int did_init = 0;
+       int err = 0;
+
+       mutex_lock(&wl->mutex);
+
        if (b43legacy_status(dev) < B43legacy_STAT_INITIALIZED) {
                err = b43legacy_wireless_core_init(dev);
                if (err)
                        goto out_mutex_unlock;
                did_init = 1;
        }
+
        if (b43legacy_status(dev) < B43legacy_STAT_STARTED) {
                err = b43legacy_wireless_core_start(dev);
                if (err) {
@@ -3240,59 +3316,21 @@ static int b43legacy_add_interface(struct ieee80211_hw *hw,
                }
        }
 
-       spin_lock_irqsave(&wl->irq_lock, flags);
-       switch (conf->type) {
-       case IEEE80211_IF_TYPE_MNTR:
-               wl->monitor++;
-               break;
-       default:
-               wl->operating = 1;
-               wl->if_id = conf->if_id;
-               wl->if_type = conf->type;
-               b43legacy_upload_card_macaddress(dev, conf->mac_addr);
-       }
-       b43legacy_adjust_opmode(dev);
-       spin_unlock_irqrestore(&wl->irq_lock, flags);
-
-       err = 0;
 out_mutex_unlock:
        mutex_unlock(&wl->mutex);
 
        return err;
 }
 
-static void b43legacy_remove_interface(struct ieee80211_hw *hw,
-                                      struct ieee80211_if_init_conf *conf)
+static void b43legacy_stop(struct ieee80211_hw *hw)
 {
        struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
-       struct b43legacy_wldev *dev;
-       unsigned long flags;
-
-       b43legacydbg(wl, "Removing Interface type %d\n", conf->type);
+       struct b43legacy_wldev *dev = wl->current_dev;
 
        mutex_lock(&wl->mutex);
-       if (conf->type == IEEE80211_IF_TYPE_MNTR) {
-               wl->monitor--;
-               B43legacy_WARN_ON(wl->monitor < 0);
-       } else {
-               B43legacy_WARN_ON(!wl->operating);
-               wl->operating = 0;
-       }
-
-       dev = wl->current_dev;
-       if (!wl->operating && wl->monitor == 0) {
-               /* No interface left. */
-               if (b43legacy_status(dev) >= B43legacy_STAT_STARTED)
-                       b43legacy_wireless_core_stop(dev);
-               b43legacy_wireless_core_exit(dev);
-       } else {
-               /* Just monitor interfaces left. */
-               spin_lock_irqsave(&wl->irq_lock, flags);
-               b43legacy_adjust_opmode(dev);
-               if (!wl->operating)
-                       b43legacy_upload_card_macaddress(dev, NULL);
-               spin_unlock_irqrestore(&wl->irq_lock, flags);
-       }
+       if (b43legacy_status(dev) >= B43legacy_STAT_STARTED)
+               b43legacy_wireless_core_stop(dev);
+       b43legacy_wireless_core_exit(dev);
        mutex_unlock(&wl->mutex);
 }
 
@@ -3305,9 +3343,11 @@ static const struct ieee80211_ops b43legacy_hw_ops = {
        .config = b43legacy_dev_config,
        .config_interface = b43legacy_config_interface,
        .set_key = b43legacy_dev_set_key,
-       .set_multicast_list = b43legacy_set_multicast_list,
+       .configure_filter = b43legacy_configure_filter,
        .get_stats = b43legacy_get_stats,
        .get_tx_stats = b43legacy_get_tx_stats,
+       .start = b43legacy_start,
+       .stop = b43legacy_stop,
 };
 
 /* Hard-reset the chip. Do not call this directly.
@@ -3445,18 +3485,13 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
        else
                have_bphy = 1;
 
-       /* Initialize LEDs structs. */
-       err = b43legacy_leds_init(dev);
-       if (err)
-               goto err_powerdown;
-
        dev->phy.gmode = (have_gphy || have_bphy);
        tmp = dev->phy.gmode ? B43legacy_TMSLOW_GMODE : 0;
        b43legacy_wireless_core_reset(dev, tmp);
 
        err = b43legacy_phy_versioning(dev);
        if (err)
-               goto err_leds_exit;
+               goto err_powerdown;
        /* Check if this device supports multiband. */
        if (!pdev ||
            (pdev->device != 0x4312 &&
@@ -3482,10 +3517,10 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
 
        err = b43legacy_validate_chipaccess(dev);
        if (err)
-               goto err_leds_exit;
+               goto err_powerdown;
        err = b43legacy_setup_modes(dev, have_bphy, have_gphy);
        if (err)
-               goto err_leds_exit;
+               goto err_powerdown;
 
        /* Now set some default "current_dev" */
        if (!wl->current_dev)
@@ -3500,8 +3535,6 @@ static int b43legacy_wireless_core_attach(struct b43legacy_wldev *dev)
 out:
        return err;
 
-err_leds_exit:
-       b43legacy_leds_exit(dev);
 err_powerdown:
        ssb_bus_may_powerdown(bus);
        return err;