| /* |
| * SYSTEM DLL routines |
| * |
| * Copyright 1996 Alexandre Julliard |
| * |
| * This library is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU Lesser General Public |
| * License as published by the Free Software Foundation; either |
| * version 2.1 of the License, or (at your option) any later version. |
| * |
| * This library is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| * Lesser General Public License for more details. |
| * |
| * You should have received a copy of the GNU Lesser General Public |
| * License along with this library; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA |
| */ |
| |
| #include <stdarg.h> |
| |
| #define NONAMELESSUNION |
| |
| #include "windef.h" |
| #include "winbase.h" |
| #include "wine/winbase16.h" |
| #include "wine/winuser16.h" |
| #include "wownt32.h" |
| #include "winternl.h" |
| #include "wine/debug.h" |
| |
| WINE_DEFAULT_DEBUG_CHANNEL(system); |
| |
| typedef struct |
| { |
| FARPROC16 callback16; |
| INT rate; |
| INT ticks; |
| } SYSTEM_TIMER; |
| |
| #define NB_SYS_TIMERS 8 |
| #define SYS_TIMER_RATE 54925 |
| |
| static SYSTEM_TIMER SYS_Timers[NB_SYS_TIMERS]; |
| static int SYS_NbTimers = 0; |
| static HANDLE SYS_timer; |
| static HANDLE SYS_thread; |
| static BOOL SYS_timers_disabled; |
| |
| |
| /*********************************************************************** |
| * SYSTEM_TimerTick |
| */ |
| static void CALLBACK SYSTEM_TimerTick( LPVOID arg, DWORD low, DWORD high ) |
| { |
| int i; |
| |
| if (SYS_timers_disabled) return; |
| for (i = 0; i < NB_SYS_TIMERS; i++) |
| { |
| if (!SYS_Timers[i].callback16) continue; |
| if ((SYS_Timers[i].ticks -= SYS_TIMER_RATE) <= 0) |
| { |
| FARPROC16 proc = SYS_Timers[i].callback16; |
| CONTEXT context; |
| |
| SYS_Timers[i].ticks += SYS_Timers[i].rate; |
| |
| memset( &context, 0, sizeof(context) ); |
| context.SegFs = wine_get_fs(); |
| context.SegGs = wine_get_gs(); |
| context.SegCs = SELECTOROF( proc ); |
| context.Eip = OFFSETOF( proc ); |
| context.Ebp = OFFSETOF(NtCurrentTeb()->WOW32Reserved) + FIELD_OFFSET(STACK16FRAME, bp); |
| context.Eax = i + 1; |
| |
| WOWCallback16Ex( 0, WCB16_REGS, 0, NULL, (DWORD *)&context ); |
| } |
| } |
| } |
| |
| |
| /*********************************************************************** |
| * SYSTEM_TimerThread |
| */ |
| static DWORD CALLBACK SYSTEM_TimerThread( void *dummy ) |
| { |
| LARGE_INTEGER when; |
| |
| if (!(SYS_timer = CreateWaitableTimerA( NULL, FALSE, NULL ))) return 0; |
| |
| when.u.LowPart = when.u.HighPart = 0; |
| SetWaitableTimer( SYS_timer, &when, (SYS_TIMER_RATE+500)/1000, SYSTEM_TimerTick, 0, FALSE ); |
| for (;;) SleepEx( INFINITE, TRUE ); |
| } |
| |
| |
| /********************************************************************** |
| * SYSTEM_StartTicks |
| * |
| * Start the system tick timer. |
| */ |
| static void SYSTEM_StartTicks(void) |
| { |
| if (!SYS_thread) SYS_thread = CreateThread( NULL, 0, SYSTEM_TimerThread, NULL, 0, NULL ); |
| } |
| |
| |
| /********************************************************************** |
| * SYSTEM_StopTicks |
| * |
| * Stop the system tick timer. |
| */ |
| static void SYSTEM_StopTicks(void) |
| { |
| if (SYS_thread) |
| { |
| CancelWaitableTimer( SYS_timer ); |
| TerminateThread( SYS_thread, 0 ); |
| CloseHandle( SYS_thread ); |
| CloseHandle( SYS_timer ); |
| SYS_thread = 0; |
| } |
| } |
| |
| |
| /*********************************************************************** |
| * InquireSystem (SYSTEM.1) |
| * |
| * Note: the function always takes 2 WORD arguments, contrary to what |
| * "Undocumented Windows" says. |
| */ |
| DWORD WINAPI InquireSystem16( WORD code, WORD arg ) |
| { |
| WORD drivetype; |
| WCHAR root[3]; |
| |
| switch(code) |
| { |
| case 0: /* Get timer resolution */ |
| return SYS_TIMER_RATE; |
| |
| case 1: /* Get drive type */ |
| root[0] = 'A' + arg; |
| root[1] = ':'; |
| root[2] = 0; |
| drivetype = GetDriveTypeW( root ); |
| if (drivetype == DRIVE_CDROM) drivetype = DRIVE_REMOTE; |
| else if (drivetype == DRIVE_NO_ROOT_DIR) drivetype = DRIVE_UNKNOWN; |
| return MAKELONG( drivetype, drivetype ); |
| |
| case 2: /* Enable one-drive logic */ |
| FIXME("Case %d: set single-drive %d not supported\n", code, arg ); |
| return 0; |
| } |
| WARN("Unknown code %d\n", code ); |
| return 0; |
| } |
| |
| |
| /*********************************************************************** |
| * CreateSystemTimer (SYSTEM.2) |
| */ |
| WORD WINAPI CreateSystemTimer16( WORD rate, FARPROC16 proc ) |
| { |
| int i; |
| for (i = 0; i < NB_SYS_TIMERS; i++) |
| if (!SYS_Timers[i].callback16) /* Found one */ |
| { |
| SYS_Timers[i].rate = (UINT)rate * 1000; |
| if (SYS_Timers[i].rate < SYS_TIMER_RATE) |
| SYS_Timers[i].rate = SYS_TIMER_RATE; |
| SYS_Timers[i].ticks = SYS_Timers[i].rate; |
| SYS_Timers[i].callback16 = proc; |
| if (++SYS_NbTimers == 1) SYSTEM_StartTicks(); |
| return i + 1; /* 0 means error */ |
| } |
| return 0; |
| } |
| |
| |
| /*********************************************************************** |
| * KillSystemTimer (SYSTEM.3) |
| * |
| * Note: do not confuse this function with USER.182 |
| */ |
| WORD WINAPI SYSTEM_KillSystemTimer( WORD timer ) |
| { |
| if ( !timer || timer > NB_SYS_TIMERS || !SYS_Timers[timer-1].callback16 ) |
| return timer; /* Error */ |
| SYS_Timers[timer-1].callback16 = 0; |
| if (!--SYS_NbTimers) SYSTEM_StopTicks(); |
| return 0; |
| } |
| |
| |
| /*********************************************************************** |
| * EnableSystemTimers (SYSTEM.4) |
| */ |
| void WINAPI EnableSystemTimers16(void) |
| { |
| SYS_timers_disabled = FALSE; |
| } |
| |
| |
| /*********************************************************************** |
| * DisableSystemTimers (SYSTEM.5) |
| */ |
| void WINAPI DisableSystemTimers16(void) |
| { |
| SYS_timers_disabled = TRUE; |
| } |
| |
| |
| /*********************************************************************** |
| * GetSystemMSecCount (SYSTEM.6) |
| */ |
| DWORD WINAPI GetSystemMSecCount16(void) |
| { |
| return GetTickCount(); |
| } |
| |
| |
| /*********************************************************************** |
| * Get80x87SaveSize (SYSTEM.7) |
| */ |
| WORD WINAPI Get80x87SaveSize16(void) |
| { |
| return 94; |
| } |
| |
| |
| /*********************************************************************** |
| * Save80x87State (SYSTEM.8) |
| */ |
| void WINAPI Save80x87State16( char *ptr ) |
| { |
| #ifdef __i386__ |
| __asm__(".byte 0x66; fsave %0; fwait" : "=m" (ptr) ); |
| #endif |
| } |
| |
| |
| /*********************************************************************** |
| * Restore80x87State (SYSTEM.9) |
| */ |
| void WINAPI Restore80x87State16( const char *ptr ) |
| { |
| #ifdef __i386__ |
| __asm__(".byte 0x66; frstor %0" : : "m" (ptr) ); |
| #endif |
| } |
| |
| |
| /*********************************************************************** |
| * A20_Proc (SYSTEM.20) |
| */ |
| void WINAPI A20_Proc16( WORD unused ) |
| { |
| /* this is also a NOP in Windows */ |
| } |