📄 bcm43xx_radio.c
字号:
bcm43xx_radio_write16(bcm, 0x0005, 0x0008); bcm43xx_radio_write16(bcm, 0x0009, 0x0040); bcm43xx_radio_write16(bcm, 0x0005, 0x00AA); bcm43xx_radio_write16(bcm, 0x0032, 0x008F); bcm43xx_radio_write16(bcm, 0x0006, 0x008F); bcm43xx_radio_write16(bcm, 0x0034, 0x008F); bcm43xx_radio_write16(bcm, 0x002C, 0x0007); bcm43xx_radio_write16(bcm, 0x0082, 0x0080); bcm43xx_radio_write16(bcm, 0x0080, 0x0000); bcm43xx_radio_write16(bcm, 0x003F, 0x00DA); bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008); bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0010); bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020); bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020); udelay(400); bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0020) | 0x0010); udelay(400); bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008) | 0x0008); bcm43xx_radio_write16(bcm, 0x0085, bcm43xx_radio_read16(bcm, 0x0085) & ~0x0010); bcm43xx_radio_write16(bcm, 0x0005, bcm43xx_radio_read16(bcm, 0x0005) & ~0x0008); bcm43xx_radio_write16(bcm, 0x0081, bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040); bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0040) | 0x0040); bcm43xx_radio_write16(bcm, 0x0005, (bcm43xx_radio_read16(bcm, 0x0081) & ~0x0008) | 0x0008); bcm43xx_phy_write(bcm, 0x0063, 0xDDC6); bcm43xx_phy_write(bcm, 0x0069, 0x07BE); bcm43xx_phy_write(bcm, 0x006A, 0x0000); err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_A, 0); assert(err == 0); udelay(1000);}static inlineu16 freq_r3A_value(u16 frequency){ u16 value; if (frequency < 5091) value = 0x0040; else if (frequency < 5321) value = 0x0000; else if (frequency < 5806) value = 0x0080; else value = 0x0040; return value;}void bcm43xx_radio_set_tx_iq(struct bcm43xx_private *bcm){ static const u8 data_high[5] = { 0x00, 0x40, 0x80, 0x90, 0xD0 }; static const u8 data_low[5] = { 0x00, 0x01, 0x05, 0x06, 0x0A }; u16 tmp = bcm43xx_radio_read16(bcm, 0x001E); int i, j; for (i = 0; i < 5; i++) { for (j = 0; j < 5; j++) { if (tmp == (data_high[i] | data_low[j])) { bcm43xx_phy_write(bcm, 0x0069, (i - j) << 8 | 0x00C0); return; } } }}int bcm43xx_radio_selectchannel(struct bcm43xx_private *bcm, u8 channel, int synthetic_pu_workaround){ struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 r8, tmp; u16 freq; if (!ieee80211_is_valid_channel(bcm->ieee, channel)) return -EINVAL; if ((radio->manufact == 0x17F) && (radio->version == 0x2060) && (radio->revision == 1)) { freq = channel2freq_a(channel); r8 = bcm43xx_radio_read16(bcm, 0x0008); bcm43xx_write16(bcm, 0x03F0, freq); bcm43xx_radio_write16(bcm, 0x0008, r8); TODO();//TODO: write max channel TX power? to Radio 0x2D tmp = bcm43xx_radio_read16(bcm, 0x002E); tmp &= 0x0080; TODO();//TODO: OR tmp with the Power out estimation for this channel? bcm43xx_radio_write16(bcm, 0x002E, tmp); if (freq >= 4920 && freq <= 5500) { /* * r8 = (((freq * 15 * 0xE1FC780F) >> 32) / 29) & 0x0F; * = (freq * 0.025862069 */ r8 = 3 * freq / 116; /* is equal to r8 = freq * 0.025862 */ } bcm43xx_radio_write16(bcm, 0x0007, (r8 << 4) | r8); bcm43xx_radio_write16(bcm, 0x0020, (r8 << 4) | r8); bcm43xx_radio_write16(bcm, 0x0021, (r8 << 4) | r8); bcm43xx_radio_write16(bcm, 0x0022, (bcm43xx_radio_read16(bcm, 0x0022) & 0x000F) | (r8 << 4)); bcm43xx_radio_write16(bcm, 0x002A, (r8 << 4)); bcm43xx_radio_write16(bcm, 0x002B, (r8 << 4)); bcm43xx_radio_write16(bcm, 0x0008, (bcm43xx_radio_read16(bcm, 0x0008) & 0x00F0) | (r8 << 4)); bcm43xx_radio_write16(bcm, 0x0029, (bcm43xx_radio_read16(bcm, 0x0029) & 0xFF0F) | 0x00B0); bcm43xx_radio_write16(bcm, 0x0035, 0x00AA); bcm43xx_radio_write16(bcm, 0x0036, 0x0085); bcm43xx_radio_write16(bcm, 0x003A, (bcm43xx_radio_read16(bcm, 0x003A) & 0xFF20) | freq_r3A_value(freq)); bcm43xx_radio_write16(bcm, 0x003D, bcm43xx_radio_read16(bcm, 0x003D) & 0x00FF); bcm43xx_radio_write16(bcm, 0x0081, (bcm43xx_radio_read16(bcm, 0x0081) & 0xFF7F) | 0x0080); bcm43xx_radio_write16(bcm, 0x0035, bcm43xx_radio_read16(bcm, 0x0035) & 0xFFEF); bcm43xx_radio_write16(bcm, 0x0035, (bcm43xx_radio_read16(bcm, 0x0035) & 0xFFEF) | 0x0010); bcm43xx_radio_set_tx_iq(bcm); TODO(); //TODO: TSSI2dbm workaround bcm43xx_phy_xmitpower(bcm);//FIXME correct? } else { if (synthetic_pu_workaround) bcm43xx_synth_pu_workaround(bcm, channel); bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL, channel2freq_bg(channel)); if (channel == 14) { if (bcm->sprom.locale == BCM43xx_LOCALE_JAPAN) { bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET, bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET) & ~(1 << 7)); } else { bcm43xx_shm_write32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET, bcm43xx_shm_read32(bcm, BCM43xx_SHM_SHARED, BCM43xx_UCODEFLAGS_OFFSET) | (1 << 7)); } bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) | (1 << 11)); } else { bcm43xx_write16(bcm, BCM43xx_MMIO_CHANNEL_EXT, bcm43xx_read16(bcm, BCM43xx_MMIO_CHANNEL_EXT) & 0xF7BF); } } radio->channel = channel; //XXX: Using the longer of 2 timeouts (8000 vs 2000 usecs). Specs states // that 2000 usecs might suffice. udelay(8000); return 0;}void bcm43xx_radio_set_txantenna(struct bcm43xx_private *bcm, u32 val){ u16 tmp; val <<= 8; tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0022) & 0xFCFF; bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0022, tmp | val); tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x03A8) & 0xFCFF; bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x03A8, tmp | val); tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x0054) & 0xFCFF; bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0054, tmp | val);}/* http://bcm-specs.sipsolutions.net/TX_Gain_Base_Band */static u16 bcm43xx_get_txgain_base_band(u16 txpower){ u16 ret; assert(txpower <= 63); if (txpower >= 54) ret = 2; else if (txpower >= 49) ret = 4; else if (txpower >= 44) ret = 5; else ret = 6; return ret;}/* http://bcm-specs.sipsolutions.net/TX_Gain_Radio_Frequency_Power_Amplifier */static u16 bcm43xx_get_txgain_freq_power_amp(u16 txpower){ u16 ret; assert(txpower <= 63); if (txpower >= 32) ret = 0; else if (txpower >= 25) ret = 1; else if (txpower >= 20) ret = 2; else if (txpower >= 12) ret = 3; else ret = 4; return ret;}/* http://bcm-specs.sipsolutions.net/TX_Gain_Digital_Analog_Converter */static u16 bcm43xx_get_txgain_dac(u16 txpower){ u16 ret; assert(txpower <= 63); if (txpower >= 54) ret = txpower - 53; else if (txpower >= 49) ret = txpower - 42; else if (txpower >= 44) ret = txpower - 37; else if (txpower >= 32) ret = txpower - 32; else if (txpower >= 25) ret = txpower - 20; else if (txpower >= 20) ret = txpower - 13; else if (txpower >= 12) ret = txpower - 8; else ret = txpower; return ret;}void bcm43xx_radio_set_txpower_a(struct bcm43xx_private *bcm, u16 txpower){ struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 pamp, base, dac, ilt; txpower = limit_value(txpower, 0, 63); pamp = bcm43xx_get_txgain_freq_power_amp(txpower); pamp <<= 5; pamp &= 0x00E0; bcm43xx_phy_write(bcm, 0x0019, pamp); base = bcm43xx_get_txgain_base_band(txpower); base &= 0x000F; bcm43xx_phy_write(bcm, 0x0017, base | 0x0020); ilt = bcm43xx_ilt_read(bcm, 0x3001); ilt &= 0x0007; dac = bcm43xx_get_txgain_dac(txpower); dac <<= 3; dac |= ilt; bcm43xx_ilt_write(bcm, 0x3001, dac); radio->txpwr_offset = txpower; TODO(); //TODO: FuncPlaceholder (Adjust BB loft cancel)}void bcm43xx_radio_set_txpower_bg(struct bcm43xx_private *bcm, u16 baseband_attenuation, u16 radio_attenuation, u16 txpower){ struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); if (baseband_attenuation == 0xFFFF) baseband_attenuation = radio->baseband_atten; if (radio_attenuation == 0xFFFF) radio_attenuation = radio->radio_atten; if (txpower == 0xFFFF) txpower = radio->txctl1; radio->baseband_atten = baseband_attenuation; radio->radio_atten = radio_attenuation; radio->txctl1 = txpower; assert(/*baseband_attenuation >= 0 &&*/ baseband_attenuation <= 11); if (radio->revision < 6) assert(/*radio_attenuation >= 0 &&*/ radio_attenuation <= 9); else assert(/* radio_attenuation >= 0 &&*/ radio_attenuation <= 31); assert(/*txpower >= 0 &&*/ txpower <= 7); bcm43xx_phy_set_baseband_attenuation(bcm, baseband_attenuation); bcm43xx_radio_write16(bcm, 0x0043, radio_attenuation); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0064, radio_attenuation); if (radio->version == 0x2050) { bcm43xx_radio_write16(bcm, 0x0052, (bcm43xx_radio_read16(bcm, 0x0052) & ~0x0070) | ((txpower << 4) & 0x0070)); } //FIXME: The spec is very weird and unclear here. if (phy->type == BCM43xx_PHYTYPE_G) bcm43xx_phy_lo_adjust(bcm, 0);}u16 bcm43xx_default_baseband_attenuation(struct bcm43xx_private *bcm){ struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); if (radio->version == 0x2050 && radio->revision < 6) return 0; return 2;}u16 bcm43xx_default_radio_attenuation(struct bcm43xx_private *bcm){ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); u16 att = 0xFFFF; if (phy->type == BCM43xx_PHYTYPE_A) return 0x60; switch (radio->version) { case 0x2053: switch (radio->revision) { case 1: att = 6; break; } break; case 0x2050: switch (radio->revision) { case 0: att = 5; break; case 1: if (phy->type == BCM43xx_PHYTYPE_G) { if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && bcm->board_type == 0x421 && bcm->board_revision >= 30) att = 3; else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && bcm->board_type == 0x416) att = 3; else att = 1; } else { if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && bcm->board_type == 0x421 && bcm->board_revision >= 30) att = 7; else att = 6; } break; case 2: if (phy->type == BCM43xx_PHYTYPE_G) { if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && bcm->board_type == 0x421 && bcm->board_revision >= 30) att = 3; else if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && bcm->board_type == 0x416) att = 5; else if (bcm->chip_id == 0x4320) att = 4; else att = 3; } else att = 6; break; case 3: att = 5; break; case 4: case 5: att = 1; break; case 6: case 7: att = 5; break; case 8: att = 0x1A; break; case 9: default: att = 5; } } if (bcm->board_vendor == PCI_VENDOR_ID_BROADCOM && bcm->board_type == 0x421) { if (bcm->board_revision < 0x43) att = 2; else if (bcm->board_revision < 0x51) att = 3; } if (att == 0xFFFF) att = 5; return att;}u16 bcm43xx_default_txctl1(struct bcm43xx_private *bcm){ struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); if (radio->version != 0x2050) return 0; if (radio->revision == 1) return 3; if (radio->revision < 6) return 2; if (radio->revision == 8) return 1; return 0;}void bcm43xx_radio_turn_on(struct bcm43xx_private *bcm){ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); int err; if (radio->enabled) return; switch (phy->type) { case BCM43xx_PHYTYPE_A: bcm43xx_radio_write16(bcm, 0x0004, 0x00C0); bcm43xx_radio_write16(bcm, 0x0005, 0x0008); bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) & 0xFFF7); bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) & 0xFFF7); bcm43xx_radio_init2060(bcm); break; case BCM43xx_PHYTYPE_B: case BCM43xx_PHYTYPE_G: bcm43xx_phy_write(bcm, 0x0015, 0x8000); bcm43xx_phy_write(bcm, 0x0015, 0xCC00); bcm43xx_phy_write(bcm, 0x0015, (phy->connected ? 0x00C0 : 0x0000)); err = bcm43xx_radio_selectchannel(bcm, BCM43xx_RADIO_DEFAULT_CHANNEL_BG, 1); assert(err == 0); break; default: assert(0); } radio->enabled = 1; dprintk(KERN_INFO PFX "Radio turned on\n"); bcm43xx_leds_update(bcm, 0);} void bcm43xx_radio_turn_off(struct bcm43xx_private *bcm){ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm); if (phy->type == BCM43xx_PHYTYPE_A) { bcm43xx_radio_write16(bcm, 0x0004, 0x00FF); bcm43xx_radio_write16(bcm, 0x0005, 0x00FB); bcm43xx_phy_write(bcm, 0x0010, bcm43xx_phy_read(bcm, 0x0010) | 0x0008); bcm43xx_phy_write(bcm, 0x0011, bcm43xx_phy_read(bcm, 0x0011) | 0x0008); } if (phy->type == BCM43xx_PHYTYPE_G && bcm->current_core->rev >= 5) { bcm43xx_phy_write(bcm, 0x0811, bcm43xx_phy_read(bcm, 0x0811) | 0x008C); bcm43xx_phy_write(bcm, 0x0812, bcm43xx_phy_read(bcm, 0x0812) & 0xFF73); } else bcm43xx_phy_write(bcm, 0x0015, 0xAA00); radio->enabled = 0; dprintk(KERN_INFO PFX "Radio turned off\n"); bcm43xx_leds_update(bcm, 0);}void bcm43xx_radio_clear_tssi(struct bcm43xx_private *bcm){ struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm); switch (phy->type) { case BCM43xx_PHYTYPE_A: bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0068, 0x7F7F); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x006a, 0x7F7F); break; case BCM43xx_PHYTYPE_B: case BCM43xx_PHYTYPE_G: bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0058, 0x7F7F); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x005a, 0x7F7F); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0070, 0x7F7F); bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x0072, 0x7F7F); break; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -