📄 bcm43xx_main.c
字号:
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;}static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm){ int err; bcm->irq = bcm->pci_dev->irq; 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 */ break; case IW_MODE_INFRA: /* nothing to be done here... */ break; default: 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); 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() */static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm){ bcm43xx_radio_turn_off(bcm); if (!modparam_noleds) bcm43xx_leds_exit(bcm); bcm43xx_gpio_cleanup(bcm); bcm43xx_release_firmware(bcm, 0);}/* Initialize the chip * http://bcm-specs.sipsolutions.net/ChipInit */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 i, tmp; u32 value32; u16 value16; bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, BCM43xx_SBF_CORE_READY | BCM43xx_SBF_400); err = bcm43xx_request_firmware(bcm); if (err) goto out; bcm43xx_upload_microcode(bcm); bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xFFFFFFFF); bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402); i = 0; while (1) { value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); if (value32 == BCM43xx_IRQ_READY) break; i++; if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) { printk(KERN_ERR PFX "IRQ_READY timeout\n"); err = -ENODEV; goto err_release_fw; } udelay(10); } bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */ value16 = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODE_REVISION); dprintk(KERN_INFO PFX "Microcode rev 0x%x, pl 0x%x " "(20%.2i-%.2i-%.2i %.2i:%.2i:%.2i)\n", value16, bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODE_PATCHLEVEL), (bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODE_DATE) >> 12) & 0xf, (bcm43xx_shm_read16(bcm
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -