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

📄 if_8139.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 4 页
字号:
#ifndef CYGPKG_IO_ETH_DRIVERS_STAND_ALONE
  /*
   * If this driver was not compiled in stand alone (without interrupts)
   * mode, enable interrupts.
   */
  OUTW(RLTK8139_IRQ, rltk8139_info->base_address + IMR);
#endif

#ifdef DEBUG_RLTK8139_DRIVER
  rltk8139_print_state(sc);
#endif
}


/*
 * Stop the chip, disabling the transmitter and receiver.
 */
static void
rltk8139_stop(struct eth_drv_sc *sc)
{
  Rltk8139_t *rltk8139_info;


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

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

  /* Disable receiver and transmitter */
  OUTB(INB(rltk8139_info->base_address + CR) & ~(TE|RE),
       rltk8139_info->base_address + CR);

  /* Mask all interrupts */
  OUTW(0, rltk8139_info->base_address + IMR);
}


/*
 * 8139 control function. Unlike a 'real' ioctl function, this function is
 * not required to tell the caller why a request failed, only that it did
 * (see the eCos documentation).
 */
static int
rltk8139_control(struct eth_drv_sc *sc, unsigned long key, void *data,
                 int data_length)
{
  int i;
  Rltk8139_t *rltk8139_info;

#ifdef CYGPKG_DEVS_ETH_RLTK_8139_WRITE_EEPROM
  cyg_uint16 WrData, RdData;
  cyg_uint8  *pSrcData;
  int iRetry;
#endif

#ifdef DEBUG_RLTK8139_DRIVER
  diag_printf("rltk8139_control(%08x, %lx)\n", sc, key);
#endif

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

  switch (key) {
#ifdef ETH_DRV_SET_MAC_ADDRESS
  case ETH_DRV_SET_MAC_ADDRESS:
    if ( 6 != data_length )
      return 1;

    /* Set the mac address */
    for (i = 0; i < 6; ++i) {
      rltk8139_info->mac[i] = *(((cyg_uint8 *)data) + i);
      OUTB(rltk8139_info->mac[i], rltk8139_info->base_address + IDR0 + i);
    }

#ifdef CYGPKG_DEVS_ETH_RLTK_8139_WRITE_EEPROM
    pSrcData = (cyg_uint8 *)data;
    for(i = 0; i < 3; i++){
      WrData  = ((cyg_uint16)(*pSrcData++)) & 0xff;
      WrData |=  ((cyg_uint16)(*pSrcData++)) << 8;
      for( iRetry = 0; iRetry < 3; iRetry++){
        rltk8139_eeprom_write(
                         (char *)(rltk8139_info->base_address + CR9346),
                                           EEPROM_CMD_WRITE, i + 7, WrData);
        RdData = rltk8139_eeprom_read(
                         (char *)(rltk8139_info->base_address + CR9346),
                                           EEPROM_CMD_READ, i + 7);
        if( RdData == WrData ){
          break;
        }
      }
    }
#endif

    return 0;
#endif

#ifdef ETH_DRV_GET_MAC_ADDRESS
    case ETH_DRV_GET_MAC_ADDRESS:
      if (6 != data_length)
        return 1;

      memcpy(data, rltk8139_info->mac, 6);
      return 0;
#endif

#ifdef ETH_DRV_GET_IF_STATS_UD
    case ETH_DRV_GET_IF_STATS_UD: // UD == UPDATE
      //ETH_STATS_INIT( sc );    // so UPDATE the statistics structure
#endif
      // drop through
#ifdef ETH_DRV_GET_IF_STATS
  case ETH_DRV_GET_IF_STATS:
#endif
#if defined(ETH_DRV_GET_IF_STATS) || defined (ETH_DRV_GET_IF_STATS_UD)
    break;
#endif

#ifdef ETH_DRV_SET_MC_LIST
  case ETH_DRV_SET_MC_LIST:
    /*
     * Program the 8139's multicast filter register. If the eth_drv_mc_list
     * contains at least one element, set the accept multicast bit in the
     * receive config register.
     */
    rltk8139_set_multicast_list(rltk8139_info, (struct eth_drv_mc_list *)data);
    if (((struct eth_drv_mc_list *)data)->len > 0)
      OUTL(INL(rltk8139_info->base_address + RCR) | AM,
           rltk8139_info->base_address + RCR);
    else
      OUTL(INL(rltk8139_info->base_address + RCR) & ~AM,
           rltk8139_info->base_address + RCR);

    return 0;
#endif // ETH_DRV_SET_MC_LIST

#ifdef ETH_DRV_SET_MC_ALL
  case ETH_DRV_SET_MC_ALL:
    /*
     * Set the accept multicast bit in the receive config register and
     * program the multicast filter to accept all addresses.
     */
    rltk8139_set_multicast_list(rltk8139_info, NULL);
    OUTL(INL(rltk8139_info->base_address + RCR) | AM,
         rltk8139_info->base_address + RCR);
    return 0;
#endif // ETH_DRV_SET_MC_ALL

  default:
    return 1;
  }

  return 1;
}


/*
 * Check if a new packet can be sent.
 */
static int
rltk8139_can_send(struct eth_drv_sc *sc)
{
  return ((Rltk8139_t *)(sc->driver_private))->tx_num_free_desc;
}


/*
 * Send a packet over the wire.
 */
static void
rltk8139_send(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list, int sg_len,
              int total_len, unsigned long key)
{
  Rltk8139_t *rltk8139_info;
  cyg_uint8 *tx_buffer;
  struct eth_drv_sg *last_sg;
  int desc;

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

#ifdef DEBUG_RLTK8139_DRIVER
  diag_printf("rltk8139_send(%s, %08x, %d, %d, %08lx)\n",
              sc->dev_name, sg_list, sg_len, total_len, key);
#endif

  CYG_ASSERT(total_len <= TX_BUF_SIZE, "packet too long");

  /*
   * Get the next free descriptor to send. We lock out all interrupts
   * and scheduling because we really, really do not want to be interrupted
   * at this point.
   *
   * IMPORTANT NOTE: the RealTek data sheet does not really make this clear,
   * but when they talk about a 'ring' of transmit descriptors, they
   * _really_ mean it, i.e. you _must_ use descriptor #1 after descriptor
   * #0 even if transmission of descriptor #0 has already completed.
   */
  cyg_drv_isr_lock();

  /*
   * Sanity check to see if '_send' was called even though there is no free
   * descriptor. This is probably unnecessary.
   */
  if (rltk8139_info->tx_num_free_desc == 0) {
      cyg_drv_isr_unlock();
#ifdef DEBUG_RLTK8139_DRIVER
    diag_printf("rltk8139_send(%s): no free descriptor available\n",
                sc->dev_name);
#endif
    return;
  }

  /*
   * Get the free descriptor and advance the descriptor counter modulo
   * TX_NUM_DESC. We assume that TX_NUM_DESC will always be a power of 2.
   */
  desc = rltk8139_info->tx_free_desc;
  rltk8139_info->tx_free_desc = (rltk8139_info->tx_free_desc + 1)
    & (NUM_TX_DESC - 1);

  /* Decrement the number of free descriptors */
  rltk8139_info->tx_num_free_desc -= 1;

  /* Reenable interrupts at this point */
  cyg_drv_isr_unlock();

  /*
   * Determine the buffer memory to use and tell the hardware about it.
   * Since we use fixed buffer addresses, we do not need to set up TSADx.
   * Memorize the key so we can call the tx_done callback correctly.
   *
   * While it would be possible to set TSADx to the packet directly if
   * it is stored in a linear memory area with 32 bit alignment, it seems
   * this happens so seldomly that it's simply not worth the extra
   * runtime check.
   */
  tx_buffer = (cyg_uint8 *)CYGARC_UNCACHED_ADDRESS(rltk8139_info->tx_buffer
                                                   + TX_BUF_SIZE * desc);
  rltk8139_info->tx_desc_key[desc] = key;

  /*
   * Copy the data to the designated position. Note that unlike the eCos
   * Intel 82559 driver, we simply assume that all the scatter/gather list
   * elements' lengths will add up to total_len exactly, and don't check
   * to make sure.
   */
  for (last_sg = &sg_list[sg_len]; sg_list < last_sg; ++sg_list) {
    memcpy(tx_buffer, (void *)(sg_list->buf), sg_list->len);
    tx_buffer += sg_list->len;
  }

  /*
   * Make sure the packet has the minimum ethernet packet size, padding
   * with zeros if necessary.
   */
  if (total_len < MIN_ETH_FRAME_SIZE) {
    memset(tx_buffer, 0, MIN_ETH_FRAME_SIZE - total_len);
    total_len = MIN_ETH_FRAME_SIZE;
  }

  /*
   * Flush the data cache here if necessary. This ensures the 8139 can
   * read the correct data from the transmit buffer.
   */
#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY
  HAL_DCACHE_FLUSH(rltk8139_info->tx_buffer + TX_BUF_SIZE * desc, total_len);
#endif

  /*
   * Now setup the correct transmit descriptor to actually send the data.
   * The early TX threshold is incremented by the driver until we reach a
   * size that prevents transmit underruns. (An earlier attempt to calculate
   * this parameter from the packet size didn't work).
   */
  OUTL((rltk8139_info->tx_threshold << ERTXTH_SHIFT) | (total_len & SIZE),
       rltk8139_info->base_address + TSD0 + (desc<<2));
}


/*
 * This routine actually retrieves data from the receive ring by
 * copying it into the specified scatter/gather buffers. Again,
 * we assume the scatter/gather list is OK and don't check against
 * total length.
 */
static void
rltk8139_recv(struct eth_drv_sc *sc, struct eth_drv_sg *sg_list,
              int sg_len)
{
  Rltk8139_t *rltk8139_info;
  struct eth_drv_sg *last_sg;
  cyg_uint8 *rx_buffer;


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

  /*
   * Invalidate the cache line(s) mapped to the receive buffer
   * if necessary.
   */
#ifdef CYGPKG_DEVS_ETH_RLTK_8139_SOFTWARE_CACHE_COHERENCY
  HAL_DCACHE_INVALIDATE(rx_buffer, rltk8139_info->rx_size);
#endif

  for (last_sg = &sg_list[sg_len]; sg_list < last_sg; ++sg_list) {
    if (sg_list->buf != (CYG_ADDRESS)0) {
      memcpy((void *)(sg_list->buf), rx_buffer, sg_list->len);
      rx_buffer += sg_list->len;
    }
  }
}


/*
 * This function does all the heavy lifting associated with interrupts.
 */
static void
rltk8139_deliver(struct eth_drv_sc *sc)
{
  Rltk8139_t *rltk8139_info;
  cyg_uint16 status, pci_status;
  cyg_uint32 tsd;
  int desc;


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

  /*
   * The RealTek data sheet claims that reading the ISR will clear
   * it. This is incorrect; to clear a bit in the ISR, a '1' must be
   * written to the ISR instead. We immediately clear the interrupt
   * bits at this point.
   */
  status = INW(rltk8139_info->base_address + ISR);
  OUTW(status, rltk8139_info->base_address + ISR);

#ifdef DEBUG_RLTK8139_DRIVER
  diag_printf("rltk8139_deliver(%s): %04x\n", sc->dev_name, status);
#endif

  /*
   * Check for a PCI error. This seems like a very serious error to
   * me, so we will reset the chip and hope for the best.
   */
  if (status & IR_SERR) {
    cyg_pci_read_config_uint16(rltk8139_info->pci_device_id,
                               CYG_PCI_CFG_STATUS, &pci_status);
    cyg_pci_write_config_uint16(rltk8139_info->pci_device_id,
                                CYG_PCI_CFG_STATUS, pci_status);
#ifdef DEBUG_RLTK8139_DRIVER
    diag_printf("rltk8139_deliver(%s): PCI error %04x\n",
                sc->dev_name, pci_status);
#endif

    rltk8139_reset(sc);
    return;
  }

  /* Check for transmission complete (with errors or not) */
  if ((status & IR_TER) || (status & IR_TOK)) {
    /*
     * Figure out which descriptors' status must be checked. We lock out
     * interrupts while manipulating the descriptor list because we do not
     * want to be interrupted at this point.
     */
    while (1) {
      cyg_drv_isr_lock();

      /* Check if all descriptors are ready, in which case we are done. */
      if (rltk8139_info->tx_num_free_desc >= NUM_TX_DESC) {
          cyg_drv_isr_unlock();
        break;
      }

      desc = (rltk8139_info->tx_free_desc
              - (NUM_TX_DESC - rltk8139_info->tx_num_free_desc))
        & (NUM_TX_DESC - 1);
      cyg_drv_isr_unlock();

      /* Get the current status of the descriptor */
      tsd = INL(rltk8139_info->base_address + TSD0 + (desc<<2));

⌨️ 快捷键说明

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