]> git.proxmox.com Git - mirror_edk2.git/blob - DuetPkg/PcRtc/RealTimeClock.c
Porting Duet module from EDKI to EDKII
[mirror_edk2.git] / DuetPkg / PcRtc / RealTimeClock.c
1 /*++
2
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
8
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.
11
12 Module Name:
13 PcRtc.c
14
15 Abstract:
16
17 RTC Architectural Protocol GUID as defined in EFI 2.0
18
19 --*/
20
21 #include "RealTimeClock.h"
22
23 BOOLEAN
24 DayValid (
25 IN EFI_TIME *Time
26 );
27
28 BOOLEAN
29 IsLeapYear (
30 IN EFI_TIME *Time
31 );
32
33 BOOLEAN
34 IsWithinOneDay (
35 IN EFI_TIME *From,
36 IN EFI_TIME *To
37 );
38
39 INTN
40 CompareHMS (
41 IN EFI_TIME *From,
42 IN EFI_TIME *To
43 );
44
45 UINT8
46 RtcRead (
47 IN UINT8 Address
48 )
49 /*++
50
51 Routine Description:
52
53 TODO: Add function description
54
55 Arguments:
56
57 Address - TODO: add argument description
58
59 Returns:
60
61 TODO: add return values
62
63 --*/
64 {
65 IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8) (Address | (UINT8) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & 0x80)));
66 return IoRead8 (PCAT_RTC_DATA_REGISTER);
67 }
68
69 INTN
70 CompareHMS (
71 IN EFI_TIME *From,
72 IN EFI_TIME *To
73 )
74 /*++
75
76 Routine Description:
77
78 Compare the Hour, Minute and Second of the 'From' time and the 'To' time.
79 Only compare H/M/S in EFI_TIME and ignore other fields here.
80
81 Arguments:
82
83 From - the first time
84 To - the second time
85
86 Returns:
87
88 >0 : The H/M/S of the 'From' time is later than those of 'To' time
89 ==0 : The H/M/S of the 'From' time is same as those of 'To' time
90 <0 : The H/M/S of the 'From' time is earlier than those of 'To' time
91
92 --*/
93
94 {
95 if ((From->Hour > To->Hour) ||
96 ((From->Hour == To->Hour) && (From->Minute > To->Minute)) ||
97 ((From->Hour == To->Hour) && (From->Minute == To->Minute) && (From->Second > To->Second))) {
98 return 1;
99 } else if ((From->Hour == To->Hour) && (From->Minute == To->Minute) && (From->Second == To->Second)) {
100 return 0;
101 } else {
102 return -1;
103 }
104 }
105
106 VOID
107 RtcWrite (
108 IN UINT8 Address,
109 IN UINT8 Data
110 )
111 /*++
112
113 Routine Description:
114
115 TODO: Add function description
116
117 Arguments:
118
119 Address - TODO: add argument description
120 Data - TODO: add argument description
121
122 Returns:
123
124 TODO: add return values
125
126 --*/
127 {
128 IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8) (Address | (UINT8) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & 0x80)));
129 IoWrite8 (PCAT_RTC_DATA_REGISTER, Data);
130 }
131
132 EFI_STATUS
133 PcRtcInit (
134 IN PC_RTC_MODULE_GLOBALS *Global
135 )
136 /*++
137
138 Routine Description:
139
140 TODO: Add function description
141
142 Arguments:
143
144 Global - TODO: add argument description
145
146 Returns:
147
148 EFI_DEVICE_ERROR - TODO: Add description for return value
149 EFI_SUCCESS - TODO: Add description for return value
150
151 --*/
152 {
153 EFI_STATUS Status;
154 RTC_REGISTER_A RegisterA;
155 RTC_REGISTER_B RegisterB;
156 RTC_REGISTER_C RegisterC;
157 RTC_REGISTER_D RegisterD;
158 UINT8 Century;
159 EFI_TIME Time;
160
161 //
162 // Acquire RTC Lock to make access to RTC atomic
163 //
164 EfiAcquireLock (&Global->RtcLock);
165
166 //
167 // Initialize RTC Register
168 //
169 // Make sure Division Chain is properly configured,
170 // or RTC clock won't "tick" -- time won't increment
171 //
172 RegisterA.Data = RTC_INIT_REGISTER_A;
173 RtcWrite (RTC_ADDRESS_REGISTER_A, RegisterA.Data);
174
175 //
176 // Read Register B
177 //
178 RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
179
180 //
181 // Clear RTC flag register
182 //
183 RegisterC.Data = RtcRead (RTC_ADDRESS_REGISTER_C);
184
185 //
186 // Clear RTC register D
187 //
188 RegisterD.Data = RTC_INIT_REGISTER_D;
189 RtcWrite (RTC_ADDRESS_REGISTER_D, RegisterD.Data);
190
191 //
192 // Wait for up to 0.1 seconds for the RTC to be updated
193 //
194 Status = RtcWaitToUpdate (100000);
195 if (EFI_ERROR (Status)) {
196 EfiReleaseLock (&Global->RtcLock);
197 return EFI_DEVICE_ERROR;
198 }
199 //
200 // Get the Time/Date/Daylight Savings values.
201 //
202 Time.Second = RtcRead (RTC_ADDRESS_SECONDS);
203 Time.Minute = RtcRead (RTC_ADDRESS_MINUTES);
204 Time.Hour = RtcRead (RTC_ADDRESS_HOURS);
205 Time.Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);
206 Time.Month = RtcRead (RTC_ADDRESS_MONTH);
207 Time.Year = RtcRead (RTC_ADDRESS_YEAR);
208
209 ConvertRtcTimeToEfiTime (&Time, RegisterB);
210
211 if (RtcTestCenturyRegister () == EFI_SUCCESS) {
212 Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f));
213 } else {
214 Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY));
215 }
216
217 Time.Year = (UINT16) (Century * 100 + Time.Year);
218
219 //
220 // Set RTC configuration after get original time
221 //
222 RtcWrite (RTC_ADDRESS_REGISTER_B, RTC_INIT_REGISTER_B);
223
224 //
225 // Release RTC Lock.
226 //
227 EfiReleaseLock (&Global->RtcLock);
228
229 //
230 // Validate time fields
231 //
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;
240 }
241 //
242 // Reset time value according to new RTC configuration
243 //
244 PcRtcSetTime (&Time, Global);
245
246 return EFI_SUCCESS;
247 }
248
249 EFI_STATUS
250 PcRtcGetTime (
251 OUT EFI_TIME *Time,
252 IN EFI_TIME_CAPABILITIES *Capabilities,
253 IN PC_RTC_MODULE_GLOBALS *Global
254 )
255 /*++
256
257 Routine Description:
258
259 Arguments:
260
261 Returns:
262 --*/
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
269 {
270 EFI_STATUS Status;
271 RTC_REGISTER_B RegisterB;
272 UINT8 Century;
273 UINTN BufferSize;
274
275 //
276 // Check parameters for null pointer
277 //
278 if (Time == NULL) {
279 return EFI_INVALID_PARAMETER;
280
281 }
282 //
283 // Acquire RTC Lock to make access to RTC atomic
284 //
285 EfiAcquireLock (&Global->RtcLock);
286
287 //
288 // Wait for up to 0.1 seconds for the RTC to be updated
289 //
290 Status = RtcWaitToUpdate (100000);
291 if (EFI_ERROR (Status)) {
292 EfiReleaseLock (&Global->RtcLock);
293 return Status;
294 }
295 //
296 // Read Register B
297 //
298 RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
299
300 //
301 // Get the Time/Date/Daylight Savings values.
302 //
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);
309
310 ConvertRtcTimeToEfiTime (Time, RegisterB);
311
312 if (RtcTestCenturyRegister () == EFI_SUCCESS) {
313 Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f));
314 } else {
315 Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY));
316 }
317
318 Time->Year = (UINT16) (Century * 100 + Time->Year);
319
320 //
321 // Release RTC Lock.
322 //
323 EfiReleaseLock (&Global->RtcLock);
324
325 //
326 // Get the variable that containts the TimeZone and Daylight fields
327 //
328 Time->TimeZone = Global->SavedTimeZone;
329 Time->Daylight = Global->Daylight;
330
331 BufferSize = sizeof (INT16) + sizeof (UINT8);
332
333 //
334 // Make sure all field values are in correct range
335 //
336 Status = RtcTimeFieldsValid (Time);
337 if (EFI_ERROR (Status)) {
338 return EFI_DEVICE_ERROR;
339 }
340 //
341 // Fill in Capabilities if it was passed in
342 //
343 if (Capabilities) {
344 Capabilities->Resolution = 1;
345 //
346 // 1 hertz
347 //
348 Capabilities->Accuracy = 50000000;
349 //
350 // 50 ppm
351 //
352 Capabilities->SetsToZero = FALSE;
353 }
354
355 return EFI_SUCCESS;
356 }
357
358 EFI_STATUS
359 PcRtcSetTime (
360 IN EFI_TIME *Time,
361 IN PC_RTC_MODULE_GLOBALS *Global
362 )
363 /*++
364
365 Routine Description:
366
367 Arguments:
368
369 Returns:
370 --*/
371 // TODO: Time - add argument and description to function comment
372 // TODO: Global - add argument and description to function comment
373 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
374 {
375 EFI_STATUS Status;
376 EFI_TIME RtcTime;
377 RTC_REGISTER_B RegisterB;
378 UINT8 Century;
379
380 if (Time == NULL) {
381 return EFI_INVALID_PARAMETER;
382 }
383 //
384 // Make sure that the time fields are valid
385 //
386 Status = RtcTimeFieldsValid (Time);
387 if (EFI_ERROR (Status)) {
388 return Status;
389 }
390
391 CopyMem (&RtcTime, Time, sizeof (EFI_TIME));
392
393 //
394 // Acquire RTC Lock to make access to RTC atomic
395 //
396 EfiAcquireLock (&Global->RtcLock);
397
398 //
399 // Wait for up to 0.1 seconds for the RTC to be updated
400 //
401 Status = RtcWaitToUpdate (100000);
402 if (EFI_ERROR (Status)) {
403 EfiReleaseLock (&Global->RtcLock);
404 return Status;
405 }
406 //
407 // Read Register B, and inhibit updates of the RTC
408 //
409 RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
410 RegisterB.Bits.SET = 1;
411 RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);
412
413 ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century);
414
415 RtcWrite (RTC_ADDRESS_SECONDS, RtcTime.Second);
416 RtcWrite (RTC_ADDRESS_MINUTES, RtcTime.Minute);
417 RtcWrite (RTC_ADDRESS_HOURS, RtcTime.Hour);
418 RtcWrite (RTC_ADDRESS_DAY_OF_THE_MONTH, RtcTime.Day);
419 RtcWrite (RTC_ADDRESS_MONTH, RtcTime.Month);
420 RtcWrite (RTC_ADDRESS_YEAR, (UINT8) RtcTime.Year);
421 if (RtcTestCenturyRegister () == EFI_SUCCESS) {
422 Century = (UINT8) ((Century & 0x7f) | (RtcRead (RTC_ADDRESS_CENTURY) & 0x80));
423 }
424
425 RtcWrite (RTC_ADDRESS_CENTURY, Century);
426
427 //
428 // Allow updates of the RTC registers
429 //
430 RegisterB.Bits.SET = 0;
431 RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);
432
433 //
434 // Release RTC Lock.
435 //
436 EfiReleaseLock (&Global->RtcLock);
437
438 //
439 // Set the variable that containts the TimeZone and Daylight fields
440 //
441 Global->SavedTimeZone = Time->TimeZone;
442 Global->Daylight = Time->Daylight;
443 return Status;
444 }
445
446 EFI_STATUS
447 EFIAPI
448 PcRtcGetWakeupTime (
449 OUT BOOLEAN *Enabled,
450 OUT BOOLEAN *Pending,
451 OUT EFI_TIME *Time,
452 IN PC_RTC_MODULE_GLOBALS *Global
453 )
454 /*++
455
456 Routine Description:
457
458 Arguments:
459
460
461
462 Returns:
463 --*/
464 // TODO: Enabled - add argument and description to function comment
465 // TODO: Pending - add argument and description to function comment
466 // TODO: Time - add argument and description to function comment
467 // TODO: Global - add argument and description to function comment
468 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
469 // TODO: EFI_DEVICE_ERROR - add return value to function comment
470 // TODO: EFI_DEVICE_ERROR - add return value to function comment
471 // TODO: EFI_SUCCESS - add return value to function comment
472 {
473 EFI_STATUS Status;
474 RTC_REGISTER_B RegisterB;
475 RTC_REGISTER_C RegisterC;
476 UINT8 Century;
477
478 //
479 // Check paramters for null pointers
480 //
481 if ((Enabled == NULL) || (Pending == NULL) || (Time == NULL)) {
482 return EFI_INVALID_PARAMETER;
483
484 }
485 //
486 // Acquire RTC Lock to make access to RTC atomic
487 //
488 EfiAcquireLock (&Global->RtcLock);
489
490 //
491 // Wait for up to 0.1 seconds for the RTC to be updated
492 //
493 Status = RtcWaitToUpdate (100000);
494 if (EFI_ERROR (Status)) {
495 EfiReleaseLock (&Global->RtcLock);
496 return EFI_DEVICE_ERROR;
497 }
498 //
499 // Read Register B and Register C
500 //
501 RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
502 RegisterC.Data = RtcRead (RTC_ADDRESS_REGISTER_C);
503
504 //
505 // Get the Time/Date/Daylight Savings values.
506 //
507 *Enabled = RegisterB.Bits.AIE;
508 if (*Enabled) {
509 Time->Second = RtcRead (RTC_ADDRESS_SECONDS_ALARM);
510 Time->Minute = RtcRead (RTC_ADDRESS_MINUTES_ALARM);
511 Time->Hour = RtcRead (RTC_ADDRESS_HOURS_ALARM);
512 Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);
513 Time->Month = RtcRead (RTC_ADDRESS_MONTH);
514 Time->Year = RtcRead (RTC_ADDRESS_YEAR);
515 } else {
516 Time->Second = 0;
517 Time->Minute = 0;
518 Time->Hour = 0;
519 Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);
520 Time->Month = RtcRead (RTC_ADDRESS_MONTH);
521 Time->Year = RtcRead (RTC_ADDRESS_YEAR);
522 }
523
524 ConvertRtcTimeToEfiTime (Time, RegisterB);
525
526 if (RtcTestCenturyRegister () == EFI_SUCCESS) {
527 Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f));
528 } else {
529 Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY));
530 }
531
532 Time->Year = (UINT16) (Century * 100 + Time->Year);
533
534 //
535 // Release RTC Lock.
536 //
537 EfiReleaseLock (&Global->RtcLock);
538
539 //
540 // Make sure all field values are in correct range
541 //
542 Status = RtcTimeFieldsValid (Time);
543 if (EFI_ERROR (Status)) {
544 return EFI_DEVICE_ERROR;
545 }
546
547 *Pending = RegisterC.Bits.AF;
548
549 return EFI_SUCCESS;
550 }
551
552 EFI_STATUS
553 EFIAPI
554 PcRtcSetWakeupTime (
555 IN BOOLEAN Enable,
556 OUT EFI_TIME *Time,
557 IN PC_RTC_MODULE_GLOBALS *Global
558 )
559 /*++
560
561 Routine Description:
562
563 Arguments:
564
565
566
567 Returns:
568 --*/
569 // TODO: Enable - add argument and description to function comment
570 // TODO: Time - add argument and description to function comment
571 // TODO: Global - add argument and description to function comment
572 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
573 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
574 // TODO: EFI_UNSUPPORTED - add return value to function comment
575 // TODO: EFI_DEVICE_ERROR - add return value to function comment
576 // TODO: EFI_SUCCESS - add return value to function comment
577 {
578 EFI_STATUS Status;
579 EFI_TIME RtcTime;
580 RTC_REGISTER_B RegisterB;
581 UINT8 Century;
582 EFI_TIME_CAPABILITIES Capabilities;
583
584 if (Enable) {
585
586 if (Time == NULL) {
587 return EFI_INVALID_PARAMETER;
588 }
589 //
590 // Make sure that the time fields are valid
591 //
592 Status = RtcTimeFieldsValid (Time);
593 if (EFI_ERROR (Status)) {
594 return EFI_INVALID_PARAMETER;
595 }
596 //
597 // Just support set alarm time within 24 hours
598 //
599 PcRtcGetTime (&RtcTime, &Capabilities, Global);
600 if (!IsWithinOneDay (&RtcTime, Time)) {
601 return EFI_UNSUPPORTED;
602 }
603 //
604 // Make a local copy of the time and date
605 //
606 CopyMem (&RtcTime, Time, sizeof (EFI_TIME));
607
608 }
609 //
610 // Acquire RTC Lock to make access to RTC atomic
611 //
612 EfiAcquireLock (&Global->RtcLock);
613
614 //
615 // Wait for up to 0.1 seconds for the RTC to be updated
616 //
617 Status = RtcWaitToUpdate (100000);
618 if (EFI_ERROR (Status)) {
619 EfiReleaseLock (&Global->RtcLock);
620 return EFI_DEVICE_ERROR;
621 }
622 //
623 // Read Register B, and inhibit updates of the RTC
624 //
625 RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
626
627 RegisterB.Bits.SET = 1;
628 RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);
629
630 if (Enable) {
631 ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century);
632
633 //
634 // Set RTC alarm time
635 //
636 RtcWrite (RTC_ADDRESS_SECONDS_ALARM, RtcTime.Second);
637 RtcWrite (RTC_ADDRESS_MINUTES_ALARM, RtcTime.Minute);
638 RtcWrite (RTC_ADDRESS_HOURS_ALARM, RtcTime.Hour);
639
640 RegisterB.Bits.AIE = 1;
641
642 } else {
643 RegisterB.Bits.AIE = 0;
644 }
645 //
646 // Allow updates of the RTC registers
647 //
648 RegisterB.Bits.SET = 0;
649 RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);
650
651 //
652 // Release RTC Lock.
653 //
654 EfiReleaseLock (&Global->RtcLock);
655
656 return EFI_SUCCESS;
657 }
658
659 UINT8
660 BcdToDecimal (
661 IN UINT8 BcdValue
662 )
663 /*++
664
665 Routine Description:
666
667 Arguments:
668
669
670
671 Returns:
672 --*/
673 // TODO: BcdValue - add argument and description to function comment
674 {
675 UINTN High;
676 UINTN Low;
677
678 High = BcdValue >> 4;
679 Low = BcdValue - (High << 4);
680
681 return (UINT8) (Low + (High * 10));
682 }
683
684 EFI_STATUS
685 RtcTestCenturyRegister (
686 VOID
687 )
688 /*++
689
690 Routine Description:
691
692 Arguments:
693
694
695
696 Returns:
697 --*/
698 // TODO: EFI_SUCCESS - add return value to function comment
699 // TODO: EFI_DEVICE_ERROR - add return value to function comment
700 {
701 UINT8 Century;
702 UINT8 Temp;
703
704 Century = RtcRead (RTC_ADDRESS_CENTURY);
705 //
706 // RtcWrite (RTC_ADDRESS_CENTURY, 0x00);
707 //
708 Temp = (UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f);
709 RtcWrite (RTC_ADDRESS_CENTURY, Century);
710 if (Temp == 0x19 || Temp == 0x20) {
711 return EFI_SUCCESS;
712 }
713
714 return EFI_DEVICE_ERROR;
715 }
716
717 VOID
718 ConvertRtcTimeToEfiTime (
719 IN EFI_TIME *Time,
720 IN RTC_REGISTER_B RegisterB
721 )
722 /*++
723
724 Routine Description:
725
726 Arguments:
727
728
729
730 Returns:
731 --*/
732 // TODO: Time - add argument and description to function comment
733 // TODO: RegisterB - add argument and description to function comment
734 {
735 BOOLEAN PM;
736
737 if ((Time->Hour) & 0x80) {
738 PM = TRUE;
739 } else {
740 PM = FALSE;
741 }
742
743 Time->Hour = (UINT8) (Time->Hour & 0x7f);
744
745 if (RegisterB.Bits.DM == 0) {
746 Time->Year = BcdToDecimal ((UINT8) Time->Year);
747 Time->Month = BcdToDecimal (Time->Month);
748 Time->Day = BcdToDecimal (Time->Day);
749 Time->Hour = BcdToDecimal (Time->Hour);
750 Time->Minute = BcdToDecimal (Time->Minute);
751 Time->Second = BcdToDecimal (Time->Second);
752 }
753 //
754 // If time is in 12 hour format, convert it to 24 hour format
755 //
756 if (RegisterB.Bits.MIL == 0) {
757 if (PM && Time->Hour < 12) {
758 Time->Hour = (UINT8) (Time->Hour + 12);
759 }
760
761 if (!PM && Time->Hour == 12) {
762 Time->Hour = 0;
763 }
764 }
765
766 Time->Nanosecond = 0;
767 Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;
768 Time->Daylight = 0;
769 }
770
771 EFI_STATUS
772 RtcWaitToUpdate (
773 UINTN Timeout
774 )
775 /*++
776
777 Routine Description:
778
779 Arguments:
780
781
782 Returns:
783 --*/
784 // TODO: Timeout - add argument and description to function comment
785 // TODO: EFI_DEVICE_ERROR - add return value to function comment
786 // TODO: EFI_DEVICE_ERROR - add return value to function comment
787 // TODO: EFI_SUCCESS - add return value to function comment
788 {
789 RTC_REGISTER_A RegisterA;
790 RTC_REGISTER_D RegisterD;
791
792 //
793 // See if the RTC is functioning correctly
794 //
795 RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D);
796
797 if (RegisterD.Bits.VRT == 0) {
798 return EFI_DEVICE_ERROR;
799 }
800 //
801 // Wait for up to 0.1 seconds for the RTC to be ready.
802 //
803 Timeout = (Timeout / 10) + 1;
804 RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A);
805 while (RegisterA.Bits.UIP == 1 && Timeout > 0) {
806 MicroSecondDelay (10);
807 RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A);
808 Timeout--;
809 }
810
811 RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D);
812 if (Timeout == 0 || RegisterD.Bits.VRT == 0) {
813 return EFI_DEVICE_ERROR;
814 }
815
816 return EFI_SUCCESS;
817 }
818
819 EFI_STATUS
820 RtcTimeFieldsValid (
821 IN EFI_TIME *Time
822 )
823 /*++
824
825 Routine Description:
826
827 Arguments:
828
829 Returns:
830 --*/
831 // TODO: Time - add argument and description to function comment
832 // TODO: EFI_INVALID_PARAMETER - add return value to function comment
833 // TODO: EFI_SUCCESS - add return value to function comment
834 {
835 if (Time->Year < 1998 ||
836 Time->Year > 2099 ||
837 Time->Month < 1 ||
838 Time->Month > 12 ||
839 (!DayValid (Time)) ||
840 Time->Hour > 23 ||
841 Time->Minute > 59 ||
842 Time->Second > 59 ||
843 Time->Nanosecond > 999999999 ||
844 (!(Time->TimeZone == EFI_UNSPECIFIED_TIMEZONE || (Time->TimeZone >= -1440 && Time->TimeZone <= 1440))) ||
845 (Time->Daylight & (~(EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT)))
846 ) {
847 return EFI_INVALID_PARAMETER;
848 }
849
850 return EFI_SUCCESS;
851 }
852
853 BOOLEAN
854 DayValid (
855 IN EFI_TIME *Time
856 )
857 /*++
858
859 Routine Description:
860
861 TODO: Add function description
862
863 Arguments:
864
865 Time - TODO: add argument description
866
867 Returns:
868
869 TODO: add return values
870
871 --*/
872 {
873
874 INTN DayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
875
876 if (Time->Day < 1 ||
877 Time->Day > DayOfMonth[Time->Month - 1] ||
878 (Time->Month == 2 && (!IsLeapYear (Time) && Time->Day > 28))
879 ) {
880 return FALSE;
881 }
882
883 return TRUE;
884 }
885
886 BOOLEAN
887 IsLeapYear (
888 IN EFI_TIME *Time
889 )
890 /*++
891
892 Routine Description:
893
894 TODO: Add function description
895
896 Arguments:
897
898 Time - TODO: add argument description
899
900 Returns:
901
902 TODO: add return values
903
904 --*/
905 {
906 if (Time->Year % 4 == 0) {
907 if (Time->Year % 100 == 0) {
908 if (Time->Year % 400 == 0) {
909 return TRUE;
910 } else {
911 return FALSE;
912 }
913 } else {
914 return TRUE;
915 }
916 } else {
917 return FALSE;
918 }
919 }
920
921 VOID
922 ConvertEfiTimeToRtcTime (
923 IN EFI_TIME *Time,
924 IN RTC_REGISTER_B RegisterB,
925 IN UINT8 *Century
926 )
927 /*++
928
929 Routine Description:
930
931 Arguments:
932
933
934 Returns:
935 --*/
936 // TODO: Time - add argument and description to function comment
937 // TODO: RegisterB - add argument and description to function comment
938 // TODO: Century - add argument and description to function comment
939 {
940 BOOLEAN PM;
941
942 PM = TRUE;
943 //
944 // Adjust hour field if RTC in in 12 hour mode
945 //
946 if (RegisterB.Bits.MIL == 0) {
947 if (Time->Hour < 12) {
948 PM = FALSE;
949 }
950
951 if (Time->Hour >= 13) {
952 Time->Hour = (UINT8) (Time->Hour - 12);
953 } else if (Time->Hour == 0) {
954 Time->Hour = 12;
955 }
956 }
957 //
958 // Set the Time/Date/Daylight Savings values.
959 //
960 *Century = DecimaltoBcd ((UINT8) (Time->Year / 100));
961
962 Time->Year = (UINT16) (Time->Year % 100);
963
964 if (RegisterB.Bits.DM == 0) {
965 Time->Year = DecimaltoBcd ((UINT8) Time->Year);
966 Time->Month = DecimaltoBcd (Time->Month);
967 Time->Day = DecimaltoBcd (Time->Day);
968 Time->Hour = DecimaltoBcd (Time->Hour);
969 Time->Minute = DecimaltoBcd (Time->Minute);
970 Time->Second = DecimaltoBcd (Time->Second);
971 }
972 //
973 // If we are in 12 hour mode and PM is set, then set bit 7 of the Hour field.
974 //
975 if (RegisterB.Bits.MIL == 0 && PM) {
976 Time->Hour = (UINT8) (Time->Hour | 0x80);
977 }
978 }
979
980 BOOLEAN
981 IsWithinOneDay (
982 IN EFI_TIME *From,
983 IN EFI_TIME *To
984 )
985 /*++
986
987 Routine Description:
988
989 Judge whether two days are adjacent.
990
991 Arguments:
992
993 From - the first day
994 To - the second day
995
996 Returns:
997
998 TRUE - The interval of two days are within one day.
999 FALSE - The interval of two days exceed ony day or parameter error.
1000
1001 --*/
1002 {
1003 UINT8 DayOfMonth[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
1004 BOOLEAN Adjacent = FALSE;
1005
1006 if (From->Year == To->Year) {
1007 if (From->Month == To->Month) {
1008 if ((From->Day + 1) == To->Day) {
1009 if ((CompareHMS(From, To) >= 0)) {
1010 Adjacent = TRUE;
1011 }
1012 } else if (From->Day == To->Day) {
1013 if ((CompareHMS(From, To) <= 0)) {
1014 Adjacent = TRUE;
1015 }
1016 }
1017 } else if (((From->Month + 1) == To->Month) && (To->Day == 1)) {
1018 if ((From->Month == 2) && !IsLeapYear(From)) {
1019 if (From->Day == 28) {
1020 if ((CompareHMS(From, To) >= 0)) {
1021 Adjacent = TRUE;
1022 }
1023 }
1024 } else if (From->Day == DayOfMonth[From->Month - 1]) {
1025 if ((CompareHMS(From, To) >= 0)) {
1026 Adjacent = TRUE;
1027 }
1028 }
1029 }
1030 } else if (((From->Year + 1) == To->Year) &&
1031 (From->Month == 12) &&
1032 (From->Day == 31) &&
1033 (To->Month == 1) &&
1034 (To->Day == 1)) {
1035 if ((CompareHMS(From, To) >= 0)) {
1036 Adjacent = TRUE;
1037 }
1038 }
1039
1040 return Adjacent;
1041 }
1042
1043 UINT8
1044 DecimaltoBcd (
1045 IN UINT8 DecValue
1046 )
1047 /*++
1048
1049 Routine Description:
1050
1051 Arguments:
1052
1053 Returns:
1054
1055 --*/
1056 // TODO: DecValue - add argument and description to function comment
1057 {
1058 UINTN High;
1059 UINTN Low;
1060
1061 High = DecValue / 10;
1062 Low = DecValue - (High * 10);
1063
1064 return (UINT8) (Low + (High << 4));
1065 }