halether.c

来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C语言 代码 · 共 325 行

C
325
字号
/*

  Copyright(c) 1998,1999 SIC/Hitachi,Ltd.

	Module Name:

		halether.c

	Revision History:

		26th April 1999		Released

*/
#include <windows.h>
#include <nkintr.h>
#include <ethdbg.h>
#include <halether.h>
#include "platform.h"
#include "drv_glob.h"
#include "oalintr.h"

#define pDriverGlobals  ((PDRIVER_GLOBALS) DRIVER_GLOBALS_PHYSICAL_MEMORY_START)

static BOOL ReadEEPROMData(DWORD *pdwIP, DWORD *pdwSubnetMask);

#define PF_ETHER_BASE ETHERNET_BASE

// The kernel exports...
#ifdef AddrCurMSec
// Some kernels export a pointer to the CurMSec variable.
static volatile DWORD * pCurMSec  = (volatile DWORD *) AddrCurMSec;
#else
extern volatile DWORD CurMSec;
static volatile DWORD * pCurMSec = &CurMSec;
#endif

/* OEMEthInit
 *
 *  Initialization routine - called from EdbgInit() to perform platform specific
 *  HW init.  The Odo platform uses a debug board based on the SMC 91C94 Ethernet
 *  controller.
 *
 *  Return Value:
 *    Return TRUE if init is successful, FALSE if error.
 */
BOOL
OEMEthInit(
    EDBG_ADAPTER *pAdapter) // OUT - Pointer to adapter info structure. Filled in with address
                            //       and SYSINTR info.
{
    // First, reset the 91C94
//   WRITE_REGISTER_USHORT( SMC_HARD_RESET_REG, 1 );
//   WRITE_REGISTER_USHORT( SMC_HARD_RESET_REG, 0 );

    // SMCInit will time out and return error if the debug Ethernet board is not present.
    // Otherwise, the HW will be initialized and our address and subnet mask will be filled
    // in (read from the on chip serial EEPROMs).    
    if (SMCInit((BYTE *) PF_ETHER_BASE,1,pAdapter->Addr.wMAC)) {

		EdbgOutputDebugString("EDBG_PHYSICAL_MEMORY_START = %Xh:\r\n", EDBG_PHYSICAL_MEMORY_START);

        // Enable filtering of broadcast packets (all except ARP packets) to reduce overhead.  We still have
        // to take an interrupt, but the driver can quickly determine whether a packet may be discarded without
        // having to copy all the data from the chip.   
//        SMCSetOptions(OPT_BROADCAST_FILTERING);

        // Read the IP address and subnet mask from the unused range 0x23-0x26 of the serial EEPROM.
        // This is stored by eboot, which gets it either from DHCP or user input.
        if (!ReadEEPROMData(&pAdapter->Addr.dwIP, &pDriverGlobals->eth.SubnetMask)) {
            EdbgOutputDebugString("!OEMEthInit: Error reading IP config from SMC EEPROM\n");
            goto ErrRet;
        }

        EdbgOutputDebugString("Read IP config from EEPROM:\r\n");
        EdbgOutputDebugString(" IP Address: %s,", inet_ntoa(pAdapter->Addr.dwIP));
        EdbgOutputDebugString(" netmask: %s\r\n", inet_ntoa(pDriverGlobals->eth.SubnetMask));

        // Copy our address into driver globals (new versions of eboot (2.0+) will do this for us,
        // so we won't even need to read the EEPROM data, but leave this in to work with old versions).
        memcpy(&pDriverGlobals->eth.PlatformAddr, &pAdapter->Addr, sizeof(EDBG_ADDR));
        
        // Fill in our SYSINTR value for the EDBG subsystem
        pAdapter->SysIntrVal = SYSINTR_ETHER;
        // Fill in our DHCP IP lease time for the EDBG subsystem
        pAdapter->DHCPLeaseTime = pDriverGlobals->eth.DHCPLeaseTime;
        pAdapter->EdbgFlags = pDriverGlobals->eth.EdbgFlags;
#if 0 // (SH_PLATFORM == PLATFORM_BIGSUR)
		// For BigSur platform, somehow bits 1,2 of CONFIG register become 11.
		// These bits should be 00 to use INTR0.
		SelectBank(BANK1);
		WriteWord(CONFIG, (0xFFF9 & ReadWord(CONFIG)) );
#endif // (SH_PLATFORM == PLATFORM_BIGSUR)

        // Fill in our SYSINTR value for the EDBG subsystem
	    // To use polling mode, put 0 as int.id
#if (SH_PLATFORM == PLATFORM_BIGSUR)
        pAdapter->SysIntrVal = 0; // SYSINTR_ETHER;
#else  // (SH_PLATFORM == PLATFORM_BIGSUR)
        pAdapter->SysIntrVal = SYSINTR_ETHER;
#endif // (SH_PLATFORM == PLATFORM_BIGSUR)
        return TRUE;
    }

ErrRet:
    pDriverGlobals->eth.etherEnabled = 0;
    pDriverGlobals->eth.etherFlags = 0;
    return FALSE;
}


// Read IP address and netmask from serial EEPROM on the SMC board (stored from the
// last time we got this info from user or DHCP).
static BOOL
ReadEEPROMData(DWORD *pdwIP, DWORD *pdwSubnetMask)
{
    UINT16 wIPH, wIPL, wSMH, wSML;

   if (!SMCReadEEPROM(0x23,&wIPL) ||
        !SMCReadEEPROM(0x24,&wIPH) ||
        !SMCReadEEPROM(0x25,&wSML) ||
        !SMCReadEEPROM(0x26,&wSMH))
        return FALSE;

    *pdwIP         = ((ULONG)wIPH << 16) | wIPL;
    *pdwSubnetMask = ((ULONG)wSMH << 16) | wSML;

    return TRUE;
}

/* OEMEthEnableInts
 *
 *  Turn on HW interrupts.  
 */
void
OEMEthEnableInts()
{
    SMCEnableInts();
}

/* OEMEthDisableInts
 *
 *  Disable HW interrupts.
 */
void
OEMEthDisableInts()
{
    SMCDisableInts();
}

/* OEMEthISR
 *
 *    ISR routine, called by EDBG IST when Ethernet controller interrupts. Also
 *    called in polling mode, to check for received data.
 *
 * Return Value:
 *    Return bitmask indicating which interrupts are pending.  Currently, the ones
 *    that EDBG cares about are the following (others should be handled internally):
 *       INTR_TYPE_RX   -- Receive interrupt. IST will call into GetFrame to read data.
 */
DWORD
OEMEthISR()
{
    return SMCGetPendingInterrupts();
}

/* OEMEthGetFrame
 *
 *   Check to see if a frame has been received, and if so copy to buffer. An optimization
 *   which may be performed in the Ethernet driver is to filter out all received broadcast
 *   packets except for ARPs.  This is done in the SMC9000 driver.
 *
 * Return Value:
 *    Return TRUE if frame has been received, FALSE if not.
 */
BOOL
OEMEthGetFrame(
    BYTE *pData,       // OUT - Receives frame data
    UINT16 *pwLength)  // IN  - Length of Rx buffer
                       // OUT - Number of bytes received
{
    return SMCGetFrame(pData, pwLength);
}

/* OEMEthSendFrame
 *
 *   Send Ethernet frame.  
 *
 *  Return Value:
 *   TRUE if frame successfully sent, FALSE otherwise.
 */
BOOL
OEMEthSendFrame(
    BYTE *pData,     // IN - Data buffer
    DWORD dwLength)  // IN - Length of buffer
{
    int retries = 0;

    // Let's be persistant here
    while (retries++ < 4) {
        if (!SMCSendFrame(pData, dwLength))
            return TRUE;
        else
            EdbgOutputDebugString("!OEMEthSendFrame failure, retry %u\n",retries);
    }
    return FALSE;
}

/* OEMEthQueryClientInfo
 *
 *    Return address information for default ethernet services, plus a buffer pool to use
 *    for formatting and receiving EDBG packets (single buffer pool specified, divided in
 *    two for Rx and Tx buffers).  By specifying a smaller window size, less memory can be
 *    used (but the protocol will be less efficient...).  The amount of memory required per
 *    client is (2*WindowSize*1500) bytes.
 *
 *    For Odo, we reserve 3 buffer pools worth of memory in the bib file, based on the IMGEBOOT
 *    flag being set.
 *
 *  Return Value:
 *    If client can be configured, return TRUE and fill in addressing and buffer info. Otherwise
 *    return FALSE.  For Odo, configure clients based on the flags set by Eshell (received in the
 *    JUMPIMG command by eboot, and placed in the uninitalized driver globals section).
 */
BOOL
OEMEthQueryClientInfo(
    UCHAR Service,         // IN - Service ID (one of EDBG_SVC defs from ethdbg.h).
    EDBG_ADDR *pPeerAddr,  // OUT -Filled in with the peer Ether/IP address and UDP port number.
    PUCHAR  pWindowSize,   // OUT -Filled in with the client window size.
    PUCHAR *ppBufferPool)  // OUT -Filled in with the packet buffer pool address.
{
    
    // We use the default window size (8) for all services
    *pWindowSize = EDBG_WINDOW_SIZE;
    
    switch (Service)
    {
        // Check the flag in driver globals (set by eboot when it receives the JUMPIMG command)
        case EDBG_SVC_DBGMSG:
            if (! (pDriverGlobals->eth.etherFlags & EDBG_FL_DBGMSG)) {
                return FALSE;
            }
            memcpy(pPeerAddr, &pDriverGlobals->eth.DbgHostAddr,sizeof(EDBG_ADDR));
            *ppBufferPool = (UCHAR *)EDBG_PHYSICAL_MEMORY_START;
            break;
        case EDBG_SVC_PPSH:
            if (! (pDriverGlobals->eth.etherFlags & EDBG_FL_PPSH)) {
                return FALSE;
            }
            memcpy(pPeerAddr, &pDriverGlobals->eth.PpshHostAddr,sizeof(EDBG_ADDR));
            *ppBufferPool = (UCHAR *)EDBG_PHYSICAL_MEMORY_START + EDBG_DFLT_BUFFER_POOL_SIZE;
            break;
        case EDBG_SVC_KDBG:
            if (! (pDriverGlobals->eth.etherFlags & EDBG_FL_KDBG)) {
                return FALSE;
            }
            memcpy(pPeerAddr, &pDriverGlobals->eth.KdbgHostAddr,sizeof(EDBG_ADDR));    
            *ppBufferPool = (UCHAR *)EDBG_PHYSICAL_MEMORY_START + 2*EDBG_DFLT_BUFFER_POOL_SIZE;
            break;            
        default:
            return FALSE;
    }
    return TRUE;
}



BOOL 
ether_KFileTimeToSystemTime(
    const FILETIME *lpft, 
    LPSYSTEMTIME lpst
    )
{
    DWORD dwBase;
	ULONG Minutes;
	ULONG Seconds;

    //
    // Take 32-bits of the 64 that we care about. New counter rate is 78125/sec.
    //
    dwBase = ((lpft->dwHighDateTime << 25) & 0xFE000000) |
             ((lpft->dwLowDateTime  >>  7) & 0x01FFFFFF);

	Seconds = dwBase / 78125;
    lpst->wSecond = (WORD)(Seconds % 60);
    
    Minutes = Seconds / 60;
    lpst->wMinute = (WORD)(Minutes % 60);
    
    lpst->wHour = (WORD)(Minutes / 60);
    
    //
    // Okay to wrap on day. Don't care about milliseconds.
    //
    lpst->wMilliseconds = 0;
    lpst->wYear = 1998;
    lpst->wMonth = 1;
    lpst->wDay = 1;

//    RETAILMSG(1, (TEXT("eKFTTST : %d:%d:%d\r\n"), lpst->wHour, lpst->wMinute, lpst->wSecond));
    return(TRUE);
}



/* OEMEthGetSecs
 *
 *  Return a count of seconds from some arbitrary time (the absolute value is not important,
 *  so long as it increments appropriately).
 */
#define FAKE_ITER    20000      // MUST BE >= 1000
DWORD OEMEthGetSecs( void ) {
    static DWORD dwFakeMSec = FAKE_ITER;
    static BOOL fRTCStarted = FALSE;

    if (!fRTCStarted) {
        if (0 == *pCurMSec) {
            return ++dwFakeMSec / FAKE_ITER;
        }
        fRTCStarted = TRUE;
        dwFakeMSec /= (FAKE_ITER/1000); // serve as the base to keep time continuous
    }

    return (dwFakeMSec + *pCurMSec) / 1000;
}

⌨️ 快捷键说明

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