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