]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/wireless/bcm43xx/bcm43xx_main.c
Merge branch 'upstream' of git://git.kernel.org/pub/scm/linux/kernel/git/linville...
[linux-2.6-omap-h63xx.git] / drivers / net / wireless / bcm43xx / bcm43xx_main.c
index 6a877df2ecf0fd17c54bfeb8e2b26b8e24e698bf..736dde96c4a38d81762bcec317bebff1bfd0b17a 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/wireless.h>
 #include <linux/workqueue.h>
 #include <linux/skbuff.h>
+#include <linux/dma-mapping.h>
 #include <net/iw_handler.h>
 
 #include "bcm43xx.h"
@@ -51,6 +52,7 @@
 #include "bcm43xx_wx.h"
 #include "bcm43xx_ethtool.h"
 #include "bcm43xx_xmit.h"
+#include "bcm43xx_sysfs.h"
 
 
 MODULE_DESCRIPTION("Broadcom BCM43xx wireless driver");
@@ -126,13 +128,15 @@ MODULE_PARM_DESC(fwpostfix, "Postfix for .fw files. Useful for debugging.");
        static struct pci_device_id bcm43xx_pci_tbl[] = {
        /* Broadcom 4303 802.11b */
        { PCI_VENDOR_ID_BROADCOM, 0x4301, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-               /* Broadcom 4307 802.11b */
+       /* Broadcom 4307 802.11b */
        { PCI_VENDOR_ID_BROADCOM, 0x4307, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-               /* Broadcom 4318 802.11b/g */
+       /* Broadcom 4318 802.11b/g */
        { PCI_VENDOR_ID_BROADCOM, 0x4318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+       /* Broadcom 4319 802.11a/b/g */
+       { PCI_VENDOR_ID_BROADCOM, 0x4319, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        /* Broadcom 4306 802.11b/g */
        { PCI_VENDOR_ID_BROADCOM, 0x4320, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
-               /* Broadcom 4306 802.11a */
+       /* Broadcom 4306 802.11a */
 //     { PCI_VENDOR_ID_BROADCOM, 0x4321, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
        /* Broadcom 4309 802.11a/b/g */
        { PCI_VENDOR_ID_BROADCOM, 0x4324, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
@@ -403,6 +407,8 @@ static void bcm43xx_write_mac_bssid_templates(struct bcm43xx_private *bcm)
                bcm43xx_ram_write(bcm, 0x478 + i, *((u32 *)(mac_bssid + i)));
 }
 
+//FIXME: Well, we should probably call them from somewhere.
+#if 0
 static void bcm43xx_set_slot_time(struct bcm43xx_private *bcm, u16 slot_time)
 {
        /* slot_time is in usec. */
@@ -421,8 +427,12 @@ static void bcm43xx_short_slot_timing_disable(struct bcm43xx_private *bcm)
 {
        bcm43xx_set_slot_time(bcm, 20);
 }
+#endif
 
-//FIXME: rename this func?
+/* FIXME: To get the MAC-filter working, we need to implement the
+ *        following functions (and rename them :)
+ */
+#if 0
 static void bcm43xx_disassociate(struct bcm43xx_private *bcm)
 {
        bcm43xx_mac_suspend(bcm);
@@ -450,7 +460,6 @@ static void bcm43xx_disassociate(struct bcm43xx_private *bcm)
        bcm43xx_mac_enable(bcm);
 }
 
-//FIXME: rename this func?
 static void bcm43xx_associate(struct bcm43xx_private *bcm,
                              const u8 *mac)
 {
@@ -461,6 +470,7 @@ static void bcm43xx_associate(struct bcm43xx_private *bcm,
        bcm43xx_write_mac_bssid_templates(bcm);
        bcm43xx_mac_enable(bcm);
 }
+#endif
 
 /* Enable a Generic IRQ. "mask" is the mask of which IRQs to enable.
  * Returns the _previously_ enabled IRQ mask.
@@ -560,12 +570,10 @@ static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm)
        radio->revision = revision;
 
        /* Set default attenuation values. */
-       radio->txpower[0] = 2;
-       radio->txpower[1] = 2;
-       if (revision == 1)
-               radio->txpower[2] = 3;
-       else
-               radio->txpower[2] = 0;
+       radio->baseband_atten = bcm43xx_default_baseband_attenuation(bcm);
+       radio->radio_atten = bcm43xx_default_radio_attenuation(bcm);
+       radio->txctl1 = bcm43xx_default_txctl1(bcm);
+       radio->txctl2 = 0xFFFF;
        if (phy->type == BCM43xx_PHYTYPE_A)
                radio->txpower_desired = bcm->sprom.maxpower_aphy;
        else
@@ -933,9 +941,9 @@ static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm)
        return 0;
 }
 
-static void bcm43xx_geo_init(struct bcm43xx_private *bcm)
+static int bcm43xx_geo_init(struct bcm43xx_private *bcm)
 {
-       struct ieee80211_geo geo;
+       struct ieee80211_geo *geo;
        struct ieee80211_channel *chan;
        int have_a = 0, have_bg = 0;
        int i;
@@ -943,7 +951,10 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm)
        struct bcm43xx_phyinfo *phy;
        const char *iso_country;
 
-       memset(&geo, 0, sizeof(geo));
+       geo = kzalloc(sizeof(*geo), GFP_KERNEL);
+       if (!geo)
+               return -ENOMEM;
+
        for (i = 0; i < bcm->nr_80211_available; i++) {
                phy = &(bcm->core_80211_ext[i].phy);
                switch (phy->type) {
@@ -961,31 +972,36 @@ static void bcm43xx_geo_init(struct bcm43xx_private *bcm)
        iso_country = bcm43xx_locale_iso(bcm->sprom.locale);
 
        if (have_a) {
-               for (i = 0, channel = 0; channel < 201; channel++) {
-                       chan = &geo.a[i++];
+               for (i = 0, channel = IEEE80211_52GHZ_MIN_CHANNEL;
+                     channel <= IEEE80211_52GHZ_MAX_CHANNEL; channel++) {
+                       chan = &geo->a[i++];
                        chan->freq = bcm43xx_channel_to_freq_a(channel);
                        chan->channel = channel;
                }
-               geo.a_channels = i;
+               geo->a_channels = i;
        }
        if (have_bg) {
-               for (i = 0, channel = 1; channel < 15; channel++) {
-                       chan = &geo.bg[i++];
+               for (i = 0, channel = IEEE80211_24GHZ_MIN_CHANNEL;
+                     channel <= IEEE80211_24GHZ_MAX_CHANNEL; channel++) {
+                       chan = &geo->bg[i++];
                        chan->freq = bcm43xx_channel_to_freq_bg(channel);
                        chan->channel = channel;
                }
-               geo.bg_channels = i;
+               geo->bg_channels = i;
        }
-       memcpy(geo.name, iso_country, 2);
+       memcpy(geo->name, iso_country, 2);
        if (0 /*TODO: Outdoor use only */)
-               geo.name[2] = 'O';
+               geo->name[2] = 'O';
        else if (0 /*TODO: Indoor use only */)
-               geo.name[2] = 'I';
+               geo->name[2] = 'I';
        else
-               geo.name[2] = ' ';
-       geo.name[3] = '\0';
+               geo->name[2] = ' ';
+       geo->name[3] = '\0';
+
+       ieee80211_set_geo(bcm->ieee, geo);
+       kfree(geo);
 
-       ieee80211_set_geo(bcm->ieee, &geo);
+       return 0;
 }
 
 /* DummyTransmission function, as documented on 
@@ -1542,6 +1558,7 @@ static void handle_irq_noise(struct bcm43xx_private *bcm)
                average *= 125;
                average += 64;
                average /= 128;
+
                tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C);
                tmp = (tmp / 128) & 0x1F;
                if (tmp >= 8)
@@ -1553,6 +1570,8 @@ static void handle_irq_noise(struct bcm43xx_private *bcm)
                else
                        average -= 48;
 
+/* FIXME: This is wrong, but people want fancy stats. well... */
+bcm->stats.noise = average;
                if (average > -65)
                        bcm->stats.link_quality = 0;
                else if (average > -75)
@@ -1785,10 +1804,6 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
                bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS);
        }
 
-       /* We get spurious IRQs, althought they are masked.
-        * Assume they are void and ignore them.
-        */
-       bcmirq_handled(~(bcm->irq_savedstate));
        /* IRQ_PIO_WORKAROUND is handled in the top-half. */
        bcmirq_handled(BCM43xx_IRQ_PIO_WORKAROUND);
 #ifdef CONFIG_BCM43XX_DEBUG
@@ -1809,41 +1824,31 @@ static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm)
        bcm43xx_unlock_mmio(bcm, flags);
 }
 
-static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm,
-                                 u32 reason, u32 mask)
+static void pio_irq_workaround(struct bcm43xx_private *bcm,
+                              u16 base, int queueidx)
 {
-       bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
-                            & 0x0001dc00;
-       bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
-                            & 0x0000dc00;
-       bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
-                            & 0x0000dc00;
-       bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
-                            & 0x0001dc00;
+       u16 rxctl;
+
+       rxctl = bcm43xx_read16(bcm, base + BCM43xx_PIO_RXCTL);
+       if (rxctl & BCM43xx_PIO_RXCTL_DATAAVAILABLE)
+               bcm->dma_reason[queueidx] |= BCM43xx_DMAIRQ_RX_DONE;
+       else
+               bcm->dma_reason[queueidx] &= ~BCM43xx_DMAIRQ_RX_DONE;
+}
 
+static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason)
+{
        if (bcm43xx_using_pio(bcm) &&
            (bcm->current_core->rev < 3) &&
            (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) {
                /* Apply a PIO specific workaround to the dma_reasons */
-
-#define apply_pio_workaround(BASE, QNUM) \
-       do {                                                                                    \
-       if (bcm43xx_read16(bcm, BASE + BCM43xx_PIO_RXCTL) & BCM43xx_PIO_RXCTL_DATAAVAILABLE)    \
-               bcm->dma_reason[QNUM] |= 0x00010000;                                            \
-       else                                                                                    \
-               bcm->dma_reason[QNUM] &= ~0x00010000;                                           \
-       } while (0)
-
-               apply_pio_workaround(BCM43xx_MMIO_PIO1_BASE, 0);
-               apply_pio_workaround(BCM43xx_MMIO_PIO2_BASE, 1);
-               apply_pio_workaround(BCM43xx_MMIO_PIO3_BASE, 2);
-               apply_pio_workaround(BCM43xx_MMIO_PIO4_BASE, 3);
-
-#undef apply_pio_workaround
+               pio_irq_workaround(bcm, BCM43xx_MMIO_PIO1_BASE, 0);
+               pio_irq_workaround(bcm, BCM43xx_MMIO_PIO2_BASE, 1);
+               pio_irq_workaround(bcm, BCM43xx_MMIO_PIO3_BASE, 2);
+               pio_irq_workaround(bcm, BCM43xx_MMIO_PIO4_BASE, 3);
        }
 
-       bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON,
-                       reason & mask);
+       bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason);
 
        bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,
                        bcm->dma_reason[0]);
@@ -1860,7 +1865,7 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
 {
        irqreturn_t ret = IRQ_HANDLED;
        struct bcm43xx_private *bcm = dev_id;
-       u32 reason, mask;
+       u32 reason;
 
        if (!bcm)
                return IRQ_NONE;
@@ -1873,11 +1878,20 @@ static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id, struct pt_re
                ret = IRQ_NONE;
                goto out;
        }
-       mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
-       if (!(reason & mask))
+       reason &= bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);
+       if (!reason)
                goto out;
 
-       bcm43xx_interrupt_ack(bcm, reason, mask);
+       bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)
+                            & 0x0001dc00;
+       bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)
+                            & 0x0000dc00;
+       bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)
+                            & 0x0000dc00;
+       bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)
+                            & 0x0001dc00;
+
+       bcm43xx_interrupt_ack(bcm, reason);
 
        /* Only accept IRQs, if we are initialized properly.
         * This avoids an RX race while initializing.
@@ -2182,13 +2196,10 @@ static int switch_to_gpio_core(struct bcm43xx_private *bcm)
                if (unlikely(err == -ENODEV)) {
                        printk(KERN_ERR PFX "gpio error: "
                               "Neither ChipCommon nor PCI core available!\n");
-                       return -ENODEV;
-               } else if (unlikely(err != 0))
-                       return -ENODEV;
-       } else if (unlikely(err != 0))
-               return -ENODEV;
+               }
+       }
 
-       return 0;
+       return err;
 }
 
 /* Initialize the GPIOs
@@ -2198,45 +2209,48 @@ static int bcm43xx_gpio_init(struct bcm43xx_private *bcm)
 {
        struct bcm43xx_coreinfo *old_core;
        int err;
-       u32 mask, value;
+       u32 mask, set;
 
-       value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
-       value &= ~0xc000;
-       bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value);
+       bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,
+                       bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)
+                       & 0xFFFF3FFF);
 
-       mask = 0x0000001F;
-       value = 0x0000000F;
-       bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL,
-                       bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL) & 0xFFF0);
+       bcm43xx_leds_switch_all(bcm, 0);
        bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
                        bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F);
 
-       old_core = bcm->current_core;
-       
-       err = switch_to_gpio_core(bcm);
-       if (err)
-               return err;
-
-       if (bcm->current_core->rev >= 2){
-               mask  |= 0x10;
-               value |= 0x10;
-       }
+       mask = 0x0000001F;
+       set = 0x0000000F;
        if (bcm->chip_id == 0x4301) {
-               mask  |= 0x60;
-               value |= 0x60;
+               mask |= 0x0060;
+               set |= 0x0060;
+       }
+       if (0 /* FIXME: conditional unknown */) {
+               bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
+                               bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK)
+                               | 0x0100);
+               mask |= 0x0180;
+               set |= 0x0180;
        }
        if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) {
-               mask  |= 0x200;
-               value |= 0x200;
+               bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,
+                               bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK)
+                               | 0x0200);
+               mask |= 0x0200;
+               set |= 0x0200;
        }
+       if (bcm->current_core->rev >= 2)
+               mask  |= 0x0010; /* FIXME: This is redundant. */
 
+       old_core = bcm->current_core;
+       err = switch_to_gpio_core(bcm);
+       if (err)
+               goto out;
        bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL,
-                       (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | value);
-
+                       (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | set);
        err = bcm43xx_switch_core(bcm, old_core);
-       assert(err == 0);
-
-       return 0;
+out:
+       return err;
 }
 
 /* Turn off all GPIO stuff. Call this on module unload, for example. */
@@ -2292,50 +2306,60 @@ void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,
                        int iw_mode)
 {
        unsigned long flags;
+       struct net_device *net_dev = bcm->net_dev;
        u32 status;
+       u16 value;
 
        spin_lock_irqsave(&bcm->ieee->lock, flags);
        bcm->ieee->iw_mode = iw_mode;
        spin_unlock_irqrestore(&bcm->ieee->lock, flags);
        if (iw_mode == IW_MODE_MONITOR)
-               bcm->net_dev->type = ARPHRD_IEEE80211;
+               net_dev->type = ARPHRD_IEEE80211;
        else
-               bcm->net_dev->type = ARPHRD_ETHER;
+               net_dev->type = ARPHRD_ETHER;
 
-       if (!bcm->initialized)
-               return;
-
-       bcm43xx_mac_suspend(bcm);
        status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
        /* Reset status to infrastructured mode */
        status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR);
-       /*FIXME: We actually set promiscuous mode as well, until we don't
-        * get the HW mac filter working */
-       status |= BCM43xx_SBF_MODE_NOTADHOC | BCM43xx_SBF_MODE_PROMISC;
+       status &= ~BCM43xx_SBF_MODE_PROMISC;
+       status |= BCM43xx_SBF_MODE_NOTADHOC;
+
+/* FIXME: Always enable promisc mode, until we get the MAC filters working correctly. */
+status |= BCM43xx_SBF_MODE_PROMISC;
 
        switch (iw_mode) {
        case IW_MODE_MONITOR:
-               status |= (BCM43xx_SBF_MODE_PROMISC |
-                          BCM43xx_SBF_MODE_MONITOR);
+               status |= BCM43xx_SBF_MODE_MONITOR;
+               status |= BCM43xx_SBF_MODE_PROMISC;
                break;
        case IW_MODE_ADHOC:
                status &= ~BCM43xx_SBF_MODE_NOTADHOC;
                break;
        case IW_MODE_MASTER:
+               status |= BCM43xx_SBF_MODE_AP;
+               break;
        case IW_MODE_SECOND:
        case IW_MODE_REPEAT:
-               /* TODO: No AP/Repeater mode for now :-/ */
-               TODO();
+               TODO(); /* TODO */
                break;
        case IW_MODE_INFRA:
                /* nothing to be done here... */
                break;
        default:
-               printk(KERN_ERR PFX "Unknown iwmode %d\n", iw_mode);
+               dprintk(KERN_ERR PFX "Unknown mode in set_iwmode: %d\n", iw_mode);
        }
-
+       if (net_dev->flags & IFF_PROMISC)
+               status |= BCM43xx_SBF_MODE_PROMISC;
        bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);
-       bcm43xx_mac_enable(bcm);
+
+       value = 0x0002;
+       if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) {
+               if (bcm->chip_id == 0x4306 && bcm->chip_rev == 3)
+                       value = 0x0064;
+               else
+                       value = 0x0032;
+       }
+       bcm43xx_write16(bcm, 0x0612, value);
 }
 
 /* This is the opposite of bcm43xx_chip_init() */
@@ -2357,7 +2381,6 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
        struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);
        struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);
        int err;
-       int iw_mode = bcm->ieee->iw_mode;
        int tmp;
        u32 value32;
        u16 value16;
@@ -2384,11 +2407,6 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
                goto err_gpio_cleanup;
        bcm43xx_radio_turn_on(bcm);
 
-       if (modparam_noleds)
-               bcm43xx_leds_turn_off(bcm);
-       else
-               bcm43xx_leds_update(bcm, 0);
-
        bcm43xx_write16(bcm, 0x03E6, 0x0000);
        err = bcm43xx_phy_init(bcm);
        if (err)
@@ -2416,20 +2434,9 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
        value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
        value32 |= BCM43xx_SBF_MODE_NOTADHOC;
        bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
-       /*FIXME: For now, use promiscuous mode at all times; otherwise we don't
-          get broadcast or multicast packets */
-       value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
-       value32 |= BCM43xx_SBF_MODE_PROMISC;
-       bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
 
-       if (iw_mode == IW_MODE_MONITOR) {
-               value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
-               value32 |= BCM43xx_SBF_MODE_PROMISC;
-               value32 |= BCM43xx_SBF_MODE_MONITOR;
-               bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
-       }
        value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);
-       value32 |= 0x100000; //FIXME: What's this? Is this correct?
+       value32 |= 0x100000;
        bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value32);
 
        if (bcm43xx_using_pio(bcm)) {
@@ -2444,13 +2451,8 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
        /* FIXME: Default to 0, has to be set by ioctl probably... :-/ */
        bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0074, 0x0000);
 
-       if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) {
-               if ((bcm->chip_id == 0x4306) && (bcm->chip_rev == 3))
-                       bcm43xx_write16(bcm, 0x0612, 0x0064);
-               else
-                       bcm43xx_write16(bcm, 0x0612, 0x0032);
-       } else
-               bcm43xx_write16(bcm, 0x0612, 0x0002);
+       /* Initially set the wireless operation mode. */
+       bcm43xx_set_iwmode(bcm, bcm->ieee->iw_mode);
 
        if (bcm->current_core->rev < 3) {
                bcm43xx_write16(bcm, 0x060E, 0x0000);
@@ -2519,7 +2521,7 @@ error:
        return -ENODEV;
 }
 
-void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy)
+static void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy)
 {
        /* Initialize a "phyinfo" structure. The structure is already
         * zeroed out.
@@ -2531,7 +2533,7 @@ void bcm43xx_init_struct_phyinfo(struct bcm43xx_phyinfo *phy)
        spin_lock_init(&phy->lock);
 }
 
-void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio)
+static void bcm43xx_init_struct_radioinfo(struct bcm43xx_radioinfo *radio)
 {
        /* Initialize a "radioinfo" structure. The structure is already
         * zeroed out.
@@ -2645,7 +2647,8 @@ static int bcm43xx_probe_cores(struct bcm43xx_private *bcm)
        }
 
        bcm->chip_id = chip_id_16;
-       bcm->chip_rev = (chip_id_32 & 0x000f0000) >> 16;
+       bcm->chip_rev = (chip_id_32 & 0x000F0000) >> 16;
+       bcm->chip_package = (chip_id_32 & 0x00F00000) >> 20;
 
        dprintk(KERN_INFO PFX "Chip ID 0x%x, rev 0x%x\n",
                bcm->chip_id, bcm->chip_rev);
@@ -3270,6 +3273,9 @@ static int bcm43xx_init_board(struct bcm43xx_private *bcm)
        bcm43xx_sysfs_register(bcm);
        //FIXME: check for bcm43xx_sysfs_register failure. This function is a bit messy regarding unwinding, though...
 
+       /*FIXME: This should be handled by softmac instead. */
+       schedule_work(&bcm->softmac->associnfo.work);
+
        assert(err == 0);
 out:
        return err;
@@ -3295,8 +3301,7 @@ static void bcm43xx_detach_board(struct bcm43xx_private *bcm)
 
        bcm43xx_chipset_detach(bcm);
        /* Do _not_ access the chip, after it is detached. */
-       iounmap(bcm->mmio_addr);
-       
+       pci_iounmap(pci_dev, bcm->mmio_addr);
        pci_release_regions(pci_dev);
        pci_disable_device(pci_dev);
 
@@ -3386,40 +3391,26 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
        struct net_device *net_dev = bcm->net_dev;
        int err;
        int i;
-       unsigned long mmio_start, mmio_flags, mmio_len;
        u32 coremask;
 
        err = pci_enable_device(pci_dev);
        if (err) {
-               printk(KERN_ERR PFX "unable to wake up pci device (%i)\n", err);
+               printk(KERN_ERR PFX "pci_enable_device() failed\n");
                goto out;
        }
-       mmio_start = pci_resource_start(pci_dev, 0);
-       mmio_flags = pci_resource_flags(pci_dev, 0);
-       mmio_len = pci_resource_len(pci_dev, 0);
-       if (!(mmio_flags & IORESOURCE_MEM)) {
-               printk(KERN_ERR PFX
-                      "%s, region #0 not an MMIO resource, aborting\n",
-                      pci_name(pci_dev));
-               err = -ENODEV;
-               goto err_pci_disable;
-       }
        err = pci_request_regions(pci_dev, KBUILD_MODNAME);
        if (err) {
-               printk(KERN_ERR PFX
-                      "could not access PCI resources (%i)\n", err);
+               printk(KERN_ERR PFX "pci_request_regions() failed\n");
                goto err_pci_disable;
        }
        /* enable PCI bus-mastering */
        pci_set_master(pci_dev);
-       bcm->mmio_addr = ioremap(mmio_start, mmio_len);
+       bcm->mmio_addr = pci_iomap(pci_dev, 0, ~0UL);
        if (!bcm->mmio_addr) {
-               printk(KERN_ERR PFX "%s: cannot remap MMIO, aborting\n",
-                      pci_name(pci_dev));
+               printk(KERN_ERR PFX "pci_iomap() failed\n");
                err = -EIO;
                goto err_pci_release;
        }
-       bcm->mmio_len = mmio_len;
        net_dev->base_addr = (unsigned long)bcm->mmio_addr;
 
        bcm43xx_pci_read_config16(bcm, PCI_SUBSYSTEM_VENDOR_ID,
@@ -3486,16 +3477,17 @@ static int bcm43xx_attach_board(struct bcm43xx_private *bcm)
                        goto err_80211_unwind;
                bcm43xx_wireless_core_disable(bcm);
        }
+       err = bcm43xx_geo_init(bcm);
+       if (err)
+               goto err_80211_unwind;
        bcm43xx_pctl_set_crystal(bcm, 0);
 
        /* Set the MAC address in the networking subsystem */
-       if (bcm43xx_current_phy(bcm)->type == BCM43xx_PHYTYPE_A)
+       if (is_valid_ether_addr(bcm->sprom.et1macaddr))
                memcpy(bcm->net_dev->dev_addr, bcm->sprom.et1macaddr, 6);
        else
                memcpy(bcm->net_dev->dev_addr, bcm->sprom.il0macaddr, 6);
 
-       bcm43xx_geo_init(bcm);
-
        snprintf(bcm->nick, IW_ESSID_MAX_SIZE,
                 "Broadcom %04X", bcm->chip_id);
 
@@ -3512,7 +3504,7 @@ err_80211_unwind:
 err_chipset_detach:
        bcm43xx_chipset_detach(bcm);
 err_iounmap:
-       iounmap(bcm->mmio_addr);
+       pci_iounmap(pci_dev, bcm->mmio_addr);
 err_pci_release:
        pci_release_regions(pci_dev);
 err_pci_disable:
@@ -3530,6 +3522,7 @@ static inline int bcm43xx_tx(struct bcm43xx_private *bcm,
                err = bcm43xx_pio_tx(bcm, txb);
        else
                err = bcm43xx_dma_tx(bcm, txb);
+       bcm->net_dev->trans_start = jiffies;
 
        return err;
 }
@@ -3538,12 +3531,18 @@ static void bcm43xx_ieee80211_set_chan(struct net_device *net_dev,
                                       u8 channel)
 {
        struct bcm43xx_private *bcm = bcm43xx_priv(net_dev);
+       struct bcm43xx_radioinfo *radio;
        unsigned long flags;
 
        bcm43xx_lock_mmio(bcm, flags);
-       bcm43xx_mac_suspend(bcm);
-       bcm43xx_radio_selectchannel(bcm, channel, 0);
-       bcm43xx_mac_enable(bcm);
+       if (bcm->initialized) {
+               bcm43xx_mac_suspend(bcm);
+               bcm43xx_radio_selectchannel(bcm, channel, 0);
+               bcm43xx_mac_enable(bcm);
+       } else {
+               radio = bcm43xx_current_radio(bcm);
+               radio->initial_channel = channel;
+       }
        bcm43xx_unlock_mmio(bcm, flags);
 }
 
@@ -3556,7 +3555,7 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
        unsigned long flags;
        int keyidx;
        
-       dprintk(KERN_INFO PFX "set security called\n");
+       dprintk(KERN_INFO PFX "set security called");
 
        bcm43xx_lock_mmio(bcm, flags);
 
@@ -3569,24 +3568,25 @@ static void bcm43xx_ieee80211_set_security(struct net_device *net_dev,
        
        if (sec->flags & SEC_ACTIVE_KEY) {
                secinfo->active_key = sec->active_key;
-               dprintk(KERN_INFO PFX "   .active_key = %d\n", sec->active_key);
+               dprintk(", .active_key = %d", sec->active_key);
        }
        if (sec->flags & SEC_UNICAST_GROUP) {
                secinfo->unicast_uses_group = sec->unicast_uses_group;
-               dprintk(KERN_INFO PFX "   .unicast_uses_group = %d\n", sec->unicast_uses_group);
+               dprintk(", .unicast_uses_group = %d", sec->unicast_uses_group);
        }
        if (sec->flags & SEC_LEVEL) {
                secinfo->level = sec->level;
-               dprintk(KERN_INFO PFX "   .level = %d\n", sec->level);
+               dprintk(", .level = %d", sec->level);
        }
        if (sec->flags & SEC_ENABLED) {
                secinfo->enabled = sec->enabled;
-               dprintk(KERN_INFO PFX "   .enabled = %d\n", sec->enabled);
+               dprintk(", .enabled = %d", sec->enabled);
        }
        if (sec->flags & SEC_ENCRYPT) {
                secinfo->encrypt = sec->encrypt;
-               dprintk(KERN_INFO PFX "   .encrypt = %d\n", sec->encrypt);
+               dprintk(", .encrypt = %d", sec->encrypt);
        }
+       dprintk("\n");
        if (bcm->initialized && !bcm->ieee->host_encrypt) {
                if (secinfo->enabled) {
                        /* upload WEP keys to hardware */
@@ -3937,9 +3937,6 @@ static int bcm43xx_resume(struct pci_dev *pdev)
 
        netif_device_attach(net_dev);
        
-       /*FIXME: This should be handled by softmac instead. */
-       schedule_work(&bcm->softmac->associnfo.work);
-
        dprintk(KERN_INFO PFX "Device resumed.\n");
 
        return 0;
@@ -3973,5 +3970,3 @@ static void __exit bcm43xx_exit(void)
 
 module_init(bcm43xx_init)
 module_exit(bcm43xx_exit)
-
-/* vim: set ts=8 sw=8 sts=8: */