halether.c

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

C
960
字号
/*++
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.
Copyright (c) 1995-2000 Microsoft Corporation.  All rights reserved.

Module Name:  
    halether.c
    
Abstract:

    Platform specific code for debug ethernet services (debug messages,
    kernel debugger, text shell (PPSH)).  These functions are all called
    from ethdbg.lib.  They are non-preemptible, and cannot make any system calls.

Functions:


Notes: 

--*/
#include <windows.h>
#include <nkintr.h>
#include <ethdbg.h>
#include <halether.h>
#include <drv_glob.h>
#include <platform.h>
#include <oalintr.h>
#ifdef KITL
#include <kitl.h>
#endif

#undef IMGSHAREETH	// VMini not in Cedar.

#define pDriverGlobals  ((PDRIVER_GLOBALS) DRIVER_GLOBALS_PHYSICAL_MEMORY_START)
extern HARP_BOOT_ARGS *pBootArgs;

//
// Function pointers to the support library functions of the currently installed
// debug ethernet controller.
//
PFN_EDBG_INIT				pfnEDbgInit;
PFN_EDBG_ENABLE_INTS			pfnEDbgEnableInts;
PFN_EDBG_DISABLE_INTS			pfnEDbgDisableInts;
PFN_EDBG_GET_PENDING_INTS		pfnEDbgGetPendingInts;
PFN_EDBG_GET_FRAME			pfnEDbgGetFrame;
PFN_EDBG_SEND_FRAME			pfnEDbgSendFrame;
PFN_EDBG_READ_EEPROM			pfnEDbgReadEEPROM;
PFN_EDBG_WRITE_EEPROM			pfnEDbgWriteEEPROM;
PFN_EDBG_SET_OPTIONS			pfnEDbgSetOptions;
#if IMGSHAREETH
PFN_EDBG_CURRENT_PACKET_FILTER	        pfnCurrentPacketFilter;
PFN_EDBG_MULTICAST_LIST			pfnMulticastList;
#endif


// Buffer for receiving frames into.  
UCHAR RcvBuf[1500];
extern DWORD EdbgDebugZone;

USHORT wLocalMAC[3];    // Saved copy of the mac address

// Well known DHCP ports for use with UDP
#define DHCP_SERVER_PORT 0x4300
#define DHCP_CLIENT_PORT 0x4400

// 
#define MAX_BOOTME_CNT   20
#define BOOTME_INTERVAL  3

typedef struct vendorid {
    DWORD dwUpperMAC; // first 3 bytes of ethernet address
    char  *szAbbrev;
} VENDORID;

static const VENDORID VendorIds[] = {
    {0x00006E, "AE" }, // Artisoft
    {0x000094, "AS" }, // ASANTE
    {0x0000E8, "AC" }, // Accton Technology
    {0x004005, "LS" }, // LinkSys
    {0x004033, "AD" }, // Addtron Technology
    {0x004092, "ASP"}, // ASP Computer Products
    {0x00800F, "SMC"}, // SMC
    {0x008048, "CPX"}, // Compex
    {0x0080AD, "CN" }, // CNET Technologies
    {0x0080C8, "DL" }, // D-Link
    {0x00A0D2, "AT" }, // Allied TeleSyn
    {0x00C00D, "ALR"}, // Advanced Logic Research
    {0x00C06D, "BR" }, // Boca Research
    {0x00C0DF, "GE" }, // Kye International GENIUS GE2000 series
    {0x00C0F0, "KS" }, // Kingston
    {0x4854E8, "WB" }  // WinBond Electronics Corp
};

#define NUM_VENDORIDS (sizeof(VendorIds)/sizeof(VENDORID))

#define PLATFORM_STRING "ARMINT"

#ifdef IMGSHAREETH
BOOL	bNewFilter = FALSE;		//	User mode --> Kernel mode to set new filter.
DWORD	dwFilter;				//	The filter..

BOOL	bNewMulticast = FALSE;	//	User mode --> Kernel mode for new list
DWORD	dwNoOfEntry;
BOOL	ucMultiAddr[8][6];		//	The new list..  
								//	VMINI assumes 8 multicast list entry..
								//							
#endif

ULONG OEMMapIntLogic2SysIntr(ULONG nLogical);

// NOTE: This function only works if i is greater than 0.
//       It's only used in this file and we know that 
//       we never call it with anything less or equal 0.
//       It must be modified if you need to extended to
//       work on generic integer.
static void
itoa10(
    int i,
    char * a
    )
{
    char * p = a;
    int c = 0;
    int n = i;
    char swap;

    //
    // Build the ascii string in reverse digit order
    //
    while (n) {
        *p = (char)(n % 10) + '0';
        n /= 10;
        p++;
        c++;
    }
    *p = 0;
    c--;

    //
    // Reverse the string in place to correct order
    //
    for (n = 0; n < c; n++, c--) {
        swap = a[n];
        a[n] = a[c];
        a[c] = swap;
    }
}

static DWORD
UpperDWFromMAC(EDBG_ADDR * pAddr)
{
    DWORD ret;

    //
    // The WORDs in wMAC field are in net order, so we need to do some
    // serious shifting around.
    // A hex ethernet address of 12 34 56 78 9a bc is stored in wMAC array as
    // wMAC[0] = 3412, wMAC[1] = 7856, wMAC[2] = bc9a.
    // The 4 byte return value should look like 0x00123456
    //
    ret = (pAddr->wMAC[0] & 0x00ff) << 16;
    ret |= pAddr->wMAC[0] & 0xff00;
    ret |= pAddr->wMAC[1] & 0x00ff;
    return ret;
}

void
CreateDeviceName(EDBG_ADDR *pMyAddr, char *szBuf)
{
    int i;
    DWORD dwUpperMAC = UpperDWFromMAC(pMyAddr);

    strcpy(szBuf,PLATFORM_STRING);
    szBuf += strlen(szBuf);

    for (i=0;i<NUM_VENDORIDS;i++) {
        if (dwUpperMAC == VendorIds[i].dwUpperMAC) {
            strcat(szBuf,VendorIds[i].szAbbrev);
            szBuf += strlen(szBuf);
            break;
        }
    }
    itoa10(((pMyAddr->wMAC[2]>>8) | ((pMyAddr->wMAC[2] & 0x00ff) << 8)), szBuf);
}


#define IPSTATE_NONE    0
#define IPSTATE_GOTIP   1
#define IPSTATE_ARP     2
#define IPSTATE_ARPED   3
#define IPSTATE_RETRY   4

#define MAX_DHCP_RETRY  3


/* OEMEthInit
 *
 *  Initialization routine - called from EdbgInit() to perform platform specific
 *  HW init.  The CEPC platform uses either an SMC 91C94 Ethernet controller or
 *  an NE2000 compatible adapter (NSC 8390 ethernet controller).
 *
 *  Return Value:
 *    Return TRUE if init is successful, FALSE if error.
 */
BOOL
OEMEthInit(EDBG_ADAPTER *pAdapter)
{
    BOOL fGotIP=FALSE, fGotJumpimg=FALSE;
    EDBG_ADDR EshellHostAddr;
    EDBG_OS_CONFIG_DATA *pCfgData;
    int BootmeCnt=0;
    DWORD dwSubnetMask;
    DWORD dwNextBootme;  // Time at which to send the next BOOTME
    char szDeviceName[EDBG_MAX_DEV_NAMELEN];
    DWORD dwIPState = IPSTATE_NONE;
    int DHCPRetry=0;
    DWORD DHCPLeaseTime;
    DWORD EdbgFlags = 0;

    memset(&EshellHostAddr,0,sizeof(EDBG_ADDR));

DEBUGMSG(1, (TEXT("+OEMEthInit\r\n")));

    // Some parameters included in boot args for future use, make sure these aren't set
    switch (pBootArgs->ucEdbgAdapterType) {
    case EDBG_ADAPTER_SMC9000:
        pfnEDbgInit           = SMCInit;
        pfnEDbgEnableInts     = SMCEnableInts;     
        pfnEDbgDisableInts    = SMCDisableInts;    
        pfnEDbgGetPendingInts = SMCGetPendingInterrupts; 
        pfnEDbgGetFrame       = SMCGetFrame;       
        pfnEDbgSendFrame      = SMCSendFrame;      
        pfnEDbgReadEEPROM     = SMCReadEEPROM;     
        pfnEDbgWriteEEPROM    = SMCWriteEEPROM;
        pfnEDbgSetOptions     = SMCSetOptions;
#ifdef IMGSHAREETH
	pfnCurrentPacketFilter= NULL;
	pfnMulticastList	  = NULL;
#endif

        EdbgOutputDebugString("INFO: EDBG using SMC9000 controller.\r\n");
        break;

    case EDBG_ADAPTER_NE2000:
        pfnEDbgInit           = NE2000Init;
        pfnEDbgEnableInts     = NE2000EnableInts;     
        pfnEDbgDisableInts    = NE2000DisableInts;    
        pfnEDbgGetPendingInts = NE2000GetPendingInts; 
        pfnEDbgGetFrame       = NE2000GetFrame;       
        pfnEDbgSendFrame      = NE2000SendFrame;      
        pfnEDbgReadEEPROM     = NE2000ReadEEPROM;     
        pfnEDbgWriteEEPROM    = NE2000WriteEEPROM;    
        pfnEDbgSetOptions     = NE2000SetOptions;
#ifdef IMGSHAREETH
	pfnCurrentPacketFilter= Ne2000CurrentPacketFilter;
	pfnMulticastList      = NE2000MulticastList;
#endif

        EdbgOutputDebugString("INFO: EDBG using NE2000 controller.\r\n");
        break;

    default:

        EdbgOutputDebugString("Unsupported debug Ethernet parameters - adapter: %u, IRQ:%u\n",
                              pBootArgs->ucEdbgAdapterType, pBootArgs->ucEdbgIRQ);
        return (FALSE);
    }

    if (!pfnEDbgInit((BYTE *) (VA_PCI_IO_BASE | pBootArgs->dwEdbgBaseAddr),1,pAdapter->Addr.wMAC) )
        return (FALSE);

    // Check the MAC address - this can be invalid if the switches are set wrong.

    if ( !pAdapter->Addr.wMAC[0] && !pAdapter->Addr.wMAC[1] && !pAdapter->Addr.wMAC[2] ) {
        EdbgOutputDebugString("Invalid Ethernet address read from the debug ethernet controller, check switch settings\n");
        return (FALSE);
    }

    // Save out local mac address.
    memcpy ((char *)wLocalMAC, pAdapter->Addr.wMAC, sizeof(wLocalMAC));
    
    EdbgOutputDebugString("Debug Ethernet card initialized, MAC Address:%B:%B:%B:%B:%B:%B\r\n",
                          pAdapter->Addr.wMAC[0] & 0x00FF, pAdapter->Addr.wMAC[0] >> 8,
                          pAdapter->Addr.wMAC[1] & 0x00FF, pAdapter->Addr.wMAC[1] >> 8,
                          pAdapter->Addr.wMAC[2] & 0x00FF, pAdapter->Addr.wMAC[2] >> 8  );

#ifdef IMGSHAREETH 
    VBridgeInit();
    VBridgeKSetLocalMacAddress((char *)wLocalMAC);
#endif


#ifndef KITL
    // Create device name based on Ethernet address
    //
    CreateDeviceName(&pAdapter->Addr, szDeviceName);
    EdbgOutputDebugString("Using device name: %s\n", szDeviceName);
#endif	// !KITL.

    // Fill in our SYSINTR value for the EDBG subsystem. Since we have limited IRQ
    // resources, just run in polled mode unless otherwise configured.
    if ( pBootArgs->ucEdbgIRQ )
    {
        pAdapter->SysIntrVal = OEMMapIntLogic2SysIntr(pBootArgs->ucEdbgIRQ);
        DEBUGMSG(1, (TEXT("INFO: Ethdbg IRQ = 0x%x  SYSINTR = 0x%x\r\n"), pBootArgs->ucEdbgIRQ, pAdapter->SysIntrVal));
    }
    else
#ifndef KITL
        pAdapter->SysIntrVal = EDBG_SYSINTR_NOINTR;
#else
        pAdapter->SysIntrVal = KITL_SYSINTR_NOINTR;
#endif


    // Check the boot parameters to see if our IP address has been configured by 

#ifndef KITL

    // bootloader, or passed in on loadcepc command line.
    //
    if ( pBootArgs->EdbgAddr.dwIP != 0 ) {
        EdbgOutputDebugString("IP address %s passed in boot args, skipping DHCP\n",inet_ntoa(pBootArgs->EdbgAddr.dwIP));
        pAdapter->Addr.dwIP = pBootArgs->EdbgAddr.dwIP;
        fGotIP = TRUE;
        dwIPState = IPSTATE_GOTIP;
    } else {
        // Need to get an IP address, either from DHCP or user input
        if ( EbootInitDHCP(&pAdapter->Addr) ) {
            EdbgOutputDebugString("Error in InitDHCP!\n");
            return (FALSE);
        }
        EdbgOutputDebugString("Wait for DHCP, enter new IP address, or CR to use existing IP:  ");
    }

    if ( pBootArgs->ucLoaderFlags & LDRFL_JUMPIMG ) {
        // Already got config from eshell
        fGotJumpimg = TRUE;
        pAdapter->DHCPLeaseTime = pBootArgs->DHCPLeaseTime;
        pAdapter->EdbgFlags = pBootArgs->EdbgFlags;
    }

    // Loop until we have an IP address and eshell tells us which services are
    // configured for Ethernet
    while ( !fGotJumpimg ) {
        USHORT wLen, wDestPort, wSrcPort, wUDPDataLen, *pwUDPData;

        // Once we get our IP address, periodically send BOOTME commands to eshell.
        switch (dwIPState) {
        case IPSTATE_NONE:
            // We haven't gotten an IP address yet.  Call into DHCP to see if we
            // need to retransmit request, and poll serial port for user input.
            EbootDHCPRetransmit(&pAdapter->Addr,NULL,NULL);
            if (EbootReadSerialIP(&pAdapter->Addr, &dwSubnetMask)) {
                fGotIP = TRUE;
                dwIPState = IPSTATE_GOTIP;
                EdbgFlags |= EDBG_FLAGS_STATIC_IP;
                DHCPLeaseTime = DEFAULT_DHCP_LEASE;
            }
            break;

        case IPSTATE_GOTIP:
            // Send a gratuitous ARP (an ARP of our new IP address) to verify that no other
            // station is using our IP address.
            if (!EbootGratuitousARP(&pAdapter->Addr, RcvBuf)) {
                dwIPState = IPSTATE_ARP;
                dwNextBootme = OEMEthGetSecs(); // use dwNextBootme for ARP timeout 
            } else {
                EdbgOutputDebugString("EbootGratuitousARP failed\r\n");
            }
            break;
        
        case IPSTATE_ARP:
            if ((OEMEthGetSecs() - dwNextBootme) >= ARP_RESPONSE_WAIT) {
                EdbgOutputDebugString("No ARP response in %d seconds, assuming ownership of %s\r\n",
                                      ARP_RESPONSE_WAIT, inet_ntoa(pAdapter->Addr.dwIP));
                dwIPState = IPSTATE_ARPED;
                dwNextBootme = 0;
            }
            break;

        case IPSTATE_ARPED:
            if ((BootmeCnt < MAX_BOOTME_CNT) &&
                ((BootmeCnt == 0) || (OEMEthGetSecs() >= dwNextBootme))) {
                EbootSendBootme(&pAdapter->Addr, 2, 0, PLATFORM_STRING, 
                                szDeviceName,  EDBG_CPU_i486, 0);
                BootmeCnt++;
                dwNextBootme = OEMEthGetSecs() + BOOTME_INTERVAL;
            }
            break;

        case IPSTATE_RETRY:
            pAdapter->Addr.dwIP = 0;
            EbootInitDHCP(&pAdapter->Addr);
            dwIPState = IPSTATE_NONE;
            break;
        }   // switch (dwIPState)

        // Get a frame and pass it to the appropriate handler routine
        wLen = sizeof(RcvBuf);
        if ( pfnEDbgGetFrame(RcvBuf, &wLen) ) {
            // Ethernet frame type is in 7th word of buffer
            USHORT wFrameType = *(USHORT *)(RcvBuf + 6*sizeof(USHORT));

            switch ( ntohs(wFrameType) ) {
            case 0x0806:
                if (EbootProcessARP(&pAdapter->Addr,RcvBuf) == PROCESS_ARP_RESPONSE) {
                    switch (dwIPState) {
                    // Someone has responded to our gratuitous ARP request so they have our IP address.
                    // We need to retry the DHCP request. 
                    case IPSTATE_ARP:
                    case IPSTATE_GOTIP:
                        DHCPRetry++;
                        if (DHCPRetry > MAX_DHCP_RETRY) {
                            EdbgOutputDebugString( "Some other station has IP Address: %s !!! Aborting.\r\n", inet_ntoa(pAdapter->Addr.dwIP));
                            return FALSE;
                        }
            
                        EdbgOutputDebugString( "Some other station has IP Address: %s !!! Retrying.\r\n", inet_ntoa(pAdapter->Addr.dwIP));
                        dwIPState = IPSTATE_RETRY;
                        break;
                    }
                }
                break;

            case 0x0800:
                if ( !EbootCheckUDP(&pAdapter->Addr, RcvBuf, &wDestPort, &wSrcPort, &pwUDPData, &wUDPDataLen) ) {

                    switch (dwIPState) {
                    case IPSTATE_NONE:
                        if ( (wDestPort == DHCP_CLIENT_PORT) && (wSrcPort == DHCP_SERVER_PORT) )
                            EbootProcessDHCP(
                                &pAdapter->Addr,
                                &dwSubnetMask,
                                (BYTE *)pwUDPData,
                                wUDPDataLen,
                                &DHCPLeaseTime,
                                &fGotIP
                                );
                        if (fGotIP) {
                            dwIPState = IPSTATE_GOTIP;
                        }
                        break;

                    case IPSTATE_ARPED:
                        pCfgData = NULL;
                        if ( EbootProcessEDBG(&pAdapter->Addr,&EshellHostAddr,RcvBuf,pwUDPData, wUDPDataLen, &fGotJumpimg, &pCfgData) ) {
                            if ( pCfgData ) {
                                if ( pCfgData->Flags & EDBG_FL_DBGMSG ) {
                                    EdbgOutputDebugString("Enabling debug messages over Ethernet, IP: %s, port:%u\n",
                                                          inet_ntoa(pCfgData->DbgMsgIPAddr),pCfgData->DbgMsgPort);
                                    memcpy(&pBootArgs->DbgHostAddr.wMAC,&EshellHostAddr.wMAC,6);
                                    pBootArgs->DbgHostAddr.dwIP  = pCfgData->DbgMsgIPAddr;
                                    pBootArgs->DbgHostAddr.wPort = pCfgData->DbgMsgPort;
                                }
                                if ( pCfgData->Flags & EDBG_FL_PPSH ) {
                                    EdbgOutputDebugString("Enabling CESH over Ethernet, IP: %s, port:%u\n",
                                                          inet_ntoa(pCfgData->PpshIPAddr),pCfgData->PpshPort);
                                    memcpy(&pBootArgs->CeshHostAddr.wMAC,&EshellHostAddr.wMAC,6);
                                    pBootArgs->CeshHostAddr.dwIP  = pCfgData->PpshIPAddr;
                                    pBootArgs->CeshHostAddr.wPort = pCfgData->PpshPort;
                                }
                                if ( pCfgData->Flags & EDBG_FL_KDBG ) {
                                    EdbgOutputDebugString("Enabling KDBG over Ethernet, IP: %s, port:%u\n",
                                                          inet_ntoa(pCfgData->KdbgIPAddr),pCfgData->KdbgPort);
                                    memcpy(&pBootArgs->KdbgHostAddr.wMAC,&EshellHostAddr.wMAC,6);
                                    pBootArgs->KdbgHostAddr.dwIP  = pCfgData->KdbgIPAddr;
                                    pBootArgs->KdbgHostAddr.wPort = pCfgData->KdbgPort;
                                }
                                pBootArgs->ucEshellFlags = pCfgData->Flags;
                            }
                        }
                        break;
                    }
                }
                break;
            default:
                break;
            }

⌨️ 快捷键说明

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