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

📄 bcm43xx_main.c

📁 博通的bcm43xx系列Minipci接口无线网卡驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
	u32 old_mask;	old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask | mask);	return old_mask;}/* Disable a Generic IRQ. "mask" is the mask of which IRQs to disable. * Returns the _previously_ enabled IRQ mask. */static inline u32 bcm43xx_interrupt_disable(struct bcm43xx_private *bcm, u32 mask){	u32 old_mask;	old_mask = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK, old_mask & ~mask);	return old_mask;}/* Make sure we don't receive more data from the device. */static int bcm43xx_disable_interrupts_sync(struct bcm43xx_private *bcm, u32 *oldstate){	u32 old;	unsigned long flags;	bcm43xx_lock_mmio(bcm, flags);	if (bcm43xx_is_initializing(bcm) || bcm->shutting_down) {		bcm43xx_unlock_mmio(bcm, flags);		return -EBUSY;	}	old = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);	tasklet_disable(&bcm->isr_tasklet);	bcm43xx_unlock_mmio(bcm, flags);	if (oldstate)		*oldstate = old;	return 0;}static int bcm43xx_read_radioinfo(struct bcm43xx_private *bcm){	struct bcm43xx_radioinfo *radio = bcm->current_core->radio;	struct bcm43xx_phyinfo *phy = bcm->current_core->phy;	u32 radio_id;	u16 manufact;	u16 version;	u8 revision;	s8 i;	if (bcm->chip_id == 0x4317) {		if (bcm->chip_rev == 0x00)			radio_id = 0x3205017F;		else if (bcm->chip_rev == 0x01)			radio_id = 0x4205017F;		else			radio_id = 0x5205017F;	} else {		bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID);		radio_id = bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_HIGH);		radio_id <<= 16;		bcm43xx_write16(bcm, BCM43xx_MMIO_RADIO_CONTROL, BCM43xx_RADIOCTL_ID);		radio_id |= bcm43xx_read16(bcm, BCM43xx_MMIO_RADIO_DATA_LOW);	}	manufact = (radio_id & 0x00000FFF);	version = (radio_id & 0x0FFFF000) >> 12;	revision = (radio_id & 0xF0000000) >> 28;	dprintk(KERN_INFO PFX "Detected Radio: ID: %x (Manuf: %x Ver: %x Rev: %x)\n",		radio_id, manufact, version, revision);	switch (phy->type) {	case BCM43xx_PHYTYPE_A:		if ((version != 0x2060) || (revision != 1) || (manufact != 0x17f))			goto err_unsupported_radio;		break;	case BCM43xx_PHYTYPE_B:		if ((version & 0xFFF0) != 0x2050)			goto err_unsupported_radio;		break;	case BCM43xx_PHYTYPE_G:		if (version != 0x2050)			goto err_unsupported_radio;		break;	}	radio->manufact = manufact;	radio->version = version;	radio->revision = revision;	/* Set default attenuation values. */	radio->txpower[0] = 2;	radio->txpower[1] = 2;	if (revision == 1)		radio->txpower[2] = 3;	else		radio->txpower[2] = 0;	if (bcm->current_core->phy->type == BCM43xx_PHYTYPE_A)		radio->txpower_desired = bcm->sprom.maxpower_aphy;	else		bcm->current_core->radio->txpower_desired = bcm->sprom.maxpower_bgphy;	/* Initialize the in-memory nrssi Lookup Table. */	for (i = 0; i < 64; i++)		radio->nrssi_lt[i] = i;	return 0;err_unsupported_radio:	printk(KERN_ERR PFX "Unsupported Radio connected to the PHY!\n");	return -ENODEV;}static const char * bcm43xx_locale_iso(u8 locale){	/* ISO 3166-1 country codes.	 * Note that there aren't ISO 3166-1 codes for	 * all or locales. (Not all locales are countries)	 */	switch (locale) {	case BCM43xx_LOCALE_WORLD:	case BCM43xx_LOCALE_ALL:		return "XX";	case BCM43xx_LOCALE_THAILAND:		return "TH";	case BCM43xx_LOCALE_ISRAEL:		return "IL";	case BCM43xx_LOCALE_JORDAN:		return "JO";	case BCM43xx_LOCALE_CHINA:		return "CN";	case BCM43xx_LOCALE_JAPAN:	case BCM43xx_LOCALE_JAPAN_HIGH:		return "JP";	case BCM43xx_LOCALE_USA_CANADA_ANZ:	case BCM43xx_LOCALE_USA_LOW:		return "US";	case BCM43xx_LOCALE_EUROPE:		return "EU";	case BCM43xx_LOCALE_NONE:		return "  ";	}	assert(0);	return "  ";}static const char * bcm43xx_locale_string(u8 locale){	switch (locale) {	case BCM43xx_LOCALE_WORLD:		return "World";	case BCM43xx_LOCALE_THAILAND:		return "Thailand";	case BCM43xx_LOCALE_ISRAEL:		return "Israel";	case BCM43xx_LOCALE_JORDAN:		return "Jordan";	case BCM43xx_LOCALE_CHINA:		return "China";	case BCM43xx_LOCALE_JAPAN:		return "Japan";	case BCM43xx_LOCALE_USA_CANADA_ANZ:		return "USA/Canada/ANZ";	case BCM43xx_LOCALE_EUROPE:		return "Europe";	case BCM43xx_LOCALE_USA_LOW:		return "USAlow";	case BCM43xx_LOCALE_JAPAN_HIGH:		return "JapanHigh";	case BCM43xx_LOCALE_ALL:		return "All";	case BCM43xx_LOCALE_NONE:		return "None";	}	assert(0);	return "";}static inline u8 bcm43xx_crc8(u8 crc, u8 data){	static const u8 t[] = {		0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,		0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,		0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,		0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,		0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,		0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,		0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,		0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,		0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,		0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,		0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,		0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,		0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,		0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,		0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,		0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,		0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,		0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,		0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,		0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,		0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,		0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,		0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,		0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,		0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,		0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,		0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,		0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,		0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,		0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,		0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,		0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,	};	return t[crc ^ data];}static u8 bcm43xx_sprom_crc(const u16 *sprom){	int word;	u8 crc = 0xFF;	for (word = 0; word < BCM43xx_SPROM_SIZE - 1; word++) {		crc = bcm43xx_crc8(crc, sprom[word] & 0x00FF);		crc = bcm43xx_crc8(crc, (sprom[word] & 0xFF00) >> 8);	}	crc = bcm43xx_crc8(crc, sprom[BCM43xx_SPROM_VERSION] & 0x00FF);	crc ^= 0xFF;	return crc;}int bcm43xx_sprom_read(struct bcm43xx_private *bcm, u16 *sprom){	int i;	u8 crc, expected_crc;	for (i = 0; i < BCM43xx_SPROM_SIZE; i++)		sprom[i] = bcm43xx_read16(bcm, BCM43xx_SPROM_BASE + (i * 2));	/* CRC-8 check. */	crc = bcm43xx_sprom_crc(sprom);	expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;	if (crc != expected_crc) {		printk(KERN_WARNING PFX "WARNING: Invalid SPROM checksum "					"(0x%02X, expected: 0x%02X)\n",		       crc, expected_crc);		return -EINVAL;	}	return 0;}int bcm43xx_sprom_write(struct bcm43xx_private *bcm, const u16 *sprom){	int i, err;	u8 crc, expected_crc;	u32 spromctl;	/* CRC-8 validation of the input data. */	crc = bcm43xx_sprom_crc(sprom);	expected_crc = (sprom[BCM43xx_SPROM_VERSION] & 0xFF00) >> 8;	if (crc != expected_crc) {		printk(KERN_ERR PFX "SPROM input data: Invalid CRC\n");		return -EINVAL;	}	printk(KERN_INFO PFX "Writing SPROM. Do NOT turn off the power! Please stand by...\n");	err = bcm43xx_pci_read_config32(bcm, BCM43xx_PCICFG_SPROMCTL, &spromctl);	if (err)		goto err_ctlreg;	spromctl |= 0x10; /* SPROM WRITE enable. */	bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);	if (err)		goto err_ctlreg;	/* We must burn lots of CPU cycles here, but that does not	 * really matter as one does not write the SPROM every other minute...	 */	printk(KERN_INFO PFX "[ 0%%");	mdelay(500);	for (i = 0; i < BCM43xx_SPROM_SIZE; i++) {		if (i == 16)			printk("25%%");		else if (i == 32)			printk("50%%");		else if (i == 48)			printk("75%%");		else if (i % 2)			printk(".");		bcm43xx_write16(bcm, BCM43xx_SPROM_BASE + (i * 2), sprom[i]);		mmiowb();		mdelay(20);	}	spromctl &= ~0x10; /* SPROM WRITE enable. */	bcm43xx_pci_write_config32(bcm, BCM43xx_PCICFG_SPROMCTL, spromctl);	if (err)		goto err_ctlreg;	mdelay(500);	printk("100%% ]\n");	printk(KERN_INFO PFX "SPROM written.\n");	bcm43xx_controller_restart(bcm, "SPROM update");	return 0;err_ctlreg:	printk(KERN_ERR PFX "Could not access SPROM control register.\n");	return -ENODEV;}static int bcm43xx_sprom_extract(struct bcm43xx_private *bcm){	u16 value;	u16 *sprom;#ifdef CONFIG_BCM947XX	char *c;#endif	sprom = kzalloc(BCM43xx_SPROM_SIZE * sizeof(u16),			GFP_KERNEL);	if (!sprom) {		printk(KERN_ERR PFX "sprom_extract OOM\n");		return -ENOMEM;	}#ifdef CONFIG_BCM947XX	sprom[BCM43xx_SPROM_BOARDFLAGS2] = atoi(nvram_get("boardflags2"));	sprom[BCM43xx_SPROM_BOARDFLAGS] = atoi(nvram_get("boardflags"));	if ((c = nvram_get("il0macaddr")) != NULL)		e_aton(c, (char *) &(sprom[BCM43xx_SPROM_IL0MACADDR]));	if ((c = nvram_get("et1macaddr")) != NULL)		e_aton(c, (char *) &(sprom[BCM43xx_SPROM_ET1MACADDR]));	sprom[BCM43xx_SPROM_PA0B0] = atoi(nvram_get("pa0b0"));	sprom[BCM43xx_SPROM_PA0B1] = atoi(nvram_get("pa0b1"));	sprom[BCM43xx_SPROM_PA0B2] = atoi(nvram_get("pa0b2"));	sprom[BCM43xx_SPROM_PA1B0] = atoi(nvram_get("pa1b0"));	sprom[BCM43xx_SPROM_PA1B1] = atoi(nvram_get("pa1b1"));	sprom[BCM43xx_SPROM_PA1B2] = atoi(nvram_get("pa1b2"));	sprom[BCM43xx_SPROM_BOARDREV] = atoi(nvram_get("boardrev"));#else	bcm43xx_sprom_read(bcm, sprom);#endif	/* boardflags2 */	value = sprom[BCM43xx_SPROM_BOARDFLAGS2];	bcm->sprom.boardflags2 = value;	/* il0macaddr */	value = sprom[BCM43xx_SPROM_IL0MACADDR + 0];	*(((u16 *)bcm->sprom.il0macaddr) + 0) = cpu_to_be16(value);	value = sprom[BCM43xx_SPROM_IL0MACADDR + 1];	*(((u16 *)bcm->sprom.il0macaddr) + 1) = cpu_to_be16(value);	value = sprom[BCM43xx_SPROM_IL0MACADDR + 2];	*(((u16 *)bcm->sprom.il0macaddr) + 2) = cpu_to_be16(value);	/* et0macaddr */	value = sprom[BCM43xx_SPROM_ET0MACADDR + 0];	*(((u16 *)bcm->sprom.et0macaddr) + 0) = cpu_to_be16(value);	value = sprom[BCM43xx_SPROM_ET0MACADDR + 1];	*(((u16 *)bcm->sprom.et0macaddr) + 1) = cpu_to_be16(value);	value = sprom[BCM43xx_SPROM_ET0MACADDR + 2];	*(((u16 *)bcm->sprom.et0macaddr) + 2) = cpu_to_be16(value);	/* et1macaddr */	value = sprom[BCM43xx_SPROM_ET1MACADDR + 0];	*(((u16 *)bcm->sprom.et1macaddr) + 0) = cpu_to_be16(value);	value = sprom[BCM43xx_SPROM_ET1MACADDR + 1];	*(((u16 *)bcm->sprom.et1macaddr) + 1) = cpu_to_be16(value);	value = sprom[BCM43xx_SPROM_ET1MACADDR + 2];	*(((u16 *)bcm->sprom.et1macaddr) + 2) = cpu_to_be16(value);	/* ethernet phy settings */	value = sprom[BCM43xx_SPROM_ETHPHY];	bcm->sprom.et0phyaddr = (value & 0x001F);	bcm->sprom.et1phyaddr = (value & 0x03E0) >> 5;	bcm->sprom.et0mdcport = (value & (1 << 14)) >> 14;	bcm->sprom.et1mdcport = (value & (1 << 15)) >> 15;	/* boardrev, antennas, locale */	value = sprom[BCM43xx_SPROM_BOARDREV];	bcm->sprom.boardrev = (value & 0x00FF);	bcm->sprom.locale = (value & 0x0F00) >> 8;	bcm->sprom.antennas_aphy = (value & 0x3000) >> 12;	bcm->sprom.antennas_bgphy = (value & 0xC000) >> 14;	if (modparam_locale != -1) {		if (modparam_locale >= 0 && modparam_locale <= 11) {			bcm->sprom.locale = modparam_locale;			printk(KERN_WARNING PFX "Operating with modified "						"LocaleCode %u (%s)\n",			       bcm->sprom.locale,			       bcm43xx_locale_string(bcm->sprom.locale));		} else {			printk(KERN_WARNING PFX "Module parameter \"locale\" "						"invalid value. (0 - 11)\n");		}	}	/* pa0b* */	value = sprom[BCM43xx_SPROM_PA0B0];	bcm->sprom.pa0b0 = value;	value = sprom[BCM43xx_SPROM_PA0B1];	bcm->sprom.pa0b1 = value;	value = sprom[BCM43xx_SPROM_PA0B2];	bcm->sprom.pa0b2 = value;	/* wl0gpio* */	value = sprom[BCM43xx_SPROM_WL0GPIO0];	if (value == 0x0000)		value = 0xFFFF;	bcm->sprom.wl0gpio0 = value & 0x00FF;	bcm->sprom.wl0gpio1 = (value & 0xFF00) >> 8;	value = sprom[BCM43xx_SPROM_WL0GPIO2];	if (value == 0x0000)		value = 0xFFFF;	bcm->sprom.wl0gpio2 = value & 0x00FF;	bcm->sprom.wl0gpio3 = (value & 0xFF00) >> 8;	/* maxpower */	value = sprom[BCM43xx_SPROM_MAXPWR];	bcm->sprom.maxpower_aphy = (value & 0xFF00) >> 8;	bcm->sprom.maxpower_bgphy = value & 0x00FF;	/* pa1b* */	value = sprom[BCM43xx_SPROM_PA1B0];	bcm->sprom.pa1b0 = value;	value = sprom[BCM43xx_SPROM_PA1B1];	bcm->sprom.pa1b1 = value;	value = sprom[BCM43xx_SPROM_PA1B2];	bcm->sprom.pa1b2 = value;	/* idle tssi target */	value = sprom[BCM43xx_SPROM_IDL_TSSI_TGT];	bcm->sprom.idle_tssi_tgt_aphy = value & 0x00FF;	bcm->sprom.idle_tssi_tgt_bgphy = (value & 0xFF00) >> 8;	/* boardflags */	value = sprom[BCM43xx_SPROM_BOARDFLAGS];	if (value == 0xFFFF)		value = 0x0000;	bcm->sprom.boardflags = value;	/* antenna gain */	value = sprom[BCM43xx_SPROM_ANTENNA_GAIN];	if (value == 0x0000 || value == 0xFFFF)		value = 0x0202;	/* convert values to Q5.2 */	bcm->sprom.antennagain_aphy = ((value & 0xFF00) >> 8) * 4;	bcm->sprom.antennagain_bgphy = (value & 0x00FF) * 4;	kfree(sprom);	return 0;}static void bcm43xx_geo_init(struct bcm43xx_private *bcm){	struct ieee80211_geo geo;	struct ieee80211_channel *chan;	int have_a = 0, have_bg = 0;	int i, num80211;	u8 channel;	struct bcm43xx_phyinfo *phy;	const char *iso_country;	memset(&geo, 0, sizeof(geo));	num80211 = bcm43xx_num_80211_cores(bcm);

⌨️ 快捷键说明

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