/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/hal/x86/time.c * PURPOSE: Getting time information * UPDATE HISTORY: */ /* INCLUDES *****************************************************************/ #include #include #include #include #define NDEBUG #include /* MACROS and CONSTANTS ******************************************************/ /* macro BCD_INT : convert bcd to int */ #define BCD_INT(bcd) (((bcd & 0xf0) >> 4) * 10 + (bcd &0x0f)) /* macro INT_BCD : convert int to bcd */ #define INT_BCD(int) (((int / 10) << 4) + (int % 10)) #define RTC_REGISTER_A 0x0A #define RTC_REG_A_UIP 0x80 /* Update In Progress bit */ #define RTC_REGISTER_B 0x0B #define RTC_REGISTER_CENTURY 0x32 /* GLOBALS ******************************************************************/ static KSPIN_LOCK CmosLock = {0}; /* FUNCTIONS *****************************************************************/ static UCHAR HalpQueryCMOS(UCHAR Reg) { UCHAR Val; ULONG Flags; Reg |= 0x80; pushfl(Flags); __asm__("cli\n"); // AP unsure as to whether to do this here WRITE_PORT_UCHAR((PUCHAR)0x70, Reg); Val = READ_PORT_UCHAR((PUCHAR)0x71); WRITE_PORT_UCHAR((PUCHAR)0x70, 0); popfl(Flags); return(Val); } static VOID HalpSetCMOS(UCHAR Reg, UCHAR Val) { ULONG Flags; Reg |= 0x80; pushfl(Flags); __asm__("cli\n"); // AP unsure as to whether to do this here WRITE_PORT_UCHAR((PUCHAR)0x70, Reg); WRITE_PORT_UCHAR((PUCHAR)0x71, Val); WRITE_PORT_UCHAR((PUCHAR)0x70, 0); popfl(Flags); } static UCHAR HalpQueryECMOS(USHORT Reg) { UCHAR Val; ULONG Flags; pushfl(Flags); __asm__("cli\n"); // AP unsure as to whether to do this here WRITE_PORT_UCHAR((PUCHAR)0x74, (UCHAR)(Reg & 0x00FF)); WRITE_PORT_UCHAR((PUCHAR)0x75, (UCHAR)(Reg>>8)); Val = READ_PORT_UCHAR((PUCHAR)0x76); popfl(Flags); return(Val); } static VOID HalpSetECMOS(USHORT Reg, UCHAR Val) { ULONG Flags; pushfl(Flags); __asm__("cli\n"); // AP unsure as to whether to do this here WRITE_PORT_UCHAR((PUCHAR)0x74, (UCHAR)(Reg & 0x00FF)); WRITE_PORT_UCHAR((PUCHAR)0x75, (UCHAR)(Reg>>8)); WRITE_PORT_UCHAR((PUCHAR)0x76, Val); popfl(Flags); } VOID STDCALL HalQueryRealTimeClock(PTIME_FIELDS Time) { KIRQL oldIrql; KeAcquireSpinLock(&CmosLock, &oldIrql); /* check 'Update In Progress' bit */ while (HalpQueryCMOS (RTC_REGISTER_A) & RTC_REG_A_UIP); Time->Second = BCD_INT(HalpQueryCMOS (0)); Time->Minute = BCD_INT(HalpQueryCMOS (2)); Time->Hour = BCD_INT(HalpQueryCMOS (4)); Time->Weekday = BCD_INT(HalpQueryCMOS (6)); Time->Day = BCD_INT(HalpQueryCMOS (7)); Time->Month = BCD_INT(HalpQueryCMOS (8)); Time->Year = BCD_INT(HalpQueryCMOS (9)); if (Time->Year > 80) Time->Year += 1900; else Time->Year += 2000; #if 0 /* Century */ Time->Year += BCD_INT(HalpQueryCMOS (RTC_REGISTER_CENTURY)) * 100; #endif KeReleaseSpinLock(&CmosLock, oldIrql); #ifndef NDEBUG DbgPrint ("HalQueryRealTimeClock() %d:%d:%d %d/%d/%d\n", Time->Hour, Time->Minute, Time->Second, Time->Day, Time->Month, Time->Year ); #endif Time->Milliseconds = 0; } VOID STDCALL HalSetRealTimeClock(PTIME_FIELDS Time) { KIRQL oldIrql; KeAcquireSpinLock(&CmosLock, &oldIrql); /* check 'Update In Progress' bit */ while (HalpQueryCMOS (RTC_REGISTER_A) & RTC_REG_A_UIP); HalpSetCMOS (0, INT_BCD(Time->Second)); HalpSetCMOS (2, INT_BCD(Time->Minute)); HalpSetCMOS (4, INT_BCD(Time->Hour)); HalpSetCMOS (6, INT_BCD(Time->Weekday)); HalpSetCMOS (7, INT_BCD(Time->Day)); HalpSetCMOS (8, INT_BCD(Time->Month)); HalpSetCMOS (9, INT_BCD(Time->Year % 100)); #if 0 /* Century */ HalpSetCMOS (RTC_REGISTER_CENTURY, INT_BCD(Time->Year / 100)); #endif KeReleaseSpinLock(&CmosLock, oldIrql); } BOOLEAN STDCALL HalGetEnvironmentVariable(PCH Name, PCH Value, USHORT ValueLength) { KIRQL oldIrql; if (_stricmp(Name, "LastKnownGood") != 0) { return FALSE; } KeAcquireSpinLock(&CmosLock, &oldIrql); if (HalpQueryCMOS(RTC_REGISTER_B) & 0x01) { strncpy(Value, "FALSE", ValueLength); } else { strncpy(Value, "TRUE", ValueLength); } KeReleaseSpinLock(&CmosLock, oldIrql); return TRUE; } BOOLEAN STDCALL HalSetEnvironmentVariable(PCH Name, PCH Value) { UCHAR Val; KIRQL oldIrql; BOOLEAN result = TRUE; if (_stricmp(Name, "LastKnownGood") != 0) return FALSE; KeAcquireSpinLock(&CmosLock, &oldIrql); Val = HalpQueryCMOS(RTC_REGISTER_B); if (_stricmp(Value, "TRUE") == 0) HalpSetCMOS(RTC_REGISTER_B, Val | 0x01); else if (_stricmp(Value, "FALSE") == 0) HalpSetCMOS(RTC_REGISTER_B, Val & ~0x01); else result = FALSE; KeReleaseSpinLock(&CmosLock, oldIrql); return result; } ULONG STDCALL HalpGetCmosData(PBUS_HANDLER BusHandler, ULONG BusNumber, ULONG SlotNumber, PVOID Buffer, ULONG Offset, ULONG Length) { PUCHAR Ptr = Buffer; ULONG Address = SlotNumber; ULONG Len = Length; KIRQL oldIrql; DPRINT("HalpGetCmosData() called.\n"); DPRINT(" BusNumber %lu\n", BusNumber); DPRINT(" SlotNumber %lu\n", SlotNumber); DPRINT(" Offset 0x%lx\n", Offset); DPRINT(" Length 0x%lx\n", Length); if (Length == 0) return 0; if (BusNumber == 0) { /* CMOS */ KeAcquireSpinLock(&CmosLock, &oldIrql); while ((Len > 0) && (Address < 0x100)) { *Ptr = HalpQueryCMOS((UCHAR)Address); Ptr = Ptr + 1; Address++; Len--; } KeReleaseSpinLock(&CmosLock, oldIrql); } else if (BusNumber == 1) { /* Extended CMOS */ KeAcquireSpinLock(&CmosLock, &oldIrql); while ((Len > 0) && (Address < 0x1000)) { *Ptr = HalpQueryECMOS((USHORT)Address); Ptr = Ptr + 1; Address++; Len--; } KeReleaseSpinLock(&CmosLock, oldIrql); } return(Length - Len); } ULONG STDCALL HalpSetCmosData(PBUS_HANDLER BusHandler, ULONG BusNumber, ULONG SlotNumber, PVOID Buffer, ULONG Offset, ULONG Length) { PUCHAR Ptr = (PUCHAR)Buffer; ULONG Address = SlotNumber; ULONG Len = Length; KIRQL oldIrql; DPRINT("HalpSetCmosData() called.\n"); DPRINT(" BusNumber %lu\n", BusNumber); DPRINT(" SlotNumber %lu\n", SlotNumber); DPRINT(" Offset 0x%lx\n", Offset); DPRINT(" Length 0x%lx\n", Length); if (Length == 0) return 0; if (BusNumber == 0) { /* CMOS */ KeAcquireSpinLock(&CmosLock, &oldIrql); while ((Len > 0) && (Address < 0x100)) { HalpSetCMOS((UCHAR)Address, *Ptr); Ptr = Ptr + 1; Address++; Len--; } KeReleaseSpinLock(&CmosLock, oldIrql); } else if (BusNumber == 1) { /* Extended CMOS */ KeAcquireSpinLock(&CmosLock, &oldIrql); while ((Len > 0) && (Address < 0x1000)) { HalpSetECMOS((USHORT)Address, *Ptr); Ptr = Ptr + 1; Address++; Len--; } KeReleaseSpinLock(&CmosLock, oldIrql); } return(Length - Len); } /* EOF */