static int ei_start_xmit(struct sk_buff *skb, struct device *dev) { int e8390_base = dev->base_addr; struct ei_device *ei_local = (struct ei_device *) dev->priv;//取出网卡设备的私有数据,和具体的网卡型号有关,在ethdev_init()函数中已经分配空间 int length, send_length; unsigned long flags; /* * We normally shouldn't be called if dev->tbusy is set, but the * existing code does anyway. If it has been too long since the * last Tx, we assume the board has died and kick it. */ if (dev->tbusy) { /* Do timeouts, just like the 8003 driver. */ ........................................ ........................................ } /* Sending a NULL skb means some higher layer thinks we've missed an tx-done interrupt. Caution: dev_tint() handles the cli()/sti() itself. */ if (skb == NULL) {//该条件似乎不会发生,这用于处理内核中的BUG dev_tint(dev);//发送设备中的所有缓存的数据包 return 0; } length = skb->len; if (skb->len <= 0) return 0; save_flags(flags); cli(); /* Block a timer-based transmit from overlapping. */ if ((set_bit(0, (void*)&dev->tbusy) != 0) || ei_local->irqlock) { printk("%s: Tx access conflict. irq=%d lock=%d tx1=%d tx2=%d last=%d\n", dev->name, dev->interrupt, ei_local->irqlock, ei_local->tx1, ei_local->tx2, ei_local->lasttx); restore_flags(flags); return 1; } /* Mask interrupts from the ethercard. */ outb(0x00, e8390_base + EN0_IMR); ei_local->irqlock = 1; restore_flags(flags); send_length = ETH_ZLEN < length ? length : ETH_ZLEN; if (ei_local->pingpong) { int output_page; if (ei_local->tx1 == 0) { output_page = ei_local->tx_start_page; ei_local->tx1 = send_length; if (ei_debug && ei_local->tx2 > 0) printk("%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n", dev->name, ei_local->tx2, ei_local->lasttx, ei_local->txing); } else if (ei_local->tx2 == 0) { output_page = ei_local->tx_start_page + 6; ei_local->tx2 = send_length; if (ei_debug && ei_local->tx1 > 0) printk("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n", dev->name, ei_local->tx1, ei_local->lasttx, ei_local->txing); } else { /* We should never get here. */ if (ei_debug) printk("%s: No Tx buffers free. irq=%d tx1=%d tx2=%d last=%d\n", dev->name, dev->interrupt, ei_local->tx1, ei_local->tx2, ei_local->lasttx); ei_local->irqlock = 0; dev->tbusy = 1; outb_p(ENISR_ALL, e8390_base + EN0_IMR); return 1; } ei_block_output(dev, length, skb->data, output_page); if (! ei_local->txing) { ei_local->txing = 1; NS8390_trigger_send(dev, send_length, output_page); dev->trans_start = jiffies; if (output_page == ei_local->tx_start_page) ei_local->tx1 = -1, ei_local->lasttx = -1; else ei_local->tx2 = -1, ei_local->lasttx = -2; } else ei_local->txqueue++; dev->tbusy = (ei_local->tx1 && ei_local->tx2); } else { /* No pingpong, just a single Tx buffer. */ ei_block_output(dev, length, skb->data, ei_local->tx_start_page); ei_local->txing = 1; NS8390_trigger_send(dev, send_length, ei_local->tx_start_page); dev->trans_start = jiffies; dev->tbusy = 1; } /* Turn 8390 interrupts back on. */ ei_local->irqlock = 0; outb_p(ENISR_ALL, e8390_base + EN0_IMR); dev_kfree_skb (skb, FREE_WRITE); return 0; |