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

📄 bcm43xx_main.c

📁 博通的bcm43xx系列Minipci接口无线网卡驱动
💻 C
📖 第 1 页 / 共 5 页
字号:
	if (!(reason & mask))		goto out;	bcm43xx_interrupt_ack(bcm, reason, mask);	/* Only accept IRQs, if we are initialized properly.	 * This avoids an RX race while initializing.	 * We should probably not enable IRQs before we are initialized	 * completely, but some careful work is needed to fix this. I think it	 * is best to stay with this cheap workaround for now... .	 */	if (likely(bcm->initialized)) {		/* 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->_lock);	return ret;}static void bcm43xx_release_firmware(struct bcm43xx_private *bcm, int force){	if (bcm->firmware_norelease && !force)		return; /* Suspending or controller reset. */	release_firmware(bcm->ucode);	bcm->ucode = NULL;	release_firmware(bcm->pcm);	bcm->pcm = NULL;	release_firmware(bcm->initvals0);	bcm->initvals0 = NULL;	release_firmware(bcm->initvals1);	bcm->initvals1 = NULL;}static int bcm43xx_request_firmware(struct bcm43xx_private *bcm){	struct bcm43xx_phyinfo *phy = bcm->current_core->phy;	u8 rev = bcm->current_core->rev;	int err = 0;	int nr;	char buf[22 + sizeof(modparam_fwpostfix) - 1] = { 0 };	if (!bcm->ucode) {		snprintf(buf, ARRAY_SIZE(buf), "bcm43xx_microcode%d%s.fw",			 (rev >= 5 ? 5 : rev),			 modparam_fwpostfix);		err = request_firmware(&bcm->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 (!bcm->pcm) {		snprintf(buf, ARRAY_SIZE(buf),			 "bcm43xx_pcm%d%s.fw",			 (rev < 5 ? 4 : 5),			 modparam_fwpostfix);		err = request_firmware(&bcm->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 (!bcm->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(&bcm->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 (bcm->initvals0->size % sizeof(struct bcm43xx_initval)) {			printk(KERN_ERR PFX "InitVals fileformat error.\n");			goto error;		}	}	if (!bcm->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(&bcm->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 (bcm->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){	const u32 *data;	unsigned int i, len;	/* Upload Microcode. */	data = (u32 *)(bcm->ucode->data);	len = bcm->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 *)(bcm->pcm->data);	len = bcm->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){	int err;	err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals0->data,				     bcm->initvals0->size / sizeof(struct bcm43xx_initval));	if (err)		goto out;	if (bcm->initvals1) {		err = bcm43xx_write_initvals(bcm, (struct bcm43xx_initval *)bcm->initvals1->data,					     bcm->initvals1->size / sizeof(struct bcm43xx_initval));		if (err)			goto out;	}out:	return err;}static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm){	int res;	unsigned int i;	u32 data;	bcm->irq = bcm->pci_dev->irq;#ifdef CONFIG_BCM947XX	if (bcm->pci_dev->bus->number == 0) {		struct pci_dev *d = NULL;		/* FIXME: we will probably need more device IDs here... */		d = pci_find_device(PCI_VENDOR_ID_BROADCOM, 0x4324, NULL);		if (d != NULL) {			bcm->irq = d->irq;		}	}#endif	res = request_irq(bcm->irq, bcm43xx_interrupt_handler,			  SA_SHIRQ, KBUILD_MODNAME, bcm);	if (res) {		printk(KERN_ERR PFX "Cannot register IRQ%d\n", bcm->irq);		return -ENODEV;	}	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xffffffff);	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);	i = 0;	while (1) {		data = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);		if (data == BCM43xx_IRQ_READY)			break;		i++;		if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {			printk(KERN_ERR PFX "Card IRQ register not responding. "					    "Giving up.\n");			free_irq(bcm->irq, bcm);			return -ENODEV;		}		udelay(10);	}	// dummy read	bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);	return 0;}/* 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 -ENODEV;		} else if (unlikely(err != 0))			return -ENODEV;	} else if (unlikely(err != 0))		return -ENODEV;	return 0;}/* 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, value;	value = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);	value &= ~0xc000;	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, value);	mask = 0x0000001F;	value = 0x0000000F;	bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_CONTROL,			bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_CONTROL) & 0xFFF0);	bcm43xx_write16(bcm, BCM43xx_MMIO_GPIO_MASK,			bcm43xx_read16(bcm, BCM43xx_MMIO_GPIO_MASK) | 0x000F);	old_core = bcm->current_core;		err = switch_to_gpio_core(bcm);	if (err)		return err;	if (bcm->current_core->rev >= 2){		mask  |= 0x10;		value |= 0x10;	}	if (bcm->chip_id == 0x4301) {		mask  |= 0x60;		value |= 0x60;	}	if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL) {		mask  |= 0x200;		value |= 0x200;	}	bcm43xx_write32(bcm, BCM43xx_GPIO_CONTROL,	                (bcm43xx_read32(bcm, BCM43xx_GPIO_CONTROL) & mask) | value);	err = bcm43xx_switch_core(bcm, old_core);	assert(err == 0);	return 0;}/* 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){	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;	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 = 100000; i; i--) {		tmp = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);		if (tmp & BCM43xx_IRQ_READY)			return;		udelay(10);	}	printkl(KERN_ERR PFX "MAC suspend failed\n");}void bcm43xx_set_iwmode(struct bcm43xx_private *bcm,			int iw_mode){	unsigned long flags;	u32 status;	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)		bcm->net_dev->type = ARPHRD_IEEE80211;	else		bcm->net_dev->type = ARPHRD_ETHER;	if (!bcm->initialized)		return;	bcm43xx_mac_suspend(bcm);	status = bcm43xx_read32(bcm, BCM43xx_MMIO_STATUS_BITFIELD);	/* Reset status to infrastructured mode */	status &= ~(BCM43xx_SBF_MODE_AP | BCM43xx_SBF_MODE_MONITOR);	/*FIXME: We actually set promiscuous mode as well, until we don't	 * get the HW mac filter working */	status |= BCM43xx_SBF_MODE_NOTADHOC | BCM43xx_SBF_MODE_PROMISC;	switch (iw_mode) {	case IW_MODE_MONITOR:		status |= (BCM43xx_SBF_MODE_PROMISC |			   BCM43xx_SBF_MODE_MONITOR);		break;	case IW_MODE_ADHOC:		status &= ~BCM43xx_SBF_MODE_NOTADHOC;		break;	case IW_MODE_MASTER:	case IW_MODE_SECOND:	case IW_MODE_REPEAT:		/* TODO: No AP/Repeater mode for now :-/ */		TODO();		break;	case IW_MODE_INFRA:		/* nothing to be done here... */		break;	default:		printk(KERN_ERR PFX "Unknown iwmode %d\n", iw_mode);	}	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);	bcm43xx_mac_enable(bcm);}/* This is the opposite of bcm43xx_chip_init() */static void bcm43x

⌨️ 快捷键说明

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