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

📄 lan91c.c

📁 Windows CE 6.0 BSP for VOIP sample phone. Intel PXA270 platform.
💻 C
📖 第 1 页 / 共 2 页
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES.
//
//------------------------------------------------------------------------------
//
//  File: lan91c.c
//
//  This file implements ethernet debug driver for SMSC LAN91Cxxx network chip.
//
#include <windows.h>
#include <halether.h>
#include <oal.h>

//------------------------------------------------------------------------------
// Types

typedef struct {
    union {
        struct {            // Bank 0
            UINT16 TCR;     // 0000
            UINT16 EPHSR;   // 0002
            UINT16 RCR;     // 0004
            UINT16 ECR;     // 0006
            UINT16 MIR;     // 0008
            UINT16 MCRPCR;  // 000A
        };
        struct {            // Bank 1
            UINT16 CR;      // 0000
            UINT16 BAR;     // 0002
            UINT16 IAR0;    // 0004
            UINT16 IAR1;    // 0006
            UINT16 IAR2;    // 0008
            UINT16 GPR;     // 000A
            UINT16 CTR;     // 000C
        };
        struct {            // Bank 2
            UINT16 MMUCR;   // 0000
            UINT16 PNRARR;  // 0002
            UINT16 FIFO;    // 0004
            UINT16 PTR;     // 0006
            UINT16 DATA;    // 0008
            UINT16 DATAEX;  // 000A
            UINT16 INTR;    // 000C
        };
        struct {            // Bank 3
            UINT16 MT[4];   // 0000
            UINT16 MGMT;    // 0008
            UINT16 REV;     // 000A
            UINT16 ERDV;    // 000C
        };
    };
    UINT16 BANKSEL;         // 000E
} LAN91C_REGS;

//------------------------------------------------------------------------------
// Defines 
#define TIMEOUT_VALUE           30000       // 30 seconds.

#define CTR_STORE               (1 << 0)
#define CTR_RELOAD              (1 << 1)
#define CTR_TEEN                (1 << 5)
#define CTR_CREN                (1 << 6)
#define CTR_LEEN                (1 << 7)
#define CTR_BIT8                (1 << 8)
#define CTR_AR                  (1 << 11)

#define CR_SETSQLCH             (1 << 9)
#define CR_NOWAIT               (1 << 12)

#define TCR_TXEN                (1 << 0)
#define TCR_PADEN               (1 << 7)
#define TCR_FDSE                (1 << 15)

#define RCR_PRMS                (1 << 1)
#define RCR_ALMUL               (1 << 2)
#define RCR_RXEN                (1 << 8)
#define RCR_STRIP_CRC           (1 << 9)

#define INTR_RX                 (1 << 0)
#define INTR_TX                 (1 << 1)
#define INTR_TX_EMPTY           (1 << 2)
#define INTR_ALLOC              (1 << 3)
#define INTR_RX_OVRN            (1 << 4)
#define INTR_EPH                (1 << 5)
#define INTR_ERCV               (1 << 6)
#define INTR_TX_IDLE            (1 << 7)
#define INTR_RX_MASK            (1 << 8)
#define INTR_TX_MASK            (1 << 9)
#define INTR_TX_EMPTY_MASK      (1 << 10)
#define INTR_ALLOC_MASK         (1 << 11)
#define INTR_RX_OVRN_MASK       (1 << 12)
#define INTR_EPH_MASK           (1 << 13)
#define INTR_ERCV_MASK          (1 << 14)
#define INTR_TX_IDLE_MASK       (1 << 15)

#define EPH_STAT_TXSUC          (1 << 0)
#define EPH_STAT_SNGLCOL        (1 << 1)
#define EPH_STAT_MULTCOL        (1 << 2)
#define EPH_STAT_LTXMULT        (1 << 3)
#define EPH_STAT_16COL          (1 << 4)
#define EPH_STAT_SQET           (1 << 5)
#define EPH_STAT_LTXBRD         (1 << 6)
#define EPH_STAT_TXDEFR         (1 << 7)
#define EPH_STAT_LATCOL         (1 << 9)
#define EPH_STAT_LOSTCARR       (1 << 10)
#define EPH_STAT_EXCDEV         (1 << 11)
#define EPH_STAT_CTRROLL        (1 << 12)
#define EPH_STAT_LINKOK         (1 << 14)
#define EPH_STAT_TXUNRN         (1 << 15)

#define PTR_RCV                 (1 << 15)
#define PTR_AUTOINC             (1 << 14)
#define PTR_READ                (1 << 13)

#define MMUCR_BUSY              (1 << 0)    // MMU busy, don't modify PNR
#define MMUCR_NOP               (0 << 4)    // No-Op command
#define MMUCR_ALLOC             (2 << 4)    // Allocate memory
#define MMUCR_RESET             (4 << 4)    // Reset MMU to initial state
#define MMUCR_REM_TOP           (6 << 4)    // Remove frame from top of RX fifo
#define MMUCR_REM_REL_TOP       (8 << 4)    // Remove and release top of RX fifo
#define MMUCR_REL_SPEC          (10 << 4)   // Release specific packet
#define MMUCR_ENQ_TX            (12 << 4)   // Enqueue to xmit fifo
#define MMUCR_ENQ_RX            (14 << 4)   // Reset xmit fifos

#define MMUCR_111_ALLOC_TX      (1 << 5)    // Allocate Tx memory
#define MMUCR_111_RESET_MMU     (2 << 5)    // Reset the MMU
#define MMUCR_111_REMOVE_RX     (3 << 5)    // Delete top Rx FIFO buffer
#define MMUCR_111_REM_REL_RX    (4 << 5)    // Delete and release Rx FIFO buffer
#define MMUCR_111_RELEASE_RX    (5 << 5)    // Release Rx buffer memory
#define MMUCR_111_RELEASE_TX    (5 << 5)    // Release Tx buffer memory
#define MMUCR_111_ENQUEUE       (6 << 5)    // Queue Tx buffer
#define MMUCR_111_RESET_TX      (7 << 5)    // 

#define STAT_ALGNERR            (1 << 15)
#define STAT_BADCRC             (1 << 13)
#define STAT_LONG               (1 << 11)
#define STAT_SHORT              (1 << 10)

#define CTRL_ODD                (1 << 13)
#define CTRL_CRC                (1 << 12)

#define MGMT_MDO                (1 << 0)
#define MGMT_MDI                (1 << 1)
#define MGMT_MCLK               (1 << 2)
#define MGMT_MDOE               (1 << 3)
#define MGMT_MSK_CRS100         (3 << 14)

#define EPHSR_LINKOK            (1 << 14)

// PHY register definitions.
#define CONTROL_MII_DIS         0x3000
#define CONTROL_LPBK            0x7000

#define GET_CHIP_ID(a)          ((a >> 4) & 0xF)
#define GET_REV_ID(a)           (a & 0xF)

#define CHIP_ID_LAN91C90        3
#define CHIP_ID_LAN91C92        3
#define CHIP_ID_LAN91C94        4
#define CHIP_ID_LAN91C95        5
#define CHIP_ID_LAN91C96        4           // revision ID starts at 6
#define CHIP_ID_LAN91C100       7
#define CHIP_ID_LAN91C100FD     8
#define CHIP_ID_LAN91C110       9
#define CHIP_ID_LAN91C111       9

//------------------------------------------------------------------------------
// Local Variables 

static LAN91C_REGS *g_pLAN91C;
static UINT16 g_chipRevision;

//------------------------------------------------------------------------------
// Local Functions 

static UINT32 Crc(UINT8 *pAddress);
static VOID PhyWrite(UINT8 address, UINT8 reg, UINT16 data);

//------------------------------------------------------------------------------

BOOL LAN91CInit(UINT8 *pAddress, UINT32 offset, UINT16 mac[3])
{
    BOOL rc = FALSE;

    OALMSGS(OAL_ETHER&&OAL_FUNC, (
        L"+LAN91CInit(0x%08x, 0x%08x, 0x%08x)\r\n", pAddress, offset, mac
    ));

    // Save address
    g_pLAN91C = (LAN91C_REGS*)pAddress;

    // Chip settle time.
    OALStall(750);

    // Verify that network chip can be detected
    if ((INPORT16(&g_pLAN91C->BANKSEL) & 0xFF00) != 0x3300) {

        OALMSGS(OAL_ERROR, (
            L"ERROR: LAN91CInit: Network Chip not found at 0x%08x\r\n", pAddress
        ));
        goto cleanUp;
    }

    // Select bank 3 and read the chip ID and revision.
    OUTPORT16(&g_pLAN91C->BANKSEL, 3);
    g_chipRevision = INPORT16(&g_pLAN91C->REV);
    OALMSGS(TRUE, (
        L"LAN91Cxxx: Chip Id %d Revision %d\r\n", 
        GET_CHIP_ID(g_chipRevision), GET_REV_ID(g_chipRevision)
    ));
           
    // Select bank 1    
    OUTPORT16(&g_pLAN91C->BANKSEL, 1);

    // Wait until reset & EEPROM load is done
    OUTPORT16(&g_pLAN91C->CTR, CTR_RELOAD);
    while ((INPORT16(&g_pLAN91C->CTR) & (CTR_RELOAD|CTR_STORE)) != 0);

    // Get MAC address from chip
    mac[0] = INPORT16(&g_pLAN91C->IAR0);
    mac[1] = INPORT16(&g_pLAN91C->IAR1);
    mac[2] = INPORT16(&g_pLAN91C->IAR2);

    // Initialize the control register
    switch (GET_CHIP_ID(g_chipRevision)) {
    case CHIP_ID_LAN91C111:
        OUTPORT16(&g_pLAN91C->CTR, CTR_TEEN);
        // The LAN91C111's internal PHY is disabled at boot time - enable it.
        PhyWrite(0, 0, CONTROL_MII_DIS);
        // Enable auto-negotiation of link speed.
        OUTPORT16(&g_pLAN91C->BANKSEL, 0);
        OUTPORT16(&g_pLAN91C->MCRPCR, 0x0800);
        break;
    default:
        // Set SQUELCH & NO WAIT bits
        OUTPORT16(&g_pLAN91C->BANKSEL, 1);
        SETPORT16(&g_pLAN91C->CR, CR_SETSQLCH|CR_NOWAIT);
        OUTPORT16(&g_pLAN91C->CTR, CTR_BIT8|CTR_TEEN);
        // Memory configuration register value.
        OUTPORT16(&g_pLAN91C->BANKSEL, 0);
        OUTPORT16(&g_pLAN91C->MCRPCR, 0x0006);
    }

    // Initialize transmit control register
    OUTPORT16(&g_pLAN91C->BANKSEL, 0);
    OUTPORT16(&g_pLAN91C->TCR, TCR_PADEN|TCR_TXEN);

    // Initialize interrupt mask register (all ints disabled to start)
    OUTPORT16(&g_pLAN91C->BANKSEL, 2);
    OUTPORT16(&g_pLAN91C->INTR, 0);

    // Initialize the Receive Control Register
    OUTPORT16(&g_pLAN91C->BANKSEL, 0);
    OUTPORT16(&g_pLAN91C->RCR, RCR_RXEN|RCR_STRIP_CRC);

    // We are done
    rc = TRUE;

cleanUp:
    OALMSGS(OAL_ETHER&&OAL_FUNC, (
        L"-LAN91CInit(mac = %02x:%02x:%02x:%02x:%02x:%02x, rc = %d)\r\n",
        mac[0]&0xFF, mac[0]>>8, mac[1]&0xFF, mac[1]>>8, mac[2]&0xFF, mac[2]>>8,
        rc
    ));

    return rc;
}


//------------------------------------------------------------------------------

UINT16 LAN91CSendFrame(UINT8 *pBuffer, UINT32 length)
{
    UINT16 rc = 0;
    UINT16 bufferSize, frameHandle;
    UINT16 packetNumber;
    UINT32 startTime;
    static BOOLEAN bAllocRequest = FALSE;

    // Calculate the amount of memory needed (must be an even number)
    bufferSize = 2 + 2 + (UINT16)length + 1;
    if ((bufferSize & 1) != 0) bufferSize++;

    switch (GET_CHIP_ID(g_chipRevision)) {
    case CHIP_ID_LAN91C111:
        // Make sure there's enough free Tx memory.
        OUTPORT16(&g_pLAN91C->BANKSEL, 0);
        if ((INPORT16(&g_pLAN91C->MIR) >> 8) == 0) {
            // No memory?  Reset the MMU.
            OUTPORT16(&g_pLAN91C->BANKSEL, 2);
            OUTPORT16(&g_pLAN91C->MMUCR, MMUCR_111_RESET_MMU);
            while ((INPORT16(&g_pLAN91C->MMUCR) & MMUCR_BUSY) != 0);

            bAllocRequest = FALSE;
        }
        // Allocate memory in the buffer for the frame
        OUTPORT16(&g_pLAN91C->BANKSEL, 2);
        if (!bAllocRequest)
        {
            OUTPORT16(&g_pLAN91C->MMUCR, MMUCR_111_ALLOC_TX);
            bAllocRequest = TRUE;
        }
        break;
    default:
        // Allocate memory in the buffer for the frame
        OUTPORT16(&g_pLAN91C->BANKSEL, 2);
        OUTPORT16(&g_pLAN91C->MMUCR, MMUCR_ALLOC|(bufferSize >> 8));
    }

    // Loop until the request is satisfied
    startTime = OALGetTickCount();
    while ((OALGetTickCount() - startTime) < TIMEOUT_VALUE)
    {
        if (INPORT16(&g_pLAN91C->INTR) & INTR_ALLOC)
        {
            break;
        }
    }
    // If we couldn't satisfy the allocation, abort - we'll give the
    // receive side time to free up some space in the MMU, then we'll
    // re-check whether the allocation succeeded on the next call.
    if ((INPORT16(&g_pLAN91C->INTR) & INTR_ALLOC) == 0)
    {
        OALMSGS(OAL_ERROR, (L"ERROR: LAN91CSendFrame: Timed out allocating frame.\r\n"));
        return(1);
    }

    bAllocRequest = FALSE;

    // Make sure the allocation didn't fail.
    if (INPORT16(&g_pLAN91C->PNRARR) & 0x8000)
    {
        OALMSGS(OAL_ERROR, (L"ERROR: LAN91CSendFrame: Failed to allocate frame.\r\n"));
        return(1);
    }

    // Get frame handle
    frameHandle = (0x3f00 & INPORT16(&g_pLAN91C->PNRARR)) >> 8;

    // Now write the frame into the buffer
    OUTPORT16(&g_pLAN91C->PNRARR, frameHandle);
    OUTPORT16(&g_pLAN91C->PTR, PTR_AUTOINC);

    // Write status word
    OUTPORT16(&g_pLAN91C->DATA, 0);
    // Write the buffer size
    OUTPORT16(&g_pLAN91C->DATA, bufferSize);

    // Now write all except possibly the last data byte
    while (length > 1) {
        OUTPORT16(&g_pLAN91C->DATA, *(UINT16*)pBuffer);
        pBuffer += sizeof(UINT16);
        length -= sizeof(UINT16);
    }

    if (length > 0) {
        // If length was odd we can put that just before the control byte
        OUTPORT16(&g_pLAN91C->DATA, *pBuffer|CTRL_ODD|CTRL_CRC);
    } else {
        // Otherwise just pad the last byte with 0
        OUTPORT16(&g_pLAN91C->DATA, CTRL_CRC);
    }        

    // Enqueue Frame number into TX FIFO
    switch (GET_CHIP_ID(g_chipRevision)) {
    case CHIP_ID_LAN91C111:
        OUTPORT16(&g_pLAN91C->MMUCR, MMUCR_111_ENQUEUE);
        break;
    default:        
        OUTPORT16(&g_pLAN91C->MMUCR, MMUCR_ENQ_TX);
    }

    // Wait until it is sent or an error is generated.
    startTime = OALGetTickCount();
    while ((OALGetTickCount() - startTime) < TIMEOUT_VALUE)
    {
        if (INPORT16(&g_pLAN91C->INTR) & INTR_TX)
        {
            break;
        }
    }

⌨️ 快捷键说明

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