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

📄 3c507.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	int ioaddr = dev->base_addr;	unsigned long shmem = dev->mem_start;	if (net_debug > 1)		printk ("%s: transmit timed out, %s?  ", dev->name,			isa_readw (shmem + iSCB_STATUS) & 0x8000 ? "IRQ conflict" :			"network cable problem");	/* Try to restart the adaptor. */	if (lp->last_restart == lp->stats.tx_packets) {		if (net_debug > 1)			printk ("Resetting board.\n");		/* Completely reset the adaptor. */		init_82586_mem (dev);	} else {		/* Issue the channel attention signal and hope it "gets better". */		if (net_debug > 1)			printk ("Kicking board.\n");		isa_writew (0xf000 | CUC_START | RX_START, shmem + iSCB_CMD);		outb (0, ioaddr + SIGNAL_CA);	/* Issue channel-attn. */		lp->last_restart = lp->stats.tx_packets;	}	dev->trans_start = jiffies;	netif_wake_queue (dev);}static int el16_send_packet (struct sk_buff *skb, struct net_device *dev){	struct net_local *lp = (struct net_local *) dev->priv;	int ioaddr = dev->base_addr;	unsigned long flags;	short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;	unsigned char *buf = skb->data;	netif_stop_queue (dev);	spin_lock_irqsave (&lp->lock, flags);	lp->stats.tx_bytes += length;	/* Disable the 82586's input to the interrupt line. */	outb (0x80, ioaddr + MISC_CTRL);	hardware_send_packet (dev, buf, length);	dev->trans_start = jiffies;	/* Enable the 82586 interrupt input. */	outb (0x84, ioaddr + MISC_CTRL);	spin_unlock_irqrestore (&lp->lock, flags);	dev_kfree_skb (skb);	/* You might need to clean up and record Tx statistics here. */	return 0;}/*	The typical workload of the driver:	Handle the network interface interrupts. */static void el16_interrupt(int irq, void *dev_id, struct pt_regs *regs){	struct net_device *dev = dev_id;	struct net_local *lp;	int ioaddr, status, boguscount = 0;	ushort ack_cmd = 0;	unsigned long shmem;	if (dev == NULL) {		printk ("net_interrupt(): irq %d for unknown device.\n", irq);		return;	}	ioaddr = dev->base_addr;	lp = (struct net_local *)dev->priv;	shmem = dev->mem_start;	spin_lock(&lp->lock);	status = isa_readw(shmem+iSCB_STATUS);	if (net_debug > 4) {		printk("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status);	}	/* Disable the 82586's input to the interrupt line. */	outb(0x80, ioaddr + MISC_CTRL);	/* Reap the Tx packet buffers. */	while (lp->tx_reap != lp->tx_head) {	  unsigned short tx_status = isa_readw(shmem+lp->tx_reap);	  if (tx_status == 0) {		if (net_debug > 5)  printk("Couldn't reap %#x.\n", lp->tx_reap);		break;	  }	  if (tx_status & 0x2000) {		lp->stats.tx_packets++;		lp->stats.collisions += tx_status & 0xf;		netif_wake_queue(dev);	  } else {		lp->stats.tx_errors++;		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++;	  }	  if (net_debug > 5)		  printk("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status);	  lp->tx_reap += TX_BUF_SIZE;	  if (lp->tx_reap > RX_BUF_START - TX_BUF_SIZE)		lp->tx_reap = TX_BUF_START;	  if (++boguscount > 4)		break;	}	if (status & 0x4000) { /* Packet received. */		if (net_debug > 5)			printk("Received packet, rx_head %04x.\n", lp->rx_head);		el16_rx(dev);	}	/* Acknowledge the interrupt sources. */	ack_cmd = status & 0xf000;	if ((status & 0x0700) != 0x0200 && netif_running(dev)) {		if (net_debug)			printk("%s: Command unit stopped, status %04x, restarting.\n",				   dev->name, status);		/* If this ever occurs we should really re-write the idle loop, reset		   the Tx list, and do a complete restart of the command unit.		   For now we rely on the Tx timeout if the resume doesn't work. */		ack_cmd |= CUC_RESUME;	}	if ((status & 0x0070) != 0x0040 && netif_running(dev)) {		static void init_rx_bufs(struct net_device *);		/* The Rx unit is not ready, it must be hung.  Restart the receiver by		   initializing the rx buffers, and issuing an Rx start command. */		if (net_debug)			printk("%s: Rx unit stopped, status %04x, restarting.\n",				   dev->name, status);		init_rx_bufs(dev);		isa_writew(RX_BUF_START,shmem+iSCB_RFA);		ack_cmd |= RX_START;	}	isa_writew(ack_cmd,shmem+iSCB_CMD);	outb(0, ioaddr + SIGNAL_CA);			/* Issue channel-attn. */	/* Clear the latched interrupt. */	outb(0, ioaddr + RESET_IRQ);	/* Enable the 82586's interrupt input. */	outb(0x84, ioaddr + MISC_CTRL);	spin_unlock(&lp->lock);}static int el16_close(struct net_device *dev){	int ioaddr = dev->base_addr;	unsigned long shmem = dev->mem_start;	netif_stop_queue(dev);	/* Flush the Tx and disable Rx. */	isa_writew(RX_SUSPEND | CUC_SUSPEND,shmem+iSCB_CMD);	outb(0, ioaddr + SIGNAL_CA);	/* Disable the 82586's input to the interrupt line. */	outb(0x80, ioaddr + MISC_CTRL);	/* We always physically use the IRQ line, so we don't do free_irq(). */	/* Update the statistics here. */	return 0;}/* Get the current statistics.	This may be called with the card open or   closed. */static struct net_device_stats *el16_get_stats(struct net_device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	/* ToDo: decide if there are any useful statistics from the SCB. */	return &lp->stats;}/* Initialize the Rx-block list. */static void init_rx_bufs(struct net_device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	unsigned long write_ptr;	unsigned short SCB_base = SCB_BASE;	int cur_rxbuf = lp->rx_head = RX_BUF_START;	/* Initialize each Rx frame + data buffer. */	do {	/* While there is room for one more. */	  write_ptr = dev->mem_start + cur_rxbuf;		isa_writew(0x0000,write_ptr);			/* Status */		isa_writew(0x0000,write_ptr+=2);			/* Command */		isa_writew(cur_rxbuf + RX_BUF_SIZE,write_ptr+=2);	/* Link */		isa_writew(cur_rxbuf + 22,write_ptr+=2);		/* Buffer offset */		isa_writew(0x0000,write_ptr+=2);			/* Pad for dest addr. */		isa_writew(0x0000,write_ptr+=2);		isa_writew(0x0000,write_ptr+=2);		isa_writew(0x0000,write_ptr+=2);			/* Pad for source addr. */		isa_writew(0x0000,write_ptr+=2);		isa_writew(0x0000,write_ptr+=2);		isa_writew(0x0000,write_ptr+=2);			/* Pad for protocol. */		isa_writew(0x0000,write_ptr+=2);			/* Buffer: Actual count */		isa_writew(-1,write_ptr+=2);			/* Buffer: Next (none). */		isa_writew(cur_rxbuf + 0x20 + SCB_base,write_ptr+=2);/* Buffer: Address low */		isa_writew(0x0000,write_ptr+=2);		/* Finally, the number of bytes in the buffer. */		isa_writew(0x8000 + RX_BUF_SIZE-0x20,write_ptr+=2);		lp->rx_tail = cur_rxbuf;		cur_rxbuf += RX_BUF_SIZE;	} while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE);	/* Terminate the list by setting the EOL bit, and wrap the pointer to make	   the list a ring. */	write_ptr = dev->mem_start + lp->rx_tail + 2;	isa_writew(0xC000,write_ptr);				/* Command, mark as last. */	isa_writew(lp->rx_head,write_ptr+2);			/* Link */}static void init_82586_mem(struct net_device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	short ioaddr = dev->base_addr;	unsigned long shmem = dev->mem_start;	/* Enable loopback to protect the wire while starting up,	   and hold the 586 in reset during the memory initialization. */	outb(0x20, ioaddr + MISC_CTRL);	/* Fix the ISCP address and base. */	init_words[3] = SCB_BASE;	init_words[7] = SCB_BASE;	/* Write the words at 0xfff6 (address-aliased to 0xfffff6). */	isa_memcpy_toio(dev->mem_end-10, init_words, 10);	/* Write the words at 0x0000. */	isa_memcpy_toio(dev->mem_start, init_words + 5, sizeof(init_words) - 10);	/* Fill in the station address. */	isa_memcpy_toio(dev->mem_start+SA_OFFSET, dev->dev_addr,		   sizeof(dev->dev_addr));	/* The Tx-block list is written as needed.  We just set up the values. */	lp->tx_cmd_link = IDLELOOP + 4;	lp->tx_head = lp->tx_reap = TX_BUF_START;	init_rx_bufs(dev);	/* Start the 586 by releasing the reset line, but leave loopback. */	outb(0xA0, ioaddr + MISC_CTRL);	/* This was time consuming to track down: you need to give two channel	   attention signals to reliably start up the i82586. */	outb(0, ioaddr + SIGNAL_CA);	{		int boguscnt = 50;		while (isa_readw(shmem+iSCB_STATUS) == 0)			if (--boguscnt == 0) {				printk("%s: i82586 initialization timed out with status %04x,"					   "cmd %04x.\n", dev->name,					   isa_readw(shmem+iSCB_STATUS), isa_readw(shmem+iSCB_CMD));				break;			}		/* Issue channel-attn -- the 82586 won't start. */		outb(0, ioaddr + SIGNAL_CA);	}	/* Disable loopback and enable interrupts. */	outb(0x84, ioaddr + MISC_CTRL);	if (net_debug > 4)		printk("%s: Initialized 82586, status %04x.\n", dev->name,			   isa_readw(shmem+iSCB_STATUS));	return;}static void hardware_send_packet(struct net_device *dev, void *buf, short length){	struct net_local *lp = (struct net_local *)dev->priv;	short ioaddr = dev->base_addr;	ushort tx_block = lp->tx_head;	unsigned long write_ptr = dev->mem_start + tx_block;	/* Set the write pointer to the Tx block, and put out the header. */	isa_writew(0x0000,write_ptr);			/* Tx status */	isa_writew(CMD_INTR|CmdTx,write_ptr+=2);		/* Tx command */	isa_writew(tx_block+16,write_ptr+=2);		/* Next command is a NoOp. */	isa_writew(tx_block+8,write_ptr+=2);			/* Data Buffer offset. */	/* Output the data buffer descriptor. */	isa_writew(length | 0x8000,write_ptr+=2);		/* Byte count parameter. */	isa_writew(-1,write_ptr+=2);			/* No next data buffer. */	isa_writew(tx_block+22+SCB_BASE,write_ptr+=2);	/* Buffer follows the NoOp command. */	isa_writew(0x0000,write_ptr+=2);			/* Buffer address high bits (always zero). */	/* Output the Loop-back NoOp command. */	isa_writew(0x0000,write_ptr+=2);			/* Tx status */	isa_writew(CmdNOp,write_ptr+=2);			/* Tx command */	isa_writew(tx_block+16,write_ptr+=2);		/* Next is myself. */	/* Output the packet at the write pointer. */	isa_memcpy_toio(write_ptr+2, buf, length);	/* Set the old command link pointing to this send packet. */	isa_writew(tx_block,dev->mem_start + lp->tx_cmd_link);	lp->tx_cmd_link = tx_block + 20;	/* Set the next free tx region. */	lp->tx_head = tx_block + TX_BUF_SIZE;	if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE)		lp->tx_head = TX_BUF_START;	if (net_debug > 4) {		printk("%s: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n",			   dev->name, ioaddr, length, tx_block, lp->tx_head);	}	if (lp->tx_head != lp->tx_reap)		netif_wake_queue(dev);}static void el16_rx(struct net_device *dev){	struct net_local *lp = (struct net_local *)dev->priv;	unsigned long shmem = dev->mem_start;	ushort rx_head = lp->rx_head;	ushort rx_tail = lp->rx_tail;	ushort boguscount = 10;	short frame_status;	while ((frame_status = isa_readw(shmem+rx_head)) < 0) {   /* Command complete */		unsigned long read_frame = dev->mem_start + rx_head;		ushort rfd_cmd = isa_readw(read_frame+2);		ushort next_rx_frame = isa_readw(read_frame+4);		ushort data_buffer_addr = isa_readw(read_frame+6);		unsigned long data_frame = dev->mem_start + data_buffer_addr;		ushort pkt_len = isa_readw(data_frame);		if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22			|| (pkt_len & 0xC000) != 0xC000) {			printk("%s: Rx frame at %#x corrupted, status %04x cmd %04x"				   "next %04x data-buf @%04x %04x.\n", dev->name, rx_head,				   frame_status, rfd_cmd, next_rx_frame, data_buffer_addr,				   pkt_len);		} else if ((frame_status & 0x2000) == 0) {			/* Frame Rxed, but with error. */			lp->stats.rx_errors++;			if (frame_status & 0x0800) lp->stats.rx_crc_errors++;			if (frame_status & 0x0400) lp->stats.rx_frame_errors++;			if (frame_status & 0x0200) lp->stats.rx_fifo_errors++;			if (frame_status & 0x0100) lp->stats.rx_over_errors++;			if (frame_status & 0x0080) lp->stats.rx_length_errors++;		} else {			/* Malloc up new buffer. */			struct sk_buff *skb;			pkt_len &= 0x3fff;			skb = dev_alloc_skb(pkt_len+2);			if (skb == NULL) {				printk("%s: Memory squeeze, dropping packet.\n", dev->name);				lp->stats.rx_dropped++;				break;			}			skb_reserve(skb,2);			skb->dev = dev;			/* 'skb->data' points to the start of sk_buff data area. */			isa_memcpy_fromio(skb_put(skb,pkt_len), data_frame + 10, pkt_len);			skb->protocol=eth_type_trans(skb,dev);			netif_rx(skb);			lp->stats.rx_packets++;		}		/* Clear the status word and set End-of-List on the rx frame. */		isa_writew(0,read_frame);		isa_writew(0xC000,read_frame+2);		/* Clear the end-of-list on the prev. RFD. */		isa_writew(0x0000,dev->mem_start + rx_tail + 2);		rx_tail = rx_head;		rx_head = next_rx_frame;		if (--boguscount == 0)			break;	}	lp->rx_head = rx_head;	lp->rx_tail = rx_tail;}#ifdef MODULEstatic struct net_device dev_3c507;static int io = 0x300;static int irq = 0;MODULE_PARM(io, "i");MODULE_PARM(irq, "i");int init_module(void){	if (io == 0)		printk("3c507: You should not use auto-probing with insmod!\n");	dev_3c507.base_addr = io;	dev_3c507.irq       = irq;	dev_3c507.init	    = el16_probe;	if (register_netdev(&dev_3c507) != 0) {		printk("3c507: register_netdev() returned non-zero.\n");		return -EIO;	}	return 0;}voidcleanup_module(void){	unregister_netdev(&dev_3c507);	kfree(dev_3c507.priv);	dev_3c507.priv = NULL;	/* If we don't do this, we can't re-insmod it later. */	free_irq(dev_3c507.irq, &dev_3c507);	release_region(dev_3c507.base_addr, EL16_IO_EXTENT);}#endif /* MODULE *//* * Local variables: *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -I/usr/src/linux/drivers/net -Wall -Wstrict-prototypes -O6 -m486 -c 3c507.c" *  version-control: t *  kept-new-versions: 5 *  tab-width: 4 *  c-indent-level: 4 * End: */

⌨️ 快捷键说明

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