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

📄 xllp_ethernet.c

📁 Xcale270Bsp包,wince平台
💻 C
📖 第 1 页 / 共 5 页
字号:
    None 

  Input Arguments:
    P_XLLP_UCHAR_T frame - a pointer to the frame.
    XLLP_UINT16_T length - length of the frame.

  Output Arguments:
    None
          
  Return Value: 
    None

*******************************************************************************/
void XllpEthernetDumpFrame(P_XLLP_UINT8_T frame, XLLP_UINT16_T length)
{
    XLLP_UINT32_T x;

    printf(" To: %02x:%02x:%02x:%02x:%02x:%02x\r\n",
              frame[0], frame[1], frame[2],
              frame[3], frame[4], frame[5]);
    printf(" From: %02x:%02x:%02x:%02x:%02x:%02x\r\n",
              frame[6], frame[7], frame[8],
              frame[9], frame[10], frame[11]);
    printf(" Type: 0x%x, Length: %u\r\n",
              ntohs(*((P_XLLP_UINT16_T)(frame + 12))), length);

    for (x = 14; x < length; x += 8)
    {
        printf(" %02x %02x %02x %02x %02x %02x %02x %02x\r\n",
                  frame[x],
                  frame[x + 1],
                  frame[x + 2],
                  frame[x + 3],
                  frame[x + 4],
                  frame[x + 5],
                  frame[x + 6],
                  frame[x + 7]);
    }
}

/******************************************************************************

  Function Name: 
    XllpEthernetVerifyRAMBuffer

  Description: 
    This routine used for debugging to verify the data placed into the RAM.

  Global Register Modified: 
    None 

  Input Arguments:
    XLLP_UINT32_T bufferSize - a length of the frame stored in the RAM

  Output Arguments:
    None
          
  Return Value: 
    None

*******************************************************************************/
void XllpEthernetVerifyRAMBuffer (XLLP_UINT32_T bufferSize)
{
    XLLP_UINT16_T j;
	XLLP_UINT32_T testValue;

    XllpEthernetSelectRegisterBank (BANK2);
    for (j = 0; j < (XLLP_UINT16_T)bufferSize; j+=4)
    {
        // Read data 
        XllpEthernetWriteWord((XLLP_UINT16_T)(XLLP_LAN91C111_PTR_AUTO_INCR | XLLP_LAN91C111_PTR_READ | j), XLLP_LAN91C111_POINTER);
        testValue = XllpEthernetReadDoubleWord(XLLP_LAN91C111_DATA_HIGH);
        printf("%d: %08X\r\n", (int)j, (int)testValue);
    }
}

/******************************************************************************

  Function Name: 
    XllpEthernetTransmitPacket

  Description: 
    This routine transmits a frame. It polls the Interrupt Status Register for the
    completion of the TX
    - It allocates a packet for transmit frame.
    - Set the Auto Increment bit in the Pointer Register to increment the internal address
      on access to the data register.
    - Writes the frame into Tx FIFO
    - Enqueue the frame number into the TX FIFO.
    - Checks the Interrupt Status Register for Transmit Empty and Tx Error.
    - Acknowledges the Transmit interrupt or errors

  Global Register Modified: 
    None 

  Input Arguments:
    P_XLLP_UINT16_T buffer  - a data buffer where the frame data will be taken from
    XLLP_UINT32_T length      - a length of the frame
  Output Arguments:
    None
          
  Return Value: 
    XLLP_UINT_T - error code if failed, zero if success

*******************************************************************************/
XLLP_UINT32_T XllpEthernetTransmitPacket(P_XLLP_UINT16_T buffer,
                                         XLLP_UINT32_T length)
{
    XLLP_UINT32_T start, timebase = getTimebase();
    XLLP_UINT32_T timeout = XLLP_LAN91C111_TO_TRANSMIT * timebase;
    XLLP_UINT8_T intStatus; 
    XLLP_UINT16_T bufferSize, x;
    XLLP_UINT16_T resultCode;
    XLLP_UINT16_T frameHandle = 0; 
    P_XLLP_UINT16_T dataP = buffer;
    XLLP_BOOL_T oddFlag = XLLP_FALSE;
    XLLP_UINT16_T revision;
    P_XLLP_VUINT8_T ioRegsP = (P_XLLP_VUINT8_T)XllpEthernetGetPointerToIORegistersBase ();     // Get pointer to I/O space

//////////////////////////////////
	// Evil hack to work around the memory leak we are currently experiencing with autorelease mode.
	// Expect that future rework to the transmit routine that checks the EPH status register will fix this problem.
	// Until then, check the available memory, and if it has decreased, reset the MMU to release these packets.
	XllpEthernetSelectRegisterBank (BANK0);
	// Upper half word
	bufferSize = (*(ioRegsP + 9));    

	// read available memory
	// if too low, reset device.
	if (bufferSize < 3)
	{
		XllpEthernetSelectRegisterBank (BANK2);
		XllpEthernetWriteWord16(XLLP_LAN91C111_MMUCR_RESET_MMU, XLLP_LAN91C111_MMU);
	}
//////////////////////////////////

    // Read the LAN91C111 revision. This assumes Bank 3 is selected.
    XllpEthernetSelectRegisterBank (BANK3);
    revision = XllpEthernetReadWord(XLLP_LAN91C111_REVISION);

    DM_CwDbgPrintf(DM_CW_LAN91C111_0, " LAN91C111 Revision: %d, Chip: %d",
                   (revision & 0x0F),
                   (revision & 0xF0) >> 4);

    // Clear the error log.
    loggedError = 0;

    // Allocate a transmit frame from the LAN91C111.
    if (XllpEthernetAllocateTxPacket(&frameHandle))
    {
        return loggedError;    
    }

    // Write the allocated packet number into the Packet Number Register.
    XllpEthernetSelectRegisterBank (BANK2);
    XllpEthernetWriteByte((XLLP_UINT8_T)frameHandle, XLLP_LAN91C111_PNR);

    // Set the Auto Increment bit in the Pointer Register to increment the
    // internal address on access to the data register.
    XllpEthernetWriteWord(XLLP_LAN91C111_PTR_AUTO_INCR, XLLP_LAN91C111_POINTER);

    // Calculate the memory needed. This includes the status word, byte count
    // data and control rounded up.
    bufferSize = sizeof(XLLP_UINT16_T) + sizeof(XLLP_UINT16_T) + length + 1;
    if (bufferSize & 1)
    {
        // Round the size up.
        bufferSize++;
    }
    else
    {
        // Check for Revision A for odd byte workaround.
        if ((revision & 0x0F) <= 1)
        {
            // Add an extra 2 bytes to the internal buffer length to workaround
            // the odd byte problem.
            bufferSize += 3;
            oddFlag = XLLP_TRUE;
            DM_CwDbgPrintf(DM_CW_LAN91C111_0, " Odd byte workaround");
        }
    }

    // Write the status word.
    XllpEthernetWriteWord16(0, XLLP_LAN91C111_DATA_HIGH);
    // Write the byte count.
    XllpEthernetWriteWord16(bufferSize, XLLP_LAN91C111_DATA_HIGH);

    // Write to the packet buffer:
    for (x = 0; x < length; x+=2)
    {
        // Write the data.
        XllpEthernetWriteWord16(*dataP++, XLLP_LAN91C111_DATA_HIGH);
    }

    // Check for Revision A for odd byte workaround.
    if ((revision & 0x0F) <= 1)
    {
        // Check for odd byte packets.
        if (oddFlag)
        {
            // Write the last byte of the packet with padding.
            XllpEthernetWriteWord16((*dataP & 0xFF), XLLP_LAN91C111_DATA_HIGH);
        }

        // Write just the control byte. Packet will alway be even.
        XllpEthernetWriteWord16((XLLP_LAN91C111_CONTROL_CRC << 8), XLLP_LAN91C111_DATA_HIGH);
    }
    else
    {
        if (length & 1)
        {
            // Write the control byte and last data byte.
             XllpEthernetWriteWord16((((XLLP_LAN91C111_CONTROL_CRC | XLLP_LAN91C111_CONTROL_ODD) << 8) | 
                                       (*(dataP) & 0xFF)), XLLP_LAN91C111_DATA_HIGH);
        }
        else
        {
            // Write just the control byte.
            XllpEthernetWriteWord16((XLLP_LAN91C111_CONTROL_CRC << 8), XLLP_LAN91C111_DATA_HIGH);
        }
    }

    // XllpEthernetVerifyRAMBuffer (bufferSize);
 
    // Enqueue the frame number into the TX FIFO.
    XllpEthernetSelectRegisterBank (BANK2);
    XllpEthernetWriteWord16(XLLP_LAN91C111_MMUCR_ENQUEUE, XLLP_LAN91C111_MMU);

    // Prepare for timeout by getting the initial time interval.
    start = TimerRegBaseP->oscr0;
    // Check the Interrupt Status Register for Transmit Empty.
    while (!((intStatus = XllpEthernetReadByte(XLLP_LAN91C111_INT_STATS)) &
            XLLP_LAN91C111_IST_TX_EMPTY_INT)) 
    {    
        if (getDelta(TimerRegBaseP, start) > timeout)
        {
            // Parse the transmit error bits.
            XllpEthernetDisplayTxStatus();
            // Cleanup after the transmit error.
            if (XllpEthernetDeallocateTxPacket())
            {
                return (loggedError);
            }
            DM_CwDbgPrintf(DM_CW_LAN91C111_1, " Timeout Tx frame");
            LOGERROR(&loggedError, 
                     ERR_L_LAN91C111, ERR_S_ALLOC, ERR_T_TIMEOUT, 
                     intStatus, 0, 0);
            return (loggedError);
        }
    }

    // Now check for transmit complete.
    if (intStatus & XLLP_LAN91C111_IST_TX_EMPTY_INT)
    {
        // Acknowledge Transmit Empty Interrupt.
        XllpEthernetWriteByte((XLLP_UINT8_T)(intStatus | XLLP_LAN91C111_IST_TX_EMPTY_INT), XLLP_LAN91C111_INT_STATS);
    }

    // Now check for transmit complete with no errors.
    if (intStatus & XLLP_LAN91C111_IST_TX_INT)
    {
        // Acknowledge the Transmit interrupt.
        XllpEthernetWriteByte((XLLP_UINT8_T)(intStatus | XLLP_LAN91C111_IST_TX_INT), XLLP_LAN91C111_INT_STATS);
        resultCode = XllpEthernetReadWord(XLLP_LAN91C111_FIFO);
        if (!(resultCode & XLLP_LAN91C111_FIFO_TEMPTY))
        {
            DM_CwDbgPrintf(DM_CW_LAN91C111_1, " Tx FIFO not empty");
            XllpEthernetWriteByte((XLLP_UINT8_T)resultCode, XLLP_LAN91C111_PNR);
            LOGERROR(&loggedError, 
                     ERR_L_LAN91C111, ERR_S_TRANSMIT, ERR_T_TIMEOUT, 
                     intStatus, 1, 0);
            return (loggedError);
        }
    }

    // Clear the collision count.
    XllpEthernetSelectRegisterBank (BANK0);
    XllpEthernetReadWord(XLLP_LAN91C111_COUNTER);

    return (loggedError);
}

/******************************************************************************

  Function Name: 
    XllpEthernetDeallocateRxPacket

  Description: 
    This routine will deallocate a receive buffer and clear any errors.

  Global Register Modified: 
    None 

  Input Arguments:
    None

  Output Arguments:
    None
          
  Return Value: 
    XLLP_UINT32_T - error code if failed, zero if success

*******************************************************************************/
static
XLLP_UINT32_T XllpEthernetDeallocateRxPacket(void)
{
    XLLP_UINT32_T start, timebase = getTimebase();
    XLLP_UINT32_T timeout = XLLP_LAN91C111_TO_ALLOC * timebase;

	loggedError = 0;

    // Release the memory from the received Frame.
    XllpEthernetSelectRegisterBank (BANK2);
    XllpEthernetWriteWord16(XLLP_LAN91C111_MMUCR_REM_REL_RX, XLLP_LAN91C111_MMU);

    // Prepare for timeout by getting the initial time interval.
    start = TimerRegBaseP->oscr0;

    while (XllpEthernetReadWord(XLLP_LAN91C111_MMU) & XLLP_LAN91C111_MMUCR_NO_BUSY)
    {
        // Get the current time interval.
        if ((getDelta(TimerRegBaseP, start)) > timeout)
        {
            DM_CwDbgPrintf(DM_CW_LAN91C111_1, " Error deallocating Rx frame");
            // Report timeout error.
            LOGERROR(&loggedError, 
                     ERR_L_LAN91C111, ERR_S_RECEIVE, ERR_T_TIMEOUT, 
                     0, 0, 0);
            return (loggedError);
        }
    }
    return (loggedError);
}

/******************************************************************************

  Function Name: 
    XllpEthernetReceiveStatus

  Description: 
    This routine returns the status of the Interrupt Status Register for 
    Receive Interrupt of the Ethernet Controller

  Global Register Modified: 
    None 

  Input Arguments:
    None

  Output Arguments:
    P_XLLP_UINT16_T rxIntStatusP - returns TRUE if the Receive Interrupt took place, 
                                   FALSE otherwise
          
  Return Value: 
    XLLP_UINT32_T - error code if failed, zero if success

*******************************************************************************/
XLLP_UINT32_T XllpEthernetReceiveStatus(P_XLLP_UINT16_T rxIntStatusP)
{
    XLLP_UINT8_T intStatus;
    XLLP_UINT32_T start, timebase = getTimebase();
    XLLP_UINT32_T timeout = XLLP_LAN91C111_TO_TRANSMIT * timebase;

	loggedError = 0;

    // Assume the failure
    *rxIntStatusP = XLLP_FALSE;

    // Prepare for timeout by getting the initial time interval.
//    start = ostCtxP->getTimer_fnp(ostCtxP);
    start = TimerRegBaseP->oscr0;

    // Check the Interrupt Status Register for Receive Interrupt.
    XllpEthernetSelectRegisterBank (BANK2);
    while (!((intStatus = XllpEthernetReadByte(XLLP_LAN91C111_INT_STATS)) &
            XLLP_LAN91C111_IST_RCV_INT))
    {    
        if (getDelta(TimerRegBaseP, start) > timeout)
        {
            DM_CwDbgPrintf(DM_CW_LAN91C111_1, " Timeout Rx Status");
            LOGERROR(&loggedError, 
                     ERR_L_LAN91C111, ERR_S_RECEIVE, ERR_T_TIMEOUT, 
                     intStatus, 0, 0);
			break;
        }
    }

    // Check for receive overrun errors
    if (intStatus & XLLP_LAN91C111_IST_RX_OVRN_INT)
    {
        // Acknowledge the Receive Overrun interrupt.
        XllpEthernetWriteByte(XLLP_LAN91C111_ACK_RX_OVRN_INT, XLLP_LAN91C111_INT_ACK);
    }
    // Check the Receive Interrupt.
    else if (intStatus & XLLP_LAN91C111_IST_RCV_INT)
    {
        // Indicate receive packet pending.
        *rxIntStatusP = XLLP_TRUE;
    }

    return (loggedError);
}

/******************************************************************************

  Function Name: 
    XllpEthernetInterruptHandler

  Description: 
    This routine handles the operations normally performed by an Interrupt
    Service Routine. Since we aren't using interrupts to drive transmit and
    receive, this routine is used in place of the ISR routine.

  Global Register Modified: 
    None 

  Input Arguments:
    None

⌨️ 快捷键说明

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