-/*++\r
-\r
-Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved. <BR>\r
-This software and associated documentation (if any) is furnished\r
-under a license and may only be used or copied in accordance\r
-with the terms of the license. Except as permitted by such\r
-license, no part of this software or documentation may be\r
-reproduced, stored in a retrieval system, or transmitted in any\r
-form or by any means without the express written consent of\r
-Intel Corporation.\r
-\r
-\r
-\r
-Module Name:\r
+/** @file\r
+ RTC Architectural Protocol GUID as defined in DxeCis 0.96.\r
\r
- PcRtc.c\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
-Abstract:\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
- RTC Architectural Protocol GUID as defined in DxeCis 0.96\r
-\r
---*/\r
+**/\r
\r
#include "PcRtc.h"\r
\r
-STATIC\r
INTN\r
CompareHMS (\r
IN EFI_TIME *From,\r
IN EFI_TIME *To\r
);\r
\r
-STATIC\r
BOOLEAN\r
IsWithinOneDay (\r
IN EFI_TIME *From,\r
IN EFI_TIME *To\r
);\r
\r
-STATIC\r
UINT8\r
RtcRead (\r
IN UINT8 Address\r
return IoRead8 (PCAT_RTC_DATA_REGISTER);\r
}\r
\r
-STATIC\r
VOID\r
RtcWrite (\r
IN UINT8 Address,\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
// Wait for up to 0.1 seconds for the RTC to be updated\r
//\r
- Status = RtcWaitToUpdate (100000);\r
+ Status = RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout));\r
if (EFI_ERROR (Status)) {\r
//BugBug: the EfiAtRuntime should be encapsulated in EfiAcquireLock or\r
// provide a new instance for EfiAcquireLock, say, RtEfiAcquireLock\r
Time.Month = RtcRead (RTC_ADDRESS_MONTH);\r
Time.Year = RtcRead (RTC_ADDRESS_YEAR);\r
\r
- ConvertRtcTimeToEfiTime (&Time, RegisterB);\r
-\r
if (RtcTestCenturyRegister () == EFI_SUCCESS) {\r
- Century = BcdToDecimal8 ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f));\r
+ Century = (UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f);\r
} else {\r
- Century = BcdToDecimal8 (RtcRead (RTC_ADDRESS_CENTURY));\r
+ Century = RtcRead (RTC_ADDRESS_CENTURY);\r
}\r
\r
- Time.Year = (UINT16) (Century * 100 + Time.Year);\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, RTC_INIT_REGISTER_B);\r
+ RtcWrite (RTC_ADDRESS_REGISTER_B, (UINT8)(RTC_INIT_REGISTER_B | (RegisterB.Data & BIT5)));\r
\r
//\r
// Release RTC Lock.\r
//\r
//BugBug: the EfiAtRuntime should be encapsulated in EfiAcquireLock or\r
// provide a new instance for EfiAcquireLock, say, RtEfiAcquireLock\r
+ //\r
if (!EfiAtRuntime ()) {\r
EfiReleaseLock (&Global->RtcLock);\r
}\r
+ \r
//\r
// Validate time fields\r
//\r
- Status = RtcTimeFieldsValid (&Time);\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.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"TimerVar",\r
+ &gEfiGenericPlatformVariableGuid,\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
// Wait for up to 0.1 seconds for the RTC to be updated\r
//\r
- Status = RtcWaitToUpdate (100000);\r
+ Status = RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout));\r
if (EFI_ERROR (Status)) {\r
//BugBug: the EfiAtRuntime should be encapsulated in EfiReleaseLock or\r
// provide a new instance for EfiReleaseLock, say, RtEfiReleaseLock\r
Time->Month = RtcRead (RTC_ADDRESS_MONTH);\r
Time->Year = RtcRead (RTC_ADDRESS_YEAR);\r
\r
- ConvertRtcTimeToEfiTime (Time, RegisterB);\r
-\r
if (RtcTestCenturyRegister () == EFI_SUCCESS) {\r
- Century = BcdToDecimal8 ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f));\r
+ Century = (UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f);\r
} else {\r
- Century = BcdToDecimal8 (RtcRead (RTC_ADDRESS_CENTURY));\r
+ Century = RtcRead (RTC_ADDRESS_CENTURY);\r
}\r
\r
- Time->Year = (UINT16) (Century * 100 + Time->Year);\r
-\r
//\r
// Release RTC Lock.\r
//\r
//\r
// Make sure all field values are in correct range\r
//\r
- Status = RtcTimeFieldsValid (Time);\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
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
// Wait for up to 0.1 seconds for the RTC to be updated\r
//\r
- Status = RtcWaitToUpdate (100000);\r
+ Status = RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout));\r
if (EFI_ERROR (Status)) {\r
//BugBug: the EfiAtRuntime should be encapsulated in EfiReleaseLock or\r
// provide a new instance for EfiReleaseLock, say, RtEfiReleaseLock\r
//\r
Global->SavedTimeZone = Time->TimeZone;\r
Global->Daylight = Time->Daylight;\r
- return Status;\r
+\r
+ TimerVar = Time->Daylight;\r
+ TimerVar = (UINT32) ((TimerVar << 16) | Time->TimeZone);\r
+ Status = EfiSetVariable (\r
+ L"TimerVar",\r
+ &gEfiGenericPlatformVariableGuid,\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
EFI_STATUS\r
//\r
// Wait for up to 0.1 seconds for the RTC to be updated\r
//\r
- Status = RtcWaitToUpdate (100000);\r
+ Status = RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout));\r
if (EFI_ERROR (Status)) {\r
//BugBug: the EfiAtRuntime should be encapsulated in EfiReleaseLock or\r
// provide a new instance for EfiReleaseLock, say, RtEfiReleaseLock\r
Time->Year = RtcRead (RTC_ADDRESS_YEAR);\r
}\r
\r
- ConvertRtcTimeToEfiTime (Time, RegisterB);\r
-\r
if (RtcTestCenturyRegister () == EFI_SUCCESS) {\r
- Century = BcdToDecimal8 ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f));\r
+ Century = (UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f);\r
} else {\r
- Century = BcdToDecimal8 (RtcRead (RTC_ADDRESS_CENTURY));\r
+ Century = RtcRead (RTC_ADDRESS_CENTURY);\r
}\r
\r
- Time->Year = (UINT16) (Century * 100 + Time->Year);\r
-\r
//\r
// Release RTC Lock.\r
//\r
//\r
// Make sure all field values are in correct range\r
//\r
- Status = RtcTimeFieldsValid (Time);\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
// Wait for up to 0.1 seconds for the RTC to be updated\r
//\r
- Status = RtcWaitToUpdate (100000);\r
+ Status = RtcWaitToUpdate (PcdGet32 (PcdRealTimeClockUpdateTimeout));\r
if (EFI_ERROR (Status)) {\r
//BugBug: the EfiAtRuntime should be encapsulated in EfiReleaseLock or\r
// provide a new instance for EfiReleaseLock, say, RtEfiReleaseLock\r
return EFI_DEVICE_ERROR;\r
}\r
\r
-VOID\r
-ConvertRtcTimeToEfiTime (\r
- IN EFI_TIME *Time,\r
- IN RTC_REGISTER_B RegisterB\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.\r
+ 0xff if Value is invalid.\r
+\r
+**/\r
+UINT8\r
+CheckAndConvertBcd8ToDecimal8 (\r
+ IN UINT8 Value\r
)\r
-/*++\r
+{\r
+ if ((Value < 0xa0) && ((Value & 0xf) < 0xa)) {\r
+ return BcdToDecimal8 (Value);\r
+ }\r
\r
-Routine Description:\r
+ return 0xff;\r
+}\r
\r
- Arguments:\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
-Returns:\r
---*/\r
-// GC_TODO: Time - add argument and description to function comment\r
-// GC_TODO: RegisterB - add argument and description to function comment\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 PM;\r
\r
Time->Hour = (UINT8) (Time->Hour & 0x7f);\r
\r
if (RegisterB.Bits.DM == 0) {\r
- Time->Year = BcdToDecimal8 ((UINT8) Time->Year);\r
- Time->Month = BcdToDecimal8 (Time->Month);\r
- Time->Day = BcdToDecimal8 (Time->Day);\r
- Time->Hour = BcdToDecimal8 (Time->Hour);\r
- Time->Minute = BcdToDecimal8 (Time->Minute);\r
- Time->Second = BcdToDecimal8 (Time->Second);\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
+ Century = CheckAndConvertBcd8ToDecimal8 (Century);\r
}\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
Time->Nanosecond = 0;\r
Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
Time->Daylight = 0;\r
+\r
+ return EFI_SUCCESS;\r
}\r
\r
EFI_STATUS\r
}\r
}\r
\r
-STATIC\r
INTN\r
CompareHMS (\r
IN EFI_TIME *From,\r
}\r
}\r
\r
-STATIC\r
BOOLEAN\r
IsWithinOneDay (\r
IN EFI_TIME *From,\r
\r
--*/\r
{\r
- UINT8 DayOfMonth[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};\r
- BOOLEAN Adjacent = FALSE;\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
if (From->Year == To->Year) {\r
if (From->Month == To->Month) {\r