+++ /dev/null
-/** @file\r
- RTC Architectural Protocol GUID as defined in DxeCis 0.96.\r
-\r
-Copyright (c) 2006 - 2007, Intel Corporation\r
-All rights reserved. This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
-**/\r
-\r
-#include "PcRtc.h"\r
-\r
-/**\r
- Compare the Hour, Minute and Second of the From time and the To time.\r
- \r
- Only compare H/M/S in EFI_TIME and ignore other fields here.\r
-\r
- @param From the first time\r
- @param To the second time\r
-\r
- @return >0 The H/M/S of the From time is later than those of To time\r
- @return ==0 The H/M/S of the From time is same as those of To time\r
- @return <0 The H/M/S of the From time is earlier than those of To time\r
-**/\r
-INTN\r
-CompareHMS (\r
- IN EFI_TIME *From,\r
- IN EFI_TIME *To\r
- );\r
-\r
-/**\r
- To check if second date is later than first date within 24 hours.\r
-\r
- @param From the first date\r
- @param To the second date\r
-\r
- @retval TRUE From is previous to To within 24 hours.\r
- @retval FALSE From is later, or it is previous to To more than 24 hours.\r
-**/\r
-BOOLEAN\r
-IsWithinOneDay (\r
- IN EFI_TIME *From,\r
- IN EFI_TIME *To\r
- );\r
-\r
-/**\r
- Read RTC content through its registers.\r
-\r
- @param Address Address offset of RTC. It is recommended to use macros such as\r
- RTC_ADDRESS_SECONDS.\r
-\r
- @return The data of UINT8 type read from RTC.\r
-**/\r
-UINT8\r
-RtcRead (\r
- IN UINT8 Address\r
- )\r
-{\r
- IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8) (Address | (UINT8) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & 0x80)));\r
- return IoRead8 (PCAT_RTC_DATA_REGISTER);\r
-}\r
-\r
-/**\r
- Write RTC through its registers.\r
-\r
- @param Address Address offset of RTC. It is recommended to use macros such as\r
- RTC_ADDRESS_SECONDS.\r
- @param Data The content you want to write into RTC.\r
-\r
-**/\r
-VOID\r
-RtcWrite (\r
- IN UINT8 Address,\r
- IN UINT8 Data\r
- )\r
-{\r
- IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8) (Address | (UINT8) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & 0x80)));\r
- IoWrite8 (PCAT_RTC_DATA_REGISTER, Data);\r
-}\r
-\r
-/**\r
- Initialize RTC.\r
-\r
- @param Global For global use inside this module.\r
-\r
- @retval EFI_DEVICE_ERROR Initialization failed due to device error.\r
- @retval EFI_SUCCESS Initialization successful.\r
-\r
-**/\r
-EFI_STATUS\r
-PcRtcInit (\r
- IN PC_RTC_MODULE_GLOBALS *Global\r
- )\r
-{\r
- EFI_STATUS Status;\r
- RTC_REGISTER_A RegisterA;\r
- RTC_REGISTER_B RegisterB;\r
- RTC_REGISTER_D RegisterD;\r
- UINT8 Century;\r
- EFI_TIME Time;\r
- UINTN DataSize;\r
- UINT32 TimerVar;\r
-\r
- //\r
- // Acquire RTC Lock to make access to RTC atomic\r
- //\r
- //Code here doesn't consider the runtime environment.\r
- if (!EfiAtRuntime ()) {\r
- EfiAcquireLock (&Global->RtcLock);\r
- }\r
- //\r
- // Initialize RTC Register\r
- //\r
- // Make sure Division Chain is properly configured,\r
- // or RTC clock won't "tick" -- time won't increment\r
- //\r
- RegisterA.Data = RTC_INIT_REGISTER_A;\r
- RtcWrite (RTC_ADDRESS_REGISTER_A, RegisterA.Data);\r
-\r
- //\r
- // Read Register B\r
- //\r
- RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);\r
-\r
- //\r
- // Clear RTC flag register\r
- //\r
- RtcRead (RTC_ADDRESS_REGISTER_C);\r
-\r
- //\r
- // Clear RTC register D\r
- //\r
- RegisterD.Data = RTC_INIT_REGISTER_D;\r
- RtcWrite (RTC_ADDRESS_REGISTER_D, RegisterD.Data);\r
-\r
- //\r
- // Wait for up to 0.1 seconds for the RTC to be updated\r
- //\r
- Status = RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout));\r
- if (EFI_ERROR (Status)) {\r
- //Code here doesn't consider the runtime environment.\r
- if (!EfiAtRuntime ()) {\r
- EfiReleaseLock (&Global->RtcLock);\r
- }\r
- return EFI_DEVICE_ERROR;\r
- }\r
- //\r
- // Get the Time/Date/Daylight Savings values.\r
- //\r
- Time.Second = RtcRead (RTC_ADDRESS_SECONDS);\r
- Time.Minute = RtcRead (RTC_ADDRESS_MINUTES);\r
- Time.Hour = RtcRead (RTC_ADDRESS_HOURS);\r
- Time.Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);\r
- Time.Month = RtcRead (RTC_ADDRESS_MONTH);\r
- Time.Year = RtcRead (RTC_ADDRESS_YEAR);\r
-\r
- Century = RtcRead (RTC_ADDRESS_CENTURY);\r
- \r
- //\r
- // Set RTC configuration after get original time\r
- // The value of bit AIE should be reserved.\r
- //\r
- RtcWrite (RTC_ADDRESS_REGISTER_B, (UINT8)(RTC_INIT_REGISTER_B | (RegisterB.Data & BIT5)));\r
-\r
- //\r
- // Release RTC Lock.\r
- //\r
- //Code here doesn't consider the runtime environment.\r
- if (!EfiAtRuntime ()) {\r
- EfiReleaseLock (&Global->RtcLock);\r
- }\r
- \r
- //\r
- // Validate time fields\r
- //\r
- Status = ConvertRtcTimeToEfiTime (&Time, Century, RegisterB);\r
- if (!EFI_ERROR (Status)) {\r
- Status = RtcTimeFieldsValid (&Time);\r
- }\r
- if (EFI_ERROR (Status)) {\r
- Time.Second = RTC_INIT_SECOND;\r
- Time.Minute = RTC_INIT_MINUTE;\r
- Time.Hour = RTC_INIT_HOUR;\r
- Time.Day = RTC_INIT_DAY;\r
- Time.Month = RTC_INIT_MONTH;\r
- Time.Year = RTC_INIT_YEAR;\r
- }\r
- //\r
- // Get the data of Daylight saving and time zone, if they have been\r
- // stored in NV variable during previous boot.\r
- //\r
- DataSize = sizeof (UINT32);\r
- Status = EfiGetVariable (\r
- L"RTC",\r
- &gEfiCallerIdGuid,\r
- NULL,\r
- &DataSize,\r
- (VOID *) &TimerVar\r
- );\r
- if (!EFI_ERROR (Status)) {\r
- Global->SavedTimeZone = (INT16) TimerVar;\r
- Global->Daylight = (UINT8) (TimerVar >> 16);\r
-\r
- Time.TimeZone = Global->SavedTimeZone;\r
- Time.Daylight = Global->Daylight;\r
- }\r
- //\r
- // Reset time value according to new RTC configuration\r
- //\r
- PcRtcSetTime (&Time, Global);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Returns the current time and date information, and the time-keeping capabilities\r
- of the hardware platform.\r
-\r
- @param Time A pointer to storage to receive a snapshot of the current time.\r
- @param Capabilities An optional pointer to a buffer to receive the real time clock\r
- device's capabilities.\r
- @param Global For global use inside this module.\r
-\r
- @retval EFI_SUCCESS The operation completed successfully.\r
- @retval EFI_INVALID_PARAMETER Time is NULL.\r
- @retval EFI_DEVICE_ERROR The time could not be retrieved due to hardware error.\r
-\r
-**/\r
-EFI_STATUS\r
-PcRtcGetTime (\r
- OUT EFI_TIME *Time,\r
- OUT EFI_TIME_CAPABILITIES *Capabilities, OPTIONAL\r
- IN PC_RTC_MODULE_GLOBALS *Global\r
- )\r
-{\r
- EFI_STATUS Status;\r
- RTC_REGISTER_B RegisterB;\r
- UINT8 Century;\r
-\r
- //\r
- // Check parameters for null pointer\r
- //\r
- if (Time == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
-\r
- }\r
- //\r
- // Acquire RTC Lock to make access to RTC atomic\r
- //\r
- //Code here doesn't consider the runtime environment.\r
- if (!EfiAtRuntime ()) {\r
- EfiAcquireLock (&Global->RtcLock);\r
- }\r
- //\r
- // Wait for up to 0.1 seconds for the RTC to be updated\r
- //\r
- Status = RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout));\r
- if (EFI_ERROR (Status)) {\r
- //Code here doesn't consider the runtime environment.\r
- if (!EfiAtRuntime ()) {\r
- EfiReleaseLock (&Global->RtcLock);\r
- }\r
- return Status;\r
- }\r
- //\r
- // Read Register B\r
- //\r
- RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);\r
-\r
- //\r
- // Get the Time/Date/Daylight Savings values.\r
- //\r
- Time->Second = RtcRead (RTC_ADDRESS_SECONDS);\r
- Time->Minute = RtcRead (RTC_ADDRESS_MINUTES);\r
- Time->Hour = RtcRead (RTC_ADDRESS_HOURS);\r
- Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);\r
- Time->Month = RtcRead (RTC_ADDRESS_MONTH);\r
- Time->Year = RtcRead (RTC_ADDRESS_YEAR);\r
-\r
- Century = RtcRead (RTC_ADDRESS_CENTURY);\r
- \r
- //\r
- // Release RTC Lock.\r
- //\r
- //Code here doesn't consider the runtime environment.\r
- if (!EfiAtRuntime ()) {\r
- EfiReleaseLock (&Global->RtcLock);\r
- }\r
- //\r
- // Get the variable that contains the TimeZone and Daylight fields\r
- //\r
- Time->TimeZone = Global->SavedTimeZone;\r
- Time->Daylight = Global->Daylight;\r
-\r
- //\r
- // Make sure all field values are in correct range\r
- //\r
- Status = ConvertRtcTimeToEfiTime (Time, Century, RegisterB);\r
- if (!EFI_ERROR (Status)) {\r
- Status = RtcTimeFieldsValid (Time);\r
- }\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
- //\r
- // Fill in Capabilities if it was passed in\r
- //\r
- if (Capabilities != NULL) {\r
- Capabilities->Resolution = 1;\r
- //\r
- // 1 hertz\r
- //\r
- Capabilities->Accuracy = 50000000;\r
- //\r
- // 50 ppm\r
- //\r
- Capabilities->SetsToZero = FALSE;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Sets the current local time and date information.\r
-\r
- @param Time A pointer to the current time.\r
- @param Global For global use inside this module.\r
-\r
- @retval EFI_SUCCESS The operation completed successfully.\r
- @retval EFI_INVALID_PARAMETER A time field is out of range.\r
- @retval EFI_DEVICE_ERROR The time could not be set due due to hardware error.\r
-\r
-**/\r
-EFI_STATUS\r
-PcRtcSetTime (\r
- IN EFI_TIME *Time,\r
- IN PC_RTC_MODULE_GLOBALS *Global\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_TIME RtcTime;\r
- RTC_REGISTER_B RegisterB;\r
- UINT8 Century;\r
- UINT32 TimerVar;\r
-\r
- if (Time == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- //\r
- // Make sure that the time fields are valid\r
- //\r
- Status = RtcTimeFieldsValid (Time);\r
- if (EFI_ERROR (Status)) {\r
- return Status;\r
- }\r
-\r
- CopyMem (&RtcTime, Time, sizeof (EFI_TIME));\r
-\r
- //\r
- // Acquire RTC Lock to make access to RTC atomic\r
- //\r
- //Code here doesn't consider the runtime environment.\r
- if (!EfiAtRuntime ()) {\r
- EfiAcquireLock (&Global->RtcLock);\r
- }\r
- //\r
- // Wait for up to 0.1 seconds for the RTC to be updated\r
- //\r
- Status = RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout));\r
- if (EFI_ERROR (Status)) {\r
- //Code here doesn't consider the runtime environment.\r
- if (!EfiAtRuntime ()) {\r
- EfiReleaseLock (&Global->RtcLock);\r
- }\r
- return Status;\r
- }\r
- //\r
- // Read Register B, and inhibit updates of the RTC\r
- //\r
- RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);\r
- RegisterB.Bits.SET = 1;\r
- RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
-\r
- ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century);\r
-\r
- RtcWrite (RTC_ADDRESS_SECONDS, RtcTime.Second);\r
- RtcWrite (RTC_ADDRESS_MINUTES, RtcTime.Minute);\r
- RtcWrite (RTC_ADDRESS_HOURS, RtcTime.Hour);\r
- RtcWrite (RTC_ADDRESS_DAY_OF_THE_MONTH, RtcTime.Day);\r
- RtcWrite (RTC_ADDRESS_MONTH, RtcTime.Month);\r
- RtcWrite (RTC_ADDRESS_YEAR, (UINT8) RtcTime.Year);\r
- RtcWrite (RTC_ADDRESS_CENTURY, Century);\r
-\r
- //\r
- // Allow updates of the RTC registers\r
- //\r
- RegisterB.Bits.SET = 0;\r
- RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
-\r
- //\r
- // Release RTC Lock.\r
- //\r
- //Code here doesn't consider the runtime environment.\r
- if (!EfiAtRuntime ()) {\r
- EfiReleaseLock (&Global->RtcLock);\r
- }\r
- //\r
- // Set the variable that contains the TimeZone and Daylight fields\r
- //\r
- Global->SavedTimeZone = Time->TimeZone;\r
- Global->Daylight = Time->Daylight;\r
-\r
- TimerVar = Time->Daylight;\r
- TimerVar = (UINT32) ((TimerVar << 16) | Time->TimeZone);\r
- Status = EfiSetVariable (\r
- L"RTC",\r
- &gEfiCallerIdGuid,\r
- EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
- sizeof (TimerVar),\r
- &TimerVar\r
- );\r
- ASSERT_EFI_ERROR (Status);\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Returns the current wakeup alarm clock setting.\r
-\r
- @param Enabled Indicates if the alarm is currently enabled or disabled.\r
- @param Pending Indicates if the alarm signal is pending and requires acknowledgment.\r
- @param Time The current alarm setting.\r
- @param Global For global use inside this module.\r
-\r
- @retval EFI_SUCCESS The alarm settings were returned.\r
- @retval EFI_INVALID_PARAMETER Enabled is NULL.\r
- @retval EFI_INVALID_PARAMETER Pending is NULL.\r
- @retval EFI_INVALID_PARAMETER Time is NULL.\r
- @retval EFI_DEVICE_ERROR The wakeup time could not be retrieved due to a hardware error.\r
- @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform.\r
-\r
-**/\r
-EFI_STATUS\r
-PcRtcGetWakeupTime (\r
- OUT BOOLEAN *Enabled,\r
- OUT BOOLEAN *Pending,\r
- OUT EFI_TIME *Time,\r
- IN PC_RTC_MODULE_GLOBALS *Global\r
- )\r
-{\r
- EFI_STATUS Status;\r
- RTC_REGISTER_B RegisterB;\r
- RTC_REGISTER_C RegisterC;\r
- UINT8 Century;\r
-\r
- //\r
- // Check parameters for null pointers\r
- //\r
- if ((Enabled == NULL) || (Pending == NULL) || (Time == NULL)) {\r
- return EFI_INVALID_PARAMETER;\r
-\r
- }\r
- //\r
- // Acquire RTC Lock to make access to RTC atomic\r
- //\r
- //Code here doesn't consider the runtime environment.\r
- if (!EfiAtRuntime ()) {\r
- EfiAcquireLock (&Global->RtcLock);\r
- }\r
- //\r
- // Wait for up to 0.1 seconds for the RTC to be updated\r
- //\r
- Status = RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout));\r
- if (EFI_ERROR (Status)) {\r
- //Code here doesn't consider the runtime environment.\r
- if (!EfiAtRuntime ()) {\r
- EfiReleaseLock (&Global->RtcLock);\r
- }\r
- return EFI_DEVICE_ERROR;\r
- }\r
- //\r
- // Read Register B and Register C\r
- //\r
- RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);\r
- RegisterC.Data = RtcRead (RTC_ADDRESS_REGISTER_C);\r
-\r
- //\r
- // Get the Time/Date/Daylight Savings values.\r
- //\r
- *Enabled = RegisterB.Bits.AIE;\r
- if (*Enabled) {\r
- Time->Second = RtcRead (RTC_ADDRESS_SECONDS_ALARM);\r
- Time->Minute = RtcRead (RTC_ADDRESS_MINUTES_ALARM);\r
- Time->Hour = RtcRead (RTC_ADDRESS_HOURS_ALARM);\r
- Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);\r
- Time->Month = RtcRead (RTC_ADDRESS_MONTH);\r
- Time->Year = RtcRead (RTC_ADDRESS_YEAR);\r
- } else {\r
- Time->Second = 0;\r
- Time->Minute = 0;\r
- Time->Hour = 0;\r
- Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);\r
- Time->Month = RtcRead (RTC_ADDRESS_MONTH);\r
- Time->Year = RtcRead (RTC_ADDRESS_YEAR);\r
- }\r
-\r
- Century = RtcRead (RTC_ADDRESS_CENTURY);\r
- \r
- //\r
- // Release RTC Lock.\r
- //\r
- //Code here doesn't consider the runtime environment.\r
- if (!EfiAtRuntime ()) {\r
- EfiReleaseLock (&Global->RtcLock);\r
- }\r
- //\r
- // Make sure all field values are in correct range\r
- //\r
- Status = ConvertRtcTimeToEfiTime (Time, Century, RegisterB);\r
- if (!EFI_ERROR (Status)) {\r
- Status = RtcTimeFieldsValid (Time);\r
- }\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- *Pending = RegisterC.Bits.AF;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Sets the system wakeup alarm clock time.\r
-\r
- @param Enabled Enable or disable the wakeup alarm.\r
- @param Time If Enable is TRUE, the time to set the wakeup alarm for.\r
- If Enable is FALSE, then this parameter is optional, and may be NULL.\r
- @param Global For global use inside this module.\r
-\r
- @retval EFI_SUCCESS If Enable is TRUE, then the wakeup alarm was enabled.\r
- If Enable is FALSE, then the wakeup alarm was disabled.\r
- @retval EFI_INVALID_PARAMETER A time field is out of range.\r
- @retval EFI_DEVICE_ERROR The wakeup time could not be set due to a hardware error.\r
- @retval EFI_UNSUPPORTED A wakeup timer is not supported on this platform.\r
-\r
-**/\r
-EFI_STATUS\r
-PcRtcSetWakeupTime (\r
- IN BOOLEAN Enable,\r
- IN EFI_TIME *Time, OPTIONAL\r
- IN PC_RTC_MODULE_GLOBALS *Global\r
- )\r
-{\r
- EFI_STATUS Status;\r
- EFI_TIME RtcTime;\r
- RTC_REGISTER_B RegisterB;\r
- UINT8 Century;\r
- EFI_TIME_CAPABILITIES Capabilities;\r
-\r
- if (Enable) {\r
-\r
- if (Time == NULL) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- //\r
- // Make sure that the time fields are valid\r
- //\r
- Status = RtcTimeFieldsValid (Time);\r
- if (EFI_ERROR (Status)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- //\r
- // Just support set alarm time within 24 hours\r
- //\r
- PcRtcGetTime (&RtcTime, &Capabilities, Global);\r
- Status = RtcTimeFieldsValid (&RtcTime);\r
- if (EFI_ERROR (Status)) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
- if (!IsWithinOneDay (&RtcTime, Time)) {\r
- return EFI_UNSUPPORTED;\r
- }\r
- //\r
- // Make a local copy of the time and date\r
- //\r
- CopyMem (&RtcTime, Time, sizeof (EFI_TIME));\r
-\r
- }\r
- //\r
- // Acquire RTC Lock to make access to RTC atomic\r
- //\r
- //Code here doesn't consider the runtime environment.\r
- if (!EfiAtRuntime ()) {\r
- EfiAcquireLock (&Global->RtcLock);\r
- }\r
- //\r
- // Wait for up to 0.1 seconds for the RTC to be updated\r
- //\r
- Status = RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout));\r
- if (EFI_ERROR (Status)) {\r
- //Code here doesn't consider the runtime environment.\r
- if (!EfiAtRuntime ()) {\r
- EfiReleaseLock (&Global->RtcLock);\r
- }\r
- return EFI_DEVICE_ERROR;\r
- }\r
- //\r
- // Read Register B, and inhibit updates of the RTC\r
- //\r
- RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);\r
-\r
- RegisterB.Bits.SET = 1;\r
- RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
-\r
- if (Enable) {\r
- ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century);\r
-\r
- //\r
- // Set RTC alarm time\r
- //\r
- RtcWrite (RTC_ADDRESS_SECONDS_ALARM, RtcTime.Second);\r
- RtcWrite (RTC_ADDRESS_MINUTES_ALARM, RtcTime.Minute);\r
- RtcWrite (RTC_ADDRESS_HOURS_ALARM, RtcTime.Hour);\r
-\r
- RegisterB.Bits.AIE = 1;\r
-\r
- } else {\r
- RegisterB.Bits.AIE = 0;\r
- }\r
- //\r
- // Allow updates of the RTC registers\r
- //\r
- RegisterB.Bits.SET = 0;\r
- RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
-\r
- //\r
- // Release RTC Lock.\r
- //\r
- //Code here doesn't consider the runtime environment.\r
- if (!EfiAtRuntime ()) {\r
- EfiReleaseLock (&Global->RtcLock);\r
- }\r
- return EFI_SUCCESS;\r
-}\r
-\r
-\r
-/**\r
- Checks an 8-bit BCD value, and converts to an 8-bit value if valid.\r
-\r
- This function checks the 8-bit BCD value specified by Value.\r
- If valid, the function converts it to an 8-bit value and returns it.\r
- Otherwise, return 0xff.\r
-\r
- @param Value The 8-bit BCD value to check and convert\r
-\r
- @return The 8-bit value converted. Or 0xff if Value is invalid.\r
-\r
-**/\r
-UINT8\r
-CheckAndConvertBcd8ToDecimal8 (\r
- IN UINT8 Value\r
- )\r
-{\r
- if ((Value < 0xa0) && ((Value & 0xf) < 0xa)) {\r
- return BcdToDecimal8 (Value);\r
- }\r
-\r
- return 0xff;\r
-}\r
-\r
-/**\r
- Converts time read from RTC to EFI_TIME format defined by UEFI spec.\r
-\r
- This function converts raw time data read from RTC to the EFI_TIME format\r
- defined by UEFI spec.\r
- If data mode of RTC is BCD, then converts it to decimal,\r
- If RTC is in 12-hour format, then converts it to 24-hour format.\r
-\r
- @param Time On input, the time data read from RTC to convert\r
- On output, the time converted to UEFI format\r
- @param Century Value of century read from RTC.\r
- @param RegisterB Value of Register B of RTC, indicating data mode\r
- and hour format.\r
-\r
- @retval EFI_INVALID_PARAMETER Parameters passed in are invalid.\r
- @retval EFI_SUCCESS Convert RTC time to EFI time successfully.\r
-\r
-**/\r
-EFI_STATUS\r
-ConvertRtcTimeToEfiTime (\r
- IN OUT EFI_TIME *Time,\r
- IN UINT8 Century,\r
- IN RTC_REGISTER_B RegisterB\r
- )\r
-{\r
- BOOLEAN IsPM;\r
-\r
- if ((Time->Hour & 0x80) != 0) {\r
- IsPM = TRUE;\r
- } else {\r
- IsPM = FALSE;\r
- }\r
-\r
- Time->Hour = (UINT8) (Time->Hour & 0x7f);\r
-\r
- if (RegisterB.Bits.DM == 0) {\r
- Time->Year = CheckAndConvertBcd8ToDecimal8 ((UINT8) Time->Year);\r
- Time->Month = CheckAndConvertBcd8ToDecimal8 (Time->Month);\r
- Time->Day = CheckAndConvertBcd8ToDecimal8 (Time->Day);\r
- Time->Hour = CheckAndConvertBcd8ToDecimal8 (Time->Hour);\r
- Time->Minute = CheckAndConvertBcd8ToDecimal8 (Time->Minute);\r
- Time->Second = CheckAndConvertBcd8ToDecimal8 (Time->Second);\r
- }\r
- Century = CheckAndConvertBcd8ToDecimal8 (Century);\r
-\r
- if (Time->Year == 0xff || Time->Month == 0xff || Time->Day == 0xff ||\r
- Time->Hour == 0xff || Time->Minute == 0xff || Time->Second == 0xff ||\r
- Century == 0xff) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
-\r
- Time->Year = (UINT16) (Century * 100 + Time->Year);\r
-\r
- //\r
- // If time is in 12 hour format, convert it to 24 hour format\r
- //\r
- if (RegisterB.Bits.MIL == 0) {\r
- if (IsPM && Time->Hour < 12) {\r
- Time->Hour = (UINT8) (Time->Hour + 12);\r
- }\r
-\r
- if (!IsPM && Time->Hour == 12) {\r
- Time->Hour = 0;\r
- }\r
- }\r
-\r
- Time->Nanosecond = 0;\r
- Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
- Time->Daylight = 0;\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- Wait for a period for the RTC to be ready.\r
-\r
- @param Timeout Tell how long it should take to wait.\r
-\r
- @retval EFI_DEVICE_ERROR RTC device error.\r
- @retval EFI_SUCCESS RTC is updated and ready. \r
-**/\r
-EFI_STATUS\r
-RtcWaitToUpdate (\r
- UINTN Timeout\r
- )\r
-{\r
- RTC_REGISTER_A RegisterA;\r
- RTC_REGISTER_D RegisterD;\r
-\r
- //\r
- // See if the RTC is functioning correctly\r
- //\r
- RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D);\r
-\r
- if (RegisterD.Bits.VRT == 0) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
- //\r
- // Wait for up to 0.1 seconds for the RTC to be ready.\r
- //\r
- Timeout = (Timeout / 10) + 1;\r
- RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A);\r
- while (RegisterA.Bits.UIP == 1 && Timeout > 0) {\r
- MicroSecondDelay (10);\r
- RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A);\r
- Timeout--;\r
- }\r
-\r
- RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D);\r
- if (Timeout == 0 || RegisterD.Bits.VRT == 0) {\r
- return EFI_DEVICE_ERROR;\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- See if all fields of a variable of EFI_TIME type is correct.\r
-\r
- @param Time The time to be checked.\r
-\r
- @retval EFI_INVALID_PARAMETER Some fields of Time are not correct.\r
- @retval EFI_SUCCESS Time is a valid EFI_TIME variable.\r
-\r
-**/\r
-EFI_STATUS\r
-RtcTimeFieldsValid (\r
- IN EFI_TIME *Time\r
- )\r
-{\r
- if (Time->Year < 1998 ||\r
- Time->Year > 2099 ||\r
- Time->Month < 1 ||\r
- Time->Month > 12 ||\r
- Time->Hour > 23 ||\r
- Time->Minute > 59 ||\r
- Time->Second > 59 ||\r
- Time->Nanosecond > 999999999 ||\r
- (!(Time->TimeZone == EFI_UNSPECIFIED_TIMEZONE || (Time->TimeZone >= -1440 && Time->TimeZone <= 1440))) ||\r
- ((Time->Daylight & (~(EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT))) != 0)\r
- ) {\r
- if (!DayValid (Time)) {\r
- return EFI_INVALID_PARAMETER;\r
- }\r
- }\r
-\r
- return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
- See if field Day of an EFI_TIME is correct.\r
-\r
- @param Time Its Day field is to be checked.\r
-\r
- @retval TRUE Day field of Time is correct.\r
- @retval FALSE Day field of Time is NOT correct.\r
-**/\r
-BOOLEAN\r
-DayValid (\r
- IN EFI_TIME *Time\r
- )\r
-{\r
- INTN DayOfMonth[12];\r
-\r
- DayOfMonth[0] = 31;\r
- DayOfMonth[1] = 29;\r
- DayOfMonth[2] = 31;\r
- DayOfMonth[3] = 30;\r
- DayOfMonth[4] = 31;\r
- DayOfMonth[5] = 30;\r
- DayOfMonth[6] = 31;\r
- DayOfMonth[7] = 31;\r
- DayOfMonth[8] = 30;\r
- DayOfMonth[9] = 31;\r
- DayOfMonth[10] = 30;\r
- DayOfMonth[11] = 31;\r
-\r
- //\r
- // The validity of Time->Month field should be checked before\r
- //\r
- ASSERT (Time->Month >=1);\r
- ASSERT (Time->Month <=12);\r
- if (Time->Day < 1 ||\r
- Time->Day > DayOfMonth[Time->Month - 1] ||\r
- (Time->Month == 2 && (!IsLeapYear (Time) && Time->Day > 28))\r
- ) {\r
- return FALSE;\r
- }\r
-\r
- return TRUE;\r
-}\r
-\r
-/**\r
- Check if it is a leap year.\r
-\r
- @param Time The time to be checked.\r
-\r
- @retval TRUE It is a leap year.\r
- @retval FALSE It is NOT a leap year.\r
-**/\r
-BOOLEAN\r
-IsLeapYear (\r
- IN EFI_TIME *Time\r
- )\r
-{\r
- if (Time->Year % 4 == 0) {\r
- if (Time->Year % 100 == 0) {\r
- if (Time->Year % 400 == 0) {\r
- return TRUE;\r
- } else {\r
- return FALSE;\r
- }\r
- } else {\r
- return TRUE;\r
- }\r
- } else {\r
- return FALSE;\r
- }\r
-}\r
-\r
-/**\r
- Converts time from EFI_TIME format defined by UEFI spec to RTC's.\r
-\r
- This function converts time from EFI_TIME format defined by UEFI spec to RTC's.\r
- If data mode of RTC is BCD, then converts EFI_TIME to it.\r
- If RTC is in 12-hour format, then converts EFI_TIME to it.\r
-\r
- @param Time On input, the time data read from UEFI to convert\r
- On output, the time converted to RTC format\r
- @param RegisterB Value of Register B of RTC, indicating data mode\r
- @param Century It is set according to EFI_TIME Time.\r
-\r
-**/\r
-VOID\r
-ConvertEfiTimeToRtcTime (\r
- IN OUT EFI_TIME *Time,\r
- IN RTC_REGISTER_B RegisterB,\r
- OUT UINT8 *Century\r
- )\r
-{\r
- BOOLEAN IsPM;\r
-\r
- IsPM = TRUE;\r
- //\r
- // Adjust hour field if RTC is in 12 hour mode\r
- //\r
- if (RegisterB.Bits.MIL == 0) {\r
- if (Time->Hour < 12) {\r
- IsPM = FALSE;\r
- }\r
-\r
- if (Time->Hour >= 13) {\r
- Time->Hour = (UINT8) (Time->Hour - 12);\r
- } else if (Time->Hour == 0) {\r
- Time->Hour = 12;\r
- }\r
- }\r
- //\r
- // Set the Time/Date/Daylight Savings values.\r
- //\r
- *Century = DecimalToBcd8 ((UINT8) (Time->Year / 100));\r
-\r
- Time->Year = (UINT16) (Time->Year % 100);\r
-\r
- if (RegisterB.Bits.DM == 0) {\r
- Time->Year = DecimalToBcd8 ((UINT8) Time->Year);\r
- Time->Month = DecimalToBcd8 (Time->Month);\r
- Time->Day = DecimalToBcd8 (Time->Day);\r
- Time->Hour = DecimalToBcd8 (Time->Hour);\r
- Time->Minute = DecimalToBcd8 (Time->Minute);\r
- Time->Second = DecimalToBcd8 (Time->Second);\r
- }\r
- //\r
- // If we are in 12 hour mode and PM is set, then set bit 7 of the Hour field.\r
- //\r
- if (RegisterB.Bits.MIL == 0 && IsPM) {\r
- Time->Hour = (UINT8) (Time->Hour | 0x80);\r
- }\r
-}\r
-\r
-/**\r
- Compare the Hour, Minute and Second of the From time and the To time.\r
- \r
- Only compare H/M/S in EFI_TIME and ignore other fields here.\r
-\r
- @param From the first time\r
- @param To the second time\r
-\r
- @return >0 The H/M/S of the From time is later than those of To time\r
- @return ==0 The H/M/S of the From time is same as those of To time\r
- @return <0 The H/M/S of the From time is earlier than those of To time\r
-**/\r
-INTN\r
-CompareHMS (\r
- IN EFI_TIME *From,\r
- IN EFI_TIME *To\r
- )\r
-{\r
- if ((From->Hour > To->Hour) ||\r
- ((From->Hour == To->Hour) && (From->Minute > To->Minute)) ||\r
- ((From->Hour == To->Hour) && (From->Minute == To->Minute) && (From->Second > To->Second))) {\r
- return 1;\r
- } else if ((From->Hour == To->Hour) && (From->Minute == To->Minute) && (From->Second == To->Second)) {\r
- return 0;\r
- } else {\r
- return -1;\r
- }\r
-}\r
-\r
-/**\r
- To check if second date is later than first date within 24 hours.\r
-\r
- @param From the first date\r
- @param To the second date\r
-\r
- @retval TRUE From is previous to To within 24 hours.\r
- @retval FALSE From is later, or it is previous to To more than 24 hours.\r
-**/\r
-BOOLEAN\r
-IsWithinOneDay (\r
- IN EFI_TIME *From,\r
- IN EFI_TIME *To\r
- )\r
-{\r
- UINT8 DayOfMonth[12];\r
- BOOLEAN Adjacent;\r
-\r
- DayOfMonth[0] = 31;\r
- DayOfMonth[1] = 29;\r
- DayOfMonth[2] = 31;\r
- DayOfMonth[3] = 30;\r
- DayOfMonth[4] = 31;\r
- DayOfMonth[5] = 30;\r
- DayOfMonth[6] = 31;\r
- DayOfMonth[7] = 31;\r
- DayOfMonth[8] = 30;\r
- DayOfMonth[9] = 31;\r
- DayOfMonth[10] = 30;\r
- DayOfMonth[11] = 31;\r
-\r
- Adjacent = FALSE;\r
-\r
- //\r
- // The validity of From->Month field should be checked before\r
- //\r
- ASSERT (From->Month >=1);\r
- ASSERT (From->Month <=12);\r
- \r
- if (From->Year == To->Year) {\r
- if (From->Month == To->Month) {\r
- if ((From->Day + 1) == To->Day) {\r
- if ((CompareHMS(From, To) >= 0)) {\r
- Adjacent = TRUE;\r
- }\r
- } else if (From->Day == To->Day) {\r
- if ((CompareHMS(From, To) <= 0)) {\r
- Adjacent = TRUE;\r
- }\r
- }\r
- } else if (((From->Month + 1) == To->Month) && (To->Day == 1)) {\r
- if ((From->Month == 2) && !IsLeapYear(From)) {\r
- if (From->Day == 28) {\r
- if ((CompareHMS(From, To) >= 0)) {\r
- Adjacent = TRUE;\r
- }\r
- }\r
- } else if (From->Day == DayOfMonth[From->Month - 1]) {\r
- if ((CompareHMS(From, To) >= 0)) {\r
- Adjacent = TRUE;\r
- }\r
- }\r
- }\r
- } else if (((From->Year + 1) == To->Year) &&\r
- (From->Month == 12) &&\r
- (From->Day == 31) &&\r
- (To->Month == 1) &&\r
- (To->Day == 1)) {\r
- if ((CompareHMS(From, To) >= 0)) {\r
- Adjacent = TRUE;\r
- }\r
- }\r
-\r
- return Adjacent;\r
-}\r
-\r