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

📄 bcm43xx_main.c

📁 linux内核源码
💻 C
📖 第 1 页 / 共 5 页
字号:
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;}static int bcm43xx_initialize_irq(struct bcm43xx_private *bcm){	int err;	bcm->irq = bcm->pci_dev->irq;	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 */		break;	case IW_MODE_INFRA:		/* nothing to be done here... */		break;	default:		dprintk(KERN_ERR PFX "Unknown mode in set_iwmode: %d\n", iw_mode);	}	if (net_dev->flags & IFF_PROMISC)		status |= BCM43xx_SBF_MODE_PROMISC;	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, status);	value = 0x0002;	if (iw_mode != IW_MODE_ADHOC && iw_mode != IW_MODE_MASTER) {		if (bcm->chip_id == 0x4306 && bcm->chip_rev == 3)			value = 0x0064;		else			value = 0x0032;	}	bcm43xx_write16(bcm, 0x0612, value);}/* This is the opposite of bcm43xx_chip_init() */static void bcm43xx_chip_cleanup(struct bcm43xx_private *bcm){	bcm43xx_radio_turn_off(bcm);	if (!modparam_noleds)		bcm43xx_leds_exit(bcm);	bcm43xx_gpio_cleanup(bcm);	bcm43xx_release_firmware(bcm, 0);}/* Initialize the chip * http://bcm-specs.sipsolutions.net/ChipInit */static int bcm43xx_chip_init(struct bcm43xx_private *bcm){	struct bcm43xx_radioinfo *radio = bcm43xx_current_radio(bcm);	struct bcm43xx_phyinfo *phy = bcm43xx_current_phy(bcm);	int err;	int i, tmp;	u32 value32;	u16 value16;	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD,			BCM43xx_SBF_CORE_READY			| BCM43xx_SBF_400);	err = bcm43xx_request_firmware(bcm);	if (err)		goto out;	bcm43xx_upload_microcode(bcm);	bcm43xx_write32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON, 0xFFFFFFFF);	bcm43xx_write32(bcm, BCM43xx_MMIO_STATUS_BITFIELD, 0x00020402);	i = 0;	while (1) {		value32 = bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON);		if (value32 == BCM43xx_IRQ_READY)			break;		i++;		if (i >= BCM43xx_IRQWAIT_MAX_RETRIES) {			printk(KERN_ERR PFX "IRQ_READY timeout\n");			err = -ENODEV;			goto err_release_fw;		}		udelay(10);	}	bcm43xx_read32(bcm, BCM43xx_MMIO_GEN_IRQ_REASON); /* dummy read */	value16 = bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,				     BCM43xx_UCODE_REVISION);	dprintk(KERN_INFO PFX "Microcode rev 0x%x, pl 0x%x "		"(20%.2i-%.2i-%.2i  %.2i:%.2i:%.2i)\n", value16,		bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,				   BCM43xx_UCODE_PATCHLEVEL),		(bcm43xx_shm_read16(bcm, BCM43xx_SHM_SHARED,				    BCM43xx_UCODE_DATE) >> 12) & 0xf,		(bcm43xx_shm_read16(bcm

⌨️ 快捷键说明

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