cfwpc.c

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

C
338
字号
/*++
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:  

Abstract:  
   This file implements the NK kernel interfaces for firmware interrupt
  support on the CEPC.
 
Functions:


Notes: 

--*/

#include "windows.h"
#include "nkintr.h"
#include "oalintr.h"
#include "pc.h"
#include <memory.h>

#ifdef WINCECODETEST
// AMC code:
extern void ThreadProcLogInitialize();
#endif
/*
          This defines the HAL layer - OEM and platform dependent pieces of
          code which we expect the OEM to deliver to us. There are three pieces
          of OEM deliverable code  - the bootstrap loader & monitor (for
          debugging), the HAL portions which are interfaces between the kernel
          and the firmware, and the driver interface. This topic covers just
          the HAL portion.

          The philosophy is to keep the HAL layer as simple as possible.  The
          HAL should not be confused with the machine or CPU independence. HAL
          is specific for a particular CPU and platform. It includes interfaces
          for the following devices:<nl>
          Real Time Clock<nl>
          Interval Timer (used for the scheduler operation) <nl>
          Interrupt handlers and support <nl>

          Note that it does not include abstractions for devices like the DMA
          controller etc. since the kernel does not use one. Also note that the
          list could change for different CPU's and platforms - for instance,
          some chips might include a lot of peripheral devices (like the
          interval timer) on the CPU chip itself, removing the need for a
          separate interface for them.

          The interfaces for the real time clock and interval timer are still
          being developed. But they should in general be extremely simple and
          straightforward. For details on the interrupt support model in the
          kernel look at <l Interrupt Support Overview.Kernel Interrupt Support>

    @xref <l Interrupt Support Overview.Kernel Interrupt Support>
          <f OEMInit> <f OEMInterruptEnable> <f OEMInterruptDisable>
          <f OEMInterruptDone> <f HookInterrupt>

 */

UCHAR   MapSysintr2Intr[SYSINTR_MAXIMUM+1];
UCHAR   MapIntr2Sysintr[INTR_MAXIMUM+1];

extern int OEMParallelPortInit(void);
extern void InitDebugEther(void);

extern void InitClock();

extern void InitPICs(void);



// -----------------------------------------------------------------------------
//
//  IsDRAM
//
//  Is there DRAM available at the specified location?  This test must be non-
//  destructive... can't alter the contents except temporarily.
//
// -----------------------------------------------------------------------------
DWORD
IsDRAM(
    DWORD dwMemStartAddr, 
    DWORD dwMaxMemLength
    )
{

#define EXTENSION_CHECK_SIZE 4
#define DRAM_TEST_INTERVAL 0x100000

    DWORD testvect [EXTENSION_CHECK_SIZE] ={0x55aaaa55,0xaa5555aa,12345678,0xf00f4466 };
    DWORD backup   [EXTENSION_CHECK_SIZE];
    DWORD *target;
    BOOL bMismatch= FALSE;
    DWORD length;

    //
    // Make sure we aren't caching this data. That wouldn't be too useful...
    //
    dwMemStartAddr |= 0x20000000;
 
    //
    // Probe each page until we find one that fails
    //
    for (length = 0; (length < dwMaxMemLength) && !bMismatch ; )
    {
        target = (PDWORD) (length + dwMemStartAddr);
        //
        // Save the original data in backup buffer
        //
        memcpy( backup, target, sizeof(testvect) );
        //  
        // Now fill memory from the test vector
        //
        memcpy( target, testvect, sizeof(testvect) );
        //  
        // Now compare memory to the test vector
        //
        if ( memcmp( target, testvect, sizeof(testvect) ) )
            bMismatch = TRUE;
        else
            length += DRAM_TEST_INTERVAL;   // OK, advance our probe pointer        
        //
        // Don't forget to restore the saved data.
        //
        memcpy( target, backup, sizeof(backup) );  
    }
    //
    // Check every 1MB but report 4MB aligned only. All 4MB must be good to pass.
    //
    length &= ~(0x00400000 - 1);
    
    DEBUGMSG(length, (TEXT("OEM Extra DRAM Detected @ base = x%X, size=%d MB \r\n"),
                  dwMemStartAddr, (length >> 20)));
    
    return (length);
}


/*
    @func   void | OEMInit | Initialize Hardware Interfaces
    @rdesc  none
    @comm   OEMInit is called by the kernel after it has performed minimal
        initialization. Interrupts are disabled and the kernel is not
        ready to handle exceptions. The only kernel service available
        to this function is <f HookInterrupt>. This should be used to
        install ISR's for all the hardware interrupts to be handled by
        the firmware. Note that ISR's must be installed for any interrupt
        that is to be routed to a device driver - otherwise the
        <f InterruptInitialize> call from the driver will fail.
    @xref   <l Overview.Windows CE Kernel OEM Interface> <f HookInterrupt>
        <f InterruptInitialize>
*/

extern DWORD MainMemoryEndAddress;

void OEMInit()
{
    // Initialize debug Ethernet hardware and configure kernel services over
    // Ethernet (debug messages, CESH, kernel debugger).
    InitDebugEther();

#ifdef DEBUG
    // Instead of calling OEMWriteDebugString directly, call through exported
    // function pointer.  This will allow these messages to be seen if debug
    // message output is redirected to Ethernet or the parallel port.  Otherwise,
    // lpWriteDebugStringFunc == OEMWriteDebugString.    
    lpWriteDebugStringFunc(TEXT("CEPC Firmware Init\r\n"));

    // this code will fault on a x86 processor that doesn't support the CPUID instruction
    // if you fault here, you will need to remove this code and rewrite the OEMFlushCache() 
    // function (in x86\oeminit.asm) to not use the CPUID instruction
    lpWriteDebugStringFunc(TEXT("Determining if CPUID is a supported instruction.  If system faults,\r\n"));
    lpWriteDebugStringFunc(TEXT("then CPUID is not a supported instruction and the OEMFlushCache()\r\n"));
    lpWriteDebugStringFunc(TEXT("function will need to be rewritten for this platform\r\n"));
    __asm {
        _emit   0fh                     // cpuid instruction
        _emit   0a2h
    }
    lpWriteDebugStringFunc(TEXT("CPUID instruction is supported!\r\n"));
#endif

    OEMParallelPortInit();

    memset(MapSysintr2Intr, 0xFF, sizeof(MapSysintr2Intr));
    memset(MapIntr2Sysintr, 0xFF, sizeof(MapIntr2Sysintr));

#define SETUP_INTERRUPT_MAP(a, b) \
    do \
    { \
        DEBUGCHK(MapSysintr2Intr[a] == 0xFF); \
        DEBUGCHK(MapIntr2Sysintr[b] == 0xFF); \
        MapSysintr2Intr[a] = b; \
        MapIntr2Sysintr[b] = a; \
    } \
    while (0)

    // IRQ0 is timer0, the scheduler tick

    SETUP_INTERRUPT_MAP(SYSINTR_KEYBOARD, 1);
    
    // IRQ2 is the cascade interrupt for the second PIC

    // Serial is particularly confusing, so here's a summary
    // Debugger - 3F8, no interrupts used
    // COM1 - 2F8, interrupt 3
    // COM2 - 3E8, interrupt 4
    // COM3 - 2E8, interrupt 5
    // This would all be much easier if we moved the debugger
    // to COM4, and left CEPC's COM1-3 at the same IOB/IRQ as
    // the PC's COM1-3.  The only reason we leave it is legacy.
    SETUP_INTERRUPT_MAP(SYSINTR_FIRMWARE+3,  3);
    SETUP_INTERRUPT_MAP(SYSINTR_FIRMWARE+4, 4);
    SETUP_INTERRUPT_MAP(SYSINTR_FIRMWARE+5, 5);
    
    // IRQ6 is normally the floppy controller.
    
    // IRQ7 is LPT1, but ppsh doesn't use interrupts.

    // IRQ8 is the real time clock.

    SETUP_INTERRUPT_MAP(SYSINTR_FIRMWARE+9,    9);
    SETUP_INTERRUPT_MAP(SYSINTR_FIRMWARE+10,  10);
    SETUP_INTERRUPT_MAP(SYSINTR_FIRMWARE+11,  11);
    SETUP_INTERRUPT_MAP(SYSINTR_TOUCH,        12);
    
    // IRQ13 is normally the coprocessor
    // IRQ14 is normally the hard disk controller.
    SETUP_INTERRUPT_MAP(SYSINTR_FIRMWARE+14,    14);
    SETUP_INTERRUPT_MAP(SYSINTR_FIRMWARE+15,    15);

#undef SETUP_INTERRUPT_MAP

    InitPICs();
    InitClock();

    //
    // Detect extra RAM.
    //
    if (MainMemoryEndAddress == CEPC_EXTRA_RAM_START)  {
       MainMemoryEndAddress += IsDRAM (MainMemoryEndAddress, CEPC_EXTRA_RAM_SIZE);
    }

#ifdef DEBUG
    lpWriteDebugStringFunc(TEXT("Firmware Init Done.\r\n"));
#endif
#ifdef WINCECODETEST
// AMC code:
// Activate the CodeTEST Hooks
   ThreadProcLogInitialize();
#endif

// Remove this line if you don't plan to support hardware debug registers 
    pKDIoControl = OEMKDIoControl;
}

/*
    @func   BOOL | OEMInterruptEnable | Enable a hardware interrupt
    @rdesc  Returns TRUE if valid interrupt ID or FALSE if invalid ID.
    @comm   This function is called by the Kernel when a device driver
            calls <f InterruptInitialize>. The system is not preemptible when this
            function is called.
    @xref   <l Overview.Windows CE Kernel OEM Interface> <f InterruptInitialize>
*/
BOOL OEMInterruptEnable (
                        DWORD idInt,       // @parm Interrupt ID to be enabled. See
                        //  <l Interrupt ID's.Interrupt ID's>  for a list of possble values.
                        LPVOID pvData,     // @parm ptr to data passed in in the <f InterruptInitialize> call
                        DWORD cbData       // @parm Size of data pointed to be <p pvData>
                        )
{
    UCHAR   ucInterrupt;

    if (idInt == SYSINTR_TIMING) {
        return (TRUE);
    }


    if ( (ucInterrupt = MapSysintr2Intr[idInt]) != 0xFF ) {
        PICEnableInterrupt(ucInterrupt, TRUE);

        return (TRUE);
    }

    return (FALSE);
}

/*
    @func   BOOL | OEMInterruptDisable | Disable a hardware interrupt
    @rdesc  none
    @comm   OEMInterruptDisable is called by the Kernel when a device driver
            calls <f InterruptDisable>. The system is not preemtible when this
            function is called.
    @xref <l Overview.Windows CE Kernel OEM Interface> <f InterruptDisable>
*/

void OEMInterruptDisable(
                        DWORD idInt     // @parm Interrupt ID to be disabled. See <t Interrupt ID's>
                        // for the list of possible values.
                        )
{
    UCHAR   ucInterrupt;

    if ( (ucInterrupt = MapSysintr2Intr[idInt]) != 0xFF ) {
        PICEnableInterrupt(ucInterrupt, FALSE);
    }
}

/*
    @func   BOOL | OEMInterruptDone | Signal completion of interrupt processing
    @rdesc  none
    @comm   OEMInterruptDone is called by the Kernel when a device driver
            calls <f InterruptDone>. The system is not preemtible when this
            function is called.
    @xref   <l Overview.Kernel Interrupt Support> <f InterruptDone>
*/

void OEMInterruptDone(
                     DWORD idInt     // @parm Interrupt ID. See <t Interrupt ID's>
                     // for the list of possible values.
                     )
{
    UCHAR   ucInterrupt;

    if ( (ucInterrupt = MapSysintr2Intr[idInt]) != 0xFF ) {
        PICEnableInterrupt(ucInterrupt, TRUE);
    }
}

BOOL OEMGetExtensionDRAM(LPDWORD lpMemStart, LPDWORD lpMemLen)
{
    return (FALSE); // no extension DRAM
}

⌨️ 快捷键说明

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