fwpc.c
来自「WinCE 3.0 BSP, 包含Inter SA1110, Intel_815」· C语言 代码 · 共 470 行
C
470 行
/*++
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:
Functions:
Notes:
--*/
#include <windows.h>
#include <bldver.h>
#include "nkintr.h"
#include "pc.h"
#include "timer.h"
// AMC CodeTEST
#ifdef WINCECODETEST
//#include "x86.h"
#ifndef __CT__
#include "ct.h"
#endif
#ifndef __CT_CE__
#include "ct_ce.h"
#endif
//-------------
// EXTERNALS
//-------------
// cannot include tagimports.h here because the ports need to be
// defined as unsigned long, not __declspec(dllexport)
extern volatile UINT32 *amc_ctrl_port;
extern volatile UINT32 *amc_data_port;
#endif //end of WINCECODETEST
#define Naked void __declspec(naked)
extern int (*PProfileInterrupt)(void);
#if (CE_MAJOR_VER == 0x0003)
extern volatile DWORD DiffMSec;
#endif
extern volatile DWORD CurMSec;
extern volatile LARGE_INTEGER CurTicks;
extern UCHAR MapIntr2Sysintr[INTR_MAXIMUM+1];
extern void KernelInitialize();
UCHAR PICGetCurrentInterrupt();
//
// Suspend handling
//
UCHAR GetPICInterruptMask(BOOL fMaster);
BOOL SetPICInterruptMask(BOOL fMaster, UCHAR ucMask);
UCHAR __inline READ_PORT_UCHAR(PUCHAR port)
{
return _inp((USHORT)port);
}
VOID __inline WRITE_PORT_UCHAR(PUCHAR port, UCHAR value)
{
_outp((USHORT)port, (value));
}
//
// Warm reset handling
//
DWORD dwRebootAddress;
void RebootHandler();
void OEMNMIHandler(void) {
}
Naked StartUp() {
__asm {
cli
jmp KernelInitialize
}
}
//
// This routine is invoked when the OFF button is pressed. It is responsible
// for any final power off state and putting the cpu into standby.
//
// Entry none
// Exit none
void OEMPowerOff(void) {
#ifdef NOTDEF
// NOTE : This bit of code will reboot the system. Some people build this way
// so that they can do a soft reboot simply by choosing suspend from the run menu.
__asm {
cli ; Disable Interrupts
mov al, 0FEh ; Reset CPU
out 064h, al
jmp near $ ; Should not get here
}
#endif
UCHAR ucOldMasterMask, ucOldSlaveMask;
INTERRUPTS_OFF();
//
// Disable all the system interrupt, except keyboard and mouse
//
ucOldMasterMask = GetPICInterruptMask(TRUE);
ucOldSlaveMask = GetPICInterruptMask(FALSE);
SetPICInterruptMask( TRUE, ~( (1<<INTR_KEYBOARD) | (1<<INTR_PIC2) ) );
SetPICInterruptMask( FALSE, ~( 1<<(INTR_MOUSE-8) ) );
__asm {
sti
hlt
cli
}
//
// We're awake! The wake-up ISR has already run.
//
// Restore old interrupt masks
SetPICInterruptMask(TRUE, ucOldMasterMask);
SetPICInterruptMask(FALSE, ucOldSlaveMask);
INTERRUPTS_ON();
}
// local version of PerfCountSinceTick that is callable from within PeRPISR()
DWORD _PerfCountSinceTick(void)
{
WORD wCurCount;
__asm {
TRY_LATCHING_AGAIN:
pushfd ; Save interrupt state
cli
in al,40h ; clear latches, in case they are loaded
in al,40h ;
mov al,11000010b ;latch status and count of counter 0
out 43h,al
in al,40h ; read status
shl eax, 16 ; move into high side of eax
in al,40h ; read counter 0 lsb
mov ah,al
in al,40h ; read msb
xchg ah, al ; Get them in the right order
mov wCurCount, ax
shr eax, 16 ; get the status back into al
popfd ; Restore interrupt state
test al, 40h ; did the latch operation fail?
jne TRY_LATCHING_AGAIN ; if so, just do it again
}
//
// Note : this is a countdown timer, not count up.
//
return TIMER_COUNT - wCurCount;
}
// PeRP interrupt service routine.
//
// This routine decode the various status registers on the PeRP to
// determine the cause of an interrupt and dispatches to the appropriate
// handler for that interrupt.
//
// Registers: v0, AT, a0-a3 available for use.
//
// Entry (a0) = 8 (hw interrupt 2)
// (a1) = ptr to apvIntrData array
// Exit (v0) = interrupt dispostion information
// (see nkintr.h for values)
#if (CE_MAJOR_VER == 0x0003)
extern DWORD ticksleft, dwSleepMin, dwPreempt;
#else
extern DWORD dwReschedTime;
#endif
extern BOOL fIntrTime;
extern DWORD dwIntrTimeIsr1;
extern DWORD dwIntrTimeIsr2;
extern DWORD dwIntrTimeNumInts;
extern DWORD dwIntrTimeCountdown;
extern DWORD dwIntrTimeCountdownRef;
extern DWORD dwIntrTimeSPC;
ULONG PeRPISR(void) {
ULONG ulRet = SYSINTR_NOP;
UCHAR ucCurrentInterrupt;
// AMC code: ISR entry
#ifdef WINCECODETEST
*amc_ctrl_port = FUNCTION_NORMAL_ENTRY | ISR; // output function entry
//RETAILMSG(1, (TEXT("AMC: ISR Entry, amc_ctrl_port = 0x%x\n"), amc_ctrl_port));
#endif
if (fIntrTime) {
//
// We're doing interrupt timing. Get Time to ISR.
//
#ifdef EXTERNAL_VERIFY
_outp((USHORT)0x80, 0xE1);
#endif
dwIntrTimeIsr1 = _PerfCountSinceTick();
dwIntrTimeNumInts++;
}
ucCurrentInterrupt = PICGetCurrentInterrupt();
if (ucCurrentInterrupt == INTR_TIMER0) {
if (PProfileInterrupt) {
ulRet= PProfileInterrupt();
} else {
#ifdef SYSTIMERLED
static BYTE bTick;
_outp((USHORT)0x80, bTick++);
#endif
CurMSec += SYSTEM_TICK_MS;
#if (CE_MAJOR_VER == 0x0003)
DiffMSec += SYSTEM_TICK_MS;
#endif
CurTicks.QuadPart += TIMER_COUNT;
if (fIntrTime) {
//
// We're doing interrupt timing. Every nth tick is a SYSINTR_TIMING.
//
dwIntrTimeCountdown--;
if (dwIntrTimeCountdown == 0) {
dwIntrTimeCountdown = dwIntrTimeCountdownRef;
dwIntrTimeNumInts = 0;
#ifdef EXTERNAL_VERIFY
_outp((USHORT)0x80, 0xE2);
#endif
dwIntrTimeIsr2 = _PerfCountSinceTick();
ulRet = SYSINTR_TIMING;
} else {
#if (CE_MAJOR_VER == 0x0003)
if (ticksleft || (dwSleepMin && (dwSleepMin <= DiffMSec)) || (dwPreempt && (dwPreempt <= DiffMSec)))
#else
if ((int) (CurMSec - dwReschedTime) >= 0)
#endif
ulRet = SYSINTR_RESCHED;
}
} else {
#if (CE_MAJOR_VER == 0x0003)
if (ticksleft || (dwSleepMin && (dwSleepMin <= DiffMSec)) || (dwPreempt && (dwPreempt <= DiffMSec)))
#else
if ((int) (CurMSec - dwReschedTime) >= 0)
#endif
ulRet = SYSINTR_RESCHED;
}
}
//
// Check if a reboot was requested.
//
if (dwRebootAddress) {
RebootHandler();
}
} else if (ucCurrentInterrupt == INTR_RTC) {
UCHAR cStatusC;
// Check to see if this was an alarm interrupt
cStatusC = CMOS_Read( RTC_STATUS_C);
if((cStatusC & (RTC_SRC_IRQ|RTC_SRC_US)) == (RTC_SRC_IRQ|RTC_SRC_US))
ulRet = SYSINTR_RTC_ALARM;
} else if (ucCurrentInterrupt <= INTR_MAXIMUM) {
// We have a physical interrupt ID, but want to return a SYSINTR_ID
#ifdef WINCECODETEST
// AMC code: check for keyboard
if (ucCurrentInterrupt == 1) {
//RETAILMSG(1, (TEXT("K")));
*amc_ctrl_port = USER_TAG_NORMAL | TAG101;
// AMCPuts("Key pressed");
}
#endif
ulRet = MapIntr2Sysintr[ucCurrentInterrupt];
if (ulRet != 0xFF)
PICEnableInterrupt(ucCurrentInterrupt, FALSE);
else
ulRet = SYSINTR_NOP;
}
if (ucCurrentInterrupt > 7 || ucCurrentInterrupt == -2) {
__asm {
mov al, 020h ; Nonspecific EOI
out 0A0h, al
}
}
__asm {
mov al, 020h ; Nonspecific EOI
out 020h, al
}
#ifdef WINCECODETEST
// AMC code: ISR exit
*amc_ctrl_port = FUNCTION_NORMAL_EXIT | ISR;
//RETAILMSG(1, (TEXT("AMC: ISR Entry\n")));
#endif
return ulRet;
}
void InitPICs(void) {
int i;
__asm {
;
; First do PIC 1
;
mov al, 011h ; Init command 1, cascade & 4th init byte
out 020h, al
jmp short $+2
mov al, 040h ; Init command 2, vector interrupts to 64
out 021h, al
jmp short $+2
mov al, 004h ; Init command 3, slave on IRQ 2
out 021h, al
jmp short $+2
mov al, 001h ; Init command 4, normal EOI
out 021h, al
jmp short $+2
mov al, 00Bh ; Select In Service Register for reads
out 020h, al
mov al, 0FFh ; Start with all interrupts disabled
out 021h, al
;
; Now do PIC 2
;
mov al, 011h ; Init command 1, cascade & 4th init byte
out 0A0h, al
jmp short $+2
mov al, 048h ; Init command 2, vector interrupts to 40
out 0A1h, al
jmp short $+2
mov al, 002h ; Init command 3, slave on IRQ 2
out 0A1h, al
jmp short $+2
mov al, 001h ; Init command 4, normal EOI
out 0A1h, al
mov al, 00Bh ; Select In Service Register for reads
out 0A0h, al
mov al, 0FFh ; Start with all interrupts disabled
out 0A1h, al
}
/* Setup the PeRP interrupt handler and enable the PeRP interrupt in the BasePSR */
for (i = 64; i < 80; i++)
HookInterrupt(i, (void *)PeRPISR);
//
// Enable interrupts from cascaded PIC
//
PICEnableInterrupt(INTR_PIC2, TRUE);
}
VOID PICEnableInterrupt(UCHAR ucInterrupt, BOOL bEnabled) {
__asm {
pushfd ; Save interrupt state
cli
mov dx, 021h ; Assume its on PIC 1
mov cl, ucInterrupt
mov ch, 8
cmp cl, ch
jl lbl10
mov dx, 0A1h ; Its actually on PIC 2
sub cl, ch
lbl10:
mov ch, 1 ; Convert interrupt number to bitmask
shl ch, cl
in al, dx ; Get currently enabled interrupts
test bEnabled, 0FFh ; Disable?
jz lbl20 ; Yes
not ch
and al, ch ; Unmask interrupt
jmp short lbl30
lbl20:
or al, ch ; Mask interrupt
lbl30:
out dx, al
popfd ; Restore interrupt state
}
}
UCHAR PICGetCurrentInterrupt() {
UCHAR ucActiveInterrupts;
UCHAR ucCurrentInterrupt;
__asm {
in al, 020h ; Get current interrupt
mov ucActiveInterrupts, al
}
for (ucCurrentInterrupt = 0; ucCurrentInterrupt < 8; ucCurrentInterrupt++)
if (ucActiveInterrupts & (1 << ucCurrentInterrupt))
break;
if (ucCurrentInterrupt == 8)
return (UCHAR)-1; // No interrupts pending on 1st PIC
if (ucCurrentInterrupt == INTR_PIC2) {
__asm {
in al, 0A0h ; Get current interrupt
mov ucActiveInterrupts, al
}
for (ucCurrentInterrupt = 0; ucCurrentInterrupt < 8; ucCurrentInterrupt++)
if (ucActiveInterrupts & (1 << ucCurrentInterrupt))
break;
if (ucCurrentInterrupt == 8)
return (UCHAR)-2; // No interrupts pending on 2nd PIC
ucCurrentInterrupt += 8;
}
return ucCurrentInterrupt;
}
UCHAR GetPICInterruptMask(BOOL fMaster) {
UCHAR ucMask;
UCHAR ucPort = (fMaster)?0x21:0xa1;
__asm {
pushfd
cli
xor dx, dx
mov dl, ucPort
in al, dx
mov ucMask, al
sti
popfd
}
return ucMask;
}
BOOL SetPICInterruptMask(BOOL fMaster, UCHAR ucMask) {
WORD wPort = (fMaster)?0x21:0xa1;
__asm {
pushfd ; Save interrupt state
cli
mov dx, wPort
mov al, ucMask
out dx, al
sti
popfd ; Restore interrupt state
}
return TRUE;
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?