?????豸???????ei_open()???????????г????豸???????????????????????????????????????????μ??

????ei_start_xmit()


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;
    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. */
  int txsr = inb(e8390_base+EN0_TSR)?? isr;
  int tickssofar = jiffies - dev->trans_start;
  if (tickssofar < TX_TIMEOUT || (tickssofar < (TX_TIMEOUT+5) && ! (txsr & ENTSR_PTX))) {
   return 1;
  }
  isr = inb(e8390_base+EN0_ISR);
  if (dev->start == 0) {
   printk("%s: xmit on stopped card "?? dev->name);
   return 1;
  }
  printk(KERN_DEBUG "%s: transmit timed out?? TX status %#2x?? ISR %#2x. "??
      dev->name?? txsr?? isr);
  /* Does the 8390 thinks it has posted an interrupt? */
  if (isr)
   printk(KERN_DEBUG "%s: Possible IRQ conflict on IRQ%d? "?? dev->name?? dev->irq);
  else {
   /* The 8390 probably hasn't gotten on the cable yet. */
   printk(KERN_DEBUG "%s: Possible network cable problem? "?? dev->name);
   if(ei_local->stat.tx_packets==0)
    ei_local->interface_num ^= 1;  /* Try a different xcvr.  */
  }
  /* Try to restart the card.  Perhaps the user has fixed something. */
  ei_reset_8390(dev);
  NS8390_init(dev?? 1);
  dev->trans_start = jiffies;
    }
   
    /* 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) {
  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 "??
  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. "??
        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. "??
        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 "??
     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;
}