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

📄 bcm43xx_main.c

📁 无线网卡驱动,有很好的参考价值,在linux_2.6.21下可以直接使用,如果在其他平台,可以参考移植
💻 C
📖 第 1 页 / 共 5 页
字号:
		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. */static void bcm43xx_wireless_core_mark_inactive(struct bcm43xx_private *bcm){	u32 sbtmstatelow;	bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);	bcm43xx_radio_turn_off(bcm);	sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);	sbtmstatelow &= 0xDFF5FFFF;	sbtmstatelow |= 0x000A0000;	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);	udelay(1);	sbtmstatelow = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATELOW);	sbtmstatelow &= 0xFFF5FFFF;	sbtmstatelow |= 0x00080000;	bcm43xx_write32(bcm, BCM43xx_CIR_SBTMSTATELOW, sbtmstatelow);	udelay(1);}static void handle_irq_transmit_status(struct bcm43xx_private *bcm){	u32 v0, v1;	u16 tmp;	struct bcm43xx_xmitstatus stat;	while (1) {		v0 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0);		if (!v0)			break;		v1 = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1);		stat.cookie = (v0 >> 16) & 0x0000FFFF;		tmp = (u16)((v0 & 0xFFF0) | ((v0 & 0xF) >> 1));		stat.flags = tmp & 0xFF;		stat.cnt1 = (tmp & 0x0F00) >> 8;		stat.cnt2 = (tmp & 0xF000) >> 12;		stat.seq = (u16)(v1 & 0xFFFF);		stat.unknown = (u16)((v1 >> 16) & 0xFF);		bcm43xx_debugfs_log_txstat(bcm, &stat);		if (stat.flags & BCM43xx_TXSTAT_FLAG_AMPDU)			continue;		if (stat.flags & BCM43xx_TXSTAT_FLAG_INTER)			continue;		if (bcm43xx_using_pio(bcm))			bcm43xx_pio_handle_xmitstatus(bcm, &stat);		else			bcm43xx_dma_handle_xmitstatus(bcm, &stat);	}}static void drain_txstatus_queue(struct bcm43xx_private *bcm){	u32 dummy;	if (bcm->current_core->rev < 5)		return;	/* Read all entries from the microcode TXstatus FIFO	 * and throw them away.	 */	while (1) {		dummy = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_0);		if (!dummy)			break;		dummy = bcm43xx_read32(bcm, BCM43xx_MMIO_XMITSTAT_1);	}}static void bcm43xx_generate_noise_sample(struct bcm43xx_private *bcm){	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x408, 0x7F7F);	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, 0x40A, 0x7F7F);	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,			bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD) | (1 << 4));	assert(bcm->noisecalc.core_at_start == bcm->current_core);	assert(bcm->noisecalc.channel_at_start == bcm43xx_current_radio(bcm)->channel);}static void bcm43xx_calculate_link_quality(struct bcm43xx_private *bcm){	/* Top half of Link Quality calculation. */	if (bcm->noisecalc.calculation_running)		return;	bcm->noisecalc.core_at_start = bcm->current_core;	bcm->noisecalc.channel_at_start = bcm43xx_current_radio(bcm)->channel;	bcm->noisecalc.calculation_running = 1;	bcm->noisecalc.nr_samples = 0;	bcm43xx_generate_noise_sample(bcm);}static void handle_irq_noise(struct bcm43xx_private *bcm){	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);	u16 tmp;	u8 noise[4];	u8 i, j;	s32 average;	/* Bottom half of Link Quality calculation. */	assert(bcm->noisecalc.calculation_running);	if (bcm->noisecalc.core_at_start != bcm->current_core ||	    bcm->noisecalc.channel_at_start != radio->channel)		goto drop_calculation;	tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x408);	noise[0] = (tmp & 0x00FF);	noise[1] = (tmp & 0xFF00) >> 8;	tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40A);	noise[2] = (tmp & 0x00FF);	noise[3] = (tmp & 0xFF00) >> 8;	if (noise[0] == 0x7F || noise[1] == 0x7F ||	    noise[2] == 0x7F || noise[3] == 0x7F)		goto generate_new;	/* Get the noise samples. */	assert(bcm->noisecalc.nr_samples < 8);	i = bcm->noisecalc.nr_samples;	noise[0] = limit_value(noise[0], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);	noise[1] = limit_value(noise[1], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);	noise[2] = limit_value(noise[2], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);	noise[3] = limit_value(noise[3], 0, ARRAY_SIZE(radio->nrssi_lt) - 1);	bcm->noisecalc.samples[i][0] = radio->nrssi_lt[noise[0]];	bcm->noisecalc.samples[i][1] = radio->nrssi_lt[noise[1]];	bcm->noisecalc.samples[i][2] = radio->nrssi_lt[noise[2]];	bcm->noisecalc.samples[i][3] = radio->nrssi_lt[noise[3]];	bcm->noisecalc.nr_samples++;	if (bcm->noisecalc.nr_samples == 8) {		/* Calculate the Link Quality by the noise samples. */		average = 0;		for (i = 0; i < 8; i++) {			for (j = 0; j < 4; j++)				average += bcm->noisecalc.samples[i][j];		}		average /= (8 * 4);		average *= 125;		average += 64;		average /= 128;		tmp = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED, 0x40C);		tmp = (tmp / 128) & 0x1F;		if (tmp >= 8)			average += 2;		else			average -= 25;		if (tmp == 8)			average -= 72;		else			average -= 48;		bcm->stats.noise = average;drop_calculation:		bcm->noisecalc.calculation_running = 0;		return;	}generate_new:	bcm43xx_generate_noise_sample(bcm);}static void handle_irq_ps(struct bcm43xx_private *bcm){	if (bcm->ieee->iw_mode == IW_MODE_MASTER) {		///TODO: PS TBTT	} else {		if (1/*FIXME: the last PSpoll frame was sent successfully */)			bcm43xx_power_saving_ctl_bits(bcm, -1, -1);	}	if (bcm->ieee->iw_mode == IW_MODE_ADHOC)		bcm->reg124_set_0x4 = 1;	//FIXME else set to false?}static void handle_irq_reg124(struct bcm43xx_private *bcm){	if (!bcm->reg124_set_0x4)		return;	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD,			bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD)			| 0x4);	//FIXME: reset reg124_set_0x4 to false?}static void handle_irq_pmq(struct bcm43xx_private *bcm){	u32 tmp;	//TODO: AP mode.	while (1) {		tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_PS_STATUS);		if (!(tmp & 0x00000008))			break;	}	/* 16bit write is odd, but correct. */	bcm43xx_write16(bcm, BCM43xx_MMIO_PS_STATUS, 0x0002);}static void bcm43xx_generate_beacon_template(struct bcm43xx_private *bcm,					     u16 ram_offset, u16 shm_size_offset){	u32 value;	u16 size = 0;	/* Timestamp. */	//FIXME: assumption: The chip sets the timestamp	value = 0;	bcm43xx_ram_write(bcm, ram_offset++, value);	bcm43xx_ram_write(bcm, ram_offset++, value);	size += 8;	/* Beacon Interval / Capability Information */	value = 0x0000;//FIXME: Which interval?	value |= (1 << 0) << 16; /* ESS */	value |= (1 << 2) << 16; /* CF Pollable */	//FIXME?	value |= (1 << 3) << 16; /* CF Poll Request */	//FIXME?	if (!bcm->ieee->open_wep)		value |= (1 << 4) << 16; /* Privacy */	bcm43xx_ram_write(bcm, ram_offset++, value);	size += 4;	/* SSID */	//TODO	/* FH Parameter Set */	//TODO	/* DS Parameter Set */	//TODO	/* CF Parameter Set */	//TODO	/* TIM */	//TODO	bcm43xx_shm_write16(bcm, BCM43xx_SHM_SHARED, shm_size_offset, size);}static void handle_irq_beacon(struct bcm43xx_private *bcm){	u32 status;	bcm->irq_savedstate &= ~BCM43xx_IRQ_BEACON;	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD);	if ((status & 0x1) && (status & 0x2)) {		/* ACK beacon IRQ. */		bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON,				BCM43xx_IRQ_BEACON);		bcm->irq_savedstate |= BCM43xx_IRQ_BEACON;		return;	}	if (!(status & 0x1)) {		bcm43xx_generate_beacon_template(bcm, 0x68, 0x18);		status |= 0x1;		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);	}	if (!(status & 0x2)) {		bcm43xx_generate_beacon_template(bcm, 0x468, 0x1A);		status |= 0x2;		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS2_BITFIELD, status);	}}/* Interrupt handler bottom-half */static void bcm43xx_interrupt_tasklet(struct bcm43xx_private *bcm){	u32 reason;	u32 dma_reason[6];	u32 merged_dma_reason = 0;	int i, activity = 0;	unsigned long flags;#ifdef CONFIG_BCM43XX_DEBUG	u32 _handled = 0x00000000;# define bcmirq_handled(irq)	do { _handled |= (irq); } while (0)#else# define bcmirq_handled(irq)	do { /* nothing */ } while (0)#endif /* CONFIG_BCM43XX_DEBUG*/	spin_lock_irqsave(&bcm->irq_lock, flags);	reason = bcm->irq_reason;	for (i = 5; i >= 0; i--) {		dma_reason[i] = bcm->dma_reason[i];		merged_dma_reason |= dma_reason[i];	}	if (unlikely(reason & BCM43xx_IRQ_XMIT_ERROR)) {		/* TX error. We get this when Template Ram is written in wrong endianess		 * in dummy_tx(). We also get this if something is wrong with the TX header		 * on DMA or PIO queues.		 * Maybe we get this in other error conditions, too.		 */		printkl(KERN_ERR PFX "FATAL ERROR: BCM43xx_IRQ_XMIT_ERROR\n");		bcmirq_handled(BCM43xx_IRQ_XMIT_ERROR);	}	if (unlikely(merged_dma_reason & BCM43xx_DMAIRQ_FATALMASK)) {		printkl(KERN_ERR PFX "FATAL ERROR: Fatal DMA error: "				     "0x%08X, 0x%08X, 0x%08X, "				     "0x%08X, 0x%08X, 0x%08X\n",		        dma_reason[0], dma_reason[1],			dma_reason[2], dma_reason[3],			dma_reason[4], dma_reason[5]);		bcm43xx_controller_restart(bcm, "DMA error");		mmiowb();		spin_unlock_irqrestore(&bcm->irq_lock, flags);		return;	}	if (unlikely(merged_dma_reason & BCM43xx_DMAIRQ_NONFATALMASK)) {		printkl(KERN_ERR PFX "DMA error: "				     "0x%08X, 0x%08X, 0x%08X, "				     "0x%08X, 0x%08X, 0x%08X\n",		        dma_reason[0], dma_reason[1],			dma_reason[2], dma_reason[3],			dma_reason[4], dma_reason[5]);	}	if (reason & BCM43xx_IRQ_PS) {		handle_irq_ps(bcm);		bcmirq_handled(BCM43xx_IRQ_PS);	}	if (reason & BCM43xx_IRQ_REG124) {		handle_irq_reg124(bcm);		bcmirq_handled(BCM43xx_IRQ_REG124);	}	if (reason & BCM43xx_IRQ_BEACON) {		if (bcm->ieee->iw_mode == IW_MODE_MASTER)			handle_irq_beacon(bcm);		bcmirq_handled(BCM43xx_IRQ_BEACON);	}	if (reason & BCM43xx_IRQ_PMQ) {		handle_irq_pmq(bcm);		bcmirq_handled(BCM43xx_IRQ_PMQ);	}	if (reason & BCM43xx_IRQ_SCAN) {		/*TODO*/		//bcmirq_handled(BCM43xx_IRQ_SCAN);	}	if (reason & BCM43xx_IRQ_NOISE) {		handle_irq_noise(bcm);		bcmirq_handled(BCM43xx_IRQ_NOISE);	}	/* Check the DMA reason registers for received data. */	if (dma_reason[0] & BCM43xx_DMAIRQ_RX_DONE) {		if (bcm43xx_using_pio(bcm))			bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue0);		else			bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring0);		/* We intentionally don't set "activity" to 1, here. */	}	assert(!(dma_reason[1] & BCM43xx_DMAIRQ_RX_DONE));	assert(!(dma_reason[2] & BCM43xx_DMAIRQ_RX_DONE));	if (dma_reason[3] & BCM43xx_DMAIRQ_RX_DONE) {		if (bcm43xx_using_pio(bcm))			bcm43xx_pio_rx(bcm43xx_current_pio(bcm)->queue3);		else			bcm43xx_dma_rx(bcm43xx_current_dma(bcm)->rx_ring3);		activity = 1;	}	assert(!(dma_reason[4] & BCM43xx_DMAIRQ_RX_DONE));	assert(!(dma_reason[5] & BCM43xx_DMAIRQ_RX_DONE));	bcmirq_handled(BCM43xx_IRQ_RX);	if (reason & BCM43xx_IRQ_XMIT_STATUS) {		handle_irq_transmit_status(bcm);		activity = 1;		//TODO: In AP mode, this also causes sending of powersave responses.		bcmirq_handled(BCM43xx_IRQ_XMIT_STATUS);	}	/* IRQ_PIO_WORKAROUND is handled in the top-half. */	bcmirq_handled(BCM43xx_IRQ_PIO_WORKAROUND);#ifdef CONFIG_BCM43XX_DEBUG	if (unlikely(reason & ~_handled)) {		printkl(KERN_WARNING PFX			"Unhandled IRQ! Reason: 0x%08x,  Unhandled: 0x%08x,  "			"DMA: 0x%08x, 0x%08x, 0x%08x, 0x%08x\n",			reason, (reason & ~_handled),			dma_reason[0], dma_reason[1],			dma_reason[2], dma_reason[3]);	}#endif#undef bcmirq_handled	if (!modparam_noleds)		bcm43xx_leds_update(bcm, activity);	bcm43xx_interrupt_enable(bcm, bcm->irq_savedstate);	mmiowb();	spin_unlock_irqrestore(&bcm->irq_lock, flags);}static void pio_irq_workaround(struct bcm43xx_private *bcm,			       u16 base, int queueidx){	u16 rxctl;	rxctl = bcm43xx_read16(bcm, base + BCM43xx_PIO_RXCTL);	if (rxctl & BCM43xx_PIO_RXCTL_DATAAVAILABLE)		bcm->dma_reason[queueidx] |= BCM43xx_DMAIRQ_RX_DONE;	else		bcm->dma_reason[queueidx] &= ~BCM43xx_DMAIRQ_RX_DONE;}static void bcm43xx_interrupt_ack(struct bcm43xx_private *bcm, u32 reason){	if (bcm43xx_using_pio(bcm) &&	    (bcm->current_core->rev < 3) &&	    (!(reason & BCM43xx_IRQ_PIO_WORKAROUND))) {		/* Apply a PIO specific workaround to the dma_reasons */		pio_irq_workaround(bcm, BCM43xx_MMIO_PIO1_BASE, 0);		pio_irq_workaround(bcm, BCM43xx_MMIO_PIO2_BASE, 1);		pio_irq_workaround(bcm, BCM43xx_MMIO_PIO3_BASE, 2);		pio_irq_workaround(bcm, BCM43xx_MMIO_PIO4_BASE, 3);	}	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, reason);	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA0_REASON,			bcm->dma_reason[0]);	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA1_REASON,			bcm->dma_reason[1]);	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA2_REASON,			bcm->dma_reason[2]);	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA3_REASON,			bcm->dma_reason[3]);	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA4_REASON,			bcm->dma_reason[4]);	bcm43xx_write32(bcm, BCM43xx_MMIO_DMA5_REASON,			bcm->dma_reason[5]);}/* Interrupt handler top-half */static irqreturn_t bcm43xx_interrupt_handler(int irq, void *dev_id){	irqreturn_t ret = IRQ_HANDLED;	struct bcm43xx_private *bcm = dev_id;	u32 reason;	if (!bcm)		return IRQ_NONE;	spin_lock(&bcm->irq_lock);	reason = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);	if (reason == 0xffffffff) {

⌨️ 快捷键说明

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