Make timer IRQ handler regular builtin interrupt handler instead of
[wine/multimedia.git] / dlls / winedos / timer.c
blob37a038568cfbc8730eb04854dc11ba51e03c52f6
1 /*
2 * 8253/8254 Programmable Interval Timer (PIT) emulation
4 * Copyright 2003 Jukka Heinonen
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
23 #include "dosexe.h"
24 #include "wine/debug.h"
25 #include "wingdi.h"
26 #include "winuser.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(int);
31 * FIXME: Move timer ioport handling here and remove
32 * Dosvm.GetTimer/Dosvm.SetTimer.
33 * FIXME: Use QueryPerformanceCounter for
34 * more precise GetTimer implementation.
35 * FIXME: Use QueryPerformanceCounter (or GetTimer implementation)
36 * in timer tick routine to compensate for lost ticks.
37 * This should also make it possible to
38 * emulate really fast timers.
39 * FIXME: Support special timer modes in addition to periodic mode.
40 * FIXME: Make sure that there are only limited number
41 * of pending timer IRQ events queued. This makes sure that
42 * timer handling does not eat all available memory even
43 * if IRQ handling stops for some reason (suspended process?).
44 * This is easy to do by using DOSRELAY parameter.
45 * FIXME: Use timeSetEvent, NtSetEvent or timer thread for more precise
46 * timing.
47 * FIXME: Move Win16 timer emulation code here.
50 /* The PC clocks ticks at 1193180 Hz. */
51 #define TIMER_FREQ 1193180
53 /* Unique system timer identifier. */
54 static UINT_PTR TIMER_id = 0;
56 /* Time when timer IRQ was last queued. */
57 static DWORD TIMER_stamp = 0;
59 /* Timer ticks between timer IRQs. */
60 static UINT TIMER_ticks = 0;
63 /***********************************************************************
64 * TIMER_TimerProc
66 static void CALLBACK TIMER_TimerProc( HWND hwnd,
67 UINT uMsg,
68 UINT_PTR idEvent,
69 DWORD dwTime )
71 TIMER_stamp = dwTime;
72 DOSVM_QueueEvent( 0, DOS_PRIORITY_REALTIME, NULL, NULL );
76 /***********************************************************************
77 * TIMER_DoSetTimer
79 static void WINAPI TIMER_DoSetTimer( ULONG_PTR arg )
81 INT millis = MulDiv( arg, 1000, TIMER_FREQ );
83 /* sanity check - too fast timer */
84 if (millis < 1)
85 millis = 1;
87 TRACE_(int)( "setting timer tick delay to %d ms\n", millis );
89 if (TIMER_id)
90 KillTimer( NULL, TIMER_id );
92 TIMER_id = SetTimer( NULL, 0, millis, TIMER_TimerProc );
93 TIMER_stamp = GetTickCount();
94 TIMER_ticks = arg;
98 /***********************************************************************
99 * GetTimer (WINEDOS.@)
101 UINT WINAPI DOSVM_GetTimer( void )
103 if (!DOSVM_IsWin16())
105 DWORD millis = GetTickCount() - TIMER_stamp;
106 INT ticks = MulDiv( millis, TIMER_FREQ, 1000 );
108 /* sanity check - tick wrap or suspended process or update race */
109 if (ticks < 0 || ticks >= TIMER_ticks)
110 ticks = 0;
112 return ticks;
115 return 0;
119 /***********************************************************************
120 * SetTimer (WINEDOS.@)
122 void WINAPI DOSVM_SetTimer( UINT ticks )
124 if (!DOSVM_IsWin16())
125 MZ_RunInThread( TIMER_DoSetTimer, ticks );
129 /***********************************************************************
130 * DOSVM_Int08Handler
132 * DOS interrupt 08h handler (IRQ0 - TIMER).
134 void WINAPI DOSVM_Int08Handler( CONTEXT86 *context )
136 BIOSDATA *bios_data = BIOS_DATA;
137 CONTEXT86 nested_context = *context;
138 FARPROC16 int1c_proc = DOSVM_GetRMHandler( 0x1c );
140 nested_context.SegCs = SELECTOROF(int1c_proc);
141 nested_context.Eip = OFFSETOF(int1c_proc);
144 * Update BIOS ticks since midnight.
146 * FIXME: What to do when number of ticks exceeds ticks per day?
148 bios_data->Ticks++;
151 * If IRQ is called from protected mode, convert
152 * context into VM86 context. Stack is invalidated so
153 * that DPMI_CallRMProc allocates a new stack.
155 if (!ISV86(&nested_context))
157 nested_context.EFlags |= V86_FLAG;
158 nested_context.SegSs = 0;
162 * Call interrupt 0x1c.
164 DPMI_CallRMProc( &nested_context, NULL, 0, TRUE );
166 DOSVM_AcknowledgeIRQ( context );