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