From 8bb5ad2bd8c69647a652d8549596cbdb429b442e Mon Sep 17 00:00:00 2001 From: Eric Kohl Date: Sat, 20 Dec 2003 12:35:27 +0000 Subject: [PATCH] - Detect PS/2 Port and Pointer Device (Mouse). - Calculate CPU speed. - Fixed delay counter overrun. svn path=/trunk/; revision=7131 --- freeldr/freeldr/CHANGELOG | 6 + freeldr/freeldr/arch/i386/hardware.c | 287 ++++++++++++++++++++++++++- freeldr/freeldr/arch/i386/hardware.h | 3 + freeldr/freeldr/arch/i386/hwcpu.c | 68 ++++++- freeldr/freeldr/arch/i386/i386cpu.S | 10 + freeldr/freeldr/include/version.h | 4 +- 6 files changed, 363 insertions(+), 15 deletions(-) diff --git a/freeldr/freeldr/CHANGELOG b/freeldr/freeldr/CHANGELOG index 6a48b4fd8c3..0f3e57384c4 100644 --- a/freeldr/freeldr/CHANGELOG +++ b/freeldr/freeldr/CHANGELOG @@ -1,3 +1,9 @@ +Changes in v1.8.19 (12/20/2003) (ekohl) + +- Detect PS/2 Port and Pointer Device (Mouse). +- Calculate CPU speed. +- Fixed delay counter overrun. + Changes in v1.8.18 (12/14/2003) (ekohl) - Detect serial ports and serial pointer devices (Mice/Trackballs) diff --git a/freeldr/freeldr/arch/i386/hardware.c b/freeldr/freeldr/arch/i386/hardware.c index a088019454f..7e2707c0259 100644 --- a/freeldr/freeldr/arch/i386/hardware.c +++ b/freeldr/freeldr/arch/i386/hardware.c @@ -50,6 +50,42 @@ #define MOUSE_TYPE_MOUSESYSTEMS 4 +/* PS2 stuff */ + +/* Controller registers. */ +#define CONTROLLER_REGISTER_STATUS 0x64 +#define CONTROLLER_REGISTER_CONTROL 0x64 +#define CONTROLLER_REGISTER_DATA 0x60 + +/* Controller commands. */ +#define CONTROLLER_COMMAND_READ_MODE 0x20 +#define CONTROLLER_COMMAND_WRITE_MODE 0x60 +#define CONTROLLER_COMMAND_GET_VERSION 0xA1 +#define CONTROLLER_COMMAND_MOUSE_DISABLE 0xA7 +#define CONTROLLER_COMMAND_MOUSE_ENABLE 0xA8 +#define CONTROLLER_COMMAND_TEST_MOUSE 0xA9 +#define CONTROLLER_COMMAND_SELF_TEST 0xAA +#define CONTROLLER_COMMAND_KEYBOARD_TEST 0xAB +#define CONTROLLER_COMMAND_KEYBOARD_DISABLE 0xAD +#define CONTROLLER_COMMAND_KEYBOARD_ENABLE 0xAE +#define CONTROLLER_COMMAND_WRITE_MOUSE_OUTPUT_BUFFER 0xD3 +#define CONTROLLER_COMMAND_WRITE_MOUSE 0xD4 + +/* Controller status */ +#define CONTROLLER_STATUS_OUTPUT_BUFFER_FULL 0x01 +#define CONTROLLER_STATUS_INPUT_BUFFER_FULL 0x02 +#define CONTROLLER_STATUS_SELF_TEST 0x04 +#define CONTROLLER_STATUS_COMMAND 0x08 +#define CONTROLLER_STATUS_UNLOCKED 0x10 +#define CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL 0x20 +#define CONTROLLER_STATUS_GENERAL_TIMEOUT 0x40 +#define CONTROLLER_STATUS_PARITY_ERROR 0x80 +#define AUX_STATUS_OUTPUT_BUFFER_FULL (CONTROLLER_STATUS_OUTPUT_BUFFER_FULL | \ + CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) + +/* Timeout in ms for sending to keyboard controller. */ +#define CONTROLLER_TIMEOUT 250 + typedef struct _CM_INT13_DRIVE_PARAMETER { @@ -122,7 +158,8 @@ __KeStallExecutionProcessor(U32 Loops) VOID KeStallExecutionProcessor(U32 Microseconds) { - __KeStallExecutionProcessor((delay_count * Microseconds) / 1000); + U64 LoopCount = ((U64)delay_count * (U64)Microseconds) / 1000ULL; + __KeStallExecutionProcessor((U32)LoopCount); } @@ -214,7 +251,6 @@ HalpCalibrateStallExecution(VOID) } /* We're finished: Do the finishing touches */ - delay_count /= (MILLISEC / 2); /* Calculate delay_count for 1ms */ } @@ -991,7 +1027,8 @@ DetectSerialPointerPeripheral(HKEY ControllerKey, "Configuration Data", REG_FULL_RESOURCE_DESCRIPTOR, (PU8)&FullResourceDescriptor, - sizeof(CM_FULL_RESOURCE_DESCRIPTOR)); + sizeof(CM_FULL_RESOURCE_DESCRIPTOR) - + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); if (Error != ERROR_SUCCESS) { DbgPrint((DPRINT_HWDETECT, @@ -1016,8 +1053,7 @@ DetectSerialPointerPeripheral(HKEY ControllerKey, static VOID -DetectSerialPorts(HKEY SystemKey, - HKEY BusKey) +DetectSerialPorts(HKEY BusKey) { PCM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor; PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialDescriptor; @@ -1153,6 +1189,230 @@ DetectSerialPorts(HKEY SystemKey, } +static VOID +PS2ControllerWait(VOID) +{ + U32 Timeout; + U8 Status; + + for (Timeout = 0; Timeout < CONTROLLER_TIMEOUT; Timeout++) + { + Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS); + if ((Status & CONTROLLER_STATUS_INPUT_BUFFER_FULL) == 0) + return; + + /* Sleep for one millisecond */ + KeStallExecutionProcessor(1000); + } +} + + +static BOOLEAN +DetectPS2AuxPort(VOID) +{ + U32 Loops; + U8 Scancode; + U8 Status; + + /* Put the value 0x5A in the output buffer using the + * "WriteAuxiliary Device Output Buffer" command (0xD3). + * Poll the Status Register for a while to see if the value really turns up + * in the Data Register. If the KEYBOARD_STATUS_MOUSE_OBF bit is also set + * to 1 in the Status Register, we assume this controller has an + * Auxiliary Port (a.k.a. Mouse Port). + */ + PS2ControllerWait(); + WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_CONTROL, + CONTROLLER_COMMAND_WRITE_MOUSE_OUTPUT_BUFFER); + PS2ControllerWait(); + + /* 0x5A is a random dummy value */ + WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA, + 0x5A); + + for (Loops = 0; Loops < 10; Loops++) + { + Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS); + + if ((Status & CONTROLLER_STATUS_OUTPUT_BUFFER_FULL) != 0) + { + Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA); + if ((Status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) != 0) + { + return TRUE; + } + break; + } + + KeStallExecutionProcessor(10000); + } + + return FALSE; +} + + +static BOOLEAN +DetectPS2AuxDevice(VOID) +{ + U8 Scancode; + U8 Status; + + PS2ControllerWait(); + WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_CONTROL, + CONTROLLER_COMMAND_WRITE_MOUSE); + PS2ControllerWait(); + + /* Identify device */ + WRITE_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA, + 0xF2); + + KeStallExecutionProcessor(10000); + + Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS); + if ((Status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) == 0) + { + return FALSE; + } + + Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA); + if (Scancode != 0xFA) + return FALSE; + + KeStallExecutionProcessor(10000); + + Status = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_STATUS); + if ((Status & CONTROLLER_STATUS_MOUSE_OUTPUT_BUFFER_FULL) == 0) + { + return FALSE; + } + + Scancode = READ_PORT_UCHAR((PUCHAR)CONTROLLER_REGISTER_DATA); + if (Scancode != 0x00) + return FALSE; + + return TRUE; +} + + +static VOID +DetectPS2Mouse(HKEY BusKey) +{ + CM_FULL_RESOURCE_DESCRIPTOR FullResourceDescriptor; + HKEY ControllerKey; + HKEY PeripheralKey; + S32 Error; + + if (DetectPS2AuxPort()) + { + DbgPrint((DPRINT_HWDETECT, "Detected PS2 port\n")); + + /* Create controller key */ + Error = RegCreateKey(BusKey, + "PointerController\\0", + &ControllerKey); + if (Error != ERROR_SUCCESS) + { + DbgPrint((DPRINT_HWDETECT, "Failed to create controller key\n")); + return; + } + DbgPrint((DPRINT_HWDETECT, "Created key: PointerController\\0\n")); + + /* Set 'ComponentInformation' value */ + SetComponentInformation(ControllerKey, + 0x20, + 0, + 0xFFFFFFFF); + + memset(&FullResourceDescriptor, 0, sizeof(CM_FULL_RESOURCE_DESCRIPTOR)); + + /* Initialize resource descriptor */ + FullResourceDescriptor.InterfaceType = Isa; + FullResourceDescriptor.BusNumber = 0; + FullResourceDescriptor.PartialResourceList.Count = 1; + + /* Set Interrupt */ + FullResourceDescriptor.PartialResourceList.PartialDescriptors[0].Type = CmResourceTypeInterrupt; + FullResourceDescriptor.PartialResourceList.PartialDescriptors[0].ShareDisposition = CmResourceShareUndetermined; + FullResourceDescriptor.PartialResourceList.PartialDescriptors[0].Flags = CM_RESOURCE_INTERRUPT_LATCHED; + FullResourceDescriptor.PartialResourceList.PartialDescriptors[0].u.Interrupt.Level = 12; + FullResourceDescriptor.PartialResourceList.PartialDescriptors[0].u.Interrupt.Vector = 12; + FullResourceDescriptor.PartialResourceList.PartialDescriptors[0].u.Interrupt.Affinity = 0xFFFFFFFF; + + /* Set 'Configuration Data' value */ + Error = RegSetValue(ControllerKey, + "Configuration Data", + REG_FULL_RESOURCE_DESCRIPTOR, + (PU8)&FullResourceDescriptor, + sizeof(CM_FULL_RESOURCE_DESCRIPTOR)); + if (Error != ERROR_SUCCESS) + { + DbgPrint((DPRINT_HWDETECT, + "RegSetValue(Configuration Data) failed (Error %u)\n", + (int)Error)); + return; + } + + + if (DetectPS2AuxDevice()) + { + DbgPrint((DPRINT_HWDETECT, "Detected PS2 mouse\n")); + + /* Create peripheral key */ + Error = RegCreateKey(ControllerKey, + "PointerPeripheral\\0", + &PeripheralKey); + if (Error != ERROR_SUCCESS) + { + DbgPrint((DPRINT_HWDETECT, "Failed to create peripheral key\n")); + return; + } + DbgPrint((DPRINT_HWDETECT, "Created key: PointerPeripheral\\0\n")); + + /* Set 'ComponentInformation' value */ + SetComponentInformation(PeripheralKey, + 0x20, + 0, + 0xFFFFFFFF); + + /* Initialize resource descriptor */ + memset(&FullResourceDescriptor, 0, sizeof(CM_FULL_RESOURCE_DESCRIPTOR)); + FullResourceDescriptor.InterfaceType = Isa; + FullResourceDescriptor.BusNumber = 0; + FullResourceDescriptor.PartialResourceList.Count = 0; + + /* Set 'Configuration Data' value */ + Error = RegSetValue(PeripheralKey, + "Configuration Data", + REG_FULL_RESOURCE_DESCRIPTOR, + (PU8)&FullResourceDescriptor, + sizeof(CM_FULL_RESOURCE_DESCRIPTOR) - + sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)); + if (Error != ERROR_SUCCESS) + { + DbgPrint((DPRINT_HWDETECT, + "RegSetValue(Configuration Data) failed (Error %u)\n", + (int)Error)); + return; + } + + /* Set 'Identifier' value */ + Error = RegSetValue(PeripheralKey, + "Identifier", + REG_SZ, + (PU8)"MICROSOFT PS2 MOUSE", + 20); + if (Error != ERROR_SUCCESS) + { + DbgPrint((DPRINT_HWDETECT, + "RegSetValue() failed (Error %u)\n", + (int)Error)); + return; + } + } + } +} + + static VOID DetectIsaBios(HKEY SystemKey, U32 *BusNumber) { @@ -1224,18 +1484,23 @@ DetectIsaBios(HKEY SystemKey, U32 *BusNumber) /* Detect ISA/BIOS devices */ DetectBiosDisks(SystemKey, BusKey); + #if 0 DetectBiosFloppyDisks(SystemKey, BusKey); #endif - DetectSerialPorts(SystemKey, BusKey); + DetectSerialPorts(BusKey); + #if 0 DetectBiosParallelPorts(); - - DetectBiosKeyboard(); - DetectBiosMouse(); #endif +#if 0 + DetectBiosKeyboard(BusKey); +#endif + + DetectPS2Mouse(BusKey); + /* FIXME: Detect more ISA devices */ } @@ -1280,10 +1545,10 @@ DetectHardware(VOID) DbgPrint((DPRINT_HWDETECT, "DetectHardware() Done\n")); -#if 0 +//#if 0 printf("*** System stopped ***\n"); for (;;); -#endif +//#endif } /* EOF */ diff --git a/freeldr/freeldr/arch/i386/hardware.h b/freeldr/freeldr/arch/i386/hardware.h index c56f103aa9f..bde9c37f597 100644 --- a/freeldr/freeldr/arch/i386/hardware.h +++ b/freeldr/freeldr/arch/i386/hardware.h @@ -153,6 +153,8 @@ typedef struct _CM_COMPONENT_INFORMATION /* PROTOTYPES ***************************************************************/ /* hardware.c */ +VOID KeStallExecutionProcessor(U32 Microseconds); + VOID SetComponentInformation(HKEY ComponentKey, U32 Flags, U32 Key, @@ -168,6 +170,7 @@ VOID GetCpuid(U32 Level, U32 *ebx, U32 *ecx, U32 *edx); +U64 RDTSC(VOID); /* i386pnp.S */ U32 PnpBiosSupported(VOID); diff --git a/freeldr/freeldr/arch/i386/hwcpu.c b/freeldr/freeldr/arch/i386/hwcpu.c index 85969e6362d..143d03a5e4a 100644 --- a/freeldr/freeldr/arch/i386/hwcpu.c +++ b/freeldr/freeldr/arch/i386/hwcpu.c @@ -77,6 +77,36 @@ typedef struct _MP_PROCESSOR_ENTRY /* FUNCTIONS ****************************************************************/ +static U32 +GetCpuSpeed(VOID) +{ + U64 Timestamp1; + U64 Timestamp2; + U64 Diff; + + /* Read TSC (Time Stamp Counter) */ + Timestamp1 = RDTSC(); + + /* Wait for 0.1 seconds (= 100 milliseconds = 100000 microseconds)*/ + KeStallExecutionProcessor(100000); + + /* Read TSC (Time Stamp Counter) again */ + Timestamp2 = RDTSC(); + + /* Calculate elapsed time (check for counter overrun) */ + if (Timestamp2 > Timestamp1) + { + Diff = Timestamp2 - Timestamp1; + } + else + { + Diff = Timestamp2 + (((U64)-1) - Timestamp1); + } + + return (U32)(Diff / 100000); +} + + static VOID DetectCPU(HKEY CpuKey, HKEY FpuKey) @@ -92,6 +122,9 @@ DetectCPU(HKEY CpuKey, U32 edx = 0; U32 *Ptr; S32 Error; + BOOL SupportTSC = FALSE; + U32 CpuSpeed; + /* Create the CPU instance key */ Error = RegCreateKey(CpuKey, @@ -136,6 +169,8 @@ DetectCPU(HKEY CpuKey, (unsigned int)((eax >> 4) & 0x0F), (unsigned int)(eax & 0x0F)); FeatureSet = edx; + if (((eax >> 8) & 0x0F) >= 5) + SupportTSC = TRUE; } else { @@ -207,7 +242,21 @@ DetectCPU(HKEY CpuKey, /* FIXME: Set 'Update Status' value (CPU only) */ - /* FIXME: Set '~MHz' value (CPU only) */ + /* Set '~MHz' value (CPU only) */ + if (SupportTSC) + { + CpuSpeed = GetCpuSpeed(); + + Error = RegSetValue(CpuInstKey, + "~MHz", + REG_DWORD, + (PU8)&CpuSpeed, + sizeof(U32)); + if (Error != ERROR_SUCCESS) + { + DbgPrint((DPRINT_HWDETECT, "RegSetValue() failed (Error %u)\n", (int)Error)); + } + } } @@ -228,6 +277,7 @@ SetMpsProcessor(HKEY CpuKey, U32 edx = 0; U32 *Ptr; S32 Error; + U32 CpuSpeed; /* Get processor instance number */ sprintf(Buffer, "%u", CpuEntry->LocalApicId); @@ -336,7 +386,21 @@ SetMpsProcessor(HKEY CpuKey, /* FIXME: Set 'Update Status' value (CPU only) */ - /* FIXME: Set '~MHz' value (CPU only) */ + /* Set '~MHz' value (CPU only) */ + if (((CpuEntry->CpuSignature >> 8) & 0x0F) >= 5) + { + CpuSpeed = GetCpuSpeed(); + + Error = RegSetValue(CpuInstKey, + "~MHz", + REG_DWORD, + (PU8)&CpuSpeed, + sizeof(U32)); + if (Error != ERROR_SUCCESS) + { + DbgPrint((DPRINT_HWDETECT, "RegSetValue() failed (Error %u)\n", (int)Error)); + } + } } diff --git a/freeldr/freeldr/arch/i386/i386cpu.S b/freeldr/freeldr/arch/i386/i386cpu.S index 7060ef2a392..7206c5b0849 100644 --- a/freeldr/freeldr/arch/i386/i386cpu.S +++ b/freeldr/freeldr/arch/i386/i386cpu.S @@ -118,4 +118,14 @@ EXTERN(_GetCpuid) popl %ebp ret + +/* + * U64 RDTSC(VOID); + */ + +EXTERN(_RDTSC) + .code32 + rdtsc + ret + /* EOF */ diff --git a/freeldr/freeldr/include/version.h b/freeldr/freeldr/include/version.h index 941bd5939e2..fbcc02ce68b 100644 --- a/freeldr/freeldr/include/version.h +++ b/freeldr/freeldr/include/version.h @@ -22,7 +22,7 @@ /* just some stuff */ -#define VERSION "FreeLoader v1.8.18" +#define VERSION "FreeLoader v1.8.19" #define COPYRIGHT "Copyright (C) 1998-2003 Brian Palmer " #define AUTHOR_EMAIL "" #define BY_AUTHOR "by Brian Palmer" @@ -36,7 +36,7 @@ // #define FREELOADER_MAJOR_VERSION 1 #define FREELOADER_MINOR_VERSION 8 -#define FREELOADER_PATCH_VERSION 18 +#define FREELOADER_PATCH_VERSION 19 #ifndef ASM