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

📄 bcm43xx_main.c

📁 无线网卡驱动,有很好的参考价值,在linux_2.6.21下可以直接使用,如果在其他平台,可以参考移植
💻 C
📖 第 1 页 / 共 5 页
字号:
		/* irq not for us (shared irq) */		ret = IRQ_NONE;		goto out;	}	reason &= bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_MASK);	if (!reason)		goto out;	assert(bcm43xx_status(bcm) == BCM43xx_STAT_INITIALIZED);	assert(bcm->current_core->id == BCM43xx_COREID_80211);	bcm->dma_reason[0] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA0_REASON)			     & 0x0001DC00;	bcm->dma_reason[1] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA1_REASON)			     & 0x0000DC00;	bcm->dma_reason[2] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA2_REASON)			     & 0x0000DC00;	bcm->dma_reason[3] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA3_REASON)			     & 0x0001DC00;	bcm->dma_reason[4] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA4_REASON)			     & 0x0000DC00;	bcm->dma_reason[5] = bcm43xx_read32(bcm, BCM43xx_MMIO_DMA5_REASON)			     & 0x0000DC00;	bcm43xx_interrupt_ack(bcm, reason);	/* disable all IRQs. They are enabled again in the bottom half. */	bcm->irq_savedstate = bcm43xx_interrupt_disable(bcm, BCM43xx_IRQ_ALL);	/* save the reason code and call our bottom half. */	bcm->irq_reason = reason;	tasklet_schedule(&bcm->isr_tasklet);out:	mmiowb();	spin_unlock(&bcm->irq_lock);	return ret;}static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force){	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);	if (bcm->firmware_norelease && !force)		return; /* Suspending or controller reset. */	release_firmware(phy->ucode);	phy->ucode = NULL;	release_firmware(phy->pcm);	phy->pcm = NULL;	release_firmware(phy->initvals0);	phy->initvals0 = NULL;	release_firmware(phy->initvals1);	phy->initvals1 = NULL;}static int bcm43xx_request_firmware(struct bcm43xx_private *bcm){	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);	u8 rev = bcm->current_core->rev;	int err = 0;	int nr;	char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };	if (!phy->ucode) {		snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",			 (rev >= 5 ? 5 : rev),			 modparam_fwpostfix);		err = request_firmware(&phy->ucode, buf, &bcm->pci_dev->dev);		if (err) {			printk(KERN_ERR PFX 			       "Error: Microcode \"%s\" not available or load failed.\n",			        buf);			goto error;		}	}	if (!phy->pcm) {		snprintf(buf, ARRAY_SIZE(buf),			 "bcm43xx_pcm%d%s.fw",			 (rev < 5 ? 4 : 5),			 modparam_fwpostfix);		err = request_firmware(&phy->pcm, buf, &bcm->pci_dev->dev);		if (err) {			printk(KERN_ERR PFX			       "Error: PCM \"%s\" not available or load failed.\n",			       buf);			goto error;		}	}	if (!phy->initvals0) {		if (rev == 2 || rev == 4) {			switch (phy->type) {			case BCM43xx_PHYTYPE_A:				nr = 3;				break;			case BCM43xx_PHYTYPE_B:			case BCM43xx_PHYTYPE_G:				nr = 1;				break;			default:				goto err_noinitval;			}				} else if (rev >= 5) {			switch (phy->type) {			case BCM43xx_PHYTYPE_A:				nr = 7;				break;			case BCM43xx_PHYTYPE_B:			case BCM43xx_PHYTYPE_G:				nr = 5;				break;			default:				goto err_noinitval;			}		} else			goto err_noinitval;		snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",			 nr, modparam_fwpostfix);		err = request_firmware(&phy->initvals0, buf, &bcm->pci_dev->dev);		if (err) {			printk(KERN_ERR PFX 			       "Error: InitVals \"%s\" not available or load failed.\n",			        buf);			goto error;		}		if (phy->initvals0->size % sizeof(struct bcm43xx_initval)) {			printk(KERN_ERR PFX "InitVals fileformat error.\n");			goto error;		}	}	if (!phy->initvals1) {		if (rev >= 5) {			u32 sbtmstatehigh;			switch (phy->type) {			case BCM43xx_PHYTYPE_A:				sbtmstatehigh = bcm43xx_read32(bcm, BCM43xx_CIR_SBTMSTATEHIGH);				if (sbtmstatehigh & 0x00010000)					nr = 9;				else					nr = 10;				break;			case BCM43xx_PHYTYPE_B:			case BCM43xx_PHYTYPE_G:					nr = 6;				break;			default:				goto err_noinitval;			}			snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_initval%02d%s.fw",				 nr, modparam_fwpostfix);			err = request_firmware(&phy->initvals1, buf, &bcm->pci_dev->dev);			if (err) {				printk(KERN_ERR PFX 				       "Error: InitVals \"%s\" not available or load failed.\n",			        	buf);				goto error;			}			if (phy->initvals1->size % sizeof(struct bcm43xx_initval)) {				printk(KERN_ERR PFX "InitVals fileformat error.\n");				goto error;			}		}	}out:	return err;error:	bcm43xx_release_firmware(bcm, 1);	goto out;err_noinitval:	printk(KERN_ERR PFX "Error: No InitVals available!\n");	err = -ENOENT;	goto error;}static void bcm43xx_upload_microcode(struct bcm43xx_private *bcm){	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);	const u32 *data;	unsigned int i, len;	/* Upload Microcode. */	data = (u32 *)(phy->ucode->data);	len = phy->ucode->size / sizeof(u32);	bcm43xx_shm_control_word(bcm, BCM43xx_SHM_UCODE, 0x0000);	for (i = 0; i < len; i++) {		bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,				be32_to_cpu(data[i]));		udelay(10);	}	/* Upload PCM data. */	data = (u32 *)(phy->pcm->data);	len = phy->pcm->size / sizeof(u32);	bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01ea);	bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA, 0x00004000);	bcm43xx_shm_control_word(bcm, BCM43xx_SHM_PCM, 0x01eb);	for (i = 0; i < len; i++) {		bcm43xx_write32(bcm, BCM43xx_MMIO_SHM_DATA,				be32_to_cpu(data[i]));		udelay(10);	}}static int bcm43xx_write_initvals(struct bcm43xx_private *bcm,				  const struct bcm43xx_initval *data,				  const unsigned int len){	u16 offset, size;	u32 value;	unsigned int i;	for (i = 0; i < len; i++) {		offset = be16_to_cpu(data[i].offset);		size = be16_to_cpu(data[i].size);		value = be32_to_cpu(data[i].value);		if (unlikely(offset >= 0x1000))			goto err_format;		if (size == 2) {			if (unlikely(value & 0xFFFF0000))				goto err_format;			bcm43xx_write16(bcm, offset, (u16)value);		} else if (size == 4) {			bcm43xx_write32(bcm, offset, value);		} else			goto err_format;	}	return 0;err_format:	printk(KERN_ERR PFX "InitVals (bcm43xx_initvalXX.fw) file-format error. "			    "Please fix your bcm43xx firmware files.\n");	return -EPROTO;}static int bcm43xx_upload_initvals(struct bcm43xx_private *bcm){	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);	int err;	err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals0->data,				     phy->initvals0->size / sizeof(struct bcm43xx_initval));	if (err)		goto out;	if (phy->initvals1) {		err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)phy->initvals1->data,					     phy->initvals1->size / sizeof(struct bcm43xx_initval));		if (err)			goto out;	}out:	return err;}#ifdef CONFIG_BCM947XXstatic struct pci_device_id bcm43xx_47xx_ids[] = {	{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4324) },	{ 0 }};#endifstatic int bcm43xx_initialize_irq(struct bcm43xx_private *bcm){	int err;	bcm->irq = bcm->pci_dev->irq;#ifdef CONFIG_BCM947XX	if (bcm->pci_dev->bus->number == 0) {		struct pci_dev *d;		struct pci_device_id *id;		for (id = bcm43xx_47xx_ids; id->vendor; id++) {			d = pci_get_device(id->vendor, id->device, NULL);			if (d != NULL) {				bcm->irq = d->irq;				pci_dev_put(d);				break;			}		}	}#endif	err = request_irq(bcm->irq, bcm43xx_interrupt_handler,			  IRQF_SHARED, KBUILD_MODNAME, bcm);	if (err)		printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);	return err;}/* Switch to the core used to write the GPIO register. * This is either the ChipCommon, or the PCI core. */static int switch_to_gpio_core(struct bcm43xx_private *bcm){	int err;	/* Where to find the GPIO register depends on the chipset.	 * If it has a ChipCommon, its register at offset 0x6c is the GPIO	 * control register. Otherwise the register at offset 0x6c in the	 * PCI core is the GPIO control register.	 */	err = bcm43xx_switch_core(bcm, &bcm->core_chipcommon);	if (err == -ENODEV) {		err = bcm43xx_switch_core(bcm, &bcm->core_pci);		if (unlikely(err == -ENODEV)) {			printk(KERN_ERR PFX "gpio error: "			       "Neither ChipCommon nor PCI core available!\n");		}	}	return err;}/* Initialize the GPIOs * http://bcm-specs.sipsolutions.net/GPIO */static int bcm43xx_gpio_init(struct bcm43xx_private *bcm){	struct bcm43xx_coreinfo *old_core;	int err;	u32 mask, set;	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,			bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)			& 0xFFFF3FFF);	bcm43xx_leds_switch_all(bcm, 0);	bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,			bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F);	mask = 0x0000001F;	set = 0x0000000F;	if (bcm->chip_id == 0x4301) {		mask |= 0x0060;		set |= 0x0060;	}	if (0 /* FIXME: conditional unknown */) {		bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,				bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK)				| 0x0100);		mask |= 0x0180;		set |= 0x0180;	}	if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) {		bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,				bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK)				| 0x0200);		mask |= 0x0200;		set |= 0x0200;	}	if (bcm->current_core->rev >= 2)		mask  |= 0x0010; /* FIXME: This is redundant. */	old_core = bcm->current_core;	err = switch_to_gpio_core(bcm);	if (err)		goto out;	bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL,	                (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | set);	err = bcm43xx_switch_core(bcm, old_core);out:	return err;}/* Turn off all GPIO stuff. Call this on module unload, for example. */static int bcm43xx_gpio_cleanup(struct bcm43xx_private *bcm){	struct bcm43xx_coreinfo *old_core;	int err;	old_core = bcm->current_core;	err = switch_to_gpio_core(bcm);	if (err)		return err;	bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL, 0x00000000);	err = bcm43xx_switch_core(bcm, old_core);	assert(err == 0);	return 0;}/* http://bcm-specs.sipsolutions.net/EnableMac */void bcm43xx_mac_enable(struct bcm43xx_private *bcm){	bcm->mac_suspended--;	assert(bcm->mac_suspended >= 0);	if (bcm->mac_suspended == 0) {		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,		                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)				| BCM43xx_SBF_MAC_ENABLED);		bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, BCM43xx_IRQ_READY);		bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD); /* dummy read */		bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */		bcm43xx_power_saving_ctl_bits(bcm, -1, -1);	}}/* http://bcm-specs.sipsolutions.net/SuspendMAC */void bcm43xx_mac_suspend(struct bcm43xx_private *bcm){	int i;	u32 tmp;	assert(bcm->mac_suspended >= 0);	if (bcm->mac_suspended == 0) {		bcm43xx_power_saving_ctl_bits(bcm, -1, 1);		bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,		                bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD)				& ~BCM43xx_SBF_MAC_ENABLED);		bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */		for (i = 10000; i; i--) {			tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);			if (tmp & BCM43xx_IRQ_READY)				goto out;			udelay(1);		}		printkl(KERN_ERR PFX "MAC suspend failed\n");	}out:	bcm->mac_suspended++;}void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,			int iw_mode){	unsigned long flags;	struct net_device *net_dev = bcm->net_dev;	u32 status;	u16 value;	spin_lock_irqsave(&bcm->ieee->lock, flags);	bcm->ieee->iw_mode = iw_mode;	spin_unlock_irqrestore(&bcm->ieee->lock, flags);	if (iw_mode == IW_MODE_MONITOR)		net_dev->type = ARPHRD_IEEE80211;	else		net_dev->type = ARPHRD_ETHER;	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);	/* Reset status to infrastructured mode */	status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR);	status &= ~BCM43xx_SBF_MODE_PROMISC;	status |= BCM43xx_SBF_MODE_NOTADHOC;/* FIXME: Always enable promisc mode, until we get the MAC filters working correctly. */status |= BCM43xx_SBF_MODE_PROMISC;	switch (iw_mode) {	case IW_MODE_MONITOR:		status |= BCM43xx_SBF_MODE_MONITOR;		status |= BCM43xx_SBF_MODE_PROMISC;		break;	case IW_MODE_ADHOC:		status &= ~BCM43xx_SBF_MODE_NOTADHOC;		break;	case IW_MODE_MASTER:		status |= BCM43xx_SBF_MODE_AP;		break;	case IW_MODE_SECOND:	case IW_MODE_REPEAT:		TODO(); /* TODO */		brea

⌨️ 快捷键说明

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