⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 power.c

📁 for power control program for VIA CN700/8
💻 C
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//

//
// Power off/Suspend routines
//

#include <windows.h>
#include <nkintr.h>
#include <oalintr.h>
#include "pc.h"
#include <oal.h>
#include <oal_nkxp.h>
#include "sci.h"
// Add for Power Management  --------Start //
#include <oemwake.h>         //longer add
#define INIT_WAKE            //longer add

BOOL bPowerOff = 0; // 0 Suspend, 1 Power Off, 2 Screen Off


// ------------------------------------End //
extern void VIASystemPowerOff(DWORD dwFlag);
extern BOOL OEMIoControl(DWORD ,LPVOID,DWORD,LPVOID ,DWORD ,LPDWORD);

static UCHAR GetPICInterruptMask(BOOL fMaster);
static BOOL SetPICInterruptMask(BOOL fMaster, UCHAR ucMask);
void OEMPowerOff(void);
//DWORD OEMPowerManagerInit(void);
//
// 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.
//
static CpuSleepX86(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

    __asm {
        sti
        hlt
        cli
    }
}


static 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;
}


static 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;
}

static DWORD dwLastWakeupSource=SYSWAKE_UNKNOWN;

static BYTE fInterruptWakeup[SYSINTR_MAXIMUM];
static BYTE fInterruptWakeupMask[SYSINTR_MAXIMUM];

static void SetInterruptMask(PBYTE pMaster,PBYTE pSlave)
{
    DWORD sysIntr;
    *pMaster=*pSlave=0;
    for (sysIntr = 0; sysIntr < SYSINTR_MAXIMUM; sysIntr++) {
        if (fInterruptWakeupMask[sysIntr]) {
             UINT32 count, *pIrqs, i;
             count = 1;
             if (!OALIntrTranslateSysIntr(sysIntr, &count, &pIrqs)) continue;
             for (i = 0; i < count; i++) {
                 if (pIrqs[i] != -1)  {
                    if (pIrqs[i] < 8) 
                        *pMaster|=(1 << pIrqs[i]);
                    else 
                        *pSlave |=(1 << (pIrqs[i] - 8));
                }
             }                 
        }
    }

}

DWORD OEMPowerManagerInit(void)
{
#ifdef INIT_WAKE
    // OEMPowerOff used to hardcode the keyboard and mouse to wake the system.
    // Device drivers can now tell the OAL to enable/disable it's wake interrupt.
    // Define INIT_WAKE if you want to use the hardcoded values.
    OEMSetWakeupSource(SYSINTR_KEYBOARD);
    OEMSetWakeupSource(SYSINTR_TOUCH);
#endif
    return 0;
}

DWORD OEMSetWakeupSource( DWORD dwSources)
{
    if (dwSources<SYSINTR_MAXIMUM) {
        fInterruptWakeupMask[dwSources]=1;
        return 1;
    } 
    return 0;
}

DWORD OEMResetWakeupSource( DWORD dwSources)
{
    if (dwSources<SYSINTR_MAXIMUM) {
        fInterruptWakeupMask[dwSources]=0;
        return 1;
    } 
    return 0;
}

DWORD OEMGetWakeupSource(void)
{
    return dwLastWakeupSource;
}

void OEMIndicateIntSource(DWORD dwSources)
{
    if (dwSources<SYSINTR_MAXIMUM ) {
        fInterruptWakeup[dwSources]=1;
    }
}

void OEMClearIntSources()
{
    memset(fInterruptWakeup,0,SYSINTR_MAXIMUM);
}

DWORD OEMFindFirstWakeSource()
{
    DWORD dwCount;

    for (dwCount=0;dwCount<SYSINTR_MAXIMUM;dwCount++) {
        if (fInterruptWakeup[dwCount]&& fInterruptWakeupMask[dwCount])
            break;
    }

    return (dwCount == SYSINTR_MAXIMUM) ? SYSWAKE_UNKNOWN : dwCount;
}

BOOL Disable_VIA_AUDIO_DMA()
{
    DWORD dwConfigID, dwDeviceID, dwIOBase;
     

   // scan PCI BUS and look for VT6102/VT6105/8231

    for (dwConfigID = 0x80000000; dwConfigID < 0x80010800; dwConfigID += 0x100) {
        _asm
        {
            mov   eax, dwConfigID
            mov   edx, 0cf8h
            out   dx, eax

            mov   edx, 0cfch
            in    eax, dx
            mov   dwDeviceID, eax
        }
		if (dwDeviceID == 0x30581106)
	{
	   RETAILMSG(1, (TEXT("VIA's 3058 controller is found, disable DMA.\r\n")));
	   _asm
           {
               mov   eax, dwConfigID
               add   eax, 010h
               mov   edx, 0cf8h
               out   dx, eax

               mov   edx, 0cfch
               in    eax, dx
               and   eax, 0fffffffeh
               mov   dwIOBase, eax
                
               mov  edx, dwIOBase     ; VT3058 I/O base address
               add  edx, 01h          ; offset 01h
               mov  al, 40h           ; Terminate SGD read channel
               out  dx, al
                
               mov  edx, dwIOBase     ; VT3058 I/O base address
               add  edx, 11h          ; offset 11h
               mov  al, 40h           ; Terminate SGD write channel
               out  dx, al
                
               mov  edx, dwIOBase     ; VT3058 I/O base address
               add  edx, 21h          ; offset 21h
               mov  al, 40h           ; Terminate FM SGD read channel
               out  dx, al
           }
	}

        if (dwDeviceID == 0x30591106)
	{
	   RETAILMSG(1, (TEXT("VIA's 3059 controller is found, disable DMA.\r\n")));
	   _asm
           {
               mov   eax, dwConfigID
               add   eax, 010h
               mov   edx, 0cf8h
               out   dx, eax

               mov   edx, 0cfch
               in    eax, dx
               and   eax, 0fffffffeh
               mov   dwIOBase, eax
                
               mov  edx, dwIOBase     ; VT3058 I/O base address
               add  edx, 01h          ; offset 01h
               mov  al, 40h           ; Terminate DXS0 SGD 
               out  dx, al
                
               mov  edx, dwIOBase     ; VT3058 I/O base address
               add  edx, 11h          ; offset 11h
               mov  al, 40h           ; Terminate DXS1 SGD 
               out  dx, al
                
               mov  edx, dwIOBase     ; VT3058 I/O base address
               add  edx, 21h          ; offset 21h
               mov  al, 40h           ; Terminate DXS2 SGD 
               out  dx, al
                
               mov  edx, dwIOBase     ; VT3058 I/O base address
               add  edx, 31h          ; offset 31h
               mov  al, 40h           ; Terminate DXS3 SGD
               out  dx, al
                
               mov  edx, dwIOBase     ; VT3058 I/O base address
               add  edx, 41h          ; offset 41h
               mov  al, 40h           ; Terminate Multichannel SGD
               out  dx, al
                
               mov  edx, dwIOBase     ; VT3058 I/O base address
               add  edx, 61h          ; offset 61h
               mov  al, 40h           ; Terminate Write 0 SGD
               out  dx, al
                
               mov  edx, dwIOBase     ; VT3058 I/O base address
               add  edx, 71h          ; offset 71h
               mov  al, 40h           ; Terminate Write 1 SGD
               out  dx, al
            }
            
	}
	}
    return TRUE;
}

/*void OEMPowerOff(void)
{
    BYTE bOldMaster,bOldSlave;
    BYTE bMaster,bSlave;
    DWORD dwWake;
    BOOL fWakePending = FALSE;

    INTERRUPTS_OFF();

    // clear our wake source, which is the reason we are exiting this routine
    dwLastWakeupSource = SYSWAKE_UNKNOWN;
        
    // get the current interrupt mask
    bOldMaster=GetPICInterruptMask(TRUE);
    bOldSlave=GetPICInterruptMask(FALSE);

    // configure the new mask and clear wake source globals
    SetInterruptMask(&bMaster,&bSlave);
    SetPICInterruptMask( TRUE, (UCHAR)~(bMaster| (1<<INTR_PIC2)));
    SetPICInterruptMask( FALSE, (UCHAR)~bSlave );

    do {
       INTERRUPTS_ON();
       // wait for an interrupt that we've enabled as a wake source
       CpuSleepX86();
       INTERRUPTS_OFF();
       // determine what woke us up
       dwWake = OEMFindFirstWakeSource();
    } while (dwWake == SYSWAKE_UNKNOWN);
    
    // restore our interrupt mask
    SetPICInterruptMask(TRUE, bOldMaster);
    SetPICInterruptMask(FALSE, bOldSlave);

    dwLastWakeupSource = dwWake;
    
    INTERRUPTS_ON();
}
*/
void OEMPowerOff(void)
{
    BYTE bOldMaster,bOldSlave;
    BYTE bMaster,bSlave;
    DWORD dwWake;
    BOOL fWakePending = FALSE;
	BYTE btemp;
    int i;
	LPVOID lpInBuf;
    LPVOID lpOutBuf;
    DWORD *lpBytesReturned = (DWORD *)malloc(1);
    RETAILMSG(1,(TEXT("VIAOEMPowerOff")));
	if(bPowerOff == 0)
	{
		// disable audio DMA
		Disable_VIA_AUDIO_DMA();

		INTERRUPTS_OFF();
        OEMIoControl(IOCTL_HAL_SCREENOFF, &lpInBuf, sizeof(lpInBuf), &lpOutBuf, sizeof(lpOutBuf), (LPDWORD)lpBytesReturned);
		// clear our wake source, which is the reason we are exiting this routine
		dwLastWakeupSource=SYSWAKE_UNKNOWN;
        
		// get the current interrupt mask
		bOldMaster=GetPICInterruptMask(TRUE);
		bOldSlave=GetPICInterruptMask(FALSE);

		// suspend if no wake source is pending
		dwWake = OEMFindFirstWakeSource();
		if(dwWake == SYSWAKE_UNKNOWN) {
			// configure the new mask and clear wake source globals
			SetInterruptMask(&bMaster,&bSlave);
			SetPICInterruptMask( TRUE, (UCHAR)~(bMaster| (1<<INTR_PIC2)));
			SetPICInterruptMask( FALSE, (UCHAR)~bSlave );
			// Check output buffer free
			INTERRUPTS_ON();

			// wait for an interrupt that we've enabled as a wake source
			CpuSleepX86();

			INTERRUPTS_OFF();

			// determine what woke us up
			dwWake = OEMFindFirstWakeSource();

			// restore our interrupt mask
			SetPICInterruptMask(TRUE, bOldMaster);
			SetPICInterruptMask(FALSE, bOldSlave);
		}

		dwLastWakeupSource=dwWake;
        OEMIoControl(IOCTL_HAL_SCREENON, &lpInBuf, sizeof(lpInBuf), &lpOutBuf, sizeof(lpOutBuf), (LPDWORD)lpBytesReturned);
		INTERRUPTS_ON();
	}
	else if(bPowerOff == 1)
		OEMIoControl(IOCTL_HAL_POWEROFF, &lpInBuf, sizeof(lpInBuf), &lpOutBuf, sizeof(lpOutBuf), (LPDWORD)lpBytesReturned);
	else
	{
		// disable audio DMA
		Disable_VIA_AUDIO_DMA();

		// turn off screen
		OEMIoControl(IOCTL_HAL_SCREENOFF, &lpInBuf, sizeof(lpInBuf), &lpOutBuf, sizeof(lpOutBuf), (LPDWORD)lpBytesReturned);
		INTERRUPTS_OFF();

		// clear our wake source, which is the reason we are exiting this routine
		dwLastWakeupSource=SYSWAKE_UNKNOWN;
        
		// get the current interrupt mask
		bOldMaster=GetPICInterruptMask(TRUE);
		bOldSlave=GetPICInterruptMask(FALSE);

		// suspend if no wake source is pending
		dwWake = OEMFindFirstWakeSource();
		if(dwWake == SYSWAKE_UNKNOWN) {
			// configure the new mask and clear wake source globals
			/*SetInterruptMask(&bMaster,&bSlave);
			SetPICInterruptMask( TRUE, (UCHAR)~(bMaster| (1<<INTR_PIC2)));
			SetPICInterruptMask( FALSE, (UCHAR)~bSlave );*/
			SetInterruptMask(&bMaster,&bSlave);
			SetPICInterruptMask( TRUE, (UCHAR)~(2 | (1<<INTR_PIC2))/*(UCHAR)~(bMaster| (1<<INTR_PIC2))*/);
			//SetPICInterruptMask( TRUE, (UCHAR)~(bMaster| (1<<INTR_PIC2)));
			SetPICInterruptMask( FALSE, (UCHAR)0xef );
			//SetPICInterruptMask( FALSE, (UCHAR)~bSlave );
			
			// Check output buffer free
			do {
				_asm {
					mov	dx, 64h
					in	al, dx
					jmp	short $+2
					mov	btemp, al
				}
			} while( btemp & 2 );

			// Clear input Buffer
			do {
				_asm {
					mov	dx, 64h
					in	al, dx
					jmp	short $+2
					mov	btemp, al
				}

				if ( btemp & 1 )
					_asm in al, 60h;

				for ( i = 0; i < 0x10000; i++) //??? Loop counts depend on main board and keyboard
				{
					_asm {
						mov	dx, 64h
						in	al, dx
						jmp	short $+2
						mov	btemp, al
					}
                   
					if (btemp & 1)
						break;
				}

			} while(btemp & 1);  

			INTERRUPTS_ON();

			// wait for an interrupt that we've enabled as a wake source
			CpuSleepX86();

			INTERRUPTS_OFF();

			// determine what woke us up
			dwWake = OEMFindFirstWakeSource();

			// restore our interrupt mask
			SetPICInterruptMask(TRUE, bOldMaster);
			SetPICInterruptMask(FALSE, bOldSlave);
		}

		dwLastWakeupSource=dwWake;
    
		INTERRUPTS_ON();

		// turn on screen
		OEMIoControl(IOCTL_HAL_SCREENON, &lpInBuf, sizeof(lpInBuf), &lpOutBuf, sizeof(lpOutBuf), (LPDWORD)lpBytesReturned);
	}
    //VIASystemPowerOff(1);
}


BOOL x86PowerIoctl (
    UINT32 code, VOID *lpInBuf, UINT32 nInBufSize, VOID *lpOutBuf, 
    UINT32 nOutBufSize, UINT32 *lpBytesReturned
) {
    switch (code) {
    case IOCTL_HAL_ENABLE_WAKE:
    case IOCTL_HAL_DISABLE_WAKE:
        if (lpInBuf && nInBufSize == sizeof(DWORD)) {
            DWORD dwReturn =
                ((code==IOCTL_HAL_ENABLE_WAKE)
                ? OEMSetWakeupSource   (*(PDWORD)lpInBuf)
                : OEMResetWakeupSource (*(PDWORD)lpInBuf));
            if (dwReturn)
                return TRUE;
        }
        break;
    case IOCTL_HAL_GET_WAKE_SOURCE:
        if (lpOutBuf && nOutBufSize>=sizeof(DWORD)) {
            *(PDWORD)lpOutBuf=OEMGetWakeupSource();
            if (lpBytesReturned)
                *lpBytesReturned=sizeof(DWORD);
            return TRUE;
        }
        break;
    case IOCTL_HAL_PRESUSPEND:
        OEMClearIntSources();
        return TRUE;
    default:
        break;
    }
    NKSetLastError (ERROR_INVALID_PARAMETER);
    return FALSE;
}

⌨️ 快捷键说明

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