hwcom.c

来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C语言 代码 · 共 1,737 行 · 第 1/4 页

C
1,737
字号
/* Copyright (c) 1998 Motorola Inc. All rights reserved. */

/*++

THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
PARTICULAR PURPOSE.

Module Name:

    hw.c

Abstract:

    MPC821 hardware-specific functions for the NDIS 4.0 ETH8XX miniport
    device driver.

Functions:

    HW_Get_IMMR()
    HW_Allocate_BDs()
    HW_Allocate_Buffers()
    HW_Internal_Setup_BDs()
    HW_Setup_BD_List()
    HW_Setup_Par_Ports()
    HW_Setup_Serial_If()
    HW_Setup_Common_Protocol_Area()
    HW_Setup_Eth_Protocol_Area()
    HW_Handshake_CPM_Init()
    HW_Clear_Init_Events()
    HW_Configure_Interrupts()
    HW_Toggle_Eth_If()
    HW_Initialize()
    HW_Read_Eth_Address()
    HW_Setup()
    HW_Reset()
    HW_Get_Interrupt_Status()
    HW_Ack_Interrupt_Status()
    HW_Block_Interrupts()
    HW_Unblock_Interrupts()
    HW_Copy_Down_Packet()
    HW_Copy_Up_Packet()
    HW_Start()
    HW_Stop()
    HW_Start_Xmit()
    HW_Advance_Element()
    HW_Fill_Multicast_Regs()
    HW_Set_All_Multicast()
    HW_Set_Promiscuous()
    HW_Set_Broadcast()

Notes:

    The routines in this file are used to support configuration and
    initialization of the Ethernet interface (when called by routines
    in eth8xx.c) and in handling Ethernet-related interrupts (when
    called by routines in interrup.c). On the MPC821ADS platform, all
    of the following components must be properly configured before
    the Ethernet interface may be used:

    1. the CPM SCC1 mode register (Ethernet must use SCC1)
    2. the CPM common protocol RAM area
    3. the CPM Ethernet-specific protocol RAM area
    4. the Ethernet mode register
    5. the Ethernet event/interrupt mask register
    6. the send/receive buffer descriptors and data buffers
    7. the parallel port pins used to pace Ethernet activity
    8. the SIU interrupt registers
    9. the BCSR1 register to enable the on-board External Ethernet
           Serial Transceiver (EEST)
    
    Only the MOTO_ADS definitions (for the MPC821ADS platform) have been
    tested. The HELLCAT platform is not currently supported.

--*/


#include <ndis.h>
#include <excpt.h>

#define ADS_IMMR    (Adapter->Immr) /* Use this to simplify access to
                     * the BCSR, CPM registers, and
                     * the Ethernet parameter RAM
                     */

/* Declarations to enable use of #pragma NDIS_PAGEABLE_FUNCTION(). */

STATIC PDA     *HW_Get_IMMR(VOID);
STATIC BOOLEAN  HW_Allocate_BDs(IN PETH8XX_ADAPTER Adapter);
STATIC BOOLEAN  HW_Allocate_Buffers(IN PETH8XX_ADAPTER Adapter);
STATIC VOID     HW_Setup_BD_List(IN BD     *pFirstBD,
                                 IN BD     *pLastBD,
                                 IN UINT    bd_status,
                     IN PUCHAR  pFirstBuffer,
                     IN UINT    bufferSize);
STATIC VOID     HW_Setup_Par_Ports(IN PETH8XX_ADAPTER Adapter);
STATIC VOID     HW_Setup_Serial_If(IN PETH8XX_ADAPTER Adapter);
STATIC VOID     HW_Setup_Common_Protocol_Area(IN PETH8XX_ADAPTER Adapter);
STATIC VOID     HW_Setup_Eth_Protocol_Area(IN PETH8XX_ADAPTER Adapter);


/*----------------------------------------------------------------------*/
#pragma NDIS_PAGEABLE_FUNCTION(HW_Get_IMMR)

PDA *HW_Get_IMMR(VOID)
/*++

Description:

    Gets a copy of the CPM IMMR (internal memory map register).
    This register is initialized during system boot and normally
    remains unchanged after that.  Note that access to the BCSR,
    CPM registers, and the Ethernet parameter RAM are all relative
    to the base memory pointer stored in the IMMR.

Arguments:

    None

Return Value:

    (PDA *)NULL if the IMMR could not be accessed
    otherwise, the value of IMMR (usable as a virtual memory pointer)

--*/
{
    ADDRESSES  immr_addr;          /* Ptr to physical/virtual address.    */
    PDA       *immr = (PDA *)NULL; /* Return CPM internal memory map ptr. */
    DWORD      parm;

    /* Messages for all possible error conditions. */
 
    DEBUGMSG(ZONE_FUNCTION | ZONE_INIT,
    (TEXT("+ETH8XX: HW_Get_IMMR\r\n")));

    if (!KernelIoControl((DWORD)OEM_IOCTL_GET_IMMR, (LPVOID)&parm,
        (DWORD)parm, (LPVOID)&immr_addr, (DWORD)parm, (LPDWORD)&parm))
    {
        ERRORMSG(1, (TEXT("HW_Get_IMMR: OEM_IOCTL_GET_IMMR failed, fatal\r\n")));       /* OEM_IOCTL_GET_IMMR failed */

    } else {

    /* OK, got IMMR as a physical address, now convert to equivalent
     * virtual memory address with appropriate access priviledges.
     * This may be done by the kernelIoControl services at some
     * point in the future.
     */
    immr = VirtualAlloc(0, sizeof(PDA), MEM_RESERVE,PAGE_NOACCESS);
    if (immr == (PDA *)NULL)
    {
        ERRORMSG(1, (TEXT("HW_Get_IMMR: IMMR VirtualAlloc failed, fatal\r\n")));    /* VirtualAlloc failed */

    } else if (!VirtualCopy(immr, immr_addr.VirtualAddress,
                sizeof(PDA), 
                        PAGE_READWRITE | PAGE_NOCACHE)) {

        ERRORMSG(1, (TEXT("HW_Get_IMMR: IMMR VirtualCopy failed, fatal\r\n"))); /* VirtualCopy failed */
        immr = (PDA *)NULL;
    }
    }

    DEBUGMSG(ZONE_FUNCTION | ZONE_INIT,
    (TEXT("-ETH8XX: HW_Get_IMMR\r\n")));

    return(immr);
}


/*----------------------------------------------------------------------*/
#pragma NDIS_PAGEABLE_FUNCTION(HW_Allocate_BDs)

STATIC BOOLEAN HW_Allocate_BDs(IN PETH8XX_ADAPTER Adapter)
/*++

Description:

    Allocates the necessary CPM buffer descriptors (for both Tx and
    Rx buffers). All of the buffer descriptors are allocated from
    the CPM dual-ported RAM. This is OK as long as we don't allocate
    too many buffer descriptors (each one requires 8 bytes).

Arguments:

    Adapter - pointer to the NDIS miniport adapter block

Return Value:

    TRUE if successfully allocated memory for buffer descriptors
    FALSE otherwise

--*/
{
    OEM_IOCTL_INT_MEM_REQUEST alloc_info;

    DWORD requested;    /* Number of bytes required.  */
    DWORD allocated;    /* Number of bytes allocated. */

    BOOLEAN  rc;    /* KernelIOControl() return code. */

    DEBUGMSG(ZONE_FUNCTION | ZONE_INIT,
    (TEXT("+ETH8XX: HW_Allocate_BDs\r\n")));

    /* Setup memory request to the HAL-layer. */
    alloc_info.MemoryType    = MEMORY_BD;
    alloc_info.NumberOfBytes = sizeof(BD) * (Adapter->NbrRxBuffers
                       + Adapter->NbrTxBuffers);

    /* Save count of required number of bytes for later comparison. */
    requested = alloc_info.NumberOfBytes;

    /* Now call HAL-layer to request internal memory. */
    rc = KernelIoControl((DWORD)OEM_IOCTL_ALLOC_MEM,
                         (LPVOID)&alloc_info, (DWORD) NOTUSED,
                     (LPVOID) &Adapter->BdStartArea,
                     (DWORD)NOTUSED, (LPDWORD)&allocated);

    if ((rc == FALSE) || (allocated != requested))
    {
        /* Something went wrong. */
        DEBUGMSG(ZONE_INIT | ZONE_ERROR,
         (TEXT("*ETH8XX: OEM_IOCTL_ALLOC_MEM failed\r\n")));
    return (FALSE);

    }

    /* The BD Base returned is relative to the begining of the
     * IMMR, so add the offset to get into the user defineable area.
     */
    Adapter->BdStartArea = (BD *)(((ULONG)(Adapter->BdStartArea))
                     + ((ULONG)ADS_IMMR)); 

    DEBUGMSG(ZONE_FUNCTION | ZONE_INIT,
    (TEXT("-ETH8XX: HW_Allocate_BDs\r\n")));

    return(TRUE);
}


/*----------------------------------------------------------------------*/
#pragma NDIS_PAGEABLE_FUNCTION(HW_Allocate_Buffers)

STATIC BOOLEAN HW_Allocate_Buffers(IN PETH8XX_ADAPTER Adapter)
/*++

Description:

    Allocates the memory for all Tx and Rx data buffers. The memory
    is allocated from external RAM rather than the CPM dual-ported
    RAM since each buffer can be quite large (currently 1520 bytes).

Arguments:

    Adapter - pointer to the NDIS miniport adapter block

Return Value:

    TRUE if successfully allocated memory for data buffers
    FALSE otherwise

--*/
{
    ULONG PoolSize;      /* Size of the data buffer pool. */
    ULONG debugBufferSize = 0;

    DEBUGMSG(ZONE_FUNCTION | ZONE_INIT,
    (TEXT("+ETH8XX: HW_Allocate_Buffers\r\n")));

    /* The Rx. and Tx. buffers should be allocated from external
     * memory as opposed to being allocated from the space-limited
     * dual-ported RAM. Allocate and copy enough space for both
     * Rx. and Tx buffers.
     */
    PoolSize = (Adapter->NbrRxBuffers * Adapter->MaxRxBufferSize) +
               (Adapter->NbrTxBuffers * Adapter->MaxTxBufferSize);

#if ETHDBG

    /* Also allocate memory for debug buffer. */
    debugBufferSize = ETH8XX_LOG_SIZE;

#endif

    if (PoolSize + debugBufferSize > ALLOCATED_BUFFER_SPACE)
    {
    /* Insufficient memory for requested number of buffers. */
        DEBUGMSG(ZONE_INIT | ZONE_ERROR,
        (TEXT("*ETH8XX: Requesting %d bytes for buffers\r\n"),
        PoolSize + debugBufferSize));
        DEBUGMSG(ZONE_INIT | ZONE_ERROR,
        (TEXT("*ETH8XX: Only reserved %d bytes in config.bib\r\n"),
        ALLOCATED_BUFFER_SPACE));
    return(FALSE);
    }

    /* First reserve the range of virtual addresses. */
    Adapter->RamBase = (PUCHAR)VirtualAlloc(0, PoolSize + debugBufferSize,
                        MEM_RESERVE,
                        PAGE_NOACCESS);
    if (!Adapter->RamBase)
    {
        DEBUGMSG(ZONE_INIT | ZONE_ERROR,
        (TEXT("*ETH8XX: Buffer allocation failed.\r\n")));
    DEBUGMSG(ZONE_INIT | ZONE_ERROR,
        (TEXT("*ETH8XX: Requested %d bytes for buffers.\r\n"),
        PoolSize + debugBufferSize));
    return(FALSE);
    }
    
    DEBUGMSG(ZONE_INIT, (TEXT(" ETH8XX: Requested %d bytes for buffers.\r\n"),
    PoolSize + debugBufferSize));

    /* Now do the actual allocation, note that the address of the
     * physical buffer must be reserved in the config.bib file and
     * ETHERNET_RAM_ADDR defined appropriately in dma.h.
     */
    if (!VirtualCopy(Adapter->RamBase, (LPVOID)ETHERNET_RAM_ADDR,
                     PoolSize, PAGE_READWRITE | PAGE_NOCACHE))
    {
        DEBUGMSG(ZONE_INIT | ZONE_ERROR,
        (TEXT("*ETH8XX: RX and Tx Buffer Copy Failed\r\n")));
    DEBUGMSG(ZONE_INIT | ZONE_ERROR,
        (TEXT("*ETH8XX: Requested location was : 0x%X.\r\n"),
            ETHERNET_RAM_ADDR));
    return(FALSE);
    }

    /* Clear the area. */
    memset(Adapter->RamBase, 0, PoolSize);

    /* Setup the start of the receive buffer area. */
    Adapter->RxStart = Adapter->RamBase;

    /* The start of the transmit buffer area. */
    Adapter->TxStart = Adapter->RamBase +
        (Adapter->NbrRxBuffers * Adapter->MaxRxBufferSize);

#if ETHDBG

    /* Also set up in-memory buffer for debug purposes. */
    eth8xxLogBuffer = (PUCHAR)(Adapter->RamBase + PoolSize);

    DEBUGMSG(ZONE_INIT, (TEXT(" ETH8XX: Debug buffer location: 0x%X (Physical).\r\n"),
         ((ETHERNET_RAM_ADDR + PoolSize) & SDB_PHYS_ADDR_MASK)));
    DEBUGMSG(ZONE_INIT, (TEXT("                                0x%X (Virtual).\r\n"),
         Adapter->RamBase + PoolSize));
    DEBUGMSG(ZONE_INIT, (TEXT(" ETH8XX: Debug buffer size    : %d bytes.\r\n"),
         ETH8XX_LOG_SIZE));

#endif

    DEBUGMSG(ZONE_FUNCTION | ZONE_INIT,
    (TEXT("-ETH8XX: HW_Allocate_Buffers\r\n")));

    return(TRUE);
}


/*----------------------------------------------------------------------*/
STATIC VOID HW_Internal_Setup_BDs(IN PETH8XX_ADAPTER Adapter)
/*++

Description:

    Sets up the receive and transmit buffer descriptors in the CPM.
    The Tx and Rx buffer descriptors must be configured as a circular
    linked-list. Each buffer descriptor contains a physical address
    pointer to its associated data buffer along with a number of status
    fields. See the MPC821 User's Manual for complete details.

    Note that the Windows CE 4GB virtual memory space is divided into 2
    equal 2 GB portions with the upper 2 GB (8000 0000 - FFFF FFFF)
    region being reserved for hardware access (i.e., write-through and
    cache-inhibited). Hence, all of the RAM and flash memory is mapped
    into a region beginning at 8000 0000. Therefore, to obtain, the 
    physical address of a data buffer, we must strip off the leading
    bit. For additional details concerning the Windows CE memory layout,
    see "Minimizing the Memory Footprint of Your Windows CE-based Program",
    Douglas Boling, Microsoft Systems Journal, may 1998, vol. 13, no. 5,
    pp.37-50.

Arguments:

    Adapter - pointer to the NDIS miniport adapter block

Return Value:

    None

--*/
{
    PUCHAR pFirstRxBuffer = (PUCHAR)(ETHERNET_RAM_ADDR & SDB_PHYS_ADDR_MASK);
    PUCHAR pFirstTxBuffer = pFirstRxBuffer
              + Adapter->NbrRxBuffers * Adapter->MaxRxBufferSize;

    DEBUGMSG(ZONE_FUNCTION | ZONE_INIT,
    (TEXT("+ETH8XX: HW_Internal_Setup_BDs\r\n")));

    /* Note: it is required that all buffer descriptors be allocated
     * contiguously, i.e. one starts every 8 bytes with no gaps. This
     * greatly simplifies access to the buffer descriptors during
     * initial setup and subsequent use. The list of buffer descriptors
     * starts with all of the Rx BDs followed by all of the Tx BDs. A
     * similar contiguous layout is also required for the data buffers.
     */
    Adapter->FirstRxBD = Adapter->BdStartArea;
    Adapter->LastRxBD  = Adapter->FirstRxBD + Adapter->NbrRxBuffers - 1;
    Adapter->FirstTxBD = Adapter->LastRxBD + 1;
    Adapter->LastTxBD  = Adapter->FirstTxBD + Adapter->NbrTxBuffers - 1;

    /* Construct the cyclic Rx buffer descriptor list. */
    HW_Setup_BD_List(Adapter->FirstRxBD, Adapter->LastRxBD,
             ETH_RX_EMPT | ETH_RX_INTR,
             pFirstRxBuffer,
             Adapter->MaxRxBufferSize);

    /* Construct the cyclic Tx buffer descriptor list. */
    HW_Setup_BD_List(Adapter->FirstTxBD, Adapter->LastTxBD,
             ETH_TX_PAD | ETH_TX_INTR | ETH_TX_CRC  | ETH_TX_LAST,
             pFirstTxBuffer,
             Adapter->MaxTxBufferSize);

    /* Reset the driver receive and transmit structures. */
    Adapter->ActiveRx.pBufferDescriptor = Adapter->FirstRxBD;
    Adapter->ActiveRx.pBuffer           = Adapter->RxStart;
    Adapter->FreeTx.pBufferDescriptor   = Adapter->FirstTxBD;
    Adapter->FreeTx.pBuffer             = Adapter->TxStart;
    Adapter->ActiveTx.pBufferDescriptor = NULL;
    Adapter->ActiveTx.pBuffer           = NULL;
    Adapter->FirstPacket                = NULL;
    Adapter->LastPacket                 = NULL;
    
    DEBUGMSG(ZONE_FUNCTION | ZONE_INIT,
    (TEXT("-ETH8XX: HW_Internal_Setup_BDs\r\n")));
}

⌨️ 快捷键说明

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