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

📄 if_8139.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 4 页
字号:
      /*
       * If a transmit FIFO underrun occurred, increment the threshold
       * value.
       */
      if ((tsd & TUN) && (rltk8139_info->tx_threshold < 64))
        rltk8139_info->tx_threshold += 1;

      /*
       * Check if a transmission completed OK. RealTek's data sheet implies
       * that a successful transmission that experiences underrun will only
       * set TUN. This is not true; TOK is set for all successful
       * transmissions.
       */
      if (tsd & TOK) {
        (sc->funs->eth_drv->tx_done)(sc, rltk8139_info->tx_desc_key[desc], 0);
      }
      else if (tsd & TABT) {
        /*
         * Set the CLRABT bit in TCR. Since I haven't encountered any
         * transmission aborts so far, I don't really know if this code
         * will work or not.
         */
        OUTL(INL(rltk8139_info->base_address + TCR) & CLRABT,
             rltk8139_info->base_address + TCR);
        (sc->funs->eth_drv->tx_done)(sc, rltk8139_info->tx_desc_key[desc], -1);
      }
      else {
        /*
         * This descriptor is not ready. Since the descriptors are used
         * in a ring, this means that no more descriptors are ready.
         */
        break;
      }

      /*
       * Clear the saved key value. This is not really necessary, since
       * the key value is never used to determine if a descriptor is
       * valid or not. However, clearing it is a tidier IMO.
       */
      rltk8139_info->tx_desc_key[desc] = 0;

      /*
       * Increment the free descriptor count and go through the loop again
       * to see if more descriptors are ready.
       */
      cyg_drv_isr_lock();
      rltk8139_info->tx_num_free_desc += 1;
      cyg_drv_isr_unlock();
    }
  }

  if (status & IR_ROK) {
    /*
     * Received a frame. Note that '_deliver' does not actually copy any
     * data; it just determines how many bytes are available and tells
     * the generic ethernet driver about it, which then calls into
     * the '_recv' function to copy the data.
     */
    cyg_uint16 rx_pos;
    cyg_uint32 header, length;

    /*
     * CAPR contains the index into the receive buffer. It is controlled
     * completely in software. For some reason, CAPR points 16 bytes
     * before the actual start of the packet.
     */
    rx_pos = (INW(rltk8139_info->base_address + CAPR) + 16) % RX_BUF_LEN;

    /*
     * Loop until the rx buffer is empty. I have no idea how the 8139
     * determines if the buffer still contains a packet; it may check
     * that CAPR points 16 bytes before CBR.
     */
    while (!(INB(rltk8139_info->base_address + CR) & BUFE)) {
      /*
       * Invalidate the data cache for the cache line containing the header
       * if necessary.
       */
#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY
      HAL_DCACHE_INVALIDATE(&rltk8139_info->rx_ring[rx_pos],
                            sizeof(cyg_uint32));
#endif

      /*
       * The 8139 prepends each packet with a 32 bit packet header that
       * contains a 16 bit length and 16 bit status field, in little-endian
       * byte order.
       */
      header = HAL_LE32TOC(*((volatile cyg_uint32 *)CYGARC_UNCACHED_ADDRESS(&rltk8139_info->rx_ring[rx_pos])));

      /*
       * If the 8139 is still copying data for this packet into the
       * receive ring, it will set packet length to 0xfff0. This shouldn't
       * ever happen because we do not use early receive.
       */
      if ((header >> 16) == 0xFFF0)
        break;

      /*
       * Since the 8139 appends the ethernet CRC to every packet, we
       * must subtract 4 from the length to get the true packet length.
       */
      length = (header >> 16) - 4;

      /*
       * Check if the packet was received correctly. The OpenBSD driver
       * resets the chip if this is not the case; we attempt to salvage
       * following packets by doing nothing.
       */
      if (!(header & HDR_ROK)) {
      }
      else {
        /*
         * Packet was received OK. Determine from where to start copying
         * bytes. This is saved in the driver private area so rlt8139_recv
         * doesn't have to redetermine this information. Then, inform
         * the generic ethernet driver about the packet.
         */
        rltk8139_info->rx_current = 
          (cyg_uint8 *)CYGARC_UNCACHED_ADDRESS(rltk8139_info->rx_ring + 
                                               rx_pos + 4);
        rltk8139_info->rx_size = length;

        /* Tell eCos about the packet */
        (sc->funs->eth_drv->recv)(sc, length);
      }

      /*
       * Update CAPR. CAPR must be aligned to a 32 bit boundary, and should
       * point 16 bytes before it's actual position.
       */
      rx_pos = ((rx_pos + length + 8 + 3) & ~3) % RX_BUF_LEN;
      OUTW((rx_pos - 16) % RX_BUF_LEN, rltk8139_info->base_address + CAPR);
    }
  }

  if (status & IR_RXOVW) {
    /*
     * In case of a receive buffer overflow, the RealTek data sheet claims we
     * should update CAPR and then write a '1'爐o ROK in ISR. However, none of
     * the other 8139 drivers I have looked at do this, so we will just reset
     * the chip instead.
     */
#ifdef DEBUG_RLTK8139_DRIVER
    diag_printf("rltk8139_deliver(%s): receive buffer overflow\n",
                sc->dev_name);
#endif
    rltk8139_reset(sc);
    return;
  }

  if (status & IR_FOVW) {
    /*
     * Rx FIFO overflow. According to RealTek's data sheet, this is cleared
     * by writing a '1' to RXOVW. Again, none of the 8139 drivers I have
     * seen actually do this, so we reset the chip instead.
     */
#ifdef DEBUG_RLTK8139_DRIVER
    diag_printf("rltk8139_deliver(%s): receive FIFO overflow\n",
                sc->dev_name);
#endif
    rltk8139_reset(sc);
    return;
  }


  if (status & IR_FUN) {
    /*
     * Packet underrun or link change interrupt.

     * A cable was packet underrun or re-connected ?

     */
#ifdef DEBUG_RLTK8139_DRIVER
    diag_printf("rltk8139_deliver(%s): packet underrun or link change\n",
                sc->dev_name);
#endif
  }

#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
  /* Finally, reenable interrupts */
#ifdef CYGPKG_DEVS_ETH_RLTK_8139_MASK_INTERRUPTS_IN_8139
  OUTW(RLTK8139_IRQ, rltk8139_info->base_address + IMR);
#else
  cyg_interrupt_unmask(rltk8139_info->vector);
#endif
#endif
}


/*
 * '_poll' does the same thing as '_deliver'. It is called periodically when
 * the ethernet driver is operated in non-interrupt mode, for instance by
 * RedBoot.
 */
static void
rltk8139_poll(struct eth_drv_sc *sc)
{
  Rltk8139_t *rltk8139_info;
  cyg_uint16 isr;


#ifdef DEBUG_RLTK8139_DRIVER
  diag_printf("rltk8139_poll(%s)\n", sc->dev_name);
#endif

  rltk8139_info = (Rltk8139_t *)(sc->driver_private);

  /*
   * Get the current interrupt status. If anything changed, call
   * _deliver.
   */
  if ((isr = INW(rltk8139_info->base_address + ISR)))
    rltk8139_deliver(sc);
}


/*
 * Return the interrupt vector used by this device.
 */
static int
rltk8139_int_vector(struct eth_drv_sc *sc)
{
  return ((Rltk8139_t *)(sc->driver_private))->vector;
}


/*
 * Quick and dirty register dump. This is somewhat dangerous, since
 * we read the register space 32 bits at a time, regardless of actual
 * register sizes.
 */
#ifdef DEBUG_RLTK8139_DRIVER
void
rltk8139_print_state(struct eth_drv_sc *sc) {
  int i;
  Rltk8139_t *rltk8139_info;


  rltk8139_info = (Rltk8139_t *)(sc->driver_private);

  for (i = IDR0; i < FFER; i += 16) {
    diag_printf("8139 reg address 0x%02x = 0x%08x", i,
                INL(rltk8139_info->base_address + i));
    diag_printf(" 0x%08x", INL(rltk8139_info->base_address + i + 4));
    diag_printf(" 0x%08x", INL(rltk8139_info->base_address + i + 8));
    diag_printf(" 0x%08x\n", INL(rltk8139_info->base_address + i + 12));
  }
}
#endif



#ifdef CYGPKG_DEVS_ETH_RLTK_8139_WRITE_EEPROM

/*
 * Read mac_address from EEPROM.
 */
static cyg_uint16
rltk8139_eeprom_read( char *rtl_addr, cyg_uint8 eeprom_cmd, cyg_uint8 eeprom_addr )
{
cyg_uint8   read_data;                   // read from eeprom bit data
cyg_uint8   org_param;                   // original register parameter
cyg_uint8   mask_bit8;                   // mask bit
int         icount;                      // for loop counter



    // get old parameter
    HAL_READ_UINT8( rtl_addr, org_param );


    // ready

    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON );


    // set command

    mask_bit8 = 0x04;
    for(icount = 0; icount < 3; icount++){

        EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_MASK( mask_bit8, eeprom_cmd ));
        mask_bit8 >>= 1;

    }

    // set address

    mask_bit8 = 0x20;
    for(icount = 0; icount < 6; icount++){
        EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_MASK( mask_bit8, eeprom_addr ));
        mask_bit8 >>= 1;

    }



    // read data

    read_data = 0;

    for(icount = 0; icount < 16; icount++){

        EEPROM_RD_DATA( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS, read_data );
    }



    // close

    EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
    EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON );


    // put old parameter
    HAL_WRITE_UINT8(rtl_addr, org_param);


    return(read_data);
}




/*
 * Write in mac_address at EEPROM.
 */
static void
rltk8139_eeprom_write( char *rtl_addr, cyg_uint8 eeprom_cmd, cyg_uint8 eeprom_addr, cyg_uint16 src_data )
{
cyg_uint8   read_data;                   // read from eeprom bit data
cyg_uint8   org_param;                   // original register parameter
cyg_uint8   mask_bit8;                   // mask bit
cyg_uint16  mask_bit16;                  // mask bit for write data
int         icount;                      // for loop counter



    // get old parameter
    HAL_READ_UINT8( rtl_addr, org_param );


    // ready

    EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON );
    EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EESK );
    EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON );


    // set EWEN (eeprom write enable)
    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_PG_EEDI );
    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_PG_EEDI );
    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_PG_EEDI );
    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
    EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON );


    // set command

    mask_bit8 = 0x04;
    for(icount = 0; icount < 3; icount++){
        EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_MASK( mask_bit8, eeprom_cmd ));
        mask_bit8 >>= 1;

    }

    // set address

    mask_bit8 = 0x20;
    for(icount = 0; icount < 6; icount++){
        EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_MASK( mask_bit8, eeprom_addr ));
        mask_bit8 >>= 1;

    }



    // set data

    mask_bit16 = 0x8000;
    for(icount = 0; icount < 16; icount++){
        EEPROM_WR_DATAPULSE( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_MASK( mask_bit16, src_data ));
        mask_bit16 >>= 1;

    }



    // close

    EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON );
    EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EESK );
    EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON );


    // write ready check
    EEPROM_WR_DATA( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );


    // wait busy disable

    icount = 0;

    while( 1 ){

        cyg_thread_delay( 1 );
        HAL_WRITE_UINT8( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS | EEPROM_PG_EESK );
        HAL_WRITE_UINT8( rtl_addr, EEPROM_PG_ON | EEPROM_PG_EECS );
        HAL_READ_UINT8( rtl_addr, read_data );
        if(( read_data & EEPROM_PG_EEDO ) != 0 ){
            break;
        }
        if( icount++ >= EEPROM_WR_BUSY_RETRIES ){

            diag_printf("EEPROM write wait error adr=0x%02x data=0x%04x\n", eeprom_addr, src_data );
            break;

        }

    }
    HAL_WRITE_UINT8( rtl_addr, EEPROM_PG_ON );


    // put old parameter
    HAL_WRITE_UINT8( rtl_addr, org_param );
}

#endif

⌨️ 快捷键说明

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