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

📄 lan91c111.c

📁 lwip tcp/ip 协议栈 adsp BF533 DSP 移植 用 visual dsp++ 编译
💻 C
📖 第 1 页 / 共 4 页
字号:
         _outp(INT_REG, IM_ALLOC_INT);
         break;
      }
   } while ( --time_out );

   // too bad, no immediate allocation...
   if ( !time_out )
   {
      /* Check the status bit one more time just in case */
      /* it snuk in between the time we last checked it */
      /* and when we set the interrupt bit */
      status = _inp(INT_REG );
      if ( !(status & IM_ALLOC_INT) )
	  {
		/* The allocation used to fail when ever the RXOVRN was set and
		 * the packets were not transmitted. This takes cares of the 
		 * above, I have not observed any packet loss, but I am not 
		 * that sure also, MC_RELEASE release the recieve packet, 
		 * At the max we may loose one packet.
		 */

		// Relase and reset the FIFO, Now the SMSC memory is free
		while ( _inpw(MMU_CMD_REG ) & 1 ) // 1 is MC_BUSY 
		{
			//when the last release is completed
			ssync();
		}
		
		_outpw(MMU_CMD_REG, MC_RELEASE);
		_outpw(MMU_CMD_REG, MC_RSTTXFIFO);

		goto TX_RETRY;
	  }
   }

   // or YES - I got my memory now...
   dev->LAN_state.alloc_success = 1;

   return (LAN91C111_hardware_send_packet(dev));
}



/******************************************************************************
 * LAN Interrupt Handler
 *****************************************************************************/
int LAN91C111_InterruptHandler(ADI_ETHER_LAN91C111_DATA *dev)
{
      /*
       * This is the main routine of the driver, to handle the
       * net_device when it needs some attention.
       * So:
       *  first, save state of the chipset
       *  branch off into routines to handle each case,
       *  and acknowledge each to the interrupt register
       *  and finally restore state.
       */
      volatile unsigned char    stat;
      volatile unsigned short   card_status;
      volatile unsigned char    mask;
      volatile unsigned short   saved_bank;
      volatile unsigned short   saved_pointer;

	  dev->int_state.saved_mask =0;

      // save current bank
      saved_bank = _inpw(BSR_REG);

      // switch to bank 2 and save pointer
      _outpw(BSR_REG, 2);
      saved_pointer = _inpw(PTR_REG);

      // read IRQ status register
      mask = _inp(IM_REG);

      // disable all LAN IRQs
      _outp(IM_REG, 0x0);

      // read the status flag and mask it
      stat = _inp(INT_REG)& mask;

	  if(!stat)
		  goto no_interrupt;

         if (stat & IM_RCV_INT)
         {
			 // disable 
		   
	      
		   if(dev->m_dma_protect == 0)
		   {
	          LAN91C111_disable_int(SMC_INTERRUPT_MASK);
	  	   	  dma_protect(dev,DMA_DIR_RX);
              // store debug
              dev->LAN_state.last_IRQ_serviced = IM_RCV_INT;
              // Got a packet(s), receive them
	  	      dev->int_state.saved_bank = saved_bank;
      	      dev->int_state.saved_pointer = saved_pointer;
	  	      dev->int_state.saved_mask = mask;

           	  LAN91C111_rcv(dev);
		   }
		   else
		   {
   				while ( _inpw(MMU_CMD_REG ) & MC_BUSY );

			   //  good or bad, delete this packet */
			   _outpw(MMU_CMD_REG, MC_RELEASE);
		   }
         }
		 if (stat & IM_TX_INT )
         {
            // store debug
            dev->LAN_state.last_IRQ_serviced = IM_TX_INT;
            LAN91C111_tx(dev);
            // Acknowledge the interrupt
            _outp(INT_REG, IM_TX_INT);

			// release the dma  tx error
			dma_relinquish();

			// enable interrupts
	 		LAN91C111_enable_int( (SMC_INTERRUPT_MASK) );

         }
		 if (stat & IM_TX_EMPTY_INT )
         {
            // store debug
            dev->LAN_state.last_IRQ_serviced = IM_TX_EMPTY_INT;

            _outpw(BSR_REG, 0);
            card_status = _inpw(COUNTER_REG );

#if LAN91C111_LOG_NET_ERRORS
            // multiple collisions
            dev->Stats->cEMAC_TX_CNT_ABORTC += card_status & 0xF;
            card_status >>= 4;
            // multiple collisions
            dev->Stats->cEMAC_TX_CNT_ABORTC += card_status & 0xF;
#endif
            _outpw(BSR_REG, 2);
            // Acknowledge the interrupt
            _outp(INT_REG, IM_TX_EMPTY_INT);
            mask &= ~IM_TX_EMPTY_INT;

#if LAN91C111_LOG_NET_ERRORS
			// Delayed tx packets
            dev->Stats->cEMAC_TX_CNT_DEFER += dev->LAN_state.packets_waiting;
#endif
            // clear state of waiting packets
            dev->LAN_state.packets_waiting = 0;

         }
		 if (stat & IM_ALLOC_INT )
         {
            // store debug
            dev->LAN_state.last_IRQ_serviced = IM_ALLOC_INT;

            // allocation IRQ
            dev->LAN_state.alloc_success = 1;

            // clear this interrupt so it doesn't happen again
            mask &= ~IM_ALLOC_INT;

            /* enable xmit interrupts based on this */
            mask |= ( IM_TX_EMPTY_INT | IM_TX_INT );

         }
		 if (stat & IM_RX_OVRN_INT )
         {
            // store debug
            dev->LAN_state.last_IRQ_serviced = IM_RX_OVRN_INT;

#if LAN91C111_LOG_NET_ERRORS
            //dev->stats.rx_errors++;
            //dev->stats.rx_fifo_errors++;
			dev->Stats->cEMAC_RX_CNT_IRL++;
#endif

            // Acknowledge the interrupt
            _outp(INT_REG, IM_RX_OVRN_INT);

            // release the dma 
            dma_relinquish();

            // enable interrupts
            LAN91C111_enable_int( (SMC_INTERRUPT_MASK) );
         }
	 if (stat & IM_EPH_INT )
         {
            // currently unsupported IRQ
            // store debug
            dev->LAN_state.last_IRQ_serviced = IM_EPH_INT;
         }
	 if (stat & IM_MDINT )
         {
            // store debug
            dev->LAN_state.last_IRQ_serviced = IM_MDINT;
            LAN91C111_phy_interrupt(dev);
            // Acknowledge the interrupt
            _outp(INT_REG, IM_MDINT);
         }
	 if (stat & IM_ERCV_INT )
         {
            // store debug
            // currently unsupported IRQ
            dev->LAN_state.last_IRQ_serviced = IM_ERCV_INT;
            // Acknowledge the interrupt
            _outp(INT_REG, IM_ERCV_INT);
         }

         // read the status flag and mask it
         stat = _inp(INT_REG)& mask;

          //restore found register states
	  // Its from  receive.
	  if(dev->int_state.saved_mask)
	  {
             ACK_LAN_INT(PF9);
             return 1;
	  }

      _outpw(PTR_REG, saved_pointer);
      _outpw(BSR_REG, saved_bank);

no_interrupt:
      ACK_LAN_INT(PF9);
      _outpw(BSR_REG, 2);
      _outp(IM_REG, mask);
      return 1;
}

/******************************************************************************
 * Configures PHY
 *****************************************************************************/
static SetPhy(ADI_ETHER_LAN91C111_DATA *dev)
{
	u16 phydat;
	
    phydat = LAN91C111_read_phy_register(PHY_CNTL_REG);
    LAN91C111_write_phy_register(PHY_CNTL_REG, 0x8000);   // get phy from reset
	phydat = 0x8000;
	while (phydat&0x8000) {
		phydat = LAN91C111_read_phy_register(PHY_CNTL_REG);
	}
	//		Program PHY registers
	phydat = 0;
	int pha;
	
	phydat = 0;
	if (dev->Auto) {
		phydat |= 0x1000;		// enable auto negotiation
	} else {
		if (dev->FullDuplex) {
			phydat |= (1 << 8);		// full duplex
		} else {
			phydat &= (~(1 << 8));	// half duplex
		}
		if (dev->Port100) {
			phydat |= (1 << 13);	// 100 Mbps
		} else {
			phydat &= (~(1 << 13));	// 10 Mbps
		}
	}
	LAN91C111_write_phy_register(PHY_CNTL_REG, phydat);
	phydat = LAN91C111_read_phy_register(PHY_CNTL_REG);
	if (dev->Loopback) {
		phydat |= (1 << 14);	// enable TX->RX loopback
	}

	LAN91C111_write_phy_register(PHY_CNTL_REG, phydat);

}
/******************************************************************************
 * LAN Initialization routine
 *****************************************************************************/
static int  StartMac(ADI_ETHER_LAN91C111_DATA *dev)
{
      int i;
      short wtmp, wstat;

      ENTER_CRITICAL_REGION();
	  pHandle = dev;// used in transmit_complete/receive_complete

      //init SMSC
      _outpw(BSR_REG, 0);                             // select bank 0
      _outpw(RCR_REG, RCR_SOFTRST);                   // issue soft reset
      LAN91C111_write_phy_register(PHY_CNTL_REG, 0x8000);   // get phy from reset
      _outpw(RCR_REG, 0);                             // clear reset


	  // Hook Interrupts
	adi_int_CECHook(dev->RXIVG,(ADI_INT_HANDLER_FN)LAN91C111_InterruptHandler,&EtherDev,FALSE);	
	adi_int_CECHook(ik_ivg13,(ADI_INT_HANDLER_FN)dma_interrupt_handler,&EtherDev,FALSE);	

	  // Enable interrupts in SIC PFB flag pin which is mapped to lan interrupt
	  //
      adi_int_SICSetIVG(ADI_INT_PFB,dev->RXIVG);
	  adi_int_SICEnable(ADI_INT_PFB);

	  smsc_sleep(250);
      // disable TX and RX functionality
      _outpw(RCR_REG, 0);                             // clear RX
      _outpw(TCR_REG, 0);                             // clear TX

      // init MAC address
      _outpw(BSR_REG, 1);                             // select bank 1
      _outpw(CFG_REG, CFG_EPH_POWER_EN);              // get out of low power mode
      _outpw(CFG_REG, _inpw(CFG_REG)|CFG_NOWAIT);     // set NO_WAIT

      if(memcmp(dev->phyAddr,"\x00\x00\x00\x00\x00\x00",6))
      {	
      	//set MAC Addr
      	wtmp = (((dev->phyAddr[1])<<8)|(dev->phyAddr[0]));
      	_outpw(ADDR0_REG, wtmp);
      	wtmp = (((dev->phyAddr[3])<<8)|(dev->phyAddr[2]));
      	_outpw(ADDR1_REG, wtmp);
      	wtmp = (((dev->phyAddr[5])<<8)|(dev->phyAddr[4]));
      	_outpw(ADDR2_REG, wtmp); 
      }
      else // get mac from the EEPROM
      {
  	  	 wtmp = _inpw(ADDR0_REG);
	     dev->phyAddr[0] = wtmp & 0x00FF;
	     dev->phyAddr[1] = wtmp >>8 & 0x00FF;

	     wtmp = _inpw(ADDR1_REG);  
	     dev->phyAddr[2] = wtmp & 0x00FF;
	     dev->phyAddr[3] = wtmp >>8 & 0x00FF;

	     wtmp = _inpw(ADDR2_REG);
	     dev->phyAddr[4] = wtmp & 0x00FF;
	     dev->phyAddr[5] = wtmp >>8 & 0x00FF;
      }
      
      // release all pending packets
      _outpw(CTL_REG, _inpw(CTL_REG)|CTL_AUTO_RELEASE);

      // reset MMU
      _outpw(BSR_REG, 2);
      _outpw(MMU_CMD_REG, MC_RESET);

      // disable all IRQs
      _outp(IM_REG, 0);

      // autonego + LEDs
      _outpw(BSR_REG, 0);
      _outpw(RPC_REG, RPC_ANEG | 0x80);
      //_outpw(RPC_REG, RPC_DEFAULT);

      // turn off isolation mode
      LAN91C111_write_phy_register(PHY_CNTL_REG, 0x3000 | (dev->Loopback?PHY_CNTL_LPBK:0));

      // read PHY_STAT once due to update latency
      LAN91C111_read_phy_register(PHY_STAT_REG);

      i= 25;
      while (i>0) {
      	wtmp = LAN91C111_read_phy_register(PHY_STAT_REG);
      	if (wtmp & PHY_STAT_LINK) break; // the link is up
      	smsc_sleep(100);
      	i--;
      }
        

#if LAN91C111_DBG
      printf("\n");
      wtmp = LAN91C111_read_phy_register(PHY_CNTL_REG);
      printf("PHY_CNTL_REG: 0x%x\n", wtmp);

      wtmp = LAN91C111_read_phy_register(PHY_STAT_REG);
      printf("PHY_STAT_REG: 0x%x\n", wtmp);

      wtmp = LAN91C111_read_phy_register(PHY_ID1_REG);
      printf("PHY_ID1_REG:  0x%x\n", wtmp);

      wtmp = LAN91C111_read_phy_register(PHY_ID2_REG);
      printf("PHY_ID2_REG:  0x%x\n", wtmp);

      wtmp = LAN91C111_read_phy_register(PHY_AD_REG);
      printf("PHY_AD_REG:   0x%x\n", wtmp);

      wtmp = LAN91C111_read_phy_register(PHY_RMT_REG);
      printf("PHY_RMT_REG:  0x%x\n", wtmp);

      wtmp = LAN91C111_read_phy_register(PHY_CFG1_REG);
      printf("PHY_CFG1_REG: 0x%x\n", wtmp);

      wtmp = LAN91C111_read_phy_register(PHY_CFG2_REG);
      printf("PHY_CFG2_REG: 0x%x\n", wtmp);

      wtmp = LAN91C111_read_phy_register(PHY_INT_REG);
      printf("PHY_INT_REG:  0x%x\n", wtmp);

      wtmp = LAN91C111_read_phy_register(PHY_STAT_REG);
      printf("PHY_STAT_REG: 0x%x\n", wtmp);
#endif //LAN91C111_DBG

      // check anego bits
      wtmp = LAN91C111_read_phy_register(PHY_STAT_REG);
      if ((wtmp & (PHY_STAT_LINK|PHY_STAT_ANEG_ACK)) == (PHY_STAT_LINK|PHY_STAT_ANEG_ACK))
      {   // success
         wstat = LAN91C111_read_phy_register(PHY_INT_REG);
#if LAN91C111_DBG
         printf("\nANEG success, Status = 0x%x", wstat);
#endif

         // read transmit register
         wtmp = _inpw(TCR_REG);

         // check for full duplex FDX
         if ((wstat & PHY_INT_DPLXDET) == PHY_INT_DPLXDET)
            wtmp |= TCR_SWFDUP;
         else
            wtmp &= ~TCR_SWFDUP;

         // write FDX result
         _outpw(TCR_REG, wtmp);
      }
      else
      {   // fail
         wstat = LAN91C111_read_phy_register(PHY_INT_REG);
#if LAN91C111_DBG
         printf("\nANEG failed, Status = 0x%x", wstat);
#endif
      }

      // device is started and active now.
      dev->Started = true;

      // enable RX and TX
      _outpw(BSR_REG, 0);
      _outpw(TCR_REG, _inpw(TCR_REG)|TCR_DEFAULT);  // enable TX
      _outpw(RCR_REG, _inpw(RCR_REG)|RCR_DEFAULT);  // enable RX

      // enable IRQs
      _outpw(BSR_REG, 2);
      _outp(IM_REG, SMC_INTERRUPT_MASK);                 // standard IRQ mask
      _outpw(BSR_REG, 0);
      EXIT_CRTICIAL_REGION();
	return 1;
}

#pragma optimize_for_speed
static int QueueNewRcvFrames (ADI_ETHER_LAN91C111_DATA *dev,ADI_ETHER_BUFFER *bufs)
{
ADI_ETHER_BUFFER *tmp_q_ele;

      if (bufs == NULL)
         return (0);

      ENTER_CRITICAL_REGION();
      
      tmp_q_ele = bufs;
      

      if (dev->m_RxEnqueuedCount)
         dev->m_RxEnqueuedTail->pNext = (ADI_ETHER_BUFFER*) tmp_q_ele;
      else
         dev->m_RxEnqueuedHead = tmp_q_ele;

      //We have attached one
      dev->m_RxEnqueuedCount++;

      //Now look for rest
      while (tmp_q_ele->pNext != NULL)
      {
         // increment the count
         dev->m_RxEnqueuedCount++;
         tmp_q_ele = (ADI_ETHER_BUFFER*)tmp_q_ele->pNext;
      }

      //Amd update tail
      dev->m_RxEnqueuedTail = tmp_q_ele;
      dev->RxStarted = 1;

      EXIT_CRTICIAL_REGION();
      //return (VCSE_MRESULT)MR_OK;
	  return 1;
}

static int QueueNewXmtFrames (ADI_ETHER_LAN91C111_DATA *dev,ADI_ETHER_BUFFER *bufs)
{
      ADI_ETHER_BUFFER *tmp_q_ele;

      // if the incoming element is NULL throw an error
      if (bufs == NULL)
         return (0);

      // Come out of critical region so that DMA interrupt
      // can be executed.
      dma_protect(dev,DMA_DIR_TX);

      ENTER_CRITICAL_REGION();
      
      tmp_q_ele = bufs;
      tmp_q_ele->ProcessedFlag = 0;
    
      if (dev->m_TxEnqueuedCount)
         dev->m_TxEnqueuedTail->pNext = (ADI_ETHER_BUFFER*)tmp_q_ele;
      else
         dev->m_TxEnqueuedHead = tmp_q_ele;

      //We have attached one
      dev->m_TxEnqueuedCount++;

      // Now look for rest
      // Note: Currently discriptor based DMA is not supported.

⌨️ 快捷键说明

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