⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 bcm43xx_radio.c

📁 无线网卡驱动,有很好的参考价值,在linux_2.6.21下可以直接使用,如果在其他平台,可以参考移植
💻 C
📖 第 1 页 / 共 4 页
字号:
	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 + -