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 + -
显示快捷键?