278 lines
6.0 KiB
C
278 lines
6.0 KiB
C
//#pragma comment(exestr, "$Header: /usr4/winnt/SOURCES/halpcims/src/hal/halsnipm/mips/RCS/xxclock.c,v 1.3 1995/11/02 11:04:33 flo Exp $")
|
||
|
||
/*++
|
||
|
||
Copyright (c) 1993-94 Siemens Nixdorf Informationssysteme AG
|
||
Copyright (c) 1985-94 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
xxclock.c
|
||
|
||
Abstract:
|
||
|
||
|
||
This module implements the function necesssary to change the clock
|
||
interrupt rate.
|
||
|
||
Environment:
|
||
|
||
Kernel mode only.
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "halp.h"
|
||
#include "eisa.h"
|
||
#include "i82C54.h"
|
||
|
||
|
||
//
|
||
// Define global data used to communicate new clock rates to the clock
|
||
// interrupt service routine.
|
||
//
|
||
|
||
ULONG HalpCurrentTimeIncrement;
|
||
ULONG HalpNextTimeIncrement;
|
||
ULONG HalpNewTimeIncrement;
|
||
|
||
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.
|
||
|
||
N.B. This function is only executed on the processor that keeps the
|
||
system time.
|
||
|
||
Arguments:
|
||
|
||
DesiredIncrement - Supplies desired number of 100ns units between clock
|
||
interrupts.
|
||
|
||
Return Value:
|
||
|
||
The actual time increment in 100ns units.
|
||
|
||
--*/
|
||
|
||
{
|
||
|
||
ULONG NewTimeIncrement;
|
||
KIRQL OldIrql;
|
||
|
||
if (DesiredIncrement < MINIMUM_INCREMENT) {
|
||
DesiredIncrement = MINIMUM_INCREMENT;
|
||
}
|
||
if (DesiredIncrement > MAXIMUM_INCREMENT) {
|
||
DesiredIncrement = MAXIMUM_INCREMENT;
|
||
}
|
||
|
||
//
|
||
// 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);
|
||
NewTimeIncrement = DesiredIncrement / MINIMUM_INCREMENT;
|
||
NewTimeIncrement = NewTimeIncrement * MINIMUM_INCREMENT;
|
||
HalpNewTimeIncrement = NewTimeIncrement ;
|
||
KeLowerIrql(OldIrql);
|
||
return NewTimeIncrement;
|
||
}
|
||
|
||
VOID
|
||
HalpProgramIntervalTimer (
|
||
IN ULONG Interval
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called to program the System clock according to the frequency
|
||
required by the specified time increment value.
|
||
|
||
N.B. this information was found in the jenson (ALPHA) HAL
|
||
also valid for MIPS computer ???
|
||
|
||
There are four different rates that are used under NT
|
||
(see page 9-8 of KN121 System Module Programmer's Reference)
|
||
|
||
.976562 ms
|
||
1.953125 ms
|
||
3.90625 ms
|
||
7.8125 ms
|
||
|
||
|
||
Arguments:
|
||
|
||
Interval - Supplies desired number of 100ns units between clock
|
||
interrupts.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
{
|
||
PEISA_CONTROL controlBase = (PEISA_CONTROL)HalpOnboardControlBase;
|
||
ULONG Count;
|
||
TIMER_CONTROL timerControl;
|
||
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);
|
||
|
||
//
|
||
// Start the system clock to interrupt at the desired interval.
|
||
//
|
||
//
|
||
|
||
timerControl.BcdMode = 0;
|
||
timerControl.Mode = TM_SQUARE_WAVE;
|
||
timerControl.SelectByte = SB_LSB_THEN_MSB;
|
||
timerControl.SelectCounter = SELECT_COUNTER_0;
|
||
|
||
//
|
||
// use timer in the onboard PC core
|
||
//
|
||
|
||
Count = TIMER_CLOCK_IN / ( 10000000 / Interval );
|
||
|
||
WRITE_REGISTER_UCHAR(&controlBase->CommandMode1, *((PUCHAR) &timerControl));
|
||
|
||
//
|
||
// Set the system clock timer to the correct frequency.
|
||
//
|
||
|
||
WRITE_REGISTER_UCHAR(&controlBase->Timer1, (UCHAR)Count);
|
||
WRITE_REGISTER_UCHAR(&controlBase->Timer1, (UCHAR)(Count >> 8));
|
||
|
||
KeLowerIrql(OldIrql);
|
||
}
|
||
|
||
|
||
VOID
|
||
HalpProgramExtraTimer (
|
||
IN ULONG Interval
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called to program the second clock generator in a multiprocessor System
|
||
according to the frequency required by the specified Interval value (in 100ns units).
|
||
|
||
|
||
Arguments:
|
||
|
||
Interval - Supplies desired number of 100ns units between clock
|
||
interrupts.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
{
|
||
|
||
volatile PLOCAL_8254 pt = (PLOCAL_8254) PCI_EXTRA_TIMER_ADDR;
|
||
ULONG Count;
|
||
TIMER_CONTROL timerControl;
|
||
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);
|
||
|
||
//
|
||
// Start the system clock to interrupt at the desired interval.
|
||
//
|
||
//
|
||
|
||
timerControl.BcdMode = 0;
|
||
timerControl.Mode = TM_SQUARE_WAVE;
|
||
timerControl.SelectByte = SB_LSB_THEN_MSB;
|
||
timerControl.SelectCounter = SELECT_COUNTER_0;
|
||
|
||
Count = EXTRA_TIMER_CLOCK_IN / (PRE_COUNT * 10000000 / Interval );
|
||
|
||
WRITE_REGISTER_UCHAR( &pt->control, *((PUCHAR) &timerControl));
|
||
WRITE_REGISTER_UCHAR(&(pt->counter0), (UCHAR)Count);
|
||
WRITE_REGISTER_UCHAR(&(pt->counter0), (UCHAR)(Count >> 8));
|
||
|
||
timerControl.BcdMode = 0;
|
||
timerControl.Mode = TM_RATE_GENERATOR;
|
||
timerControl.SelectByte = SB_LSB_THEN_MSB;
|
||
timerControl.SelectCounter = SELECT_COUNTER_2;
|
||
|
||
// the output of counter 2 is hardwired as input to counter 0/1
|
||
// so we use it as a pre-counter
|
||
|
||
WRITE_REGISTER_UCHAR( &pt->control, *((PUCHAR) &timerControl));
|
||
WRITE_REGISTER_UCHAR(&(pt->counter2), (UCHAR)PRE_COUNT);
|
||
WRITE_REGISTER_UCHAR(&(pt->counter2), (UCHAR)(PRE_COUNT >>8));
|
||
|
||
KeLowerIrql(OldIrql);
|
||
|
||
}
|
||
|
||
|
||
VOID
|
||
HalpProgramExtraTimerPciT (
|
||
IN ULONG Interval
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This function is called to program the second clock generator in PCI tower
|
||
according to the frequency required by the specified Interval value (in 100ns units).
|
||
|
||
|
||
Arguments:
|
||
|
||
Interval - Supplies desired number of 100ns units between clock
|
||
interrupts.
|
||
|
||
Return Value:
|
||
|
||
none.
|
||
|
||
--*/
|
||
{
|
||
|
||
KIRQL OldIrql;
|
||
|
||
//Stop the timer
|
||
WRITE_REGISTER_UCHAR(PCI_TOWER_TIMER_CMD_REG,0);
|
||
|
||
//Reset Timer-Count Register
|
||
WRITE_REGISTER_UCHAR(PCI_TOWER_TIMER_COUNT_REG,0);
|
||
|
||
//Set Timer-Value Register in ms
|
||
WRITE_REGISTER_UCHAR(PCI_TOWER_TIMER_VALUE_REG,(UCHAR)(Interval/10000));
|
||
|
||
//Start Timer
|
||
WRITE_REGISTER_UCHAR(PCI_TOWER_TIMER_CMD_REG,1);
|
||
|
||
KeRaiseIrql(HIGH_LEVEL, &OldIrql);
|
||
|
||
KeLowerIrql(OldIrql);
|
||
|
||
}
|