📄 bcm43xx_main.c
字号:
for (i = 0; i < num80211; i++) { phy = bcm->phy + i; switch (phy->type) { case BCM43xx_PHYTYPE_B: case BCM43xx_PHYTYPE_G: have_bg = 1; break; case BCM43xx_PHYTYPE_A: have_a = 1; break; default: assert(0); } } iso_country = bcm43xx_locale_iso(bcm->sprom.locale); if (have_a) { for (i = 0, channel = 0; channel < 201; channel++) { chan = &geo.a[i++]; chan->freq = bcm43xx_channel_to_freq_a(channel); chan->channel = channel; } geo.a_channels = i; } if (have_bg) { for (i = 0, channel = 1; channel < 15; channel++) { chan = &geo.bg[i++]; chan->freq = bcm43xx_channel_to_freq_bg(channel); chan->channel = channel; } geo.bg_channels = i; } memcpy(geo.name, iso_country, 2); if (0 /*TODO: Outdoor use only */) geo.name[2] = 'O'; else if (0 /*TODO: Indoor use only */) geo.name[2] = 'I'; else geo.name[2] = ' '; geo.name[3] = '\0'; ieee80211_set_geo(bcm->ieee, &geo);}/* DummyTransmission function, as documented on * http://bcm-specs.sipsolutions.net/DummyTransmission */void bcm43xx_dummy_transmission(struct bcm43xx_private *bcm){ struct bcm43xx_phyinfo *phy = bcm->current_core->phy; struct bcm43xx_radioinfo *radio = bcm->current_core->radio; unsigned int i, max_loop; u16 value = 0; u32 buffer[5] = { 0x00000000, 0x0000D400, 0x00000000, 0x00000001, 0x00000000, };/* FIXME: It seems like a dummy_transmission corrupts the DMA engines, * once they are initialized. So avoid doing a dummy_transmission, * if the DMA engines are running. */if (bcm->initialized)return; switch (phy->type) { case BCM43xx_PHYTYPE_A: max_loop = 0x1E; buffer[0] = 0xCC010200; break; case BCM43xx_PHYTYPE_B: case BCM43xx_PHYTYPE_G: max_loop = 0xFA; buffer[0] = 0x6E840B00; break; default: assert(0); return; } for (i = 0; i < 5; i++) bcm43xx_ram_write(bcm, i * 4, buffer[i]); bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */ bcm43xx_write16(bcm, 0x0568, 0x0000); bcm43xx_write16(bcm, 0x07C0, 0x0000); bcm43xx_write16(bcm, 0x050C, ((phy->type == BCM43xx_PHYTYPE_A) ? 1 : 0)); bcm43xx_write16(bcm, 0x0508, 0x0000); bcm43xx_write16(bcm, 0x050A, 0x0000); bcm43xx_write16(bcm, 0x054C, 0x0000); bcm43xx_write16(bcm, 0x056A, 0x0014); bcm43xx_write16(bcm, 0x0568, 0x0826); bcm43xx_write16(bcm, 0x0500, 0x0000); bcm43xx_write16(bcm, 0x0502, 0x0030); if (radio->version == 0x2050 && radio->revision <= 0x5) bcm43xx_radio_write16(bcm, 0x0051, 0x0017); for (i = 0x00; i < max_loop; i++) { value = bcm43xx_read16(bcm, 0x050E); if (value & 0x0080) break; udelay(10); } for (i = 0x00; i < 0x0A; i++) { value = bcm43xx_read16(bcm, 0x050E); if (value & 0x0400) break; udelay(10); } for (i = 0x00; i < 0x0A; i++) { value = bcm43xx_read16(bcm, 0x0690); if (!(value & 0x0100)) break; udelay(10); } if (radio->version == 0x2050 && radio->revision <= 0x5) bcm43xx_radio_write16(bcm, 0x0051, 0x0037);}static void key_write(struct bcm43xx_private *bcm, u8 index, u8 algorithm, const u16 *key){ unsigned int i, basic_wep = 0; u32 offset; u16 value; /* Write associated key information */ bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x100 + (index * 2), ((index << 4) | (algorithm & 0x0F))); /* The first 4 WEP keys need extra love */ if (((algorithm == BCM43xx_SEC_ALGO_WEP) || (algorithm == BCM43xx_SEC_ALGO_WEP104)) && (index < 4)) basic_wep = 1; /* Write key payload, 8 little endian words */ offset = bcm->security_offset + (index * BCM43xx_SEC_KEYSIZE); for (i = 0; i < (BCM43xx_SEC_KEYSIZE / sizeof(u16)); i++) { value = cpu_to_le16(key[i]); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, offset + (i * 2), value); if (!basic_wep) continue; bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, offset + (i * 2) + 4 * BCM43xx_SEC_KEYSIZE, value); }}static void keymac_write(struct bcm43xx_private *bcm, u8 index, const u32 *addr){ /* for keys 0-3 there is no associated mac address */ if (index < 4) return; index -= 4; if (bcm->current_core->rev >= 5) { bcm43xx_shm_write32(bcm, BCM43xx_SHM_HWMAC, index * 2, cpu_to_be32(*addr)); bcm43xx_shm_write16(bcm, BCM43xx_SHM_HWMAC, (index * 2) + 1, cpu_to_be16(*((u16 *)(addr + 1)))); } else { if (index < 8) { TODO(); /* Put them in the macaddress filter */ } else { TODO(); /* Put them BCM43xx_SHM_SHARED, stating index 0x0120. Keep in mind to update the count of keymacs in 0x003E as well! */ } }}static int bcm43xx_key_write(struct bcm43xx_private *bcm, u8 index, u8 algorithm, const u8 *_key, int key_len, const u8 *mac_addr){ u8 key[BCM43xx_SEC_KEYSIZE] = { 0 }; if (index >= ARRAY_SIZE(bcm->key)) return -EINVAL; if (key_len > ARRAY_SIZE(key)) return -EINVAL; if (algorithm < 1 || algorithm > 5) return -EINVAL; memcpy(key, _key, key_len); key_write(bcm, index, algorithm, (const u16 *)key); keymac_write(bcm, index, (const u32 *)mac_addr); bcm->key[index].algorithm = algorithm; return 0;}static void bcm43xx_clear_keys(struct bcm43xx_private *bcm){ static const u32 zero_mac[2] = { 0 }; unsigned int i,j, nr_keys = 54; u16 offset; if (bcm->current_core->rev < 5) nr_keys = 16; assert(nr_keys <= ARRAY_SIZE(bcm->key)); for (i = 0; i < nr_keys; i++) { bcm->key[i].enabled = 0; /* returns for i < 4 immediately */ keymac_write(bcm, i, zero_mac); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x100 + (i * 2), 0x0000); for (j = 0; j < 8; j++) { offset = bcm->security_offset + (j * 4) + (i * BCM43xx_SEC_KEYSIZE); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, offset, 0x0000); } } dprintk(KERN_INFO PFX "Keys cleared\n");}/* Lowlevel core-switch function. This is only to be used in * bcm43xx_switch_core() and bcm43xx_probe_cores() */static int _switch_core(struct bcm43xx_private *bcm, int core){ int err; int attempts = 0; u32 current_core; assert(core >= 0); while (1) { err = bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE, (core * 0x1000) + 0x18000000); if (unlikely(err)) goto error; err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_ACTIVE_CORE, ¤t_core); if (unlikely(err)) goto error; current_core = (current_core - 0x18000000) / 0x1000; if (current_core == core) break; if (unlikely(attempts++ > BCM43xx_SWITCH_CORE_MAX_RETRIES)) goto error; udelay(10); }#ifdef CONFIG_BCM947XX if (bcm->pci_dev->bus->number == 0) bcm->current_core_offset = 0x1000 * core; else bcm->current_core_offset = 0;#endif return 0;error: printk(KERN_ERR PFX "Failed to switch to core %d\n", core); return -ENODEV;}int bcm43xx_switch_core(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *new_core){ int err; if (unlikely(!new_core)) return 0; if (!(new_core->flags & BCM43xx_COREFLAG_AVAILABLE)) return -ENODEV; if (bcm->current_core == new_core) return 0; err = _switch_core(bcm, new_core->index); if (likely(!err)) bcm->current_core = new_core; return err;}static int bcm43xx_core_enabled(struct bcm43xx_private *bcm){ u32 value; value = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); value &= BCM43xx_SBTMSTATELOW_CLOCK | BCM43xx_SBTMSTATELOW_RESET | BCM43xx_SBTMSTATELOW_REJECT; return (value == BCM43xx_SBTMSTATELOW_CLOCK);}/* disable current core */static int bcm43xx_core_disable(struct bcm43xx_private *bcm, u32 core_flags){ u32 sbtmstatelow; u32 sbtmstatehigh; int i; /* fetch sbtmstatelow from core information registers */ sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); /* core is already in reset */ if (sbtmstatelow & BCM43xx_SBTMSTATELOW_RESET) goto out; if (sbtmstatelow & BCM43xx_SBTMSTATELOW_CLOCK) { sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | BCM43xx_SBTMSTATELOW_REJECT; bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); for (i = 0; i < 1000; i++) { sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); if (sbtmstatelow & BCM43xx_SBTMSTATELOW_REJECT) { i = -1; break; } udelay(10); } if (i != -1) { printk(KERN_ERR PFX "Error: core_disable() REJECT timeout!\n"); return -EBUSY; } for (i = 0; i < 1000; i++) { sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); if (!(sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_BUSY)) { i = -1; break; } udelay(10); } if (i != -1) { printk(KERN_ERR PFX "Error: core_disable() BUSY timeout!\n"); return -EBUSY; } sbtmstatelow = BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK | BCM43xx_SBTMSTATELOW_REJECT | BCM43xx_SBTMSTATELOW_RESET | BCM43xx_SBTMSTATELOW_CLOCK | core_flags; bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); udelay(10); } sbtmstatelow = BCM43xx_SBTMSTATELOW_RESET | BCM43xx_SBTMSTATELOW_REJECT | core_flags; bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);out: bcm->current_core->flags &= ~ BCM43xx_COREFLAG_ENABLED; return 0;}/* enable (reset) current core */static int bcm43xx_core_enable(struct bcm43xx_private *bcm, u32 core_flags){ u32 sbtmstatelow; u32 sbtmstatehigh; u32 sbimstate; int err; err = bcm43xx_core_disable(bcm, core_flags); if (err) goto out; sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | BCM43xx_SBTMSTATELOW_RESET | BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK | core_flags; bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); udelay(1); sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH); if (sbtmstatehigh & BCM43xx_SBTMSTATEHIGH_SERROR) { sbtmstatehigh = 0x00000000; bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATEHIGH, sbtmstatehigh); } sbimstate = bcm43xx_read32(bcm, BCM43xx_CIR_SBIMSTATE); if (sbimstate & (BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT)) { sbimstate &= ~(BCM43xx_SBIMSTATE_IB_ERROR | BCM43xx_SBIMSTATE_TIMEOUT); bcm43xx_write32(bcm, BCM43xx_CIR_SBIMSTATE, sbimstate); } sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | BCM43xx_SBTMSTATELOW_FORCE_GATE_CLOCK | core_flags; bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); udelay(1); sbtmstatelow = BCM43xx_SBTMSTATELOW_CLOCK | core_flags; bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); udelay(1); bcm->current_core->flags |= BCM43xx_COREFLAG_ENABLED; assert(err == 0);out: return err;}/* http://bcm-specs.sipsolutions.net/80211CoreReset */void bcm43xx_wireless_core_reset(struct bcm43xx_private *bcm, int connect_phy){ u32 flags = 0x00040000; if ((bcm43xx_core_enabled(bcm)) && !bcm43xx_using_pio(bcm)) {//FIXME: Do we _really_ want #ifndef CONFIG_BCM947XX here?#ifndef CONFIG_BCM947XX /* reset all used DMA controllers. */ bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA1_BASE); bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA2_BASE); bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA3_BASE); bcm43xx_dmacontroller_tx_reset(bcm, BCM43xx_MMIO_DMA4_BASE); bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA1_BASE); if (bcm->current_core->rev < 5) bcm43xx_dmacontroller_rx_reset(bcm, BCM43xx_MMIO_DMA4_BASE);#endif } if (bcm->shutting_down) { bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) & ~(BCM43xx_SBF_MAC_ENABLED | 0x00000002)); } else { if (connect_phy) flags |= 0x20000000; bcm43xx_phy_connect(bcm, connect_phy); bcm43xx_core_enable(bcm, flags); bcm43xx_write16(bcm, 0x03E6, 0x0000); bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD) | BCM43xx_SBF_400); }}static void bcm43xx_wireless_core_disable(struct bcm43xx_private *bcm){ bcm43xx_radio_turn_off(bcm); bcm43xx_write16(bcm, 0x03E6, 0x00F4); bcm43xx_core_disable(bcm, 0);}/* Mark the current 80211 core inactive. * "active_80211_core" is the other 80211 core, which is used. */static int bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm, struct bcm43xx_coreinfo *active_80211_core){ u32 sbtmstatelow; struct bcm43xx_coreinfo *old_core; int err = 0; bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL); bcm43xx_radio_turn_off(bcm); sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW); sbtmstatelow &= ~0x200a0000; sbtmstatelow |= 0xa0000; bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow); udelay(1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -