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

📄 ks5000_ether.c

📁 eCos/RedBoot for勤研ARM AnywhereII(4510) 含全部源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
#endif  
  return CYG_ISR_HANDLED;
}



//======================================================================
// This interrupt only happens when errors occur
static cyg_uint32 BDMA_Tx_isr(cyg_vector_t vector, cyg_addrword_t data)
{
  U32 IntBDMATxStatus;

  cyg_drv_interrupt_acknowledge(vector);
  
  IntBDMATxStatus = BDMASTAT;
  BDMASTAT = IntBDMATxStatus;

  ++ks5000_BDMA_Tx_Isr_Cnt;
#if defined(CYGPKG_NET)  
  ++ifStats.interrupts;
#endif  
  if (IntBDMATxStatus & BDMASTAT_TX_CCP) 
    {
      debug1_printf("+-- Control Packet Transfered : %x\r",ERMPZCNT);
      debug1_printf("    Tx Control Frame Status : %x\r",ETXSTAT);
    }

  if (IntBDMATxStatus & (BDMASTAT_TX_NL|BDMASTAT_TX_NO|BDMASTAT_TX_EMPTY) )
    {
      if (IntBDMATxStatus & BDMASTAT_TX_NL)
        BDMATxErrCnt.BTxNLErr++;
      if (IntBDMATxStatus & BDMASTAT_TX_NO)
        BDMATxErrCnt.BTxNOErr++;
      if (IntBDMATxStatus & BDMASTAT_TX_EMPTY)
        BDMATxErrCnt.BTxEmptyErr++;
    }
  
  // free any buffers we're done with

  while (txDonePointer->FrameDataPtr && !(txDonePointer->FrameDataPtr & FRM_OWNERSHIP_BDMA))
    {
      freeBuffer((tEthBuffer*)txDonePointer->FrameDataPtr);
      txDonePointer->FrameDataPtr = 0;
      txDonePointer = txDonePointer->NextFD;
    }

  // don't call tx dsr for now -- it has nothing to do

  return CYG_ISR_HANDLED;
}


static void BDMA_Tx_dsr(cyg_vector_t vector, cyg_ucount32 count, cyg_addrword_t data)
{
  ++ks5000_BDMA_Tx_Dsr_Cnt;
}



//======================================================================
static cyg_uint32 BDMA_Rx_isr(cyg_vector_t vector, cyg_addrword_t data)
{
  U32 IntBDMARxStatus;
  
  cyg_drv_interrupt_acknowledge(vector);
  
  IntBDMARxStatus = BDMASTAT;
  BDMASTAT = IntBDMARxStatus;

  ++ks5000_BDMA_Rx_Isr_Cnt;
#if defined(CYGPKG_NET)  
  ++ifStats.interrupts;
#endif
  if (IntBDMARxStatus & (BDMASTAT_RX_NL  | BDMASTAT_RX_NO |
                         BDMASTAT_RX_MSO | BDMASTAT_RX_EMPTY |
                         BDMASTAT_RX_SEARLY) )
    {
//      printf("RxIsr %u\r\n", (unsigned)cyg_current_time());
      if (IntBDMARxStatus & BDMASTAT_RX_NL)
        BDMARxErrCnt.BRxNLErr++;
      if (IntBDMARxStatus & BDMASTAT_RX_NO)
        BDMARxErrCnt.BRxNOErr++;
      if (IntBDMARxStatus & BDMASTAT_RX_MSO)
        BDMARxErrCnt.BRxMSOErr++;
      if (IntBDMARxStatus & BDMASTAT_RX_EMPTY)
        BDMARxErrCnt.BRxEmptyErr++;
      if (IntBDMARxStatus & BDMASTAT_RX_SEARLY)
        BDMARxErrCnt.sBRxSEarly++;
    }
  
  return CYG_ISR_HANDLED|CYG_ISR_CALL_DSR;
}

static void eth_handle_recv_buffer(tEthBuffer*);

static cyg_handle_t  bdmaRxIntrHandle;
static cyg_handle_t  bdmaTxIntrHandle;
static cyg_handle_t  macRxIntrHandle;
static cyg_handle_t  macTxIntrHandle;

static cyg_interrupt  bdmaRxIntrObject;
static cyg_interrupt  bdmaTxIntrObject;
static cyg_interrupt  macRxIntrObject;
static cyg_interrupt  macTxIntrObject;

static int ethernetRunning;

#if HavePHYinterrupt
static cyg_handle_t  macPhyIntrHandle;
static cyg_interrupt  macPhyIntrObject;
#endif

static void ks32c5000_eth_deliver(struct eth_drv_sc *sc)
{
  unsigned short p;
  tEthBuffer *rxBuffer;
  extern void cyg_interrupt_post_dsr(CYG_ADDRWORD intr_obj);
  
  ++ks5000_BDMA_Rx_Dsr_Cnt;
  
  while (1)
    {
      if (!rx_frame_avail())
        {
          // no more frames
          return;
        }
      
      if (!(rxBuffer=ks32c5000_eth_get_recv_buffer()))
        {
          // no buffers available
          return;
        }
      
      p = *((unsigned short*)(rxBuffer->data+EtherFramePadding+ETH_HEADER_SIZE-2));
      
      if (ethernetRunning)
        eth_handle_recv_buffer(rxBuffer);
      else
        freeBuffer(rxBuffer);
    }
}


static void installInterrupts(void)
{
  extern struct eth_drv_sc ks32c5000_sc;
  static bool firstTime=true;

  debug1_printf("ks5000_ether: installInterrupts()\n");
  
  if (!firstTime)
    return;
  firstTime = false;
  
  initFreeList();
  Init_RxFrameDescriptorArray();
  Init_TxFrameDescriptorArray();
  
  BDMARXPTR = (U32)rxReadPointer;
  BDMATXPTR = (U32)txWritePointer;
  
  cyg_drv_mutex_init(&txMutex);
  cyg_drv_mutex_init(&oldRxMutex);
  cyg_drv_cond_init(&oldRxCond,&oldRxMutex);

  cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_ETH_BDMA_RX,0,(unsigned)&ks32c5000_sc,BDMA_Rx_isr,eth_drv_dsr,&bdmaRxIntrHandle,&bdmaRxIntrObject);
  cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_ETH_BDMA_TX,0,0,BDMA_Tx_isr,BDMA_Tx_dsr,&bdmaTxIntrHandle,&bdmaTxIntrObject);
  cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_ETH_MAC_RX,0,0,MAC_Rx_isr,NULL,&macRxIntrHandle,&macRxIntrObject);
  cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_ETH_MAC_TX,0,0,MAC_Tx_isr,NULL,&macTxIntrHandle,&macTxIntrObject);
#if HavePHYinterrupt
  cyg_drv_interrupt_create(CYGNUM_HAL_INTERRUPT_EXT0,0,0,MAC_Phy_isr,NULL,&macPhyIntrHandle,&macPhyIntrObject);
  cyg_drv_interrupt_attach(macPhyIntrHandle);
#endif  
  
  cyg_drv_interrupt_attach(bdmaRxIntrHandle);
  cyg_drv_interrupt_attach(bdmaTxIntrHandle);
  cyg_drv_interrupt_attach(macRxIntrHandle);
  cyg_drv_interrupt_attach(macTxIntrHandle);
  
#if HavePHYinterrupt
  cyg_drv_interrupt_acknowledge(CYGNUM_HAL_INTERRUPT_EXT0);
  cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_EXT0);
#endif  
}

//======================================================================
// Driver code that interfaces to the TCP/IP stack via the common
// Ethernet interface.

    
// don't have any private data, but if we did, this is where it would go
typedef struct
{
  int j;
}ks32c5000_priv_data_t;

ks32c5000_priv_data_t ks32c5000_priv_data;    

#define eth_drv_tx_done(sc,key,retval) (sc)->funs->eth_drv->tx_done(sc,key,retval)
#define eth_drv_init(sc,enaddr)  ((sc)->funs->eth_drv->init)(sc, enaddr)
#define eth_drv_recv(sc,len)  ((sc)->funs->eth_drv->recv)(sc, len)

static bool ks32c5000_eth_init(struct cyg_netdevtab_entry *tab)
{
  unsigned char myMacAddr[6] = { CYGPKG_DEVS_ETH_ARM_KS32C5000_MACADDR };
  struct eth_drv_sc *sc = (struct eth_drv_sc *)tab->device_instance;
  bool ok;

#ifdef CYGHWR_DEVS_ETH_ARM_KS32C5000_GET_ESA
  // Get MAC address from RedBoot configuration variables
  CYGHWR_DEVS_ETH_ARM_KS32C5000_GET_ESA(&myMacAddr[0], ok);
  // If this call fails myMacAddr is unchanged and MAC address from CDL is used
#endif

  debug1_printf("ks32c5000_eth_init()\n");
  debug1_printf("  MAC address %02x:%02x:%02x:%02x:%02x:%02x\n",myMacAddr[0],myMacAddr[1],myMacAddr[2],myMacAddr[3],myMacAddr[4],myMacAddr[5]);
#if defined(CYGPKG_NET)  
  ifStats.duplex = 1;      //unknown
  ifStats.operational = 1; //unknown
  ifStats.tx_queue_len = MAX_TX_FRAME_DESCRIPTORS;
  strncpy(ifStats.description,"Ethernet device",sizeof(ifStats.description));
  ifStats.snmp_chipset[0] = 0;
  ifStats.supports_dot3 = 1; // support dot3
#endif  
  installInterrupts();
  EthInit(myMacAddr);
  cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_ETH_BDMA_RX);
  cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_ETH_BDMA_TX);
  cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_ETH_MAC_RX);
  cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_ETH_MAC_TX);
  configDone = 1;
  ethernetRunning = 1;
  eth_drv_init(sc, myMacAddr);
  return true;
}

static void ks32c5000_eth_start(struct eth_drv_sc *sc, unsigned char *enaddr, int flags)
{
  debug2_printf("ks32c5000_eth_start()\n");
  if (!ethernetRunning)
    {
      cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_ETH_BDMA_RX);
      cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_ETH_BDMA_TX);
      cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_ETH_MAC_RX);
      cyg_drv_interrupt_mask(CYGNUM_HAL_INTERRUPT_ETH_MAC_TX);
      EthInit(enaddr);
      cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_ETH_BDMA_RX);
      cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_ETH_BDMA_TX);
      cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_ETH_MAC_RX);
      cyg_drv_interrupt_unmask(CYGNUM_HAL_INTERRUPT_ETH_MAC_TX);
      ethernetRunning = 1;
    }
}

static void ks32c5000_eth_stop(struct eth_drv_sc *sc)
{
  debug1_printf("ks32c5000_eth_stop()\n");
  ethernetRunning = 0;
}
 
static int ks32c5000_eth_control(struct eth_drv_sc *sc, 
                          unsigned long cmd, 
                          void *data, 
                          int len)
{
  switch (cmd)
    {
#if defined(CYGPKG_NET)      
     case ETH_DRV_GET_IF_STATS_UD:
     case ETH_DRV_GET_IF_STATS:
        {
          struct ether_drv_stats *p = (struct ether_drv_stats*)data;

#if CYGINT_DEVS_ETH_ARM_KS32C5000_PHY
          unsigned linkStatus;

          // Read link status to be up to date
          linkStatus = PhyStatus();
          if (linkStatus & PhyStatus_FullDuplex)
            ifStats.duplex = 3;
          else
            ifStats.duplex = 2;

          if (linkStatus & PhyStatus_LinkUp)
            ifStats.operational = 3;
          else
            ifStats.operational = 2;

          if (linkStatus & PhyStatus_100Mb)
            ifStats.speed = 100000000;
          else
            ifStats.speed = 10000000;
#endif

          *p = ifStats;
          return 0;
        }
#endif      
     case ETH_DRV_SET_MAC_ADDRESS: {
         int act;

         if (ETHER_ADDR_LEN != len)
             return -1;
         debug1_printf("ks32c5000_eth_control: ETH_DRV_SET_MAC_ADDRESS.\n");
         act = ethernetRunning;
         ks32c5000_eth_stop(sc);
         ks32c5000_eth_start(sc, data, 0);
         ethernetRunning = act;
         return 0;
     }
#ifdef	ETH_DRV_GET_MAC_ADDRESS
     case ETH_DRV_GET_MAC_ADDRESS: {
         if (len < ETHER_ADDR_LEN)
             return -1;
         debug1_printf("ks32c5000_eth_control: ETH_DRV_GET_MAC_ADDRESS.\n");
         memcpy(data, (void *)CAM_BaseAddr, ETHER_ADDR_LEN);
         return 0;
     }
#endif
     default:
      return -1;
    }
}

static int ks32c5000_eth_can_send_count=0;
static int ks32c5000_eth_can_send_count_OK=0;

// In case there are multiple Tx frames waiting, we should
// return how many empty Tx spots we have.  For now we just
// return 0 or 1.
static int ks32c5000_eth_can_send(struct eth_drv_sc *sc)
{
  FRAME_DESCRIPTOR *TxFp, *StartFp;
  
  // find the next unused spot in the queue

  ++ks32c5000_eth_can_send_count;
  
  StartFp = TxFp = (FRAME_DESCRIPTOR*)BDMATXPTR;
  
  while (TxFp->FrameDataPtr & FRM_OWNERSHIP_BDMA)
    {
      TxFp = TxFp->NextFD;
      if (TxFp == StartFp)
        return 0;
    }
  ++ks32c5000_eth_can_send_count_OK;
  return 1;
}

static int ks5000_eth_send_count=0;

static void ks32c5000_eth_send(struct eth_drv_sc *sc,
                               struct eth_drv_sg *sg_list,
                               int sg_len,
                               int total_len,
                               unsigned long key)
{
  unsigned char *dest;
  unsigned        len;
  tEthBuffer *buf;

  if (total_len >= MAX_ETH_FRAME_SIZE)
    {
      eth_drv_tx_done(sc,key,-EINVAL);
      return;
    }

  ++ks5000_eth_send_count;

  // allocate buffer

  buf = allocBuffer();
  if (!buf)
    {
      // out of buffers
      eth_drv_tx_done(sc,key,-EIO);
      return;
    }

  // copy data from scatter/gather list into BDMA data buffer

  len = 0;
  dest = buf->data;
  
  while (sg_len)
    {
      memcpy(dest,(unsigned char*)sg_list->buf,sg_list->len);
      len += sg_list->len;
      dest += sg_list->len;
      ++sg_list;
      --sg_len;
    }
  
  buf->length = len;
  
  // tell upper layer that we're done with this sglist

  eth_drv_tx_done(sc,key,0);
  
  // queue packet for transmit
  
  while(!ks32c5000_eth_buffer_send(buf))
    {
#if defined(CYGPKG_KERNEL)
      // wait a tick and try again.
      cyg_thread_delay(1);
#else
      // toss it.
      freeBuffer(buf);
      break;
#endif      
    }
  
}


static int ks5000_eth_rcv_count=0;
static tEthBuffer *tcpIpRxBuffer;

// called from DSR
static void eth_handle_recv_buffer(tEthBuffer* rxBuffer)
{
  extern struct eth_drv_sc ks32c5000_sc;
  tcpIpRxBuffer = rxBuffer;
  eth_drv_recv(&ks32c5000_sc,tcpIpRxBuffer->length-4);  // discard 32-bit CRC
}

static void ks32c5000_eth_recv(struct eth_drv_sc *sc,
                        struct eth_drv_sg *sg_list,
                        int sg_len)
{
  unsigned char *source;

  ++ks5000_eth_rcv_count;
  
  if (!tcpIpRxBuffer)
      return;  // no packet waiting, shouldn't be here!

  // copy data from eth buffer into scatter/gather list

  source = tcpIpRxBuffer->data + EtherFramePadding;
  
  while (sg_len)
    {
	  if (sg_list->buf)
		memcpy((unsigned char*)sg_list->buf,source,sg_list->len);
      source += sg_list->len;
      ++sg_list;
      --sg_len;
    }

  freeBuffer(tcpIpRxBuffer);
  tcpIpRxBuffer = NULL;
  return;
}

// routine called to handle ethernet controller in polled mode
static void ks32c5000_eth_poll(struct eth_drv_sc *sc)
{
  BDMA_Rx_isr(CYGNUM_HAL_INTERRUPT_ETH_BDMA_RX, 0); // Call ISR routine
  ks32c5000_eth_deliver(sc);  // handle rx frames
  ks32c5000_handle_tx_complete();
}

static int ks32c5000_eth_int_vector(struct eth_drv_sc *sc)
{
  return CYGNUM_HAL_INTERRUPT_ETH_BDMA_RX;
}


ETH_DRV_SC(ks32c5000_sc,
           &ks32c5000_priv_data, // Driver specific data
           "eth0",                // Name for this interface
           ks32c5000_eth_start,
           ks32c5000_eth_stop,
           ks32c5000_eth_control,
           ks32c5000_eth_can_send,
           ks32c5000_eth_send,
           ks32c5000_eth_recv,
           ks32c5000_eth_deliver,
           ks32c5000_eth_poll,
           ks32c5000_eth_int_vector
           );

NETDEVTAB_ENTRY(ks32c5000_netdev, 
                "ks32c5000", 
                ks32c5000_eth_init, 
                &ks32c5000_sc);

// EOF ks5000_ether.c

⌨️ 快捷键说明

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