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

📄 lance.c

📁 LINUX1.0内核源代码,学习LINUX编程的一定要看。
💻 C
📖 第 1 页 / 共 2 页
字号:
    if (lance_debug > 2)	printk("%s: LANCE open after %d ticks, init block %#x csr0 %4.4x.\n",	       dev->name, i, (int) &lp->init_block, inw(ioaddr+LANCE_DATA));    return 0;			/* Always succeed */}/* Initialize the LANCE Rx and Tx rings. */static voidlance_init_ring(struct device *dev){    struct lance_private *lp = (struct lance_private *)dev->priv;    int i;    lp->cur_rx = lp->cur_tx = 0;    lp->dirty_rx = lp->dirty_tx = 0;    for (i = 0; i < RX_RING_SIZE; i++) {	lp->rx_ring[i].base = (lp->rx_buffs + i*PKT_BUF_SZ) | 0x80000000;	lp->rx_ring[i].buf_length = -PKT_BUF_SZ;    }    /* The Tx buffer address is filled in as needed, but we do need to clear       the upper ownership bit. */    for (i = 0; i < TX_RING_SIZE; i++) {	lp->tx_ring[i].base = 0;    }    lp->init_block.mode = 0x0000;    for (i = 0; i < 6; i++)	lp->init_block.phys_addr[i] = dev->dev_addr[i];    lp->init_block.filter[0] = 0x00000000;    lp->init_block.filter[1] = 0x00000000;    lp->init_block.rx_ring = (int)lp->rx_ring | RX_RING_LEN_BITS;    lp->init_block.tx_ring = (int)lp->tx_ring | TX_RING_LEN_BITS;}static intlance_start_xmit(struct sk_buff *skb, struct device *dev){    struct lance_private *lp = (struct lance_private *)dev->priv;    int ioaddr = dev->base_addr;    int entry;    /* Transmitter timeout, serious problems. */    if (dev->tbusy) {	int tickssofar = jiffies - dev->trans_start;	if (tickssofar < 10)	    return 1;	outw(0, ioaddr+LANCE_ADDR);	printk("%s: transmit timed out, status %4.4x, resetting.\n",	       dev->name, inw(ioaddr+LANCE_DATA));	outw(0x0001, ioaddr+LANCE_DATA);	lp->stats.tx_errors++;#ifndef final_version	{	    int i;	    printk(" Ring data dump: dirty_tx %d cur_tx %d cur_rx %d.",		   lp->dirty_tx, lp->cur_tx, lp->cur_rx);	    for (i = 0 ; i < RX_RING_SIZE; i++)		printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ",		       lp->rx_ring[i].base, -lp->rx_ring[i].buf_length,		       lp->rx_ring[i].msg_length);	    for (i = 0 ; i < TX_RING_SIZE; i++)		printk(" %s%08x %04x %04x", i & 0x3 ? "" : "\n ",		       lp->tx_ring[i].base, -lp->tx_ring[i].length,		       lp->tx_ring[i].misc);	    printk("\n");	}#endif	lance_init_ring(dev);	outw(0x0043, ioaddr+LANCE_DATA);	dev->tbusy=0;	dev->trans_start = jiffies;	return 0;    }    if (skb == NULL) {	dev_tint(dev);	return 0;    }    /* Fill in the ethernet header. */    if (!skb->arp  &&  dev->rebuild_header(skb->data, dev)) {	skb->dev = dev;	arp_queue (skb);	return 0;    }    skb->arp=1;    if (skb->len <= 0)	return 0;    if (lance_debug > 3) {	outw(0x0000, ioaddr+LANCE_ADDR);	printk("%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name,	       inw(ioaddr+LANCE_DATA));	outw(0x0000, ioaddr+LANCE_DATA);    }    /* 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);    /* Fill in a Tx ring entry */    /* Mask to ring buffer boundary. */    entry = lp->cur_tx & TX_RING_MOD_MASK;    /* Caution: the write order is important here, set the base address       with the "ownership" bits last. */    /* The old LANCE chips doesn't automatically pad buffers to min. size. */    if (lp->old_lance) {	lp->tx_ring[entry].length =	    -(ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN);    } else	lp->tx_ring[entry].length = -skb->len;    lp->tx_ring[entry].misc = 0x0000;    /* If any part of this buffer is >16M we must copy it to a low-memory       buffer. */    if ((int)(skb->data) + skb->len > 0x01000000) {	if (lance_debug > 5)	    printk("%s: bouncing a high-memory packet (%#x).\n",		   dev->name, (int)(skb->data));	memcpy(&lp->tx_bounce_buffs[entry], skb->data, skb->len);	lp->tx_ring[entry].base =	    (int)(lp->tx_bounce_buffs + entry) | 0x83000000;	if (skb->free)	    kfree_skb (skb, FREE_WRITE);    } else {    	/* We can't free the packet yet, so we inform the memory management	   code that we are still using it. */    	if(skb->free==0)    		skb_kept_by_device(skb);	lp->tx_ring[entry].base = (int)(skb->data) | 0x83000000;    }    lp->cur_tx++;    /* Trigger an immediate send poll. */    outw(0x0000, ioaddr+LANCE_ADDR);    outw(0x0048, ioaddr+LANCE_DATA);    dev->trans_start = jiffies;    if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0)	dev->tbusy=0;    return 0;}/* The LANCE interrupt handler. */static voidlance_interrupt(int reg_ptr){    int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);    struct device *dev = (struct device *)(irq2dev_map[irq]);    struct lance_private *lp;    int csr0, ioaddr;    if (dev == NULL) {	printk ("lance_interrupt(): irq %d for unknown device.\n", irq);	return;    }    ioaddr = dev->base_addr;    lp = (struct lance_private *)dev->priv;    if (dev->interrupt)	printk("%s: Re-entering the interrupt handler.\n", dev->name);    dev->interrupt = 1;    outw(0x00, dev->base_addr + LANCE_ADDR);    csr0 = inw(dev->base_addr + LANCE_DATA);    /* Acknowledge all of the current interrupt sources ASAP. */    outw(csr0 & ~0x004f, dev->base_addr + LANCE_DATA);    if (lance_debug > 5)	printk("%s: interrupt  csr0=%#2.2x new csr=%#2.2x.\n",	       dev->name, csr0, inw(dev->base_addr + LANCE_DATA));    if (csr0 & 0x0400)		/* Rx interrupt */	lance_rx(dev);    if (csr0 & 0x0200) {	/* Tx-done interrupt */	int dirty_tx = lp->dirty_tx;	while (dirty_tx < lp->cur_tx) {	    int entry = dirty_tx & TX_RING_MOD_MASK;	    int status = lp->tx_ring[entry].base;	    void *databuff;	    	    if (status < 0)		break;		/* It still hasn't been Txed */	    lp->tx_ring[entry].base = 0;	    databuff = (void*)(status & 0x00ffffff);	    if (status & 0x40000000) { /* There was an major error, log it. */		int err_status = lp->tx_ring[entry].misc;		lp->stats.tx_errors++;		if (err_status & 0x0400) lp->stats.tx_aborted_errors++;		if (err_status & 0x0800) lp->stats.tx_carrier_errors++;		if (err_status & 0x1000) lp->stats.tx_window_errors++;		if (err_status & 0x4000) lp->stats.tx_fifo_errors++;		/* Perhaps we should re-init() after the FIFO error. */	    } else {		if (status & 0x18000000)		    lp->stats.collisions++;		lp->stats.tx_packets++;	    }	    /* We don't free the skb if it's a data-only copy in the bounce	       buffer.  The address checks here are sorted -- the first test	       should always work.  */	    if (databuff >= (void*)(&lp->tx_bounce_buffs[TX_RING_SIZE])		|| databuff < (void*)(lp->tx_bounce_buffs)) {		struct sk_buff *skb = ((struct sk_buff *)databuff) - 1;		if (skb->free)		    kfree_skb(skb, FREE_WRITE);		else		    skb_device_release(skb,FREE_WRITE);		/* Warning: skb may well vanish at the point you call		   device_release! */	    }	    dirty_tx++;	}#ifndef final_version	if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) {	    printk("out-of-sync dirty pointer, %d vs. %d.\n",		   dirty_tx, lp->cur_tx);	    dirty_tx += TX_RING_SIZE;	}#endif	if (dev->tbusy  &&  dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) {	    /* The ring is no longer full, clear tbusy. */	    dev->tbusy = 0;	    mark_bh(INET_BH);	}	lp->dirty_tx = dirty_tx;    }    if (csr0 & 0x8000) {	if (csr0 & 0x4000) lp->stats.tx_errors++;	if (csr0 & 0x1000) lp->stats.rx_errors++;    }    /* Clear the interrupts we've handled. */    outw(0x0000, dev->base_addr + LANCE_ADDR);    outw(0x7f40, dev->base_addr + LANCE_DATA);    if (lance_debug > 4)	printk("%s: exiting interrupt, csr%d=%#4.4x.\n",	       dev->name, inw(ioaddr + LANCE_ADDR),	       inw(dev->base_addr + LANCE_DATA));    dev->interrupt = 0;    return;}static intlance_rx(struct device *dev){    struct lance_private *lp = (struct lance_private *)dev->priv;    int entry = lp->cur_rx & RX_RING_MOD_MASK;	    /* If we own the next entry, it's a new packet. Send it up. */    while (lp->rx_ring[entry].base >= 0) {	int status = lp->rx_ring[entry].base >> 24;	if (status != 0x03) {		/* There was an error. */	    /* There is an tricky error noted by John Murphy,	       <murf@perftech.com> to Russ Nelson: Even with full-sized	       buffers it's possible for a jabber packet to use two	       buffers, with only the last correctly noting the error. */	    if (status & 0x01)	/* Only count a general error at the */		lp->stats.rx_errors++; /* end of a packet.*/	    if (status & 0x20) lp->stats.rx_frame_errors++;	    if (status & 0x10) lp->stats.rx_over_errors++;	    if (status & 0x08) lp->stats.rx_crc_errors++;	    if (status & 0x04) lp->stats.rx_fifo_errors++;	} else {	    /* Malloc up new buffer, compatible with net-2e. */	    short pkt_len = lp->rx_ring[entry].msg_length;	    int sksize = sizeof(struct sk_buff) + pkt_len;	    struct sk_buff *skb;	    skb = alloc_skb(sksize, GFP_ATOMIC);	    if (skb == NULL) {		printk("%s: Memory squeeze, deferring packet.\n", dev->name);		lp->stats.rx_dropped++;	/* Really, deferred. */		break;	    }	    skb->mem_len = sksize;	    skb->mem_addr = skb;	    skb->len = pkt_len;	    skb->dev = dev;	    memcpy(skb->data,		   (unsigned char *)(lp->rx_ring[entry].base & 0x00ffffff),		   pkt_len);#ifdef HAVE_NETIF_RX	    netif_rx(skb);#else	    skb->lock = 0;	    if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) {		kfree_skbmem(skb, sksize);		lp->stats.rx_dropped++;		break;	    }#endif	    lp->stats.rx_packets++;	}	lp->rx_ring[entry].base |= 0x80000000;	entry = (++lp->cur_rx) & RX_RING_MOD_MASK;    }    /* We should check that at least two ring entries are free.  If not,       we should free one and mark stats->rx_dropped++. */    return 0;}static intlance_close(struct device *dev){    int ioaddr = dev->base_addr;    struct lance_private *lp = (struct lance_private *)dev->priv;    dev->start = 0;    dev->tbusy = 1;    outw(112, ioaddr+LANCE_ADDR);    lp->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);    outw(0, ioaddr+LANCE_ADDR);    if (lance_debug > 1)	printk("%s: Shutting down ethercard, status was %2.2x.\n",	       dev->name, inw(ioaddr+LANCE_DATA));    /* We stop the LANCE here -- it occasionally polls       memory if we don't. */    outw(0x0004, ioaddr+LANCE_DATA);    disable_dma(dev->dma);    free_irq(dev->irq);    free_dma(dev->dma);    irq2dev_map[dev->irq] = 0;    return 0;}static struct enet_statistics *lance_get_stats(struct device *dev){    struct lance_private *lp = (struct lance_private *)dev->priv;    short ioaddr = dev->base_addr;    short saved_addr;    cli();    saved_addr = inw(ioaddr+LANCE_ADDR);    outw(112, ioaddr+LANCE_ADDR);    lp->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA);    outw(saved_addr, ioaddr+LANCE_ADDR);    sti();    return &lp->stats;}#ifdef HAVE_MULTICAST/* Set or clear the multicast filter for this adaptor.   num_addrs == -1	Promiscuous mode, receive all packets   num_addrs == 0	Normal mode, clear multicast list   num_addrs > 0	Multicast mode, receive normal and MC packets, and do   			best-effort filtering. */static voidset_multicast_list(struct device *dev, int num_addrs, void *addrs){    short ioaddr = dev->base_addr;    /* We take the simple way out and always enable promiscuous mode. */    outw(0, ioaddr+LANCE_ADDR);    outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance.  */    outw(15, ioaddr+LANCE_ADDR);    if (num_addrs >= 0) {	short multicast_table[4];	int i;	/* We don't use the multicast table, but rely on upper-layer filtering. */	memset(multicast_table, (num_addrs == 0) ? 0 : -1, sizeof(multicast_table));	for (i = 0; i < 4; i++) {	    outw(8 + i, ioaddr+LANCE_ADDR);	    outw(multicast_table[i], ioaddr+LANCE_DATA);	}	outw(0x0000, ioaddr+LANCE_DATA); /* Unset promiscuous mode */    } else {	outw(0x8000, ioaddr+LANCE_DATA); /* Set promiscuous mode */    }    outw(0, ioaddr+LANCE_ADDR);    outw(0x0142, ioaddr+LANCE_DATA); /* Resume normal operation. */}#endif#ifdef HAVE_DEVLISTstatic unsigned int lance_portlist[] = {0x300, 0x320, 0x340, 0x360, 0};struct netdev_entry lance_drv ={"lance", lance_probe1, LANCE_TOTAL_SIZE, lance_portlist};#endif/* * Local variables: *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c lance.c" * End: */

⌨️ 快捷键说明

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