2 * COPYRIGHT: GPL - See COPYING in the top level directory
3 * PROJECT: ReactOS Virtual DOS Machine
5 * PURPOSE: Programmable Interval Timer emulation
6 * PROGRAMMERS: Aleksandar Andrejevic <theflash AT sdf DOT lonestar DOT org>
9 /* INCLUDES *******************************************************************/
18 /* PRIVATE VARIABLES **********************************************************/
20 static PIT_CHANNEL PitChannels
[PIT_CHANNELS
];
21 PPIT_CHANNEL PitChannel2
= &PitChannels
[2];
23 /* PUBLIC FUNCTIONS ***********************************************************/
25 VOID
PitWriteCommand(BYTE Value
)
27 BYTE Channel
= Value
>> 6;
28 BYTE Mode
= (Value
>> 1) & 0x07;
30 /* Check if this is a counter latch command */
31 if (((Value
>> 4) & 3) == 0)
33 PitChannels
[Channel
].LatchSet
= TRUE
;
34 PitChannels
[Channel
].LatchedValue
= PitChannels
[Channel
].CurrentValue
;
38 /* Set the access mode and reset flip-flops */
39 PitChannels
[Channel
].AccessMode
= (Value
>> 4) & 3;
40 PitChannels
[Channel
].Pulsed
= FALSE
;
41 PitChannels
[Channel
].LatchSet
= FALSE
;
42 PitChannels
[Channel
].InputFlipFlop
= FALSE
;
43 PitChannels
[Channel
].OutputFlipFlop
= FALSE
;
54 PitChannels
[Channel
].Mode
= Mode
;
60 PitChannels
[Channel
].Mode
= PIT_MODE_RATE_GENERATOR
;
66 PitChannels
[Channel
].Mode
= PIT_MODE_SQUARE_WAVE
;
72 BYTE
PitReadData(BYTE Channel
)
74 WORD CurrentValue
= PitChannels
[Channel
].CurrentValue
;
75 BYTE AccessMode
= PitChannels
[Channel
].AccessMode
;
77 /* Check if the value was latched */
78 if (PitChannels
[Channel
].LatchSet
)
80 CurrentValue
= PitChannels
[Channel
].LatchedValue
;
82 if (AccessMode
== 1 || AccessMode
== 2)
84 /* The latched value was read as one byte */
85 PitChannels
[Channel
].LatchSet
= FALSE
;
89 /* Use the flip-flop for access mode 3 */
92 AccessMode
= PitChannels
[Channel
].InputFlipFlop
? 1 : 2;
93 PitChannels
[Channel
].InputFlipFlop
= !PitChannels
[Channel
].InputFlipFlop
;
95 /* Check if this was the last read for the latched value */
96 if (!PitChannels
[Channel
].InputFlipFlop
)
98 /* Yes, the latch value was read as two bytes */
99 PitChannels
[Channel
].LatchSet
= FALSE
;
108 return CurrentValue
& 0x00FF;
114 return CurrentValue
>> 8;
118 /* Shouldn't get here */
122 VOID
PitWriteData(BYTE Channel
, BYTE Value
)
124 BYTE AccessMode
= PitChannels
[Channel
].AccessMode
;
126 /* Use the flip-flop for access mode 3 */
127 if (PitChannels
[Channel
].AccessMode
== 3)
129 AccessMode
= PitChannels
[Channel
].InputFlipFlop
? 1 : 2;
130 PitChannels
[Channel
].InputFlipFlop
= !PitChannels
[Channel
].InputFlipFlop
;
138 PitChannels
[Channel
].ReloadValue
&= 0xFF00;
139 PitChannels
[Channel
].ReloadValue
|= Value
;
146 PitChannels
[Channel
].ReloadValue
&= 0x00FF;
147 PitChannels
[Channel
].ReloadValue
|= Value
<< 8;
152 static BYTE WINAPI
PitReadPort(ULONG Port
)
156 case PIT_DATA_PORT(0):
157 case PIT_DATA_PORT(1):
158 case PIT_DATA_PORT(2):
160 return PitReadData(Port
- PIT_DATA_PORT(0));
167 static VOID WINAPI
PitWritePort(ULONG Port
, BYTE Data
)
171 case PIT_COMMAND_PORT
:
173 PitWriteCommand(Data
);
177 case PIT_DATA_PORT(0):
178 case PIT_DATA_PORT(1):
179 case PIT_DATA_PORT(2):
181 PitWriteData(Port
- PIT_DATA_PORT(0), Data
);
187 VOID
PitDecrementCount(DWORD Count
)
191 for (i
= 0; i
< PIT_CHANNELS
; i
++)
193 switch (PitChannels
[i
].Mode
)
195 case PIT_MODE_INT_ON_TERMINAL_COUNT
:
197 /* Decrement the value */
198 if (Count
> PitChannels
[i
].CurrentValue
)
200 /* The value does not reload in this case */
201 PitChannels
[i
].CurrentValue
= 0;
203 else PitChannels
[i
].CurrentValue
-= Count
;
205 /* Did it fall to the terminal count? */
206 if (PitChannels
[i
].CurrentValue
== 0 && !PitChannels
[i
].Pulsed
)
208 /* Yes, raise the output line */
209 if (i
== 0) PicInterruptRequest(0);
210 PitChannels
[i
].Pulsed
= TRUE
;
215 case PIT_MODE_RATE_GENERATOR
:
217 BOOLEAN Reloaded
= FALSE
;
221 if ((Count
> PitChannels
[i
].CurrentValue
)
222 && (PitChannels
[i
].CurrentValue
!= 0))
224 /* Decrease the count */
225 Count
-= PitChannels
[i
].CurrentValue
;
227 /* Reload the value */
228 PitChannels
[i
].CurrentValue
= PitChannels
[i
].ReloadValue
;
235 /* Decrease the value */
236 PitChannels
[i
].CurrentValue
-= Count
;
238 /* Clear the count */
241 /* Did it fall to zero? */
242 if (PitChannels
[i
].CurrentValue
== 0)
244 PitChannels
[i
].CurrentValue
= PitChannels
[i
].ReloadValue
;
250 /* If there was a reload on channel 0, raise IRQ 0 */
251 if ((i
== 0) && Reloaded
) PicInterruptRequest(0);
256 case PIT_MODE_SQUARE_WAVE
:
259 WORD ReloadValue
= PitChannels
[i
].ReloadValue
;
261 /* The reload value must be even */
266 if (((Count
* 2) > PitChannels
[i
].CurrentValue
)
267 && (PitChannels
[i
].CurrentValue
!= 0))
269 /* Decrease the count */
270 Count
-= PitChannels
[i
].CurrentValue
/ 2;
272 /* Reload the value */
273 PitChannels
[i
].CurrentValue
= ReloadValue
;
275 /* Increment the reload count */
280 /* Decrease the value */
281 PitChannels
[i
].CurrentValue
-= Count
* 2;
283 /* Clear the count */
286 /* Did it fall to zero? */
287 if (PitChannels
[i
].CurrentValue
== 0)
289 /* Reload the value */
290 PitChannels
[i
].CurrentValue
= ReloadValue
;
292 /* Increment the reload count */
298 if (ReloadCount
== 0) break;
300 /* Toggle the flip-flop if the number of reloads was odd */
303 PitChannels
[i
].OutputFlipFlop
= !PitChannels
[i
].OutputFlipFlop
;
306 /* Was there any rising edge on channel 0 ? */
307 if (((PitChannels
[i
].OutputFlipFlop
&& (ReloadCount
== 1))
308 || (ReloadCount
> 1))
312 PicInterruptRequest(0);
318 case PIT_MODE_SOFTWARE_STROBE
:
320 // TODO: NOT IMPLEMENTED
324 case PIT_MODE_HARDWARE_ONE_SHOT
:
325 case PIT_MODE_HARDWARE_STROBE
:
327 /* These modes do not work on x86 PCs */
334 DWORD
PitGetResolution(VOID
)
337 DWORD MinReloadValue
= 65536;
339 for (i
= 0; i
< PIT_CHANNELS
; i
++)
341 DWORD ReloadValue
= PitChannels
[i
].ReloadValue
;
344 if (ReloadValue
== 0) ReloadValue
= 65536;
346 if (ReloadValue
< MinReloadValue
) MinReloadValue
= ReloadValue
;
349 /* Return the frequency resolution */
350 return PIT_BASE_FREQUENCY
/ MinReloadValue
;
353 BOOLEAN
PitInitialize(VOID
)
355 /* Register the I/O Ports */
356 RegisterIoPort(PIT_COMMAND_PORT
, NULL
, PitWritePort
);
357 RegisterIoPort(PIT_DATA_PORT(0), PitReadPort
, PitWritePort
);
358 RegisterIoPort(PIT_DATA_PORT(1), PitReadPort
, PitWritePort
);
359 RegisterIoPort(PIT_DATA_PORT(2), PitReadPort
, PitWritePort
);