Author: ros-arm-bringup
Date: Fri Jan 8 05:31:19 2010
New Revision: 44991
URL:
http://svn.reactos.org/svn/reactos?rev=44991&view=rev
Log:
- Document and define Timer and System Control Ports (0x43, 0x61) as defined in ISA System
Architecture 3rd Edition and The Undocumented PC.
- Document PIT access modes, channels and operating modes.
- Rewrite HalHandleNMI to use the System Control Port definitions instead of magic values
that were never explained.
- Rewrite HalMakeBeep not to program the PIT with magic hexadecimal values that were not
explained anywhere and seem dubious.
- Fix the PIT frequency to match its correct value of ~1.19318MHz which is what every x86
book states and what Linux and all other operating systems use. This is equivalent to one
third of the NTSC color burst (subcarrier frequency) used on CGA computers for video
output. Previously, the HAL used 1.193167MHz, which is only used by NT and isn't
documented anywhere, and in fact appears to be a typo in the NT sources (a less accurate
way of dividing the NTSC color burst gives 1.19318167MHz). Somehow, the ReactOS developer
of this function must have made the same "typo", by complete coincidence, of
course.
- Rewrite part of HalpInitializeClock to use the new definitions. This function was at
least somewhat documenting the magic values.
Modified:
trunk/reactos/hal/halx86/generic/beep.c
trunk/reactos/hal/halx86/generic/misc.c
trunk/reactos/hal/halx86/generic/timer.c
trunk/reactos/hal/halx86/include/halp.h
Modified: trunk/reactos/hal/halx86/generic/beep.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/generic/beep.c?…
==============================================================================
--- trunk/reactos/hal/halx86/generic/beep.c [iso-8859-1] (original)
+++ trunk/reactos/hal/halx86/generic/beep.c [iso-8859-1] Fri Jan 8 05:31:19 2010
@@ -1,10 +1,9 @@
/*
* PROJECT: ReactOS HAL
- * LICENSE: GPL - See COPYING in the top level directory
+ * LICENSE: BSD - See COPYING.ARM in the top level directory
* FILE: hal/halx86/generic/beep.c
* PURPOSE: Speaker support (beeping)
- * PROGRAMMERS: Alex Ionescu (alex.ionescu(a)reactos.org)
- * Eric Kohl (ekohl(a)abo.rhein-zeitung.de)
+ * PROGRAMMERS: ReactOS Portable Systems Group
*/
/* INCLUDES ******************************************************************/
@@ -12,13 +11,6 @@
#include <hal.h>
#define NDEBUG
#include <debug.h>
-
-/* CONSTANTS *****************************************************************/
-
-#define TIMER2 (PUCHAR)0x42
-#define TIMER3 (PUCHAR)0x43
-#define PORT_B (PUCHAR)0x61
-#define CLOCKFREQ 1193167
/* FUNCTIONS *****************************************************************/
@@ -29,42 +21,96 @@
NTAPI
HalMakeBeep(IN ULONG Frequency)
{
- UCHAR Data;
+ SYSTEM_CONTROL_PORT_B_REGISTER SystemControl;
+ TIMER_CONTROL_PORT_REGISTER TimerControl;
ULONG Divider;
+ BOOLEAN Result = FALSE;
- /* Acquire CMOS Lock */
+ //
+ // Acquire CMOS Lock
+ //
HalpAcquireSystemHardwareSpinLock();
- /* Turn the register off */
- Data = READ_PORT_UCHAR(PORT_B);
- WRITE_PORT_UCHAR(PORT_B, Data & 0xFC);
+ //
+ // Turn the timer off by disconnecting its output pin and speaker gate
+ //
+ SystemControl.Bits = __inbyte(SYSTEM_CONTROL_PORT_B);
+ SystemControl.SpeakerDataEnable = FALSE;
+ SystemControl.Timer2GateToSpeaker = FALSE;
+ __outbyte(SYSTEM_CONTROL_PORT_B, SystemControl.Bits);
- /* Check if we have a frequency */
+ //
+ // Check if we have a frequency
+ //
if (Frequency)
{
- /* Set the divider */
- Divider = CLOCKFREQ / Frequency;
+ //
+ // Set the divider
+ //
+ Divider = PIT_FREQUENCY / Frequency;
- /* Check if it's too large */
- if (Divider > 0x10000)
+ //
+ // Check if it's too large
+ //
+ if (Divider <= 0x10000)
{
- /* Fail */
- HalpReleaseCmosSpinLock();
- return FALSE;
+ //
+ // Program the PIT for binary mode
+ //
+ TimerControl.BcdMode = FALSE;
+
+ //
+ // Program the PIT to generate a square wave (Mode 3) on channel 2.
+ // Channel 0 is used for the IRQ0 clock interval timer, and channel
+ // 1 is used for DRAM refresh.
+ //
+ // Mode 2 gives much better accuracy, but generates an output signal
+ // that drops to low for each input signal cycle at 0.8381 useconds.
+ // This is too fast for the PC speaker to process and would result
+ // in no sound being emitted.
+ //
+ // Mode 3 will generate a high pulse that is a bit longer and will
+ // allow the PC speaker to notice. Additionally, take note that on
+ // channel 2, when input goes low the counter will stop and output
+ // will go to high.
+ //
+ TimerControl.OperatingMode = PitOperatingMode3;
+ TimerControl.Channel = PitChannel2;
+
+ //
+ // Set the access mode that we'll use to program the reload value.
+ //
+ TimerControl.AccessMode = PitAccessModeLowHigh;
+
+ //
+ // Now write the programming bits
+ //
+ __outbyte(TIMER_CONTROL_PORT, TimerControl.Bits);
+
+ //
+ // Next we write the reload value for channel 2
+ //
+ __outbyte(TIMER_CHANNEL2_DATA_PORT, Divider & 0xFF);
+ __outbyte(TIMER_CHANNEL2_DATA_PORT, Divider >> 8);
+
+ //
+ // Reconnect the speaker to the timer and re-enable the output pin
+ //
+ SystemControl.Bits = __inbyte(SYSTEM_CONTROL_PORT_B);
+ SystemControl.SpeakerDataEnable = TRUE;
+ SystemControl.Timer2GateToSpeaker = TRUE;
+ __outbyte(SYSTEM_CONTROL_PORT_B, SystemControl.Bits);
+ Result = TRUE;
}
-
- /* Set timer divider */
- WRITE_PORT_UCHAR(TIMER3, 0xB6);
- WRITE_PORT_UCHAR(TIMER2, (UCHAR)(Divider & 0xFF));
- WRITE_PORT_UCHAR(TIMER2, (UCHAR)((Divider>>8) & 0xFF));
-
- /* Turn speaker on */
- WRITE_PORT_UCHAR(PORT_B, READ_PORT_UCHAR(PORT_B) | 0x03);
}
- /* Release CMOS lock */
+ //
+ // Release CMOS lock
+ //
HalpReleaseCmosSpinLock();
- /* Return success */
- return TRUE;
+ //
+ // Return success
+ //
+ return Result;
}
Modified: trunk/reactos/hal/halx86/generic/misc.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/generic/misc.c?…
==============================================================================
--- trunk/reactos/hal/halx86/generic/misc.c [iso-8859-1] (original)
+++ trunk/reactos/hal/halx86/generic/misc.c [iso-8859-1] Fri Jan 8 05:31:19 2010
@@ -88,7 +88,7 @@
Cr4 = __readcr4();
//
- // Disable global pit
+ // Disable global bit
//
__writecr4(Cr4 & ~CR4_PGE);
@@ -121,7 +121,7 @@
NTAPI
HalHandleNMI(IN PVOID NmiInfo)
{
- UCHAR NmiStatus;
+ SYSTEM_CONTROL_PORT_B_REGISTER SystemControl;
//
// Don't recurse
@@ -129,9 +129,9 @@
if (HalpNMIInProgress++) while (TRUE);
//
- // Get the NMI Flag
- //
- NmiStatus = READ_PORT_UCHAR((PUCHAR)0x61);
+ // Read the system control register B
+ //
+ SystemControl.Bits = __inbyte(SYSTEM_CONTROL_PORT_B);
//
// Switch to boot vieo
@@ -161,29 +161,29 @@
//
// Display NMI failure string
//
- HalDisplayString("\n*** Hardware Malfunction\n\n");
- HalDisplayString("Call your hardware vendor for support\n\n");
+ InbvDisplayString("\n*** Hardware Malfunction\n\n");
+ InbvDisplayString("Call your hardware vendor for support\n\n");
//
// Check for parity error
//
- if (NmiStatus & 0x80)
+ if (SystemControl.ParityCheck)
{
//
// Display message
//
- HalDisplayString("NMI: Parity Check / Memory Parity Error\n");
+ InbvDisplayString("NMI: Parity Check / Memory Parity Error\n");
}
//
// Check for I/O failure
//
- if (NmiStatus & 0x40)
+ if (SystemControl.ChannelCheck)
{
//
// Display message
//
- HalDisplayString("NMI: Channel Check / IOCHK\n");
+ InbvDisplayString("NMI: Channel Check / IOCHK\n");
}
//
@@ -200,12 +200,12 @@
//
// Halt the system
//
- HalDisplayString("\n*** The system has halted ***\n");
+ InbvDisplayString("\n*** The system has halted ***\n");
//
// Enter the debugger if possible
//
- //if (!KdDebuggerNotPresent && KdDebuggerEnabled) KeEnterKernelDebugger();
+ //if (!(KdDebuggerNotPresent) && (KdDebuggerEnabled))
KeEnterKernelDebugger();
//
// Freeze the system
Modified: trunk/reactos/hal/halx86/generic/timer.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/generic/timer.c…
==============================================================================
--- trunk/reactos/hal/halx86/generic/timer.c [iso-8859-1] (original)
+++ trunk/reactos/hal/halx86/generic/timer.c [iso-8859-1] Fri Jan 8 05:31:19 2010
@@ -49,6 +49,7 @@
ULONG Increment;
USHORT RollOver;
ULONG_PTR Flags;
+ TIMER_CONTROL_PORT_REGISTER TimerControl;
/* Check the CPU Type */
if (Prcb->CpuType <= 4)
@@ -59,7 +60,7 @@
}
/* Get increment and rollover for the largest time clock ms possible */
- Increment= HalpRolloverTable[HalpLargestClockMS - 1].HighPart;
+ Increment = HalpRolloverTable[HalpLargestClockMS - 1].HighPart;
RollOver = (USHORT)HalpRolloverTable[HalpLargestClockMS - 1].LowPart;
/* Set the maximum and minimum increment with the kernel */
@@ -69,11 +70,37 @@
/* Disable interrupts */
Flags = __readeflags();
_disable();
+
+ //
+ // Program the PIT for binary mode
+ //
+ TimerControl.BcdMode = FALSE;
- /* Set the rollover */
- __outbyte(TIMER_CONTROL_PORT, TIMER_SC0 | TIMER_BOTH | TIMER_MD2);
- __outbyte(TIMER_DATA_PORT0, RollOver & 0xFF);
- __outbyte(TIMER_DATA_PORT0, RollOver >> 8);
+ //
+ // Program the PIT to generate a normal rate wave (Mode 3) on channel 0.
+ // Channel 0 is used for the IRQ0 clock interval timer, and channel
+ // 1 is used for DRAM refresh.
+ //
+ // Mode 2 gives much better accuracy than Mode 3.
+ //
+ TimerControl.OperatingMode = PitOperatingMode2;
+ TimerControl.Channel = PitChannel0;
+
+ //
+ // Set the access mode that we'll use to program the reload value.
+ //
+ TimerControl.AccessMode = PitAccessModeLowHigh;
+
+ //
+ // Now write the programming bits
+ //
+ __outbyte(TIMER_CONTROL_PORT, TimerControl.Bits);
+
+ //
+ // Next we write the reload value for channel 0
+ //
+ __outbyte(TIMER_CHANNEL0_DATA_PORT, RollOver & 0xFF);
+ __outbyte(TIMER_CHANNEL0_DATA_PORT, RollOver >> 8);
/* Restore interrupts if they were previously enabled */
__writeeflags(Flags);
Modified: trunk/reactos/hal/halx86/include/halp.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/hal/halx86/include/halp.h?…
==============================================================================
--- trunk/reactos/hal/halx86/include/halp.h [iso-8859-1] (original)
+++ trunk/reactos/hal/halx86/include/halp.h [iso-8859-1] Fri Jan 8 05:31:19 2010
@@ -16,13 +16,6 @@
#define RTC_REG_A_UIP 0x80
#define RTC_REGISTER_CENTURY 0x32
-/* Timer Registers and Ports */
-#define TIMER_CONTROL_PORT 0x43
-#define TIMER_DATA_PORT0 0x40
-#define TIMER_SC0 0
-#define TIMER_BOTH 0x30
-#define TIMER_MD2 0x4
-
/* Usage flags */
#define IDT_REGISTERED 0x01
#define IDT_LATCHED 0x02
@@ -34,7 +27,106 @@
(((bcd & 0xF0) >> 4) * 10 + (bcd & 0x0F))
#define INT_BCD(int) \
(UCHAR)(((int / 10) << 4) + (int % 10))
-
+
+//
+// Commonly stated as being 1.19318MHz
+//
+// See ISA System Architecture 3rd Edition (Tom Shanley, Don Anderson, John Swindle)
+// P. 471
+//
+// However, the true value is closer to 1.19318181[...]81MHz since this is 1/3rd
+// of the NTSC color subcarrier frequency which runs at 3.57954545[...]45MHz.
+//
+// Note that Windows uses 1.193167MHz which seems to have no basis. However, if
+// one takes the NTSC color subcarrier frequency as being 3.579545 (trimming the
+// infinite series) and divides it by three, one obtains 1.19318167.
+//
+// It may be that the original NT HAL source code introduced a typo and turned
+// 119318167 into 1193167 by ommitting the "18". This is very plausible as the
+// number is quite long.
+//
+#define PIT_FREQUENCY 1193182
+
+//
+// These ports are controlled by the i8254 Programmable Interrupt Timer (PIT)
+//
+#define TIMER_CHANNEL0_DATA_PORT 0x40
+#define TIMER_CHANNEL1_DATA_PORT 0x41
+#define TIMER_CHANNEL2_DATA_PORT 0x42
+#define TIMER_CONTROL_PORT 0x43
+
+//
+// Mode 0 - Interrupt On Terminal Count
+// Mode 1 - Hardware Re-triggerable One-Shot
+// Mode 2 - Rate Generator
+// Mode 3 - Square Wave Generator
+// Mode 4 - Software Triggered Strobe
+// Mode 5 - Hardware Triggered Strobe
+//
+typedef enum _TIMER_OPERATING_MODES
+{
+ PitOperatingMode0,
+ PitOperatingMode1,
+ PitOperatingMode2,
+ PitOperatingMode3,
+ PitOperatingMode4,
+ PitOperatingMode5,
+ PitOperatingMode2Reserved,
+ PitOperatingMode5Reserved
+} TIMER_OPERATING_MODES;
+
+typedef enum _TIMER_ACCESS_MODES
+{
+ PitAccessModeCounterLatch,
+ PitAccessModeLow,
+ PitAccessModeHigh,
+ PitAccessModeLowHigh
+} TIMER_ACCESS_MODES;
+
+typedef enum _TIMER_CHANNELS
+{
+ PitChannel0,
+ PitChannel1,
+ PitChannel2,
+ PitReadBack
+} TIMER_CHANNELS;
+
+typedef union _TIMER_CONTROL_PORT_REGISTER
+{
+ struct
+ {
+ UCHAR BcdMode:1;
+ TIMER_OPERATING_MODES OperatingMode:3;
+ TIMER_ACCESS_MODES AccessMode:2;
+ TIMER_CHANNELS Channel:2;
+ };
+ UCHAR Bits;
+} TIMER_CONTROL_PORT_REGISTER, *PTIMER_CONTROL_PORT_REGISTER;
+
+//
+// See ISA System Architecture 3rd Edition (Tom Shanley, Don Anderson, John Swindle)
+// P. 400
+//
+// This port is controled by the i8255 Programmable Peripheral Interface (PPI)
+//
+#define SYSTEM_CONTROL_PORT_A 0x92
+#define SYSTEM_CONTROL_PORT_B 0x61
+typedef union _SYSTEM_CONTROL_PORT_B_REGISTER
+{
+ struct
+ {
+ UCHAR Timer2GateToSpeaker:1;
+ UCHAR SpeakerDataEnable:1;
+ UCHAR ParityCheckEnable:1;
+ UCHAR ChannelCheckEnable:1;
+ UCHAR RefreshRequest:1;
+ UCHAR Timer2Output:1;
+ UCHAR ChannelCheck:1;
+ UCHAR ParityCheck:1;
+ };
+ UCHAR Bits;
+} SYSTEM_CONTROL_PORT_B_REGISTER, *PSYSTEM_CONTROL_PORT_B_REGISTER;
+
//
// Mm PTE/PDE to Hal PTE/PDE
//