summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/haldti/mips/xxclock.c
blob: 27a981d7b792139fc2eb3f0d42a06ad0f543d544 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
/*++

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