172 lines
3.5 KiB
C
172 lines
3.5 KiB
C
/*++
|
||
|
||
Copyright (c) 1994 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
xxclock.c
|
||
|
||
Abstract:
|
||
|
||
|
||
This module implements the function necesssary to change the clock
|
||
interrupt rate.
|
||
|
||
Author:
|
||
|
||
David N. Cutler (davec) 7-Feb-1994
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "halp.h"
|
||
#include "eisa.h"
|
||
|
||
//
|
||
// Define clock count and time table.
|
||
//
|
||
|
||
typedef struct _COUNT_ENTRY {
|
||
ULONG Count;
|
||
ULONG Time;
|
||
} COUNT_ENTRY, *PCOUNT_ENTRY;
|
||
|
||
COUNT_ENTRY TimeTable[] = {
|
||
{1197, 10032},
|
||
{2394, 20064},
|
||
{3591, 30096},
|
||
{4767, 39952},
|
||
{5964, 49984},
|
||
{7161, 60016},
|
||
{8358, 70048},
|
||
{9555, 80080},
|
||
{10731, 89936},
|
||
{11928, 99968}
|
||
};
|
||
|
||
//
|
||
// Define global data used to communicate new clock rates to the clock
|
||
// interrupt service routine.
|
||
//
|
||
|
||
ULONG HalpCurrentTimeIncrement;
|
||
ULONG HalpNextIntervalCount;
|
||
ULONG HalpNextTimeIncrement;
|
||
ULONG HalpNewTimeIncrement;
|
||
|
||
VOID
|
||
HalpProgramIntervalTimer(
|
||
IN ULONG IntervalCount
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called to program the interval timer. It is used during
|
||
Phase 1 initialization to start the heartbeat timer. It also used by
|
||
the clock interrupt interrupt routine to change the hearbeat timer rate
|
||
when a call to HalSetTimeIncrement has been made in the previous time slice.
|
||
|
||
Arguments:
|
||
|
||
IntervalCount - Supplies cound value to be placed in the timer/counter.
|
||
|
||
Return Value:
|
||
|
||
None
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
PEISA_CONTROL controlBase;
|
||
TIMER_CONTROL timerControl;
|
||
|
||
//
|
||
// Set the system clock timer to the correct mode.
|
||
//
|
||
|
||
timerControl.BcdMode = 0;
|
||
timerControl.Mode = TM_SQUARE_WAVE;
|
||
timerControl.SelectByte = SB_LSB_THEN_MSB;
|
||
timerControl.SelectCounter = SELECT_COUNTER_0;
|
||
|
||
controlBase = HalpEisaControlBase;
|
||
|
||
WRITE_REGISTER_UCHAR(&controlBase->CommandMode1, *((PUCHAR) &timerControl));
|
||
|
||
//
|
||
// Set the system clock timer to the correct frequency.
|
||
//
|
||
|
||
WRITE_REGISTER_UCHAR(&controlBase->Timer1, (UCHAR)IntervalCount);
|
||
WRITE_REGISTER_UCHAR(&controlBase->Timer1, (UCHAR)(IntervalCount >> 8));
|
||
}
|
||
|
||
ULONG
|
||
HalSetTimeIncrement (
|
||
IN ULONG DesiredIncrement
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called to set the clock interrupt rate to the frequency
|
||
required by the specified time increment value.
|
||
|
||
Arguments:
|
||
|
||
DesiredIncrement - Supplies desired number of 100ns units between clock
|
||
interrupts.
|
||
|
||
Return Value:
|
||
|
||
The actual time increment in 100ns units.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
ULONG Index;
|
||
KIRQL OldIrql;
|
||
|
||
//
|
||
// Raise IRQL to the highest level, set the new clock interrupt
|
||
// parameters, lower IRQl, and return the new time increment value.
|
||
//
|
||
|
||
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
||
|
||
//
|
||
// The new clock count value is selected from a precomputed table of
|
||
// count/time pairs. The values in the table were selected for their
|
||
// accuracy and closeness to the values of 1ms, 2ms, 3ms, etc. to 10ms.
|
||
//
|
||
// N.B. The NT executive guarantees that this function will never
|
||
// be called with the desired incrment less than the minimum
|
||
// increment or greater than the maximum increment.
|
||
//
|
||
|
||
for (Index = 0; Index < sizeof(TimeTable) / sizeof(COUNT_ENTRY); Index += 1) {
|
||
if (DesiredIncrement <= TimeTable[Index].Time) {
|
||
break;
|
||
}
|
||
}
|
||
|
||
if (DesiredIncrement < TimeTable[Index].Time) {
|
||
Index -= 1;
|
||
}
|
||
|
||
HalpNextIntervalCount = TimeTable[Index].Count;
|
||
HalpNewTimeIncrement = TimeTable[Index].Time;
|
||
KeLowerIrql(OldIrql);
|
||
return TimeTable[Index].Time;
|
||
}
|