📄 bcm43xx_main.c
字号:
/* irq not for us (shared irq) */ ret = IRQ_NONE; goto out; } reason &= bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK); if (!reason) goto out; assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED); assert(bcm->current_core->id == BCM43xx_COREID_80211); bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA0_REASON) & 0x0001DC00; bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON) & 0x0000DC00; bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON) & 0x0000DC00; bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON) & 0x0001DC00; bcm->dma_reason[4] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON) & 0x0000DC00; bcm->dma_reason[5] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA5_REASON) & 0x0000DC00; bcm43xx_interrupt_ack(bcm, reason); /* 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->irq_lock); return ret;}static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force){ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); if (bcm->firmware_norelease && !force) return; /* Suspending or controller reset. */ release_firmware(phy->ucode); phy->ucode = NULL; release_firmware(phy->pcm); phy->pcm = NULL; release_firmware(phy->initvals0); phy->initvals0 = NULL; release_firmware(phy->initvals1); phy->initvals1 = NULL;}static int bcm43xx_request_firmware(struct bcm43xx_private *bcm){ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); u8 rev = bcm->current_core->rev; int err = 0; int nr; char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 }; if (!phy->ucode) { snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw", (rev >= 5 ? 5 : rev), modparam_fwpostfix); err = request_firmware(&phy->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 (!phy->pcm) { snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_pcm%d%s.fw", (rev < 5 ? 4 : 5), modparam_fwpostfix); err = request_firmware(&phy->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 (!phy->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(&phy->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 (phy->initvals0->size % sizeof(struct bcm43xx_initval)) { printk(KERN_ERR PFX "InitVals fileformat error.\n"); goto error; } } if (!phy->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(&phy->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 (phy->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){ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); const u32 *data; unsigned int i, len; /* Upload Microcode. */ data = (u32 *)(phy->ucode->data); len = phy->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 *)(phy->pcm->data); len = phy->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){ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); int err; err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals0->data, phy->initvals0->size / sizeof(struct bcm43xx_initval)); if (err) goto out; if (phy->initvals1) { err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals1->data, phy->initvals1->size / sizeof(struct bcm43xx_initval)); if (err) goto out; }out: return err;}#ifdef CONFIG_BCM947XXstatic struct pci_device_id bcm43xx_47xx_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) }, { 0 }};#endifstatic int bcm43xx_initialize_irq(struct bcm43xx_private *bcm){ int err; bcm->irq = bcm->pci_dev->irq;#ifdef CONFIG_BCM947XX if (bcm->pci_dev->bus->number == 0) { struct pci_dev *d; struct pci_device_id *id; for (id = bcm43xx_47xx_ids; id->vendor; id++) { d = pci_get_device(id->vendor, id->device, NULL); if (d != NULL) { bcm->irq = d->irq; pci_dev_put(d); break; } } }#endif err = request_irq(bcm->irq, bcm43xx_interrupt_handler, IRQF_SHARED, KBUILD_MODNAME, bcm); if (err) printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq); return err;}/* 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 err;}/* 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, set; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) & 0xFFFF3FFF); bcm43xx_leds_switch_all(bcm, 0); bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK, bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F); mask = 0x0000001F; set = 0x0000000F; if (bcm->chip_id == 0x4301) { 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) { 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) | set); err = bcm43xx_switch_core(bcm, old_core);out: return err;}/* 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){ bcm->mac_suspended--; assert(bcm->mac_suspended >= 0); if (bcm->mac_suspended == 0) { 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; assert(bcm->mac_suspended >= 0); if (bcm->mac_suspended == 0) { 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 = 10000; i; i--) { tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); if (tmp & BCM43xx_IRQ_READY) goto out; udelay(1); } printkl(KERN_ERR PFX "MAC suspend failed\n"); }out: bcm->mac_suspended++;}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) net_dev->type = ARPHRD_IEEE80211; else net_dev->type = ARPHRD_ETHER; status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* Reset status to infrastructured mode */ status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR); 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_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(); /* TODO */ brea
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -