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

📄 bcm43xx_main.c

📁 博通的bcm43xx系列Minipci接口无线网卡驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
	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,						&current_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 + -