📄 bcm43xx_main.c
字号:
if (!(reason & mask)) goto out; bcm43xx_interrupt_ack(bcm, reason, mask); /* Only accept IRQs, if we are initialized properly. * This avoids an RX race while initializing. * We should probably not enable IRQs before we are initialized * completely, but some careful work is needed to fix this. I think it * is best to stay with this cheap workaround for now... . */ if (likely(bcm->initialized)) { /* disable all IRQs. They are enabled again in the bottom half. */ bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); /* save the reason code and call our bottom half. */ bcm->irq_reason = reason; tasklet_schedule(&bcm->isr_tasklet); }out: mmiowb(); spin_unlock(&bcm->_lock); return ret;}static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force){ if (bcm->firmware_norelease && !force) return; /* Suspending or controller reset. */ release_firmware(bcm->ucode); bcm->ucode = NULL; release_firmware(bcm->pcm); bcm->pcm = NULL; release_firmware(bcm->initvals0); bcm->initvals0 = NULL; release_firmware(bcm->initvals1); bcm->initvals1 = NULL;}static int bcm43xx_request_firmware(struct bcm43xx_private *bcm){ struct bcm43xx_phyinfo *phy = bcm->current_core->phy; u8 rev = bcm->current_core->rev; int err = 0; int nr; char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 }; if (!bcm->ucode) { snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw", (rev >= 5 ? 5 : rev), modparam_fwpostfix); err = request_firmware(&bcm->ucode, buf, &bcm->pci_dev->dev); if (err) { printk(KERN_ERR PFX "Error: Microcode \"%s\" not available or load failed.\n", buf); goto error; } } if (!bcm->pcm) { snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_pcm%d%s.fw", (rev < 5 ? 4 : 5), modparam_fwpostfix); err = request_firmware(&bcm->pcm, buf, &bcm->pci_dev->dev); if (err) { printk(KERN_ERR PFX "Error: PCM \"%s\" not available or load failed.\n", buf); goto error; } } if (!bcm->initvals0) { if (rev == 2 || rev == 4) { switch (phy->type) { case BCM43xx_PHYTYPE_A: nr = 3; break; case BCM43xx_PHYTYPE_B: case BCM43xx_PHYTYPE_G: nr = 1; break; default: goto err_noinitval; } } else if (rev >= 5) { switch (phy->type) { case BCM43xx_PHYTYPE_A: nr = 7; break; case BCM43xx_PHYTYPE_B: case BCM43xx_PHYTYPE_G: nr = 5; break; default: goto err_noinitval; } } else goto err_noinitval; snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", nr, modparam_fwpostfix); err = request_firmware(&bcm->initvals0, buf, &bcm->pci_dev->dev); if (err) { printk(KERN_ERR PFX "Error: InitVals \"%s\" not available or load failed.\n", buf); goto error; } if (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) { printk(KERN_ERR PFX "InitVals fileformat error.\n"); goto error; } } if (!bcm->initvals1) { if (rev >= 5) { u32 sbtmstatehigh; switch (phy->type) { case BCM43xx_PHYTYPE_A: sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); if (sbtmstatehigh & 0x00010000) nr = 9; else nr = 10; break; case BCM43xx_PHYTYPE_B: case BCM43xx_PHYTYPE_G: nr = 6; break; default: goto err_noinitval; } snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw", nr, modparam_fwpostfix); err = request_firmware(&bcm->initvals1, buf, &bcm->pci_dev->dev); if (err) { printk(KERN_ERR PFX "Error: InitVals \"%s\" not available or load failed.\n", buf); goto error; } if (bcm->initvals1->size % sizeof(struct bcm43xx_initval)) { printk(KERN_ERR PFX "InitVals fileformat error.\n"); goto error; } } }out: return err;error: bcm43xx_release_firmware(bcm, 1); goto out;err_noinitval: printk(KERN_ERR PFX "Error: No InitVals available!\n"); err = -ENOENT; goto error;}static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm){ const u32 *data; unsigned int i, len; /* Upload Microcode. */ data = (u32 *)(bcm->ucode->data); len = bcm->ucode->size / sizeof(u32); bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000); for (i = 0; i < len; i++) { bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, be32_to_cpu(data[i])); udelay(10); } /* Upload PCM data. */ data = (u32 *)(bcm->pcm->data); len = bcm->pcm->size / sizeof(u32); bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea); bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000); bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb); for (i = 0; i < len; i++) { bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, be32_to_cpu(data[i])); udelay(10); }}static int bcm43xx_write_initvals(struct bcm43xx_private *bcm, const struct bcm43xx_initval *data, const unsigned int len){ u16 offset, size; u32 value; unsigned int i; for (i = 0; i < len; i++) { offset = be16_to_cpu(data[i].offset); size = be16_to_cpu(data[i].size); value = be32_to_cpu(data[i].value); if (unlikely(offset >= 0x1000)) goto err_format; if (size == 2) { if (unlikely(value & 0xFFFF0000)) goto err_format; bcm43xx_write16(bcm, offset, (u16)value); } else if (size == 4) { bcm43xx_write32(bcm, offset, value); } else goto err_format; } return 0;err_format: printk(KERN_ERR PFX "InitVals (bcm43xx_initvalXX.fw) file-format error. " "Please fix your bcm43xx firmware files.\n"); return -EPROTO;}static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm){ int err; err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data, bcm->initvals0->size / sizeof(struct bcm43xx_initval)); if (err) goto out; if (bcm->initvals1) { err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data, bcm->initvals1->size / sizeof(struct bcm43xx_initval)); if (err) goto out; }out: return err;}static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm){ int res; unsigned int i; u32 data; bcm->irq = bcm->pci_dev->irq;#ifdef CONFIG_BCM947XX if (bcm->pci_dev->bus->number == 0) { struct pci_dev *d = NULL; /* FIXME: we will probably need more device IDs here... */ d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL); if (d != NULL) { bcm->irq = d->irq; } }#endif res = request_irq(bcm->irq, bcm43xx_interrupt_handler, SA_SHIRQ, KBUILD_MODNAME, bcm); if (res) { printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq); return -ENODEV; } bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff); bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402); i = 0; while (1) { data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); if (data == BCM43xx_IRQ_READY) break; i++; if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) { printk(KERN_ERR PFX "Card IRQ register not responding. " "Giving up.\n"); free_irq(bcm->irq, bcm); return -ENODEV; } udelay(10); } // dummy read bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); return 0;}/* Switch to the core used to write the GPIO register. * This is either the ChipCommon, or the PCI core. */static int switch_to_gpio_core(struct bcm43xx_private *bcm){ int err; /* Where to find the GPIO register depends on the chipset. * If it has a ChipCommon, its register at offset 0x6c is the GPIO * control register. Otherwise the register at offset 0x6c in the * PCI core is the GPIO control register. */ err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon); if (err == -ENODEV) { err = bcm43xx_switch_core(bcm, &bcm->core_pci); 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;}/* Initialize the GPIOs * http://bcm-specs.sipsolutions.net/GPIO */static int bcm43xx_gpio_init(struct bcm43xx_private *bcm){ struct bcm43xx_coreinfo *old_core; int err; u32 mask, value; value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); value &= ~0xc000; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value); mask = 0x0000001F; value = 0x0000000F; bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL, bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL) & 0xFFF0); 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; } if (bcm->chip_id == 0x4301) { mask |= 0x60; value |= 0x60; } if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) { mask |= 0x200; value |= 0x200; } bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | value); err = bcm43xx_switch_core(bcm, old_core); assert(err == 0); return 0;}/* Turn off all GPIO stuff. Call this on module unload, for example. */static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm){ struct bcm43xx_coreinfo *old_core; int err; old_core = bcm->current_core; err = switch_to_gpio_core(bcm); if (err) return err; bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, 0x00000000); err = bcm43xx_switch_core(bcm, old_core); assert(err == 0); return 0;}/* http://bcm-specs.sipsolutions.net/EnableMac */void bcm43xx_mac_enable(struct bcm43xx_private *bcm){ bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) | BCM43xx_SBF_MAC_ENABLED); bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY); bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ bcm43xx_power_saving_ctl_bits(bcm, -1, -1);}/* http://bcm-specs.sipsolutions.net/SuspendMAC */void bcm43xx_mac_suspend(struct bcm43xx_private *bcm){ int i; u32 tmp; bcm43xx_power_saving_ctl_bits(bcm, -1, 1); bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) & ~BCM43xx_SBF_MAC_ENABLED); bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ for (i = 100000; i; i--) { tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); if (tmp & BCM43xx_IRQ_READY) return; udelay(10); } printkl(KERN_ERR PFX "MAC suspend failed\n");}void bcm43xx_set_iwmode(struct bcm43xx_private *bcm, int iw_mode){ unsigned long flags; u32 status; 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; else bcm->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; switch (iw_mode) { case IW_MODE_MONITOR: status |= (BCM43xx_SBF_MODE_PROMISC | BCM43xx_SBF_MODE_MONITOR); break; case IW_MODE_ADHOC: status &= ~BCM43xx_SBF_MODE_NOTADHOC; break; case IW_MODE_MASTER: case IW_MODE_SECOND: case IW_MODE_REPEAT: /* TODO: No AP/Repeater mode for now :-/ */ TODO(); break; case IW_MODE_INFRA: /* nothing to be done here... */ break; default: printk(KERN_ERR PFX "Unknown iwmode %d\n", iw_mode); } bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status); bcm43xx_mac_enable(bcm);}/* This is the opposite of bcm43xx_chip_init() */static void bcm43x
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -