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

📄 82596.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 3 页
字号:
{	struct i596_private *lp = (struct i596_private *) dev->priv;	struct tx_cmd *tx_cmd;	struct i596_tbd *tbd;	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;	dev->trans_start = jiffies;	DEB(DEB_STARTTX,printk("%s: i596_start_xmit(%x,%x) called\n", dev->name,				skb->len, (unsigned int)skb->data));	netif_stop_queue(dev);	tx_cmd = lp->tx_cmds + lp->next_tx_cmd;	tbd = lp->tbds + lp->next_tx_cmd;	if (tx_cmd->cmd.command) {		DEB(DEB_ERRORS,printk ("%s: xmit ring full, dropping packet.\n",				dev->name));		lp->stats.tx_dropped++;		dev_kfree_skb(skb);	} else {		if (++lp->next_tx_cmd == TX_RING_SIZE)			lp->next_tx_cmd = 0;		tx_cmd->tbd = WSWAPtbd(virt_to_bus(tbd));		tbd->next = I596_NULL;		tx_cmd->cmd.command = CMD_FLEX | CmdTx;		tx_cmd->skb = skb;		tx_cmd->pad = 0;		tx_cmd->size = 0;		tbd->pad = 0;		tbd->size = EOF | length;		tbd->data = WSWAPchar(virt_to_bus(skb->data));#ifdef __mc68000__		cache_push(virt_to_phys(skb->data), length);#endif		DEB(DEB_TXADDR,print_eth(skb->data, "tx-queued"));		i596_add_cmd(dev, &tx_cmd->cmd);		lp->stats.tx_packets++;		lp->stats.tx_bytes += length;	}	netif_start_queue(dev);	return 0;}static void print_eth(unsigned char *add, char *str){	int i;	printk("i596 0x%p, ", add);	for (i = 0; i < 6; i++)		printk(" %02X", add[i + 6]);	printk(" -->");	for (i = 0; i < 6; i++)		printk(" %02X", add[i]);	printk(" %02X%02X, %s\n", add[12], add[13], str);}int __init i82596_probe(struct net_device *dev){	int i;	struct i596_private *lp;	char eth_addr[8];	static int probed;	if (probed)		return -ENODEV;	probed++;#ifdef ENABLE_MVME16x_NET	if (MACH_IS_MVME16x) {		if (mvme16x_config & MVME16x_CONFIG_NO_ETHERNET) {			printk("Ethernet probe disabled - chip not present\n");			return -ENODEV;		}		memcpy(eth_addr, (void *) 0xfffc1f2c, 6);	/* YUCK! Get addr from NOVRAM */		dev->base_addr = MVME_I596_BASE;		dev->irq = (unsigned) MVME16x_IRQ_I596;	}#endif#ifdef ENABLE_BVME6000_NET	if (MACH_IS_BVME6000) {		volatile unsigned char *rtc = (unsigned char *) BVME_RTC_BASE;		unsigned char msr = rtc[3];		int i;		rtc[3] |= 0x80;		for (i = 0; i < 6; i++)			eth_addr[i] = rtc[i * 4 + 7];	/* Stored in RTC RAM at offset 1 */		rtc[3] = msr;		dev->base_addr = BVME_I596_BASE;		dev->irq = (unsigned) BVME_IRQ_I596;	}#endif#ifdef ENABLE_APRICOT	{		int checksum = 0;		int ioaddr = 0x300;		/* this is easy the ethernet interface can only be at 0x300 */		/* first check nothing is already registered here */		if (!request_region(ioaddr, I596_TOTAL_SIZE, dev->name)) {			printk("82596: IO address 0x%04x in use\n", ioaddr);			return -EBUSY;		}		for (i = 0; i < 8; i++) {			eth_addr[i] = inb(ioaddr + 8 + i);			checksum += eth_addr[i];		}		/* checksum is a multiple of 0x100, got this wrong first time		   some machines have 0x100, some 0x200. The DOS driver doesn't		   even bother with the checksum.		   Some other boards trip the checksum.. but then appear as		   ether address 0. Trap these - AC */		if ((checksum % 0x100) || 		    (memcmp(eth_addr, "\x00\x00\x49", 3) != 0)) {			release_region(ioaddr, I596_TOTAL_SIZE);			return -ENODEV;		}		dev->base_addr = ioaddr;		dev->irq = 10;	}#endif	dev->mem_start = (int)__get_free_pages(GFP_ATOMIC, 0);	if (!dev->mem_start) {#ifdef ENABLE_APRICOT		release_region(dev->base_addr, I596_TOTAL_SIZE);#endif		return -ENOMEM;	}	ether_setup(dev);	DEB(DEB_PROBE,printk("%s: 82596 at %#3lx,", dev->name, dev->base_addr));	for (i = 0; i < 6; i++)		DEB(DEB_PROBE,printk(" %2.2X", dev->dev_addr[i] = eth_addr[i]));	DEB(DEB_PROBE,printk(" IRQ %d.\n", dev->irq));	DEB(DEB_PROBE,printk(version));	/* The 82596-specific entries in the device structure. */	dev->open = i596_open;	dev->stop = i596_close;	dev->hard_start_xmit = i596_start_xmit;	dev->get_stats = i596_get_stats;	dev->set_multicast_list = set_multicast_list;	dev->tx_timeout = i596_tx_timeout;	dev->watchdog_timeo = TX_TIMEOUT;	dev->priv = (void *)(dev->mem_start);	lp = (struct i596_private *) dev->priv;	DEB(DEB_INIT,printk ("%s: lp at 0x%08lx (%d bytes), lp->scb at 0x%08lx\n",			dev->name, (unsigned long)lp,			sizeof(struct i596_private), (unsigned long)&lp->scb));	memset((void *) lp, 0, sizeof(struct i596_private));#ifdef __mc68000__	cache_push(virt_to_phys((void *)(dev->mem_start)), 4096);	cache_clear(virt_to_phys((void *)(dev->mem_start)), 4096);	kernel_set_cachemode((void *)(dev->mem_start), 4096, IOMAP_NOCACHE_SER);#endif	lp->scb.command = 0;	lp->scb.cmd = I596_NULL;	lp->scb.rfd = I596_NULL;	lp->lock = SPIN_LOCK_UNLOCKED;	return 0;}static void i596_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = dev_id;	struct i596_private *lp;	short ioaddr;	unsigned short status, ack_cmd = 0;#ifdef ENABLE_BVME6000_NET	if (MACH_IS_BVME6000) {		if (*(char *) BVME_LOCAL_IRQ_STAT & BVME_ETHERR) {			i596_error(BVME_IRQ_I596, NULL, NULL);			return;		}	}#endif	if (dev == NULL) {		printk("i596_interrupt(): irq %d for unknown device.\n", irq);		return;	}	ioaddr = dev->base_addr;	lp = (struct i596_private *) dev->priv;	spin_lock (&lp->lock);	wait_cmd(dev,lp,100,"i596 interrupt, timeout");	status = lp->scb.status;	DEB(DEB_INTS,printk("%s: i596 interrupt, IRQ %d, status %4.4x.\n",			dev->name, irq, status));	ack_cmd = status & 0xf000;	if ((status & 0x8000) || (status & 0x2000)) {		struct i596_cmd *ptr;		if ((status & 0x8000))			DEB(DEB_INTS,printk("%s: i596 interrupt completed command.\n", dev->name));		if ((status & 0x2000))			DEB(DEB_INTS,printk("%s: i596 interrupt command unit inactive %x.\n", dev->name, status & 0x0700));		while ((lp->cmd_head != I596_NULL) && (lp->cmd_head->status & STAT_C)) {			ptr = lp->cmd_head;			DEB(DEB_STATUS,printk("cmd_head->status = %04x, ->command = %04x\n",				       lp->cmd_head->status, lp->cmd_head->command));			lp->cmd_head = ptr->v_next;			lp->cmd_backlog--;			switch ((ptr->command) & 0x7) {			case CmdTx:			    {				struct tx_cmd *tx_cmd = (struct tx_cmd *) ptr;				struct sk_buff *skb = tx_cmd->skb;				if ((ptr->status) & STAT_OK) {					DEB(DEB_TXADDR,print_eth(skb->data, "tx-done"));				} else {					lp->stats.tx_errors++;					if ((ptr->status) & 0x0020)						lp->stats.collisions++;					if (!((ptr->status) & 0x0040))						lp->stats.tx_heartbeat_errors++;					if ((ptr->status) & 0x0400)						lp->stats.tx_carrier_errors++;					if ((ptr->status) & 0x0800)						lp->stats.collisions++;					if ((ptr->status) & 0x1000)						lp->stats.tx_aborted_errors++;				}				dev_kfree_skb_irq(skb);				tx_cmd->cmd.command = 0; /* Mark free */				break;			    }			case CmdTDR:			    {				unsigned short status = ((struct tdr_cmd *)ptr)->status;				if (status & 0x8000) {					DEB(DEB_ANY,printk("%s: link ok.\n", dev->name));				} else {					if (status & 0x4000)						printk("%s: Transceiver problem.\n", dev->name);					if (status & 0x2000)						printk("%s: Termination problem.\n", dev->name);					if (status & 0x1000)						printk("%s: Short circuit.\n", dev->name);					DEB(DEB_TDR,printk("%s: Time %d.\n", dev->name, status & 0x07ff));				}				break;			    }			case CmdConfigure:				/* Zap command so set_multicast_list() knows it is free */				ptr->command = 0;				break;			}			ptr->v_next = ptr->b_next = I596_NULL;			lp->last_cmd = jiffies;		}		ptr = lp->cmd_head;		while ((ptr != I596_NULL) && (ptr != lp->cmd_tail)) {			ptr->command &= 0x1fff;			ptr = ptr->v_next;		}		if ((lp->cmd_head != I596_NULL))			ack_cmd |= CUC_START;		lp->scb.cmd = WSWAPcmd(virt_to_bus(&lp->cmd_head->status));	}	if ((status & 0x1000) || (status & 0x4000)) {		if ((status & 0x4000))			DEB(DEB_INTS,printk("%s: i596 interrupt received a frame.\n", dev->name));		i596_rx(dev);		/* Only RX_START if stopped - RGH 07-07-96 */		if (status & 0x1000) {			if (netif_running(dev)) {				DEB(DEB_ERRORS,printk("%s: i596 interrupt receive unit inactive, status 0x%x\n", dev->name, status));				ack_cmd |= RX_START;				lp->stats.rx_errors++;				lp->stats.rx_fifo_errors++;				rebuild_rx_bufs(dev);			}		}	}	wait_cmd(dev,lp,100,"i596 interrupt, timeout");	lp->scb.command = ack_cmd;#ifdef ENABLE_MVME16x_NET	if (MACH_IS_MVME16x) {		/* Ack the interrupt */		volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;		pcc2[0x2a] |= 0x08;	}#endif#ifdef ENABLE_BVME6000_NET	if (MACH_IS_BVME6000) {		volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;		*ethirq = 1;		*ethirq = 3;	}#endif#ifdef ENABLE_APRICOT	(void) inb(ioaddr + 0x10);	outb(4, ioaddr + 0xf);#endif	CA(dev);	DEB(DEB_INTS,printk("%s: exiting interrupt.\n", dev->name));	spin_unlock (&lp->lock);	return;}static int i596_close(struct net_device *dev){	struct i596_private *lp = (struct i596_private *) dev->priv;	unsigned long flags;	netif_stop_queue(dev);	DEB(DEB_INIT,printk("%s: Shutting down ethercard, status was %4.4x.\n",		       dev->name, lp->scb.status));	save_flags(flags);	cli();	wait_cmd(dev,lp,100,"close1 timed out");	lp->scb.command = CUC_ABORT | RX_ABORT;	CA(dev);	wait_cmd(dev,lp,100,"close2 timed out");	restore_flags(flags);	DEB(DEB_STRUCT,i596_display_data(dev));	i596_cleanup_cmd(dev,lp);#ifdef ENABLE_MVME16x_NET	if (MACH_IS_MVME16x) {		volatile unsigned char *pcc2 = (unsigned char *) 0xfff42000;		/* Disable all ints */		pcc2[0x28] = 1;		pcc2[0x2a] = 0x40;		pcc2[0x2b] = 0x40;	/* Set snooping bits now! */	}#endif#ifdef ENABLE_BVME6000_NET	if (MACH_IS_BVME6000) {		volatile unsigned char *ethirq = (unsigned char *) BVME_ETHIRQ_REG;		*ethirq = 1;	}#endif	free_irq(dev->irq, dev);	remove_rx_bufs(dev);	MOD_DEC_USE_COUNT;	return 0;}static struct net_device_stats * i596_get_stats(struct net_device *dev){	struct i596_private *lp = (struct i596_private *) dev->priv;	return &lp->stats;}/* *    Set or clear the multicast filter for this adaptor. */static void set_multicast_list(struct net_device *dev){	struct i596_private *lp = (struct i596_private *) dev->priv;	int config = 0, cnt;	DEB(DEB_MULTI,printk("%s: set multicast list, %d entries, promisc %s, allmulti %s\n", dev->name, dev->mc_count, dev->flags & IFF_PROMISC ? "ON" : "OFF", dev->flags & IFF_ALLMULTI ? "ON" : "OFF"));	if ((dev->flags & IFF_PROMISC) && !(lp->cf_cmd.i596_config[8] & 0x01)) {		lp->cf_cmd.i596_config[8] |= 0x01;		config = 1;	}	if (!(dev->flags & IFF_PROMISC) && (lp->cf_cmd.i596_config[8] & 0x01)) {		lp->cf_cmd.i596_config[8] &= ~0x01;		config = 1;	}	if ((dev->flags & IFF_ALLMULTI) && (lp->cf_cmd.i596_config[11] & 0x20)) {		lp->cf_cmd.i596_config[11] &= ~0x20;		config = 1;	}	if (!(dev->flags & IFF_ALLMULTI) && !(lp->cf_cmd.i596_config[11] & 0x20)) {		lp->cf_cmd.i596_config[11] |= 0x20;		config = 1;	}	if (config) {		if (lp->cf_cmd.cmd.command)			printk("%s: config change request already queued\n",			       dev->name);		else {			lp->cf_cmd.cmd.command = CmdConfigure;			i596_add_cmd(dev, &lp->cf_cmd.cmd);		}	}	cnt = dev->mc_count;	if (cnt > MAX_MC_CNT)	{		cnt = MAX_MC_CNT;		printk("%s: Only %d multicast addresses supported",			dev->name, cnt);	}		if (dev->mc_count > 0) {		struct dev_mc_list *dmi;		unsigned char *cp;		struct mc_cmd *cmd;		cmd = &lp->mc_cmd;		cmd->cmd.command = CmdMulticastList;		cmd->mc_cnt = dev->mc_count * 6;		cp = cmd->mc_addrs;		for (dmi = dev->mc_list; cnt && dmi != NULL; dmi = dmi->next, cnt--, cp += 6) {			memcpy(cp, dmi->dmi_addr, 6);			if (i596_debug > 1)				DEB(DEB_MULTI,printk("%s: Adding address %02x:%02x:%02x:%02x:%02x:%02x\n",						dev->name, cp[0],cp[1],cp[2],cp[3],cp[4],cp[5]));		}		i596_add_cmd(dev, &cmd->cmd);	}}#ifdef MODULEstatic struct net_device dev_82596 = { init: i82596_probe };#ifdef ENABLE_APRICOTstatic int io = 0x300;static int irq = 10;MODULE_PARM(irq, "i");MODULE_PARM_DESC(irq, "Apricot IRQ number");#endifMODULE_PARM(debug, "i");MODULE_PARM_DESC(debug, "i82596 debug mask");static int debug = -1;int init_module(void){#ifdef ENABLE_APRICOT	dev_82596.base_addr = io;	dev_82596.irq = irq;#endif	if (debug >= 0)		i596_debug = debug;	if (register_netdev(&dev_82596) != 0)		return -EIO;	return 0;}void cleanup_module(void){	unregister_netdev(&dev_82596);#ifdef __mc68000__	/* XXX This assumes default cache mode to be IOMAP_FULL_CACHING,	 * XXX which may be invalid (CONFIG_060_WRITETHROUGH)	 */	kernel_set_cachemode((void *)(dev_82596.mem_start), 4096,			IOMAP_FULL_CACHING);#endif	free_page ((u32)(dev_82596.mem_start));	dev_82596.priv = NULL;#ifdef ENABLE_APRICOT	/* If we don't do this, we can't re-insmod it later. */	release_region(dev_82596.base_addr, I596_TOTAL_SIZE);#endif}#endif				/* MODULE *//* * Local variables: *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 82596.c" * End: */

⌨️ 快捷键说明

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