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

📄 mac.c

📁 Windows CE 6.0 BSP for VOIPAC Board (PXA270) Version 2b.
💻 C
字号:
//
// 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:  mac.c
//
#include <windows.h>
#include <nkintr.h>
#include <ceddk.h>
#include <ethdbg.h>
#include <oal.h>
#include <au1.h>

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

static AU1_MAC_REGS *g_macRegs;
static AU1_MACDMA_REGS *g_dmaRegs;
static AU1_MACEN_REGS *g_enRegs;

static UINT32 g_dmaAddress = 0;
static UINT32 g_dmaSize = 0;
static UINT32 g_enId = 0;

static UINT32 g_rxBufAddr[MAC_RX_BUFFERS];
static UINT32 g_txBufAddr[MAC_TX_BUFFERS];

static UINT32 g_rxPos;
static UINT32 g_txPosUp;
static UINT32 g_txPosDn;
static UINT32 g_txCount;

static UINT16 g_mac[3];
static UINT32 g_hash[2];
static UINT8  g_phy;

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

static UINT16 PhyRead(UINT8 phy, UINT8 reg)
{
   // Wait while MII is busy
   while ((INREG32(&g_macRegs->MIICTRL) & MAC_MIICTRL_MB) != 0);
   // Set address
   OUTREG32(&g_macRegs->MIICTRL, (phy << 11)|(reg << 6));
   // Wait while MII is busy
   while ((INREG32(&g_macRegs->MIICTRL) & MAC_MIICTRL_MB) != 0);
   // Return data
   return (UINT16)INREG32(&g_macRegs->MIIDATA);
}

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

static void PhyWrite(UINT8 phy, UINT8 reg, UINT16 data)
{
   // Wait while MII is busy
   while ((INREG32(&g_macRegs->MIICTRL) & MAC_MIICTRL_MB) != 0);
   // Set data
   OUTREG32(&g_macRegs->MIIDATA, data);
   // Set address
   OUTREG32(&g_macRegs->MIICTRL, (phy << 11)|(reg << 6)|MAC_MIICTRL_MW);
   // Wait while MII is busy
   while ((INREG32(&g_macRegs->MIICTRL) & MAC_MIICTRL_MB) != 0);
}

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

static BOOL PhyInit(BOOL *pFullDuplex)
{
    BOOL rc = FALSE;
    UINT16 id1, id2;

    // First find PHY
    for (g_phy = 0; g_phy < 32; g_phy++) {
        id1 = PhyRead(g_phy, MAC_PHY_PHYIDR1);
        if (id1 == 0xFFFF) continue;
        id2 = PhyRead(g_phy, MAC_PHY_PHYIDR2);
        if (id2 == 0xFFFF) continue;
        break;
    };

    // There is something wrong if we don't find PHY device, leave
    if (g_phy >= 32) {
        OALMSGS(OAL_ERROR, (L"Au1EdbgInit: Failed to detect PHY device\r\n"));
        goto cleanUp;
    }

    // Wait until link is up
    OALLogSerial(L"Au1 MAC: Wait for link...");
    PhyRead(g_phy, MAC_PHY_BMSR);
    while ((PhyRead(g_phy, MAC_PHY_BMSR) & MAC_PHY_BMSR_LINK) == 0);
    OALLogSerial(L" Link detected\r\n");

    // Check if final mode is full duplex
    *pFullDuplex = (
        PhyRead(g_phy, MAC_PHY_ANAR) & PhyRead(g_phy, MAC_PHY_ANLPAR) &
        (MAC_PHY_AN_100FD | MAC_PHY_AN_10FD)
    ) != 0;

    // We are done
    rc = TRUE;

cleanUp:
    return rc;
}

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

static UINT32 HashAddress(UCHAR* pAddress)
{
   UINT32 crc, carry;
   UINT i, j;
   UCHAR uc;

   crc = 0xFFFFFFFF;
   for (i = 0; i < MAC_ADDR_SIZE; i++) {
      uc = pAddress[i];
      for (j = 0; j < 8; j++) {
         carry = ((crc & 0x80000000) ? 1 : 0) ^ (uc & 0x01);
         crc <<= 1;
         uc >>= 1;
         if (carry) crc = (crc ^ 0x04c11db7) | carry;
      }
   }
   return crc;
}

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

static BOOL HWInit()
{
    BOOL rc = FALSE;
    UINT32 address, i, ctrl;
    BOOL fullDuplex;

    // Enable clock
    OUTREG32(&g_enRegs->MAC[g_enId], MACEN_CE);

    // Enable MAC
    OUTREG32(&g_enRegs->MAC[g_enId], MACEN_E2 | MACEN_E1 | MACEN_E0 | MACEN_CE);

    // Initialize RX structures
    address = g_dmaAddress;
    for (i = 0; i < MAC_RX_BUFFERS; i++) {
        g_rxBufAddr[i] = address;
        OUTREG32(
            &g_dmaRegs->RX[i].ADDR,
            OALVAtoPA((VOID*)address) | MACDMA_ADDR_EN
        );
        address += MAC_BUFFER_SIZE;
    }
    g_rxPos = (INREG32(&g_dmaRegs->RX[0].ADDR) & MACDMA_ADDR_CB) >> 2;

    // Initialize TX structures
    for (i = 0; i < MAC_TX_BUFFERS; i++) {
        g_txBufAddr[i] = address;
        OUTREG32(&g_dmaRegs->TX[i].STAT, 0);
        OUTREG32(&g_dmaRegs->TX[i].ADDR, 0);
        address += MAC_BUFFER_SIZE;
    }
    g_txPosUp = (INREG32(&g_dmaRegs->TX[0].ADDR) & MACDMA_ADDR_CB) >> 2;
    g_txPosDn = g_txPosUp;
    g_txCount = 0;

    // Setup MAC address
    OUTREG32(&g_macRegs->ADDRLOW, g_mac[0] |(g_mac[1] << 16));
    OUTREG32(&g_macRegs->ADDRHIGH, g_mac[2]);

    // Then hast table
    OUTREG32(&g_macRegs->HASHLOW, g_hash[0]);
    OUTREG32(&g_macRegs->HASHHIGH, g_hash[1]);

    // Initialize PHY
    if (!(rc = PhyInit(&fullDuplex))) goto cleanUp;

    // And enable rx&tx
    ctrl = MAC_CTRL_DO|MAC_CTRL_AP|MAC_CTRL_RE|MAC_CTRL_TE;
    if (fullDuplex) ctrl |= MAC_CTRL_F;
    OUTREG32(&g_macRegs->CTRL, ctrl);

cleanUp:
    return rc;
}

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

BOOL Au1EdbgInitDMABuffer(UINT32 address, UINT32 size)
{
    BOOL rc = FALSE;
    UINT32 offset;

    OALMSGS(OAL_ETHER&&OAL_FUNC, (
        L"+Au1EdbgInitDMABuffer(0x%08x, 0x%08x)\r\n", address, size
    ));

    // Buffers must be aligned to 32 bytes boundary
    offset = address & 0x1F;
    if (offset != 0) {
        address = address + 0x20 - offset;
        size = size + 0x20 - offset;
    }
    // Check if buffer is big enough
    if (size < MAC_BUFFER_SIZE * (MAC_TX_BUFFERS + MAC_RX_BUFFERS)) {
        OALMSGS(OAL_ERROR, (
            L"ERROR: Au1EdbgInitDMABuffer: DMA buffer is too small\r\n"
        ));
        goto cleanUp;
    }

    // Store address and size
    g_dmaAddress = (UINT32)OALCAtoUA(address);
    g_dmaSize = size;

    // Done
    rc = TRUE;

cleanUp:
    OALMSGS(OAL_ETHER&&OAL_FUNC, (L"-Au1EdbgInitDMABuffer(rc = %d)\r\n", rc));
    return rc;
}

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

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

    OALMSGS(OAL_ETHER&&OAL_FUNC, (
        L"+Au1EdbgInit(0x%X, 0x%X, %02x:%02x:%02x:%02x:%02x:%02x)\r\n",
        pAddress, offset, mac[0]&0xFF, mac[0]>>8, mac[1]&0xFF, mac[1]>>8,
        mac[2]&0xFF, mac[2]>>8
    ));

    // Set device addresses
    address = OALVAtoPA(pAddress);
    if (address == AU1_MACA0_REGS_PA) {
        g_macRegs = (AU1_MAC_REGS*)OALPAtoUA(AU1_MACA0_REGS_PA);
        g_dmaRegs = (AU1_MACDMA_REGS*)OALPAtoUA(AU1_MACDMA0_REGS_PA);
        g_enRegs = (AU1_MACEN_REGS*)OALPAtoUA(AU1_MACAEN_REGS_PA);
        g_enId = 0;
    } else if (address == AU1_MACA1_REGS_PA) {
        g_macRegs = (AU1_MAC_REGS*)OALPAtoUA(AU1_MACA1_REGS_PA);
        g_dmaRegs = (AU1_MACDMA_REGS*)OALPAtoUA(AU1_MACDMA1_REGS_PA);
        g_enRegs = (AU1_MACEN_REGS*)OALPAtoUA(AU1_MACAEN_REGS_PA);
        g_enId = 1;
    } else if (address == AU1_MACB0_REGS_PA) {
        g_macRegs = (AU1_MAC_REGS*)OALPAtoUA(AU1_MACB0_REGS_PA);
        g_dmaRegs = (AU1_MACDMA_REGS*)OALPAtoUA(AU1_MACDMA0_REGS_PA);
        g_enRegs = (AU1_MACEN_REGS*)OALPAtoUA(AU1_MACBEN_REGS_PA);
        g_enId = 0;
    } else if (address == AU1_MACB1_REGS_PA) {
        g_macRegs = (AU1_MAC_REGS*)OALPAtoUA(AU1_MACB1_REGS_PA);
        g_dmaRegs = (AU1_MACDMA_REGS*)OALPAtoUA(AU1_MACDMA1_REGS_PA);
        g_enRegs = (AU1_MACEN_REGS*)OALPAtoUA(AU1_MACBEN_REGS_PA);
        g_enId = 1;
    } else {
        goto cleanUp;
    }

    // Save MAC address to global variable
    g_mac[0] = mac[0]; g_mac[1] = mac[1]; g_mac[2] = mac[2];

    // Start with empty hash table
    g_hash[0] = g_hash[1] = 0;

    // Initialize hardware
    rc = HWInit();

cleanUp:
    OALMSGS(OAL_ETHER&&OAL_FUNC, (L"-Au1EdbgInit(rc = %d)\r\n", rc));
    return rc;
}

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

VOID Au1EdbgPowerOff()
{
    // Disable clock to device
    OUTREG32(&g_enRegs->MAC[g_enId], 0);
}

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

VOID Au1EdbgPowerOn()
{
    HWInit();
}

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

UINT16 Au1EdbgGetFrame(UINT8 *pData, UINT16 *pLength)
{
    UINT32 stat, length;

    // Let be pesimistic
    length = 0;
    // When packet is in buffer DN bit is set
    while ((INREG32(&g_dmaRegs->RX[g_rxPos].ADDR) & MACDMA_ADDR_DN) != 0) {
        // Get result
        stat = INREG32(&g_dmaRegs->RX[g_rxPos].STAT);
        length = (stat & MACDMA_STATRX_LEN) - 4;
        // Copy packet if there is no problem
        if ((stat & MACDMA_STATRX_ERR) == 0 && length <= *pLength) {
            memcpy(pData, (VOID*)g_rxBufAddr[g_rxPos], length);
        } else {
            length = 0;
        }
        // Reinitialize channel
        OUTREG32(&g_dmaRegs->RX[g_rxPos].STAT, 0);
        OUTREG32(
            &g_dmaRegs->RX[g_rxPos].ADDR,
            OALVAtoPA((VOID*)g_rxBufAddr[g_rxPos])|MACDMA_ADDR_EN
        );
        // Move to next possition
        if (++g_rxPos >= MAC_RX_BUFFERS) g_rxPos = 0;
        // If we get a packet break loop
        if (length > 0) break;
    }
    *pLength = (USHORT)length;

#if 0
    // Clear all TxDone
    ClearTxDone();
#endif

    // Return size
    return *pLength;
}

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

UINT16 Au1EdbgSendFrame(UCHAR *pData, UINT32 length)
{
    UINT16 rc = 1;
    
    // Fail when packet is too long...
    if (length > MAC_BUFFER_SIZE) goto cleanUp;

    if (g_txPosUp != ((INREG32(&g_dmaRegs->TX[0].ADDR) & 0x0C) >> 2)) {
        OALMSGS(OAL_ERROR, (
            L"Au1EdbgSendFrame: DMA out of sync: %d - 0x%08x\r\n", 
            g_txPosUp, INREG32(&g_dmaRegs->TX[0].ADDR)
        ));
    }

    // Copy packet to buffer
    memcpy((PVOID)g_txBufAddr[g_txPosUp], pData, length);

    // Set status, length & buffer address
    OUTREG32(&g_dmaRegs->TX[g_txPosUp].STAT, 0);
    OUTREG32(&g_dmaRegs->TX[g_txPosUp].LEN, length);
    OUTREG32(
        &g_dmaRegs->TX[g_txPosUp].ADDR,
        OALVAtoPA((VOID*)g_txBufAddr[g_txPosUp])|MACDMA_ADDR_EN
    );

    // Wait until packet is send
    while ((INREG32(&g_dmaRegs->TX[g_txPosUp].ADDR) & MACDMA_ADDR_DN) == 0);
    OUTREG32(&g_dmaRegs->TX[g_txPosUp].ADDR, 0);

    // Move to next possition
    if (++g_txPosUp >= MAC_TX_BUFFERS) g_txPosUp = 0;

    // And it is done
    rc = 0;

cleanUp:
    return 0;
}

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

VOID Au1EdbgEnableInts()
{
    OALMSGS(OAL_ETHER&&OAL_FUNC, (L"+Au1EdbgEnableInts\r\n"));
    OALMSGS(OAL_ETHER&&OAL_FUNC, (L"-Au1EdbgEnableInts\r\n"));
}

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

VOID Au1EdbgDisableInts()
{
    OALMSGS(OAL_ETHER&&OAL_FUNC, (L"+Au1EdbgDisableInts\r\n"));
    OALMSGS(OAL_ETHER&&OAL_FUNC, (L"-Au1EdbgDisableInts\r\n"));
}

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

VOID Au1EdbgCurrentPacketFilter(UINT32 filter)
{
    UINT32 ctrl;

    OALMSG(OAL_ETHER&&OAL_FUNC, (
        L"+Au1EdbgCurrentPacketFilter(0x%08x)\r\n", filter
    ));

    ctrl = INREG32(&g_macRegs->CTRL);
#if 0
    if ((filter & PACKET_TYPE_ALL_MULTICAST) != 0) {
        ctrl |= MAC_CTRL_PM;
    } else {
        ctrl &= ~MAC_CTRL_PM;
    }
    if ((filter & PACKET_TYPE_MULTICAST) != 0) {
        ctrl |= MAC_CTRL_HP;
    } else {
        ctrl &= ~MAC_CTRL_HP;
    }
#else
    if (
        (filter & PACKET_TYPE_ALL_MULTICAST) != 0 ||
        (filter & PACKET_TYPE_MULTICAST) != 0
    ) {
        ctrl |= MAC_CTRL_PM;
    } else {
        ctrl &= ~MAC_CTRL_PM;
    }
#endif
    if ((filter & PACKET_TYPE_PROMISCUOUS) != 0) {
        ctrl |= MAC_CTRL_PR;
    } else {
        ctrl &= ~MAC_CTRL_PR;
    }
    OUTREG32(&g_macRegs->CTRL, ctrl);

    OALMSG(OAL_ETHER&&OAL_FUNC, (L"-Au1EdbgCurrentPacketFilter\r\n"));
}

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

BOOL Au1EdbgMulticastList(UINT8 *pAddresses, UINT32 count)
{
    UINT32 i, crc, bit;

    OALMSG(OAL_ETHER&&OAL_FUNC, (
        L"+Au1EdbgMulticastList(0x%08x, %d)\r\n", pAddresses, count
    ));

    g_hash[0] = g_hash[1] = 0;
    for (i = 0; i < count; i++) {
        crc = HashAddress(pAddresses);
        bit = crc >> 26;
        g_hash[bit >> 5] |= 1 << (bit & 0x1F);
        pAddresses += MAC_ADDR_SIZE;
    }
    OUTREG32(&g_macRegs->HASHHIGH, g_hash[1]);
    OUTREG32(&g_macRegs->HASHLOW, g_hash[0]);

    OALMSG(OAL_ETHER&&OAL_FUNC, (L"-Au1EdbgMulticastList(rc = 1)\r\n"));
    return TRUE;
}

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

⌨️ 快捷键说明

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