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

📄 smc91111.c

📁 smc9111网卡芯片的linux驱动程序
💻 C
📖 第 1 页 / 共 5 页
字号:
	}	PRINTK2("%s: smc_probe\n", dev->name);	PRINTK("Trying to request region for base addr %x\n", ioaddr);	/* Grab the region so that no one else tries to probe our ioports. */	if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name))		return -EBUSY;	PRINTK("request_region successful, try to read data from chip:\n");	/* First, see if the high byte is 0x33 */	bank = SMC_inw(ioaddr, BANK_SELECT);	PRINTK("bank got %x from SMC_inw\n", bank);	if ((bank & 0xFF00) != 0x3300)		return -ENODEV;	/* The above MIGHT indicate a device, but I need to write to further test this.  */	SMC_outw(0x0, ioaddr, BANK_SELECT);	bank = SMC_inw(ioaddr, BANK_SELECT);	if ((bank & 0xFF00) != 0x3300) {		retval = -ENODEV;		goto err_out;	}	/* well, we've already written once, so hopefully another time won't	   hurt.  This time, I need to switch the bank register to bank 1,	   so I can access the base address register */		SMC_SELECT_BANK(1);		base_address_register = SMC_inw(ioaddr, BASE_REG);	PRINTK("base_address_register = %x\n",base_address_register);			/* go check those pesky isa io addresses >:( */	if ((ioaddr&0x0fff) != (base_address_register >> 3 & 0x3E0)) {		printk("%s: ioaddr %x doesn't match configuration (%x)."		       "Probably not a SMC chip\n", CARDNAME,		       (ioaddr&0x0fff), base_address_register >> 3 & 0x3E0);		/* well, the base address register didn't match.  Must not have		   been a SMC chip after all. */		retval = -ENODEV;		goto err_out;	}	/*  check if the revision register is something that I recognize.	   These might need to be added to later, as future revisions	   could be added.  */	SMC_SELECT_BANK(3);	revision_register = SMC_inw(ioaddr, REV_REG);	if (!chip_ids[(revision_register >> 4) & 0xF]) {		/* I don't recognize this chip, so... */		printk		    ("%s: IO %x: Unrecognized revision register: %x, Contact author. \n",		     dev->name, ioaddr, revision_register);		retval = -ENODEV;		goto err_out;	}	PRINTK("revision_register = %x\n",revision_register);	/* at this point I'll assume that the chip is an SMC9xxx.	   It might be prudent to check a listing of MAC addresses	   against the hardware address, or do some other tests. */	/* Note also that ChipID's for smc91c110 and 91c111 are 	   *  both '9'.  ?????  [jws] */	if (version_printed++ == 0)		PRINTK("%s", version);	/* fill in some of the fields */	dev->base_addr = ioaddr;	/*	   . Get the MAC address ( bank 1, regs 4 - 9 )  Some folks don't use the	   . eeprom, or use it in different ways, so we need a platform specific	   . mac address initializer:	 */	smc_init_mac_addr( dev, ioaddr, interface);		if (!is_valid_ether_addr(dev->dev_addr)) {		if (!is_valid_ether_addr(fallback_mac))			printk("%s: Invalid ethernet MAC address.  Please set using "				"ifconfig\n", dev->name);		else {			printk("%s: Unitialized MAC address detected -- using a dummy one\n",		     		dev->name);			for (i = 0; i < 6; i++)				dev->dev_addr[i] = fallback_mac[i];							/* support for multiple chips */				dev->dev_addr[5] = (ioaddr >> 8) & 0xff;		}	}		/* get the memory information */	SMC_SELECT_BANK(0);	memory_info_register = SMC_inw(ioaddr, MIR_REG);	memory = memory_info_register & (u16) 0x00ff;	memory *= LAN91C111_MEMORY_MULTIPLIER;	/*	   Now, I want to find out more about the chip.  This is sort of	   redundant, but it's cleaner to have it in both, rather than having	   one VERY long probe procedure.	 */	SMC_SELECT_BANK(3);	revision_register = SMC_inw(ioaddr, REV_REG);	version_string = chip_ids[(revision_register >> 4) & 0xF];	if (!version_string) {		/* I shouldn't get here because this call was done before.... */		retval = -ENODEV;		goto err_out;	}	/* now, reset the chip, and put it into a known state */	smc_reset(dev);#if 0	/*	   . If dev->irq is 0, then the device has to be banged on to see	   . what the IRQ is.	   .	   . This banging doesn't always detect the IRQ, for unknown reasons.	   . a workaround is to reset the chip and try again.	   .	   . Interestingly, the DOS packet driver *SETS* the IRQ on the card to	   . be what is requested on the command line.   I don't do that, mostly	   . because the card that I have uses a non-standard method of accessing	   . the IRQs, and because this _should_ work in most configurations.	   .	   . Specifying an IRQ is done with the assumption that the user knows	   . what (s)he is doing.  No checking is done!!!!	   .	 */	if (dev->irq < 2) {		int trials;		trials = 3;		while (trials--) {			dev->irq = smc_findirq(ioaddr);			if (dev->irq)				break;			/* kick the card and try again */			smc_reset(dev);		}	}	if (dev->irq == 0) {		printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n",		       dev->name);		retval = -ENODEV;		goto err_out;	}	/* can't assume this for non-PC architectures, folks */	if (dev->irq == 2) {		/* Fixup for users that don't know that IRQ 2 is really IRQ 9,		 * or don't know which one to set.		 */		dev->irq = 9;	}#endif	/* Initialize the private structure. */	if (dev->priv == NULL) {		dev->priv = kmalloc(sizeof (struct smc_local), GFP_KERNEL);		if (dev->priv == NULL) {			retval = -ENOMEM;			goto err_out;		}	}	/* set the private data to zero by default */	memset(dev->priv, 0, sizeof (struct smc_local));	lp = (struct smc_local *) dev->priv;	/* Fill in the fields of the device structure with ethernet values. */	ether_setup(dev);	/* get extra config data for interface */	lp->dev_dma_phys = smc_config[interface].dma_addr;	lp->use_32bit    = smc_config[interface].use_32bit;#if 0	GPDR(IRQ_TO_GPIO_2_80(dev->irq)) &=	 ~GPIO_bit(IRQ_TO_GPIO_2_80(dev->irq));	set_GPIO_IRQ_edge(IRQ_TO_GPIO_2_80(dev->irq), IRQT_RISING);	/* treat a dma addr of zero as no dma */	if( lp->dev_dma_phys)	{		#if 0		retval = pxa_request_dma(dev->name, DMA_PRIO_LOW, smc_dma_irq, (void *) lp);		if (retval < 0) {			printk("%s: unable to acquire a DMA channel.\n", dev->name);			kfree(dev->priv);			dev->priv = NULL;			goto err_out;		}		dev->dma = retval;		PRINTK("%s: got dma channel number %d for smc rx\n", __FUNCTION__,				dev->dma);		PRINTK("%s: using %0#10lx for phys addr for smc device number %d\n",				__FUNCTION__, lp->dev_dma_phys, i);		#endif	}#endif	/* Grab the IRQ */	retval = request_irq(IRQ_EINT2, &smc_interrupt, 0, dev->name, dev);	if (retval) {		printk("%s: unable to get IRQ %d (irqval=%d).\n",		       dev->name, IRQ_EINT2, retval);#if 0                                           /*modified by syx*/		if( lp->dev_dma_phys) 			pxa_free_dma(dev->dma);	#endif		kfree(dev->priv);		dev->priv = NULL;		goto err_out;	}	dev->open = smc_open;	dev->stop = smc_close;	dev->hard_start_xmit = smc_wait_to_send_packet;	dev->tx_timeout = smc_timeout;	dev->get_stats = smc_query_statistics;#ifdef	HAVE_MULTICAST	dev->set_multicast_list = &smc_set_multicast_list;#endif	/* => Store the ChipRevision and ChipID, to be used in resolving the Odd-Byte	 *  issue in RevB of LAN91C111; Pramod	 */	SMC_SELECT_BANK(3);	revision_register = SMC_inw(ioaddr, REV_REG);	lp->ChipID = (revision_register >> 4) & 0xF;	lp->ChipRev = revision_register & 0xF;	/* now, print out the card info, in a short format.. */	printk("%s: %s(rev:%d) at %#3x IRQ:%d DMA:%d (%s) MEM:%db NOWAIT:%d ",	       dev->name,	       version_string, revision_register & 0xF, ioaddr, dev->irq, dev->dma,	       lp->use_32bit?"32-bit":"16-bit",	       memory, wait_mode[(int)(dev->name[3]) - 48]);	/*	   . Print the Ethernet address	 */	printk("ADDR: ");	for (i = 0; i < 5; i++)		printk("%2.2x:", dev->dev_addr[i]);	printk("%2.2x \n", dev->dev_addr[5]);	PRINTK("ChipID: %x, ChipRev: %x, stored in dev->priv at %p\n",	       lp->ChipID, lp->ChipRev, lp);	return 0;      err_out:	release_region(ioaddr, SMC_IO_EXTENT);	return retval;}#if SMC_DEBUG > 2static voidprint_packet(unsigned char *buf, int length){	int i;	int remainder;	int lines;	printk("Packet of length %d \n", length);#if SMC_DEBUG > 3	lines = length / 16;	remainder = length % 16;	for (i = 0; i < lines; i++) {		int cur;		for (cur = 0; cur < 8; cur++) {			u8 a, b;			a = *(buf++);			b = *(buf++);			printk("%02x%02x ", a, b);		}		printk("\n");	}	for (i = 0; i < remainder / 2; i++) {		u8 a, b;		a = *(buf++);		b = *(buf++);		printk("%02x%02x ", a, b);	}	printk("\n");#endif}#endif/* * Open and Initialize the board * * Set up everything, reset the card, etc .. * */static intsmc_open(struct net_device *dev){	struct smc_local *lp = (struct smc_local *) dev->priv;	unsigned int ioaddr = dev->base_addr;	int i;			/* used to set hw ethernet address */	u16 phy_status;	u8 phyaddr = lp->phyaddr;	PRINTK2("%s:smc_open\n", dev->name);		/* in spite of checks earlier, someone may set a bogus mac addr via some other	 * mechanism.  We *really* need to prevent invalid addresses, particularly	 * 0:0:0:0:0:0 and ff:ff:ff:ff:ff:ff, from hitting the wire, as this wreaks	 * havoc with some switches.	 */		if (!is_valid_ether_addr(dev->dev_addr)) {		printk(KERN_INFO "%s: Invalid network MAC address for %s encountered.\n",				__FUNCTION__,dev->name);		return -EINVAL;	}	// Setup the default Register Modes	lp->tcr_cur_mode = TCR_DEFAULT;	lp->rcr_cur_mode = RCR_DEFAULT;	lp->rpc_cur_mode = RPC_DEFAULT;	// Set default parameters (files)#ifdef CONFIG_SYSCTL	lp->ctl_swfdup = 0;	lp->ctl_ephloop = 0;	lp->ctl_miiop = 0;	lp->ctl_autoneg = 1;	lp->ctl_rfduplx = 1;	lp->ctl_rspeed = 100;	lp->ctl_afduplx = 0;	lp->ctl_aspeed = 100;	lp->ctl_lnkfail = 1;	lp->ctl_forcol = 0;	lp->ctl_filtcar = 0;#endif        spin_lock_init(&lp->mmu_lock);	/* reset the hardware */	smc_reset(dev);	smc_enable(dev);	/* Configure the PHY */	smc_phy_configure(dev);	/* jws: read status of phy */	phy_status = smc_read_phy_register(ioaddr, phyaddr, PHY_STAT_REG);	if ((phy_status & PHY_STAT_REM_FLT) || !(phy_status & PHY_STAT_LINK)) {		printk("%s: ERROR: remote fault or cable not connected.\n",		       __FUNCTION__);		return -ENOLINK;	}	/*	   According to Becker, I have to set the hardware address	   at this point, because the (l)user can set it with an	   ioctl.  Easily done...	 */	SMC_SELECT_BANK(1);	for (i = 0; i < 6; i += 2) {		u16 address;		address = dev->dev_addr[i + 1] << 8;		address |= dev->dev_addr[i];		SMC_outw(address, ioaddr, ADDR0_REG + i);	}#ifdef MODULE	MOD_INC_USE_COUNT;#endif#ifdef CONFIG_SYSCTL	smc_sysctl_register(dev);#endif	netif_start_queue(dev);	return 0;}/*-------------------------------------------------------- . Called by the kernel to send a packet out into the void . of the net.  This routine is largely based on . skeleton.c, from Becker. .--------------------------------------------------------*/static int smc_get_reg(int bank, unsigned int ioaddr, int reg);static inline void smc_dump_registers( unsigned int ioaddr){        int oldbank = inw( ioaddr + BANK_SELECT);        printk("-----smc_dump-----\n");        printk("-----BANK0-----\n");        printk("TCR = %04x\n", smc_get_reg(0, ioaddr, TCR_REG));        printk("EPH = %04x\n", smc_get_reg(0, ioaddr, EPH_STATUS_REG));        printk("RCR = %04x\n", smc_get_reg(0, ioaddr, RCR_REG));        printk("CNT = %04x\n", smc_get_reg(0, ioaddr, COUNTER_REG));        printk("MIR = %04x\n", smc_get_reg(0, ioaddr, MIR_REG));        printk("RPC = %04x\n", smc_get_reg(0, ioaddr, RPC_REG));        printk("-----BANK1-----\n");        printk("CFG = %04x\n", smc_get_reg(1, ioaddr, CONFIG_REG));        printk("BAS = %04x\n", smc_get_reg(1, ioaddr, BASE_REG));        printk("GPR = %04x\n", smc_get_reg(1, ioaddr, GP_REG));        printk("CTL = %04x\n", smc_get_reg(1, ioaddr, CTL_REG));        printk("-----BANK2-----\n");        printk("ARPN= %04x\n", smc_get_reg(2, ioaddr, PN_REG));        printk("RXTX= %04x\n", smc_get_reg(2, ioaddr, RXFIFO_REG));        printk("PTR = %04x\n", smc_get_reg(2, ioaddr, PTR_REG));        printk("ISR = %04x\n", smc_get_reg(2, ioaddr, INT_REG));        printk("-----BANK3-----\n");        printk("REV = %04x\n", smc_get_reg(3, ioaddr, REV_REG));        printk("ERX = %04x\n", smc_get_reg(3, ioaddr, ERCV_REG));        outw( oldbank, ioaddr + BANK_SELECT );}static voidsmc_timeout(struct net_device *dev){	PRINTK3("%s:smc_send_packet\n", dev->name);	/* If we get here, some higher level has decided we are broken.	   There should really be a "kick me" function call instead. */	printk(KERN_INFO "%s: transmit timed out, %s?\n", dev->name,	       tx_done(dev) ? "IRQ conflict" : "network cable problem");	smc_dump_registers( dev->base_addr);#if 0	/* "kick" the adaptor */	smc_reset(dev);	smc_enable(dev);	/* Reconfigure the PHY */	smc_phy_configure(dev);#endif	((struct smc_local *) dev->priv)->saved_skb = NULL;	netif_wake_queue(dev);	dev->trans_start = jiffies;	/* clear anything saved *///	netif_wake_queue(dev);}/*-------------------------------------------------------------------- . . This is the main routine of the driver, to handle the net_device when . it needs some attention. . . So: .   first, save state of the chipset .   branch off into routines to handle each case, and acknowledge .	    each to the interrupt register .   and finally restore state. . ---------------------------------------------------------------------*/static voidsmc_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = dev_id;

⌨️ 快捷键说明

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