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

📄 radio.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 4 页
字号:
/*  Broadcom B43legacy wireless driver  Copyright (c) 2005 Martin Langer <martin-langer@gmx.de>,		     Stefano Brivio <st3@riseup.net>		     Michael Buesch <mbuesch@freenet.de>		     Danny van Dyk <kugelfang@gentoo.org>		     Andreas Jaggi <andreas.jaggi@waterwave.ch>  Copyright (c) 2007 Larry Finger <Larry.Finger@lwfinger.net>  Some parts of the code in this file are derived from the ipw2200  driver  Copyright(c) 2003 - 2004 Intel Corporation.  This program is free software; you can redistribute it and/or modify  it under the terms of the GNU General Public License as published by  the Free Software Foundation; either version 2 of the License, or  (at your option) any later version.  This program is distributed in the hope that it will be useful,  but WITHOUT ANY WARRANTY; without even the implied warranty of  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the  GNU General Public License for more details.  You should have received a copy of the GNU General Public License  along with this program; see the file COPYING.  If not, write to  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,  Boston, MA 02110-1301, USA.*/#include <linux/delay.h>#include "b43legacy.h"#include "main.h"#include "phy.h"#include "radio.h"#include "ilt.h"/* Table for b43legacy_radio_calibrationvalue() */static const u16 rcc_table[16] = {	0x0002, 0x0003, 0x0001, 0x000F,	0x0006, 0x0007, 0x0005, 0x000F,	0x000A, 0x000B, 0x0009, 0x000F,	0x000E, 0x000F, 0x000D, 0x000F,};/* Reverse the bits of a 4bit value. * Example:  1101 is flipped 1011 */static u16 flip_4bit(u16 value){	u16 flipped = 0x0000;	B43legacy_BUG_ON(!((value & ~0x000F) == 0x0000));	flipped |= (value & 0x0001) << 3;	flipped |= (value & 0x0002) << 1;	flipped |= (value & 0x0004) >> 1;	flipped |= (value & 0x0008) >> 3;	return flipped;}/* Get the freq, as it has to be written to the device. */static inlineu16 channel2freq_bg(u8 channel){	/* Frequencies are given as frequencies_bg[index] + 2.4GHz	 * Starting with channel 1	 */	static const u16 frequencies_bg[14] = {		12, 17, 22, 27,		32, 37, 42, 47,		52, 57, 62, 67,		72, 84,	};	if (unlikely(channel < 1 || channel > 14)) {		printk(KERN_INFO "b43legacy: Channel %d is out of range\n",				  channel);		dump_stack();		return 2412;	}	return frequencies_bg[channel - 1];}void b43legacy_radio_lock(struct b43legacy_wldev *dev){	u32 status;	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);	status |= B43legacy_SBF_RADIOREG_LOCK;	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);	mmiowb();	udelay(10);}void b43legacy_radio_unlock(struct b43legacy_wldev *dev){	u32 status;	b43legacy_read16(dev, B43legacy_MMIO_PHY_VER); /* dummy read */	status = b43legacy_read32(dev, B43legacy_MMIO_STATUS_BITFIELD);	status &= ~B43legacy_SBF_RADIOREG_LOCK;	b43legacy_write32(dev, B43legacy_MMIO_STATUS_BITFIELD, status);	mmiowb();}u16 b43legacy_radio_read16(struct b43legacy_wldev *dev, u16 offset){	struct b43legacy_phy *phy = &dev->phy;	switch (phy->type) {	case B43legacy_PHYTYPE_B:		if (phy->radio_ver == 0x2053) {			if (offset < 0x70)				offset += 0x80;			else if (offset < 0x80)				offset += 0x70;		} else if (phy->radio_ver == 0x2050)			offset |= 0x80;		else			B43legacy_WARN_ON(1);		break;	case B43legacy_PHYTYPE_G:		offset |= 0x80;		break;	default:		B43legacy_BUG_ON(1);	}	b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);	return b43legacy_read16(dev, B43legacy_MMIO_RADIO_DATA_LOW);}void b43legacy_radio_write16(struct b43legacy_wldev *dev, u16 offset, u16 val){	b43legacy_write16(dev, B43legacy_MMIO_RADIO_CONTROL, offset);	mmiowb();	b43legacy_write16(dev, B43legacy_MMIO_RADIO_DATA_LOW, val);}static void b43legacy_set_all_gains(struct b43legacy_wldev *dev,				  s16 first, s16 second, s16 third){	struct b43legacy_phy *phy = &dev->phy;	u16 i;	u16 start = 0x08;	u16 end = 0x18;	u16 offset = 0x0400;	u16 tmp;	if (phy->rev <= 1) {		offset = 0x5000;		start = 0x10;		end = 0x20;	}	for (i = 0; i < 4; i++)		b43legacy_ilt_write(dev, offset + i, first);	for (i = start; i < end; i++)		b43legacy_ilt_write(dev, offset + i, second);	if (third != -1) {		tmp = ((u16)third << 14) | ((u16)third << 6);		b43legacy_phy_write(dev, 0x04A0,				    (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF)				    | tmp);		b43legacy_phy_write(dev, 0x04A1,				    (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF)				    | tmp);		b43legacy_phy_write(dev, 0x04A2,				    (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF)				    | tmp);	}	b43legacy_dummy_transmission(dev);}static void b43legacy_set_original_gains(struct b43legacy_wldev *dev){	struct b43legacy_phy *phy = &dev->phy;	u16 i;	u16 tmp;	u16 offset = 0x0400;	u16 start = 0x0008;	u16 end = 0x0018;	if (phy->rev <= 1) {		offset = 0x5000;		start = 0x0010;		end = 0x0020;	}	for (i = 0; i < 4; i++) {		tmp = (i & 0xFFFC);		tmp |= (i & 0x0001) << 1;		tmp |= (i & 0x0002) >> 1;		b43legacy_ilt_write(dev, offset + i, tmp);	}	for (i = start; i < end; i++)		b43legacy_ilt_write(dev, offset + i, i - start);	b43legacy_phy_write(dev, 0x04A0,			    (b43legacy_phy_read(dev, 0x04A0) & 0xBFBF)			    | 0x4040);	b43legacy_phy_write(dev, 0x04A1,			    (b43legacy_phy_read(dev, 0x04A1) & 0xBFBF)			    | 0x4040);	b43legacy_phy_write(dev, 0x04A2,			    (b43legacy_phy_read(dev, 0x04A2) & 0xBFBF)			    | 0x4000);	b43legacy_dummy_transmission(dev);}/* Synthetic PU workaround */static void b43legacy_synth_pu_workaround(struct b43legacy_wldev *dev,					  u8 channel){	struct b43legacy_phy *phy = &dev->phy;	might_sleep();	if (phy->radio_ver != 0x2050 || phy->radio_rev >= 6)		/* We do not need the workaround. */		return;	if (channel <= 10)		b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,				  channel2freq_bg(channel + 4));	else		b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,				  channel2freq_bg(channel));	msleep(1);	b43legacy_write16(dev, B43legacy_MMIO_CHANNEL,			  channel2freq_bg(channel));}u8 b43legacy_radio_aci_detect(struct b43legacy_wldev *dev, u8 channel){	struct b43legacy_phy *phy = &dev->phy;	u8 ret = 0;	u16 saved;	u16 rssi;	u16 temp;	int i;	int j = 0;	saved = b43legacy_phy_read(dev, 0x0403);	b43legacy_radio_selectchannel(dev, channel, 0);	b43legacy_phy_write(dev, 0x0403, (saved & 0xFFF8) | 5);	if (phy->aci_hw_rssi)		rssi = b43legacy_phy_read(dev, 0x048A) & 0x3F;	else		rssi = saved & 0x3F;	/* clamp temp to signed 5bit */	if (rssi > 32)		rssi -= 64;	for (i = 0; i < 100; i++) {		temp = (b43legacy_phy_read(dev, 0x047F) >> 8) & 0x3F;		if (temp > 32)			temp -= 64;		if (temp < rssi)			j++;		if (j >= 20)			ret = 1;	}	b43legacy_phy_write(dev, 0x0403, saved);	return ret;}u8 b43legacy_radio_aci_scan(struct b43legacy_wldev *dev){	struct b43legacy_phy *phy = &dev->phy;	u8 ret[13];	unsigned int channel = phy->channel;	unsigned int i;	unsigned int j;	unsigned int start;	unsigned int end;	unsigned long phylock_flags;	if (!((phy->type == B43legacy_PHYTYPE_G) && (phy->rev > 0)))		return 0;	b43legacy_phy_lock(dev, phylock_flags);	b43legacy_radio_lock(dev);	b43legacy_phy_write(dev, 0x0802,			    b43legacy_phy_read(dev, 0x0802) & 0xFFFC);	b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,			    b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)			    & 0x7FFF);	b43legacy_set_all_gains(dev, 3, 8, 1);	start = (channel - 5 > 0) ? channel - 5 : 1;	end = (channel + 5 < 14) ? channel + 5 : 13;	for (i = start; i <= end; i++) {		if (abs(channel - i) > 2)			ret[i-1] = b43legacy_radio_aci_detect(dev, i);	}	b43legacy_radio_selectchannel(dev, channel, 0);	b43legacy_phy_write(dev, 0x0802,			    (b43legacy_phy_read(dev, 0x0802) & 0xFFFC)			    | 0x0003);	b43legacy_phy_write(dev, 0x0403,			    b43legacy_phy_read(dev, 0x0403) & 0xFFF8);	b43legacy_phy_write(dev, B43legacy_PHY_G_CRS,			    b43legacy_phy_read(dev, B43legacy_PHY_G_CRS)			    | 0x8000);	b43legacy_set_original_gains(dev);	for (i = 0; i < 13; i++) {		if (!ret[i])			continue;		end = (i + 5 < 13) ? i + 5 : 13;		for (j = i; j < end; j++)			ret[j] = 1;	}	b43legacy_radio_unlock(dev);	b43legacy_phy_unlock(dev, phylock_flags);	return ret[channel - 1];}/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */void b43legacy_nrssi_hw_write(struct b43legacy_wldev *dev, u16 offset, s16 val){	b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset);	mmiowb();	b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_DATA, (u16)val);}/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */s16 b43legacy_nrssi_hw_read(struct b43legacy_wldev *dev, u16 offset){	u16 val;	b43legacy_phy_write(dev, B43legacy_PHY_NRSSILT_CTRL, offset);	val = b43legacy_phy_read(dev, B43legacy_PHY_NRSSILT_DATA);	return (s16)val;}/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */void b43legacy_nrssi_hw_update(struct b43legacy_wldev *dev, u16 val){	u16 i;	s16 tmp;	for (i = 0; i < 64; i++) {		tmp = b43legacy_nrssi_hw_read(dev, i);		tmp -= val;		tmp = limit_value(tmp, -32, 31);		b43legacy_nrssi_hw_write(dev, i, tmp);	}}/* http://bcm-specs.sipsolutions.net/NRSSILookupTable */void b43legacy_nrssi_mem_update(struct b43legacy_wldev *dev){	struct b43legacy_phy *phy = &dev->phy;	s16 i;	s16 delta;	s32 tmp;	delta = 0x1F - phy->nrssi[0];	for (i = 0; i < 64; i++) {		tmp = (i - delta) * phy->nrssislope;		tmp /= 0x10000;		tmp += 0x3A;		tmp = limit_value(tmp, 0, 0x3F);		phy->nrssi_lt[i] = tmp;	}}static void b43legacy_calc_nrssi_offset(struct b43legacy_wldev *dev){	struct b43legacy_phy *phy = &dev->phy;	u16 backup[20] = { 0 };	s16 v47F;	u16 i;	u16 saved = 0xFFFF;	backup[0] = b43legacy_phy_read(dev, 0x0001);	backup[1] = b43legacy_phy_read(dev, 0x0811);	backup[2] = b43legacy_phy_read(dev, 0x0812);	backup[3] = b43legacy_phy_read(dev, 0x0814);	backup[4] = b43legacy_phy_read(dev, 0x0815);	backup[5] = b43legacy_phy_read(dev, 0x005A);	backup[6] = b43legacy_phy_read(dev, 0x0059);	backup[7] = b43legacy_phy_read(dev, 0x0058);	backup[8] = b43legacy_phy_read(dev, 0x000A);	backup[9] = b43legacy_phy_read(dev, 0x0003);	backup[10] = b43legacy_radio_read16(dev, 0x007A);	backup[11] = b43legacy_radio_read16(dev, 0x0043);	b43legacy_phy_write(dev, 0x0429,			    b43legacy_phy_read(dev, 0x0429) & 0x7FFF);	b43legacy_phy_write(dev, 0x0001,			    (b43legacy_phy_read(dev, 0x0001) & 0x3FFF)			    | 0x4000);	b43legacy_phy_write(dev, 0x0811,			    b43legacy_phy_read(dev, 0x0811) | 0x000C);	b43legacy_phy_write(dev, 0x0812,			    (b43legacy_phy_read(dev, 0x0812) & 0xFFF3)			    | 0x0004);	b43legacy_phy_write(dev, 0x0802,			    b43legacy_phy_read(dev, 0x0802) & ~(0x1 | 0x2));	if (phy->rev >= 6) {		backup[12] = b43legacy_phy_read(dev, 0x002E);		backup[13] = b43legacy_phy_read(dev, 0x002F);		backup[14] = b43legacy_phy_read(dev, 0x080F);		backup[15] = b43legacy_phy_read(dev, 0x0810);		backup[16] = b43legacy_phy_read(dev, 0x0801);		backup[17] = b43legacy_phy_read(dev, 0x0060);		backup[18] = b43legacy_phy_read(dev, 0x0014);		backup[19] = b43legacy_phy_read(dev, 0x0478);		b43legacy_phy_write(dev, 0x002E, 0);		b43legacy_phy_write(dev, 0x002F, 0);		b43legacy_phy_write(dev, 0x080F, 0);		b43legacy_phy_write(dev, 0x0810, 0);		b43legacy_phy_write(dev, 0x0478,				    b43legacy_phy_read(dev, 0x0478) | 0x0100);		b43legacy_phy_write(dev, 0x0801,				    b43legacy_phy_read(dev, 0x0801) | 0x0040);		b43legacy_phy_write(dev, 0x0060,				    b43legacy_phy_read(dev, 0x0060) | 0x0040);		b43legacy_phy_write(dev, 0x0014,				    b43legacy_phy_read(dev, 0x0014) | 0x0200);	}	b43legacy_radio_write16(dev, 0x007A,				b43legacy_radio_read16(dev, 0x007A) | 0x0070);	b43legacy_radio_write16(dev, 0x007A,				b43legacy_radio_read16(dev, 0x007A) | 0x0080);	udelay(30);	v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);	if (v47F >= 0x20)		v47F -= 0x40;	if (v47F == 31) {		for (i = 7; i >= 4; i--) {			b43legacy_radio_write16(dev, 0x007B, i);			udelay(20);			v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8)							 & 0x003F);			if (v47F >= 0x20)				v47F -= 0x40;			if (v47F < 31 && saved == 0xFFFF)				saved = i;		}		if (saved == 0xFFFF)			saved = 4;	} else {		b43legacy_radio_write16(dev, 0x007A,					b43legacy_radio_read16(dev, 0x007A)					& 0x007F);		b43legacy_phy_write(dev, 0x0814,				    b43legacy_phy_read(dev, 0x0814) | 0x0001);		b43legacy_phy_write(dev, 0x0815,				    b43legacy_phy_read(dev, 0x0815) & 0xFFFE);		b43legacy_phy_write(dev, 0x0811,				    b43legacy_phy_read(dev, 0x0811) | 0x000C);		b43legacy_phy_write(dev, 0x0812,				    b43legacy_phy_read(dev, 0x0812) | 0x000C);		b43legacy_phy_write(dev, 0x0811,				    b43legacy_phy_read(dev, 0x0811) | 0x0030);		b43legacy_phy_write(dev, 0x0812,				    b43legacy_phy_read(dev, 0x0812) | 0x0030);		b43legacy_phy_write(dev, 0x005A, 0x0480);		b43legacy_phy_write(dev, 0x0059, 0x0810);		b43legacy_phy_write(dev, 0x0058, 0x000D);		if (phy->analog == 0)			b43legacy_phy_write(dev, 0x0003, 0x0122);		else			b43legacy_phy_write(dev, 0x000A,					    b43legacy_phy_read(dev, 0x000A)					    | 0x2000);		b43legacy_phy_write(dev, 0x0814,				    b43legacy_phy_read(dev, 0x0814) | 0x0004);		b43legacy_phy_write(dev, 0x0815,				    b43legacy_phy_read(dev, 0x0815) & 0xFFFB);		b43legacy_phy_write(dev, 0x0003,				    (b43legacy_phy_read(dev, 0x0003) & 0xFF9F)				    | 0x0040);		b43legacy_radio_write16(dev, 0x007A,					b43legacy_radio_read16(dev, 0x007A)					| 0x000F);		b43legacy_set_all_gains(dev, 3, 0, 1);		b43legacy_radio_write16(dev, 0x0043,					(b43legacy_radio_read16(dev, 0x0043)					& 0x00F0) | 0x000F);		udelay(30);		v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >> 8) & 0x003F);		if (v47F >= 0x20)			v47F -= 0x40;		if (v47F == -32) {			for (i = 0; i < 4; i++) {				b43legacy_radio_write16(dev, 0x007B, i);				udelay(20);				v47F = (s16)((b43legacy_phy_read(dev, 0x047F) >>								 8) & 0x003F);				if (v47F >= 0x20)					v47F -= 0x40;				if (v47F > -31 && saved == 0xFFFF)					saved = i;			}			if (saved == 0xFFFF)				saved = 3;		} else			saved = 0;	}	b43legacy_radio_write16(dev, 0x007B, saved);	if (phy->rev >= 6) {		b43legacy_phy_write(dev, 0x002E, backup[12]);		b43legacy_phy_write(dev, 0x002F, backup[13]);		b43legacy_phy_write(dev, 0x080F, backup[14]);		b43legacy_phy_write(dev, 0x0810, backup[15]);	}	b43legacy_phy_write(dev, 0x0814, backup[3]);	b43legacy_phy_write(dev, 0x0815, backup[4]);	b43legacy_phy_write(dev, 0x005A, backup[5]);	b43legacy_phy_write(dev, 0x0059, backup[6]);	b43legacy_phy_write(dev, 0x0058, backup[7]);	b43legacy_phy_write(dev, 0x000A, backup[8]);	b43legacy_phy_write(dev, 0x0003, backup[9]);	b43legacy_radio_write16(dev, 0x0043, backup[11]);	b43legacy_radio_write16(dev, 0x007A, backup[10]);	b43legacy_phy_write(dev, 0x0802,			    b43legacy_phy_read(dev, 0x0802) | 0x1 | 0x2);	b43legacy_phy_write(dev, 0x0429,			    b43legacy_phy_read(dev, 0x0429) | 0x8000);	b43legacy_set_original_gains(dev);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -