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

📄 znet.c

📁 讲述linux的初始化过程
💻 C
📖 第 1 页 / 共 2 页
字号:
		*zn.tx_cur++ = length;		if (zn.tx_cur + rnd_len + 1 > zn.tx_end) {			int semi_cnt = (zn.tx_end - zn.tx_cur)<<1; /* Cvrt to byte cnt. */			memcpy(zn.tx_cur, buf, semi_cnt);			rnd_len -= semi_cnt>>1;			memcpy(zn.tx_start, buf + semi_cnt, length - semi_cnt);			zn.tx_cur = zn.tx_start + rnd_len;		} else {			memcpy(zn.tx_cur, buf, skb->len);			zn.tx_cur += rnd_len;		}		*zn.tx_cur++ = 0;		spin_lock_irqsave(&lp->lock, flags);		{			*tx_link = CMD0_TRANSMIT + CMD0_CHNL_1;			/* Is this always safe to do? */			outb(CMD0_TRANSMIT + CMD0_CHNL_1,ioaddr);		}		spin_unlock_irqrestore (&lp->lock, flags);		dev->trans_start = jiffies;		netif_start_queue (dev);		if (znet_debug > 4)		  printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length);	}	dev_kfree_skb(skb); 	return 0;}/* The ZNET interrupt handler. */static void	znet_interrupt(int irq, void *dev_id, struct pt_regs * regs){	struct net_device *dev = dev_id;	struct net_local *lp = (struct net_local *)dev->priv;	int ioaddr;	int boguscnt = 20;	if (dev == NULL) {		printk(KERN_WARNING "znet_interrupt(): IRQ %d for unknown device.\n", irq);		return;	}	spin_lock (&lp->lock);		ioaddr = dev->base_addr;	outb(CMD0_STAT0, ioaddr);	do {		ushort status = inb(ioaddr);		if (znet_debug > 5) {			ushort result, rx_ptr, running;			outb(CMD0_STAT1, ioaddr);			result = inw(ioaddr);			outb(CMD0_STAT2, ioaddr);			rx_ptr = inw(ioaddr);			outb(CMD0_STAT3, ioaddr);			running = inb(ioaddr);			printk(KERN_DEBUG "%s: interrupt, status %02x, %04x %04x %02x serial %d.\n",				 dev->name, status, result, rx_ptr, running, boguscnt);		}		if ((status & 0x80) == 0)			break;		if ((status & 0x0F) == 4) {	/* Transmit done. */			int tx_status;			outb(CMD0_STAT1, ioaddr);			tx_status = inw(ioaddr);			/* It's undocumented, but tx_status seems to match the i82586. */			if (tx_status & 0x2000) {				lp->stats.tx_packets++;				lp->stats.collisions += tx_status & 0xf;			} else {				if (tx_status & 0x0600)  lp->stats.tx_carrier_errors++;				if (tx_status & 0x0100)  lp->stats.tx_fifo_errors++;				if (!(tx_status & 0x0040)) lp->stats.tx_heartbeat_errors++;				if (tx_status & 0x0020)  lp->stats.tx_aborted_errors++;				/* ...and the catch-all. */				if ((tx_status | 0x0760) != 0x0760)				  lp->stats.tx_errors++;			}			netif_wake_queue (dev);		}		if ((status & 0x40)			|| (status & 0x0f) == 11) {			znet_rx(dev);		}		/* Clear the interrupts we've handled. */		outb(CMD0_ACK,ioaddr);	} while (boguscnt--);	spin_unlock (&lp->lock);		return;}static void znet_rx(struct net_device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	int ioaddr = dev->base_addr;	int boguscount = 1;	short next_frame_end_offset = 0; 		/* Offset of next frame start. */	short *cur_frame_end;	short cur_frame_end_offset;	outb(CMD0_STAT2, ioaddr);	cur_frame_end_offset = inw(ioaddr);	if (cur_frame_end_offset == zn.rx_cur - zn.rx_start) {		printk(KERN_WARNING "%s: Interrupted, but nothing to receive, offset %03x.\n",			   dev->name, cur_frame_end_offset);		return;	}	/* Use same method as the Crynwr driver: construct a forward list in	   the same area of the backwards links we now have.  This allows us to	   pass packets to the upper layers in the order they were received --	   important for fast-path sequential operations. */	 while (zn.rx_start + cur_frame_end_offset != zn.rx_cur			&& ++boguscount < 5) {		unsigned short hi_cnt, lo_cnt, hi_status, lo_status;		int count, status;		if (cur_frame_end_offset < 4) {			/* Oh no, we have a special case: the frame trailer wraps around			   the end of the ring buffer.  We've saved space at the end of			   the ring buffer for just this problem. */			memcpy(zn.rx_end, zn.rx_start, 8);			cur_frame_end_offset += (RX_BUF_SIZE/2);		}		cur_frame_end = zn.rx_start + cur_frame_end_offset - 4;		lo_status = *cur_frame_end++;		hi_status = *cur_frame_end++;		status = ((hi_status & 0xff) << 8) + (lo_status & 0xff);		lo_cnt = *cur_frame_end++;		hi_cnt = *cur_frame_end++;		count = ((hi_cnt & 0xff) << 8) + (lo_cnt & 0xff);		if (znet_debug > 5)		  printk(KERN_DEBUG "Constructing trailer at location %03x, %04x %04x %04x %04x"				 " count %#x status %04x.\n",				 cur_frame_end_offset<<1, lo_status, hi_status, lo_cnt, hi_cnt,				 count, status);		cur_frame_end[-4] = status;		cur_frame_end[-3] = next_frame_end_offset;		cur_frame_end[-2] = count;		next_frame_end_offset = cur_frame_end_offset;		cur_frame_end_offset -= ((count + 1)>>1) + 3;		if (cur_frame_end_offset < 0)		  cur_frame_end_offset += RX_BUF_SIZE/2;	};	/* Now step  forward through the list. */	do {		ushort *this_rfp_ptr = zn.rx_start + next_frame_end_offset;		int status = this_rfp_ptr[-4];		int pkt_len = this_rfp_ptr[-2];	  		if (znet_debug > 5)		  printk(KERN_DEBUG "Looking at trailer ending at %04x status %04x length %03x"				 " next %04x.\n", next_frame_end_offset<<1, status, pkt_len,				 this_rfp_ptr[-3]<<1);		/* Once again we must assume that the i82586 docs apply. */		if ( ! (status & 0x2000)) {				/* There was an error. */			lp->stats.rx_errors++;			if (status & 0x0800) lp->stats.rx_crc_errors++;			if (status & 0x0400) lp->stats.rx_frame_errors++;			if (status & 0x0200) lp->stats.rx_over_errors++; /* Wrong. */			if (status & 0x0100) lp->stats.rx_fifo_errors++;			if (status & 0x0080) lp->stats.rx_length_errors++;		} else if (pkt_len > 1536) {			lp->stats.rx_length_errors++;		} else {			/* Malloc up new buffer. */			struct sk_buff *skb;			skb = dev_alloc_skb(pkt_len);			if (skb == NULL) {				if (znet_debug)				  printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name);				lp->stats.rx_dropped++;				break;			}			skb->dev = dev;			if (&zn.rx_cur[(pkt_len+1)>>1] > zn.rx_end) {				int semi_cnt = (zn.rx_end - zn.rx_cur)<<1;				memcpy(skb_put(skb,semi_cnt), zn.rx_cur, semi_cnt);				memcpy(skb_put(skb,pkt_len-semi_cnt), zn.rx_start,					   pkt_len - semi_cnt);			} else {				memcpy(skb_put(skb,pkt_len), zn.rx_cur, pkt_len);				if (znet_debug > 6) {					unsigned int *packet = (unsigned int *) skb->data;					printk(KERN_DEBUG "Packet data is %08x %08x %08x %08x.\n", packet[0],						   packet[1], packet[2], packet[3]);				}		  }		  skb->protocol=eth_type_trans(skb,dev);		  netif_rx(skb);		  lp->stats.rx_packets++;		}		zn.rx_cur = this_rfp_ptr;		if (zn.rx_cur >= zn.rx_end)			zn.rx_cur -= RX_BUF_SIZE/2;		update_stop_hit(ioaddr, (zn.rx_cur - zn.rx_start)<<1);		next_frame_end_offset = this_rfp_ptr[-3];		if (next_frame_end_offset == 0)		/* Read all the frames? */			break;			/* Done for now */		this_rfp_ptr = zn.rx_start + next_frame_end_offset;	} while (--boguscount);	/* If any worth-while packets have been received, dev_rint()	   has done a mark_bh(INET_BH) for us and will work on them	   when we get to the bottom-half routine. */	return;}/* The inverse routine to znet_open(). */static int znet_close(struct net_device *dev){	unsigned long flags;	int ioaddr = dev->base_addr;	netif_stop_queue (dev);	outb(CMD0_RESET, ioaddr);			/* CMD0_RESET */	flags=claim_dma_lock();	disable_dma(zn.rx_dma);	disable_dma(zn.tx_dma);	release_dma_lock(flags);	free_irq(dev->irq, dev);	if (znet_debug > 1)		printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name);	/* Turn off transceiver power. */	outb(0x10, 0xe6);					/* Select LAN control register */	outb(inb(0xe7) & ~0x84, 0xe7);		/* Turn on LAN power (bit 2). */	return 0;}/* Get the current statistics.	This may be called with the card open or   closed. */static struct net_device_stats *net_get_stats(struct net_device *dev){		struct net_local *lp = (struct net_local *)dev->priv;		return &lp->stats;}/* Set or clear the multicast filter for this adaptor.   As a side effect this routine must also initialize the device parameters.   This is taken advantage of in open().   N.B. that we change i593_init[] in place.  This (properly) makes the   mode change persistent, but must be changed if this code is moved to   a multiple adaptor environment. */static void set_multicast_list(struct net_device *dev){	short ioaddr = dev->base_addr;	if (dev->flags&IFF_PROMISC) {		/* Enable promiscuous mode */		i593_init[7] &= ~3;		i593_init[7] |= 1;		i593_init[13] &= ~8;	i593_init[13] |= 8;	} else if (dev->mc_list || (dev->flags&IFF_ALLMULTI)) {		/* Enable accept-all-multicast mode */		i593_init[7] &= ~3;		i593_init[7] |= 0;		i593_init[13] &= ~8;	i593_init[13] |= 8;	} else {					/* Enable normal mode. */		i593_init[7] &= ~3;		i593_init[7] |= 0;		i593_init[13] &= ~8;	i593_init[13] |= 0;	}	*zn.tx_cur++ = sizeof(i593_init);	memcpy(zn.tx_cur, i593_init, sizeof(i593_init));	zn.tx_cur += sizeof(i593_init)/2;	outb(CMD0_CONFIGURE+CMD0_CHNL_1, ioaddr);#ifdef not_tested	if (num_addrs > 0) {		int addrs_len = 6*num_addrs;		*zn.tx_cur++ = addrs_len;		memcpy(zn.tx_cur, addrs, addrs_len);		outb(CMD0_MULTICAST_LIST+CMD0_CHNL_1, ioaddr);		zn.tx_cur += addrs_len>>1;	}#endif}void show_dma(void){	unsigned long flags;	short dma_port = ((zn.tx_dma&3)<<2) + IO_DMA2_BASE;	unsigned addr = inb(dma_port);	addr |= inb(dma_port) << 8;	flags=claim_dma_lock();	printk("Addr: %04x cnt:%3x...", addr<<1, get_dma_residue(zn.tx_dma));	release_dma_lock(flags);}/* Initialize the hardware.  We have to do this when the board is open()ed   or when we come out of suspend mode. */static void hardware_init(struct net_device *dev){	unsigned long flags;	short ioaddr = dev->base_addr;	zn.rx_cur = zn.rx_start;	zn.tx_cur = zn.tx_start;	/* Reset the chip, and start it up. */	outb(CMD0_RESET, ioaddr);	flags=claim_dma_lock();	disable_dma(zn.rx_dma); 		/* reset by an interrupting task. */	clear_dma_ff(zn.rx_dma);	set_dma_mode(zn.rx_dma, DMA_RX_MODE);	set_dma_addr(zn.rx_dma, (unsigned int) zn.rx_start);	set_dma_count(zn.rx_dma, RX_BUF_SIZE);	enable_dma(zn.rx_dma);	/* Now set up the Tx channel. */	disable_dma(zn.tx_dma);	clear_dma_ff(zn.tx_dma);	set_dma_mode(zn.tx_dma, DMA_TX_MODE);	set_dma_addr(zn.tx_dma, (unsigned int) zn.tx_start);	set_dma_count(zn.tx_dma, zn.tx_buf_len<<1);	enable_dma(zn.tx_dma);	release_dma_lock(flags);		if (znet_debug > 1)	  printk(KERN_DEBUG "%s: Initializing the i82593, tx buf %p... ", dev->name,			 zn.tx_start);	/* Do an empty configure command, just like the Crynwr driver.  This	   resets to chip to its default values. */	*zn.tx_cur++ = 0;	*zn.tx_cur++ = 0;	printk("stat:%02x ", inb(ioaddr)); show_dma();	outb(CMD0_CONFIGURE+CMD0_CHNL_1, ioaddr);	*zn.tx_cur++ = sizeof(i593_init);	memcpy(zn.tx_cur, i593_init, sizeof(i593_init));	zn.tx_cur += sizeof(i593_init)/2;	printk("stat:%02x ", inb(ioaddr)); show_dma();	outb(CMD0_CONFIGURE+CMD0_CHNL_1, ioaddr);	*zn.tx_cur++ = 6;	memcpy(zn.tx_cur, dev->dev_addr, 6);	zn.tx_cur += 3;	printk("stat:%02x ", inb(ioaddr)); show_dma();	outb(CMD0_IA_SETUP + CMD0_CHNL_1, ioaddr);	printk("stat:%02x ", inb(ioaddr)); show_dma();	update_stop_hit(ioaddr, 8192);	if (znet_debug > 1)  printk("enabling Rx.\n");	outb(CMD0_Rx_ENABLE+CMD0_CHNL_0, ioaddr);	netif_start_queue (dev);}static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset){	outb(CMD0_PORT_1, ioaddr);	if (znet_debug > 5)	  printk(KERN_DEBUG "Updating stop hit with value %02x.\n",			 (rx_stop_offset >> 6) | 0x80);	outb((rx_stop_offset >> 6) | 0x80, ioaddr);	outb(CMD1_PORT_0, ioaddr);}/* * Local variables: *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c znet.c" *  version-control: t *  kept-new-versions: 5 *  c-indent-level: 4 *  tab-width: 4 * End: */

⌨️ 快捷键说明

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