cfwpc.c
来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C语言 代码 · 共 345 行
C
345 行
/*++
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);
}
#ifdef NOTDEF
if (idInt == SYSINTR_VMINI)
{
DEBUGMSG (1, (TEXT("Accepting VMini interrupt enable request.\r\n")));
return (TRUE);
}
#endif
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 + -
显示快捷键?