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

📄 lan91c.c

📁 老外的一个开源项目
💻 C
📖 第 1 页 / 共 2 页
字号:
// Copyright (c) David Vescovi.  All rights reserved.
// Part of Project DrumStix
// Windows Embedded Developers Interest Group (WE-DIG) community project.
// http://www.we-dig.org
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
//------------------------------------------------------------------------------
//
//  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
            UINT16 DUMMY ;  // 000C
        };
        struct {            // Bank 1
            UINT16 CFR;     // 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           2000        // 2 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 CFR_SETSQLCH            (1 << 9)
#define CFR_NOWAIT              (1 << 12)
#define CFR_EPH_PWR_EN          (1 << 15)

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

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

#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 volatile LAN91C_REGS __unaligned *g_pLAN91C;
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);
static void print_registers(void);

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


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

//OALLogSetZones( 0xfdffffff);

    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 ((READ_REGISTER_USHORT(&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.
    WRITE_REGISTER_USHORT(&g_pLAN91C->BANKSEL, 3);
    g_chipRevision = READ_REGISTER_USHORT(&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    
    WRITE_REGISTER_USHORT(&g_pLAN91C->BANKSEL, 1);

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

	// no eeprom storage..
	// Setup MAC Address in SMSC LAN91C111

	// Get MAC address from chip ... if you can
    if (READ_REGISTER_USHORT(&g_pLAN91C->IAR0) == 0 &&
		READ_REGISTER_USHORT(&g_pLAN91C->IAR1) == 0 &&
		READ_REGISTER_USHORT(&g_pLAN91C->IAR2) == 0)
	{
		WRITE_REGISTER_USHORT(&g_pLAN91C->IAR0, mac[0]);
		WRITE_REGISTER_USHORT(&g_pLAN91C->IAR1, mac[1]);
		WRITE_REGISTER_USHORT(&g_pLAN91C->IAR2, mac[2]);
	}

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

    // Initialize the control register
    switch (GET_CHIP_ID(g_chipRevision)) {
    case CHIP_ID_LAN91C111:
        WRITE_REGISTER_USHORT(&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.
        WRITE_REGISTER_USHORT(&g_pLAN91C->BANKSEL, 0);
        WRITE_REGISTER_USHORT(&g_pLAN91C->MCRPCR, 0x0800);
        break;
    default:
        // Set SQUELCH & NO WAIT bits
        WRITE_REGISTER_USHORT(&g_pLAN91C->BANKSEL, 1);
        SETPORT16(&g_pLAN91C->CFR, CFR_SETSQLCH|CFR_NOWAIT);
        WRITE_REGISTER_USHORT(&g_pLAN91C->CTR, CTR_BIT8|CTR_TEEN);
        // Memory configuration register value.
        WRITE_REGISTER_USHORT(&g_pLAN91C->BANKSEL, 0);
        WRITE_REGISTER_USHORT(&g_pLAN91C->MCRPCR, 0x0006);
    }

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

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

    // Initialize the Receive Control Register
    WRITE_REGISTER_USHORT(&g_pLAN91C->BANKSEL, 0);
    WRITE_REGISTER_USHORT(&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.
        WRITE_REGISTER_USHORT(&g_pLAN91C->BANKSEL, 0);
        if ((READ_REGISTER_USHORT(&g_pLAN91C->MIR) >> 8) == 0) {
            // No memory?  Reset the MMU.
            WRITE_REGISTER_USHORT(&g_pLAN91C->BANKSEL, 2);
            WRITE_REGISTER_USHORT(&g_pLAN91C->MMUCR, MMUCR_111_RESET_MMU);
            while ((READ_REGISTER_USHORT(&g_pLAN91C->MMUCR) & MMUCR_BUSY) != 0);

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

    // Loop until the request is satisfied
    startTime = OALGetTickCount();
    while ((OALGetTickCount() - startTime) < TIMEOUT_VALUE)
    {
        if (READ_REGISTER_USHORT(&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 ((READ_REGISTER_USHORT(&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 (READ_REGISTER_USHORT(&g_pLAN91C->PNRARR) & 0x8000)
    {
        OALMSGS(OAL_ERROR, (L"ERROR: LAN91CSendFrame: Failed to allocate frame.\r\n"));
        return(1);
    }

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

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

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

    // Now write all except possibly the last data byte
    while (length > 1) {
        WRITE_REGISTER_USHORT(&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
        WRITE_REGISTER_USHORT(&g_pLAN91C->DATA, *pBuffer|CTRL_ODD|CTRL_CRC);
    } else {
        // Otherwise just pad the last byte with 0
        WRITE_REGISTER_USHORT(&g_pLAN91C->DATA, CTRL_CRC);
    }        

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

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

    if ((READ_REGISTER_USHORT(&g_pLAN91C->INTR) & INTR_TX) == 0)
    {
        OALMSGS(OAL_ERROR, (L"ERROR: LAN91CSendFrame: Timed out waiting for the transfer to complete.\r\n"));
        return(1);
    }

	// Read TXDONE Pkt# from FIFO Port Register
    WRITE_REGISTER_USHORT(&g_pLAN91C->BANKSEL, 2);
    packetNumber = (READ_REGISTER_USHORT(&g_pLAN91C->FIFO) & 0x3F);

	// Write to Packet Number Register
    WRITE_REGISTER_USHORT(&g_pLAN91C->PNRARR, packetNumber);

	// Retrieve packet status

⌨️ 快捷键说明

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