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

📄 at1700.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 2 页
字号:
	dev->start = 1;	MOD_INC_USE_COUNT;	return 0;}static intnet_send_packet(struct sk_buff *skb, struct device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	int ioaddr = dev->base_addr;	if (dev->tbusy) {		/* If we get here, some higher level has decided we are broken.		   There should really be a "kick me" function call instead. */		int tickssofar = jiffies - dev->trans_start;		if (tickssofar < 10)			return 1;		printk("%s: transmit timed out with status %04x, %s?\n", dev->name,			   inw(ioaddr + STATUS), inb(ioaddr + TX_STATUS) & 0x80			   ? "IRQ conflict" : "network cable problem");		printk("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n",			   dev->name, inw(ioaddr + 0), inw(ioaddr + 2), inw(ioaddr + 4),			   inw(ioaddr + 6), inw(ioaddr + 8), inw(ioaddr + 10),			   inw(ioaddr + 12), inw(ioaddr + 14));		lp->stats.tx_errors++;		/* ToDo: We should try to restart the adaptor... */		outw(0xffff, ioaddr + 24);		outw(0xffff, ioaddr + TX_STATUS);		outw(0xe85a, ioaddr + CONFIG_0);		outw(0x8100, ioaddr + TX_INTR);		dev->tbusy=0;		dev->trans_start = jiffies;		lp->tx_started = 0;		lp->tx_queue = 0;		lp->tx_queue_len = 0;	}	/* If some higher layer thinks we've missed an tx-done interrupt	   we are passed NULL. Caution: dev_tint() handles the cli()/sti()	   itself. */	if (skb == NULL) {		dev_tint(dev);		return 0;	}	/* Block a timer-based transmit from overlapping.  This could better be	   done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */	if (set_bit(0, (void*)&dev->tbusy) != 0)		printk("%s: Transmitter access conflict.\n", dev->name);	else {		short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;		unsigned char *buf = skb->data;		/* Turn off the possible Tx interrupts. */		outb(0x00, ioaddr + TX_INTR);		outw(length, ioaddr + DATAPORT);		outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);		lp->tx_queue++;		lp->tx_queue_len += length + 2;		if (lp->tx_started == 0) {			/* If the Tx is idle, always trigger a transmit. */			outb(0x80 | lp->tx_queue, ioaddr + TX_START);			lp->tx_queue = 0;			lp->tx_queue_len = 0;			dev->trans_start = jiffies;			lp->tx_started = 1;			dev->tbusy = 0;		} else if (lp->tx_queue_len < 4096 - 1502)			/* Yes, there is room for one more packet. */			dev->tbusy = 0;		/* Turn on Tx interrupts back on. */		outb(0x82, ioaddr + TX_INTR);	}	dev_kfree_skb (skb, FREE_WRITE);	return 0;}/* The typical workload of the driver:   Handle the network interface interrupts. */static voidnet_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct device *dev = dev_id;	struct net_local *lp;	int ioaddr, status;	if (dev == NULL) {		printk ("at1700_interrupt(): irq %d for unknown device.\n", irq);		return;	}	dev->interrupt = 1;	ioaddr = dev->base_addr;	lp = (struct net_local *)dev->priv;	status = inw(ioaddr + TX_STATUS);	outw(status, ioaddr + TX_STATUS);	if (net_debug > 4)		printk("%s: Interrupt with status %04x.\n", dev->name, status);	if (status & 0xff00		||  (inb(ioaddr + RX_MODE) & 0x40) == 0) {			/* Got a packet(s). */		net_rx(dev);	}	if (status & 0x00ff) {		if (status & 0x80) {			lp->stats.tx_packets++;			if (lp->tx_queue) {				outb(0x80 | lp->tx_queue, ioaddr + TX_START);				lp->tx_queue = 0;				lp->tx_queue_len = 0;				dev->trans_start = jiffies;				dev->tbusy = 0;				mark_bh(NET_BH);	/* Inform upper layers. */			} else {				lp->tx_started = 0;				/* Turn on Tx interrupts off. */				outb(0x00, ioaddr + TX_INTR);				dev->tbusy = 0;				mark_bh(NET_BH);	/* Inform upper layers. */			}		}	}	dev->interrupt = 0;	return;}/* We have a good packet(s), get it/them out of the buffers. */static voidnet_rx(struct device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	int ioaddr = dev->base_addr;	int boguscount = 5;	while ((inb(ioaddr + RX_MODE) & 0x40) == 0) {		ushort status = inw(ioaddr + DATAPORT);		ushort pkt_len = inw(ioaddr + DATAPORT);		if (net_debug > 4)			printk("%s: Rxing packet mode %02x status %04x.\n",				   dev->name, inb(ioaddr + RX_MODE), status);#ifndef final_version		if (status == 0) {			outb(0x05, ioaddr + 14);			break;		}#endif		if ((status & 0xF0) != 0x20) {	/* There was an error. */			lp->stats.rx_errors++;			if (status & 0x08) lp->stats.rx_length_errors++;			if (status & 0x04) lp->stats.rx_frame_errors++;			if (status & 0x02) lp->stats.rx_crc_errors++;			if (status & 0x01) lp->stats.rx_over_errors++;		} else {			/* Malloc up new buffer. */			struct sk_buff *skb;			if (pkt_len > 1550) {				printk("%s: The AT1700 claimed a very large packet, size %d.\n",					   dev->name, pkt_len);				/* Prime the FIFO and then flush the packet. */				inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);				outb(0x05, ioaddr + 14);				lp->stats.rx_errors++;				break;			}			skb = dev_alloc_skb(pkt_len+3);			if (skb == NULL) {				printk("%s: Memory squeeze, dropping packet (len %d).\n",					   dev->name, pkt_len);				/* Prime the FIFO and then flush the packet. */				inw(ioaddr + DATAPORT); inw(ioaddr + DATAPORT);				outb(0x05, ioaddr + 14);				lp->stats.rx_dropped++;				break;			}			skb->dev = dev;			skb_reserve(skb,2);			insw(ioaddr + DATAPORT, skb_put(skb,pkt_len), (pkt_len + 1) >> 1);			skb->protocol=eth_type_trans(skb, dev);			netif_rx(skb);			lp->stats.rx_packets++;		}		if (--boguscount <= 0)			break;	}	/* If any worth-while packets have been received, dev_rint()	   has done a mark_bh(NET_BH) for us and will work on them	   when we get to the bottom-half routine. */	{		int i;		for (i = 0; i < 20; i++) {			if ((inb(ioaddr + RX_MODE) & 0x40) == 0x40)				break;			inw(ioaddr + DATAPORT);				/* dummy status read */			outb(0x05, ioaddr + 14);		}		if (net_debug > 5)			printk("%s: Exint Rx packet with mode %02x after %d ticks.\n",				   dev->name, inb(ioaddr + RX_MODE), i);	}	return;}/* The inverse routine to net_open(). */static int net_close(struct device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	int ioaddr = dev->base_addr;	dev->tbusy = 1;	dev->start = 0;	/* Set configuration register 0 to disable Tx and Rx. */	outb(0xda, ioaddr + CONFIG_0);	/* No statistic counters on the chip to update. */#if 0	/* Disable the IRQ on boards where it is feasible. */	if (lp->jumpered) {		outb(0x00, ioaddr + IOCONFIG1);		free_irq(dev->irq, dev);	}#endif	/* Power-down the chip.  Green, green, green! */	outb(0x00, ioaddr + CONFIG_1);	MOD_DEC_USE_COUNT;	return 0;}/* Get the current statistics.   This may be called with the card open or closed.   There are no on-chip counters, so this function is trivial.*/static struct enet_statistics *net_get_stats(struct device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	return &lp->stats;}/*  Set the multicast/promiscuous mode for this adaptor.*//* The little-endian AUTODIN II ethernet CRC calculation.   N.B. Do not use for bulk data, use a table-based routine instead.   This is common code and should be moved to net/core/crc.c */static unsigned const ethernet_polynomial_le = 0xedb88320U;static inline unsigned ether_crc_le(int length, unsigned char *data){	unsigned int crc = 0xffffffff;	/* Initial value. */	while(--length >= 0) {		unsigned char current_octet = *data++;		int bit;		for (bit = 8; --bit >= 0; current_octet >>= 1) {			if ((crc ^ current_octet) & 1) {				crc >>= 1;				crc ^= ethernet_polynomial_le;			} else				crc >>= 1;		}	}	return crc;}static voidset_rx_mode(struct device *dev){	int ioaddr = dev->base_addr;	struct net_local *lp = (struct net_local *)dev->priv;	unsigned char mc_filter[8];		 /* Multicast hash filter */	long flags;	int i;	if (dev->flags & IFF_PROMISC) {		/* Unconditionally log net taps. */		printk("%s: Promiscuous mode enabled.\n", dev->name);		memset(mc_filter, 0xff, sizeof(mc_filter));		outb(3, ioaddr + RX_MODE);	/* Enable promiscuous mode */	} else if (dev->mc_count > MC_FILTERBREAK			   ||  (dev->flags & IFF_ALLMULTI)) {		/* Too many to filter perfectly -- accept all multicasts. */		memset(mc_filter, 0xff, sizeof(mc_filter));		outb(2, ioaddr + RX_MODE);	/* Use normal mode. */	} else if (dev->mc_count == 0) {		memset(mc_filter, 0x00, sizeof(mc_filter));		outb(1, ioaddr + RX_MODE);	/* Ignore almost all multicasts. */	} else {		struct dev_mc_list *mclist;		int i;		memset(mc_filter, 0, sizeof(mc_filter));		for (i = 0, mclist = dev->mc_list; mclist && i < dev->mc_count;			 i++, mclist = mclist->next)			set_bit(ether_crc_le(ETH_ALEN, mclist->dmi_addr) >> 26,					mc_filter);	}	save_flags(flags);	cli();	if (memcmp(mc_filter, lp->mc_filter, sizeof(mc_filter))) {		int saved_bank = inw(ioaddr + CONFIG_0);		/* Switch to bank 1 and set the multicast table. */		outw((saved_bank & ~0x0C00) | 0x0480, ioaddr + CONFIG_0);		for (i = 0; i < 8; i++)			outb(mc_filter[i], ioaddr + 8 + i);		memcpy(lp->mc_filter, mc_filter, sizeof(mc_filter));		outw(saved_bank, ioaddr + CONFIG_0);	}	restore_flags(flags);	return;}#ifdef MODULEstatic char devicename[9] = { 0, };static struct device dev_at1700 = {	devicename, /* device name is inserted by linux/drivers/net/net_init.c */	0, 0, 0, 0,	0, 0,	0, 0, 0, NULL, at1700_probe };static int io = 0x260;static int irq = 0;int init_module(void){	if (io == 0)		printk("at1700: You should not use auto-probing with insmod!\n");	dev_at1700.base_addr = io;	dev_at1700.irq       = irq;	if (register_netdev(&dev_at1700) != 0) {		printk("at1700: register_netdev() returned non-zero.\n");		return -EIO;	}	return 0;}voidcleanup_module(void){	unregister_netdev(&dev_at1700);	kfree(dev_at1700.priv);	dev_at1700.priv = NULL;	/* If we don't do this, we can't re-insmod it later. */	free_irq(dev_at1700.irq, NULL);	release_region(dev_at1700.base_addr, AT1700_IO_EXTENT);}#endif /* MODULE *//* * Local variables: *  compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c at1700.c" *  alt-compile-command: "gcc -DMODVERSIONS -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c at1700.c" *  tab-width: 4 *  c-basic-offset: 4 *  c-indent-level: 4 * End: */

⌨️ 快捷键说明

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