3 Copyright (c) 2005 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 RTC Architectural Protocol GUID as defined in EFI 2.0
21 #include "RealTimeClock.h"
45 INTN mDayOfMonth
[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
55 TODO: Add function description
59 Address - TODO: add argument description
63 TODO: add return values
67 IoWrite8 (PCAT_RTC_ADDRESS_REGISTER
, (UINT8
) (Address
| (UINT8
) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER
) & 0x80)));
68 return IoRead8 (PCAT_RTC_DATA_REGISTER
);
80 Compare the Hour, Minute and Second of the 'From' time and the 'To' time.
81 Only compare H/M/S in EFI_TIME and ignore other fields here.
90 >0 : The H/M/S of the 'From' time is later than those of 'To' time
91 ==0 : The H/M/S of the 'From' time is same as those of 'To' time
92 <0 : The H/M/S of the 'From' time is earlier than those of 'To' time
97 if ((From
->Hour
> To
->Hour
) ||
98 ((From
->Hour
== To
->Hour
) && (From
->Minute
> To
->Minute
)) ||
99 ((From
->Hour
== To
->Hour
) && (From
->Minute
== To
->Minute
) && (From
->Second
> To
->Second
))) {
101 } else if ((From
->Hour
== To
->Hour
) && (From
->Minute
== To
->Minute
) && (From
->Second
== To
->Second
)) {
117 TODO: Add function description
121 Address - TODO: add argument description
122 Data - TODO: add argument description
126 TODO: add return values
130 IoWrite8 (PCAT_RTC_ADDRESS_REGISTER
, (UINT8
) (Address
| (UINT8
) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER
) & 0x80)));
131 IoWrite8 (PCAT_RTC_DATA_REGISTER
, Data
);
136 IN PC_RTC_MODULE_GLOBALS
*Global
142 TODO: Add function description
146 Global - TODO: add argument description
150 EFI_DEVICE_ERROR - TODO: Add description for return value
151 EFI_SUCCESS - TODO: Add description for return value
156 RTC_REGISTER_A RegisterA
;
157 RTC_REGISTER_B RegisterB
;
158 //RTC_REGISTER_C RegisterC;
159 RTC_REGISTER_D RegisterD
;
164 // Acquire RTC Lock to make access to RTC atomic
166 EfiAcquireLock (&Global
->RtcLock
);
169 // Initialize RTC Register
171 // Make sure Division Chain is properly configured,
172 // or RTC clock won't "tick" -- time won't increment
174 RegisterA
.Data
= RTC_INIT_REGISTER_A
;
175 RtcWrite (RTC_ADDRESS_REGISTER_A
, RegisterA
.Data
);
180 RegisterB
.Data
= RtcRead (RTC_ADDRESS_REGISTER_B
);
183 // Clear RTC flag register
185 //RegisterC.Data = RtcRead (RTC_ADDRESS_REGISTER_C);
188 // Clear RTC register D
190 RegisterD
.Data
= RTC_INIT_REGISTER_D
;
191 RtcWrite (RTC_ADDRESS_REGISTER_D
, RegisterD
.Data
);
194 // Wait for up to 0.1 seconds for the RTC to be updated
196 // KEN: BUGBUG following wait action will cause failure under vmware environment.
198 //Status = RtcWaitToUpdate (100000);
199 //if (EFI_ERROR (Status)) {
200 // EfiReleaseLock (&Global->RtcLock);
201 // return EFI_DEVICE_ERROR;
204 // Get the Time/Date/Daylight Savings values.
206 Time
.Second
= RtcRead (RTC_ADDRESS_SECONDS
);
207 Time
.Minute
= RtcRead (RTC_ADDRESS_MINUTES
);
208 Time
.Hour
= RtcRead (RTC_ADDRESS_HOURS
);
209 Time
.Day
= RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH
);
210 Time
.Month
= RtcRead (RTC_ADDRESS_MONTH
);
211 Time
.Year
= RtcRead (RTC_ADDRESS_YEAR
);
213 ConvertRtcTimeToEfiTime (&Time
, RegisterB
);
215 Century
= BcdToDecimal8 (RtcRead (RTC_ADDRESS_CENTURY
));
217 Time
.Year
= (UINT16
) (Century
* 100 + Time
.Year
);
220 // Set RTC configuration after get original time
222 RtcWrite (RTC_ADDRESS_REGISTER_B
, RTC_INIT_REGISTER_B
);
227 EfiReleaseLock (&Global
->RtcLock
);
230 // Validate time fields
232 Status
= RtcTimeFieldsValid (&Time
);
233 if (EFI_ERROR (Status
)) {
234 Time
.Second
= RTC_INIT_SECOND
;
235 Time
.Minute
= RTC_INIT_MINUTE
;
236 Time
.Hour
= RTC_INIT_HOUR
;
237 Time
.Day
= RTC_INIT_DAY
;
238 Time
.Month
= RTC_INIT_MONTH
;
239 Time
.Year
= RTC_INIT_YEAR
;
242 // Reset time value according to new RTC configuration
244 PcRtcSetTime (&Time
, Global
);
252 IN EFI_TIME_CAPABILITIES
*Capabilities
,
253 IN PC_RTC_MODULE_GLOBALS
*Global
263 // TODO: Time - add argument and description to function comment
264 // TODO: Capabilities - add argument and description to function comment
265 // TODO: Global - add argument and description to function comment
266 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
267 // TODO: EFI_DEVICE_ERROR - add return value to function comment
268 // TODO: EFI_SUCCESS - add return value to function comment
271 RTC_REGISTER_B RegisterB
;
276 // Check parameters for null pointer
279 return EFI_INVALID_PARAMETER
;
283 // Acquire RTC Lock to make access to RTC atomic
285 EfiAcquireLock (&Global
->RtcLock
);
288 // Wait for up to 0.1 seconds for the RTC to be updated
290 Status
= RtcWaitToUpdate (100000);
291 if (EFI_ERROR (Status
)) {
292 EfiReleaseLock (&Global
->RtcLock
);
298 RegisterB
.Data
= RtcRead (RTC_ADDRESS_REGISTER_B
);
301 // Get the Time/Date/Daylight Savings values.
303 Time
->Second
= RtcRead (RTC_ADDRESS_SECONDS
);
304 Time
->Minute
= RtcRead (RTC_ADDRESS_MINUTES
);
305 Time
->Hour
= RtcRead (RTC_ADDRESS_HOURS
);
306 Time
->Day
= RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH
);
307 Time
->Month
= RtcRead (RTC_ADDRESS_MONTH
);
308 Time
->Year
= RtcRead (RTC_ADDRESS_YEAR
);
310 ConvertRtcTimeToEfiTime (Time
, RegisterB
);
312 Century
= BcdToDecimal8 (RtcRead (RTC_ADDRESS_CENTURY
));
314 Time
->Year
= (UINT16
) (Century
* 100 + Time
->Year
);
319 EfiReleaseLock (&Global
->RtcLock
);
322 // Get the variable that containts the TimeZone and Daylight fields
324 Time
->TimeZone
= Global
->SavedTimeZone
;
325 Time
->Daylight
= Global
->Daylight
;
327 //BufferSize = sizeof (INT16) + sizeof (UINT8);
330 // Make sure all field values are in correct range
332 Status
= RtcTimeFieldsValid (Time
);
333 if (EFI_ERROR (Status
)) {
334 return EFI_DEVICE_ERROR
;
337 // Fill in Capabilities if it was passed in
340 Capabilities
->Resolution
= 1;
344 Capabilities
->Accuracy
= 50000000;
348 Capabilities
->SetsToZero
= FALSE
;
357 IN PC_RTC_MODULE_GLOBALS
*Global
367 // TODO: Time - add argument and description to function comment
368 // TODO: Global - add argument and description to function comment
369 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
373 RTC_REGISTER_B RegisterB
;
377 return EFI_INVALID_PARAMETER
;
380 // Make sure that the time fields are valid
382 Status
= RtcTimeFieldsValid (Time
);
383 if (EFI_ERROR (Status
)) {
387 CopyMem (&RtcTime
, Time
, sizeof (EFI_TIME
));
390 // Acquire RTC Lock to make access to RTC atomic
392 EfiAcquireLock (&Global
->RtcLock
);
395 // Wait for up to 0.1 seconds for the RTC to be updated
397 Status
= RtcWaitToUpdate (100000);
398 if (EFI_ERROR (Status
)) {
399 EfiReleaseLock (&Global
->RtcLock
);
403 // Read Register B, and inhibit updates of the RTC
405 RegisterB
.Data
= RtcRead (RTC_ADDRESS_REGISTER_B
);
406 RegisterB
.Bits
.SET
= 1;
407 RtcWrite (RTC_ADDRESS_REGISTER_B
, RegisterB
.Data
);
409 ConvertEfiTimeToRtcTime (&RtcTime
, RegisterB
, &Century
);
411 RtcWrite (RTC_ADDRESS_SECONDS
, RtcTime
.Second
);
412 RtcWrite (RTC_ADDRESS_MINUTES
, RtcTime
.Minute
);
413 RtcWrite (RTC_ADDRESS_HOURS
, RtcTime
.Hour
);
414 RtcWrite (RTC_ADDRESS_DAY_OF_THE_MONTH
, RtcTime
.Day
);
415 RtcWrite (RTC_ADDRESS_MONTH
, RtcTime
.Month
);
416 RtcWrite (RTC_ADDRESS_YEAR
, (UINT8
) RtcTime
.Year
);
417 RtcWrite (RTC_ADDRESS_CENTURY
, Century
);
420 // Allow updates of the RTC registers
422 RegisterB
.Bits
.SET
= 0;
423 RtcWrite (RTC_ADDRESS_REGISTER_B
, RegisterB
.Data
);
428 EfiReleaseLock (&Global
->RtcLock
);
431 // Set the variable that containts the TimeZone and Daylight fields
433 Global
->SavedTimeZone
= Time
->TimeZone
;
434 Global
->Daylight
= Time
->Daylight
;
441 OUT BOOLEAN
*Enabled
,
442 OUT BOOLEAN
*Pending
,
444 IN PC_RTC_MODULE_GLOBALS
*Global
456 // TODO: Enabled - add argument and description to function comment
457 // TODO: Pending - add argument and description to function comment
458 // TODO: Time - add argument and description to function comment
459 // TODO: Global - add argument and description to function comment
460 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
461 // TODO: EFI_DEVICE_ERROR - add return value to function comment
462 // TODO: EFI_DEVICE_ERROR - add return value to function comment
463 // TODO: EFI_SUCCESS - add return value to function comment
466 RTC_REGISTER_B RegisterB
;
467 RTC_REGISTER_C RegisterC
;
471 // Check paramters for null pointers
473 if ((Enabled
== NULL
) || (Pending
== NULL
) || (Time
== NULL
)) {
474 return EFI_INVALID_PARAMETER
;
478 // Acquire RTC Lock to make access to RTC atomic
480 EfiAcquireLock (&Global
->RtcLock
);
483 // Wait for up to 0.1 seconds for the RTC to be updated
485 Status
= RtcWaitToUpdate (100000);
486 if (EFI_ERROR (Status
)) {
487 EfiReleaseLock (&Global
->RtcLock
);
488 return EFI_DEVICE_ERROR
;
491 // Read Register B and Register C
493 RegisterB
.Data
= RtcRead (RTC_ADDRESS_REGISTER_B
);
494 RegisterC
.Data
= RtcRead (RTC_ADDRESS_REGISTER_C
);
497 // Get the Time/Date/Daylight Savings values.
499 *Enabled
= RegisterB
.Bits
.AIE
;
501 Time
->Second
= RtcRead (RTC_ADDRESS_SECONDS_ALARM
);
502 Time
->Minute
= RtcRead (RTC_ADDRESS_MINUTES_ALARM
);
503 Time
->Hour
= RtcRead (RTC_ADDRESS_HOURS_ALARM
);
504 Time
->Day
= RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH
);
505 Time
->Month
= RtcRead (RTC_ADDRESS_MONTH
);
506 Time
->Year
= RtcRead (RTC_ADDRESS_YEAR
);
511 Time
->Day
= RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH
);
512 Time
->Month
= RtcRead (RTC_ADDRESS_MONTH
);
513 Time
->Year
= RtcRead (RTC_ADDRESS_YEAR
);
516 ConvertRtcTimeToEfiTime (Time
, RegisterB
);
518 Century
= BcdToDecimal8 (RtcRead (RTC_ADDRESS_CENTURY
));
520 Time
->Year
= (UINT16
) (Century
* 100 + Time
->Year
);
525 EfiReleaseLock (&Global
->RtcLock
);
528 // Make sure all field values are in correct range
530 Status
= RtcTimeFieldsValid (Time
);
531 if (EFI_ERROR (Status
)) {
532 return EFI_DEVICE_ERROR
;
535 *Pending
= RegisterC
.Bits
.AF
;
545 IN PC_RTC_MODULE_GLOBALS
*Global
557 // TODO: Enable - add argument and description to function comment
558 // TODO: Time - add argument and description to function comment
559 // TODO: Global - add argument and description to function comment
560 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
561 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
562 // TODO: EFI_UNSUPPORTED - add return value to function comment
563 // TODO: EFI_DEVICE_ERROR - add return value to function comment
564 // TODO: EFI_SUCCESS - add return value to function comment
568 RTC_REGISTER_B RegisterB
;
570 EFI_TIME_CAPABILITIES Capabilities
;
575 return EFI_INVALID_PARAMETER
;
578 // Make sure that the time fields are valid
580 Status
= RtcTimeFieldsValid (Time
);
581 if (EFI_ERROR (Status
)) {
582 return EFI_INVALID_PARAMETER
;
585 // Just support set alarm time within 24 hours
587 PcRtcGetTime (&RtcTime
, &Capabilities
, Global
);
588 if (!IsWithinOneDay (&RtcTime
, Time
)) {
589 return EFI_UNSUPPORTED
;
592 // Make a local copy of the time and date
594 CopyMem (&RtcTime
, Time
, sizeof (EFI_TIME
));
598 // Acquire RTC Lock to make access to RTC atomic
600 EfiAcquireLock (&Global
->RtcLock
);
603 // Wait for up to 0.1 seconds for the RTC to be updated
605 Status
= RtcWaitToUpdate (100000);
606 if (EFI_ERROR (Status
)) {
607 EfiReleaseLock (&Global
->RtcLock
);
608 return EFI_DEVICE_ERROR
;
611 // Read Register B, and inhibit updates of the RTC
613 RegisterB
.Data
= RtcRead (RTC_ADDRESS_REGISTER_B
);
615 RegisterB
.Bits
.SET
= 1;
616 RtcWrite (RTC_ADDRESS_REGISTER_B
, RegisterB
.Data
);
619 ConvertEfiTimeToRtcTime (&RtcTime
, RegisterB
, &Century
);
622 // Set RTC alarm time
624 RtcWrite (RTC_ADDRESS_SECONDS_ALARM
, RtcTime
.Second
);
625 RtcWrite (RTC_ADDRESS_MINUTES_ALARM
, RtcTime
.Minute
);
626 RtcWrite (RTC_ADDRESS_HOURS_ALARM
, RtcTime
.Hour
);
628 RegisterB
.Bits
.AIE
= 1;
631 RegisterB
.Bits
.AIE
= 0;
634 // Allow updates of the RTC registers
636 RegisterB
.Bits
.SET
= 0;
637 RtcWrite (RTC_ADDRESS_REGISTER_B
, RegisterB
.Data
);
642 EfiReleaseLock (&Global
->RtcLock
);
648 ConvertRtcTimeToEfiTime (
650 IN RTC_REGISTER_B RegisterB
662 // TODO: Time - add argument and description to function comment
663 // TODO: RegisterB - add argument and description to function comment
667 if ((Time
->Hour
) & 0x80) {
673 Time
->Hour
= (UINT8
) (Time
->Hour
& 0x7f);
675 if (RegisterB
.Bits
.DM
== 0) {
676 Time
->Year
= BcdToDecimal8 ((UINT8
) Time
->Year
);
677 Time
->Month
= BcdToDecimal8 (Time
->Month
);
678 Time
->Day
= BcdToDecimal8 (Time
->Day
);
679 Time
->Hour
= BcdToDecimal8 (Time
->Hour
);
680 Time
->Minute
= BcdToDecimal8 (Time
->Minute
);
681 Time
->Second
= BcdToDecimal8 (Time
->Second
);
684 // If time is in 12 hour format, convert it to 24 hour format
686 if (RegisterB
.Bits
.MIL
== 0) {
687 if (PM
&& Time
->Hour
< 12) {
688 Time
->Hour
= (UINT8
) (Time
->Hour
+ 12);
691 if (!PM
&& Time
->Hour
== 12) {
696 Time
->Nanosecond
= 0;
697 Time
->TimeZone
= EFI_UNSPECIFIED_TIMEZONE
;
714 // TODO: Timeout - add argument and description to function comment
715 // TODO: EFI_DEVICE_ERROR - add return value to function comment
716 // TODO: EFI_DEVICE_ERROR - add return value to function comment
717 // TODO: EFI_SUCCESS - add return value to function comment
719 RTC_REGISTER_A RegisterA
;
720 RTC_REGISTER_D RegisterD
;
723 // See if the RTC is functioning correctly
725 RegisterD
.Data
= RtcRead (RTC_ADDRESS_REGISTER_D
);
727 if (RegisterD
.Bits
.VRT
== 0) {
728 return EFI_DEVICE_ERROR
;
731 // Wait for up to 0.1 seconds for the RTC to be ready.
733 Timeout
= (Timeout
/ 10) + 1;
734 RegisterA
.Data
= RtcRead (RTC_ADDRESS_REGISTER_A
);
735 while (RegisterA
.Bits
.UIP
== 1 && Timeout
> 0) {
736 MicroSecondDelay (10);
737 RegisterA
.Data
= RtcRead (RTC_ADDRESS_REGISTER_A
);
741 RegisterD
.Data
= RtcRead (RTC_ADDRESS_REGISTER_D
);
742 if (Timeout
== 0 || RegisterD
.Bits
.VRT
== 0) {
743 return EFI_DEVICE_ERROR
;
761 // TODO: Time - add argument and description to function comment
762 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
763 // TODO: EFI_SUCCESS - add return value to function comment
765 if (Time
->Year
< 1998 ||
769 (!DayValid (Time
)) ||
773 Time
->Nanosecond
> 999999999 ||
774 (!(Time
->TimeZone
== EFI_UNSPECIFIED_TIMEZONE
|| (Time
->TimeZone
>= -1440 && Time
->TimeZone
<= 1440))) ||
775 (Time
->Daylight
& (~(EFI_TIME_ADJUST_DAYLIGHT
| EFI_TIME_IN_DAYLIGHT
)))
777 return EFI_INVALID_PARAMETER
;
791 TODO: Add function description
795 Time - TODO: add argument description
799 TODO: add return values
806 Time
->Day
> mDayOfMonth
[Time
->Month
- 1] ||
807 (Time
->Month
== 2 && (!IsLeapYear (Time
) && Time
->Day
> 28))
823 TODO: Add function description
827 Time - TODO: add argument description
831 TODO: add return values
835 if (Time
->Year
% 4 == 0) {
836 if (Time
->Year
% 100 == 0) {
837 if (Time
->Year
% 400 == 0) {
851 ConvertEfiTimeToRtcTime (
853 IN RTC_REGISTER_B RegisterB
,
865 // TODO: Time - add argument and description to function comment
866 // TODO: RegisterB - add argument and description to function comment
867 // TODO: Century - add argument and description to function comment
873 // Adjust hour field if RTC in in 12 hour mode
875 if (RegisterB
.Bits
.MIL
== 0) {
876 if (Time
->Hour
< 12) {
880 if (Time
->Hour
>= 13) {
881 Time
->Hour
= (UINT8
) (Time
->Hour
- 12);
882 } else if (Time
->Hour
== 0) {
887 // Set the Time/Date/Daylight Savings values.
889 *Century
= DecimaltoBcd ((UINT8
) (Time
->Year
/ 100));
891 Time
->Year
= (UINT16
) (Time
->Year
% 100);
893 if (RegisterB
.Bits
.DM
== 0) {
894 Time
->Year
= DecimaltoBcd ((UINT8
) Time
->Year
);
895 Time
->Month
= DecimaltoBcd (Time
->Month
);
896 Time
->Day
= DecimaltoBcd (Time
->Day
);
897 Time
->Hour
= DecimaltoBcd (Time
->Hour
);
898 Time
->Minute
= DecimaltoBcd (Time
->Minute
);
899 Time
->Second
= DecimaltoBcd (Time
->Second
);
902 // If we are in 12 hour mode and PM is set, then set bit 7 of the Hour field.
904 if (RegisterB
.Bits
.MIL
== 0 && PM
) {
905 Time
->Hour
= (UINT8
) (Time
->Hour
| 0x80);
918 Judge whether two days are adjacent.
927 TRUE - The interval of two days are within one day.
928 FALSE - The interval of two days exceed ony day or parameter error.
932 BOOLEAN Adjacent
= FALSE
;
934 if (From
->Year
== To
->Year
) {
935 if (From
->Month
== To
->Month
) {
936 if ((From
->Day
+ 1) == To
->Day
) {
937 if ((CompareHMS(From
, To
) >= 0)) {
940 } else if (From
->Day
== To
->Day
) {
941 if ((CompareHMS(From
, To
) <= 0)) {
945 } else if (((From
->Month
+ 1) == To
->Month
) && (To
->Day
== 1)) {
946 if ((From
->Month
== 2) && !IsLeapYear(From
)) {
947 if (From
->Day
== 28) {
948 if ((CompareHMS(From
, To
) >= 0)) {
952 } else if (From
->Day
== mDayOfMonth
[From
->Month
- 1]) {
953 if ((CompareHMS(From
, To
) >= 0)) {
958 } else if (((From
->Year
+ 1) == To
->Year
) &&
959 (From
->Month
== 12) &&
963 if ((CompareHMS(From
, To
) >= 0)) {
984 // TODO: DecValue - add argument and description to function comment
989 High
= DecValue
/ 10;
990 Low
= DecValue
- (High
* 10);
992 return (UINT8
) (Low
+ (High
<< 4));