]> git.proxmox.com Git - mirror_edk2.git/blob - PcAtChipsetPkg/PcRtc/RealTimeClock.c
1) Add package description file (dec) for PcAtChipsetPkg
[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 Century = BcdToDecimal8 (RtcRead (RTC_ADDRESS_CENTURY));
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 Century = BcdToDecimal8 (RtcRead (RTC_ADDRESS_CENTURY));
313
314 Time->Year = (UINT16) (Century * 100 + Time->Year);
315
316 //
317 // Release RTC Lock.
318 //
319 EfiReleaseLock (&Global->RtcLock);
320
321 //
322 // Get the variable that containts the TimeZone and Daylight fields
323 //
324 Time->TimeZone = Global->SavedTimeZone;
325 Time->Daylight = Global->Daylight;
326
327 //BufferSize = sizeof (INT16) + sizeof (UINT8);
328
329 //
330 // Make sure all field values are in correct range
331 //
332 Status = RtcTimeFieldsValid (Time);
333 if (EFI_ERROR (Status)) {
334 return EFI_DEVICE_ERROR;
335 }
336 //
337 // Fill in Capabilities if it was passed in
338 //
339 if (Capabilities) {
340 Capabilities->Resolution = 1;
341 //
342 // 1 hertz
343 //
344 Capabilities->Accuracy = 50000000;
345 //
346 // 50 ppm
347 //
348 Capabilities->SetsToZero = FALSE;
349 }
350
351 return EFI_SUCCESS;
352 }
353
354 EFI_STATUS
355 PcRtcSetTime (
356 IN EFI_TIME *Time,
357 IN PC_RTC_MODULE_GLOBALS *Global
358 )
359 /*++
360
361 Routine Description:
362
363 Arguments:
364
365 Returns:
366 --*/
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
370 {
371 EFI_STATUS Status;
372 EFI_TIME RtcTime;
373 RTC_REGISTER_B RegisterB;
374 UINT8 Century;
375
376 if (Time == NULL) {
377 return EFI_INVALID_PARAMETER;
378 }
379 //
380 // Make sure that the time fields are valid
381 //
382 Status = RtcTimeFieldsValid (Time);
383 if (EFI_ERROR (Status)) {
384 return Status;
385 }
386
387 CopyMem (&RtcTime, Time, sizeof (EFI_TIME));
388
389 //
390 // Acquire RTC Lock to make access to RTC atomic
391 //
392 EfiAcquireLock (&Global->RtcLock);
393
394 //
395 // Wait for up to 0.1 seconds for the RTC to be updated
396 //
397 Status = RtcWaitToUpdate (100000);
398 if (EFI_ERROR (Status)) {
399 EfiReleaseLock (&Global->RtcLock);
400 return Status;
401 }
402 //
403 // Read Register B, and inhibit updates of the RTC
404 //
405 RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
406 RegisterB.Bits.SET = 1;
407 RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);
408
409 ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century);
410
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);
418
419 //
420 // Allow updates of the RTC registers
421 //
422 RegisterB.Bits.SET = 0;
423 RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);
424
425 //
426 // Release RTC Lock.
427 //
428 EfiReleaseLock (&Global->RtcLock);
429
430 //
431 // Set the variable that containts the TimeZone and Daylight fields
432 //
433 Global->SavedTimeZone = Time->TimeZone;
434 Global->Daylight = Time->Daylight;
435 return Status;
436 }
437
438 EFI_STATUS
439 EFIAPI
440 PcRtcGetWakeupTime (
441 OUT BOOLEAN *Enabled,
442 OUT BOOLEAN *Pending,
443 OUT EFI_TIME *Time,
444 IN PC_RTC_MODULE_GLOBALS *Global
445 )
446 /*++
447
448 Routine Description:
449
450 Arguments:
451
452
453
454 Returns:
455 --*/
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
464 {
465 EFI_STATUS Status;
466 RTC_REGISTER_B RegisterB;
467 RTC_REGISTER_C RegisterC;
468 UINT8 Century;
469
470 //
471 // Check paramters for null pointers
472 //
473 if ((Enabled == NULL) || (Pending == NULL) || (Time == NULL)) {
474 return EFI_INVALID_PARAMETER;
475
476 }
477 //
478 // Acquire RTC Lock to make access to RTC atomic
479 //
480 EfiAcquireLock (&Global->RtcLock);
481
482 //
483 // Wait for up to 0.1 seconds for the RTC to be updated
484 //
485 Status = RtcWaitToUpdate (100000);
486 if (EFI_ERROR (Status)) {
487 EfiReleaseLock (&Global->RtcLock);
488 return EFI_DEVICE_ERROR;
489 }
490 //
491 // Read Register B and Register C
492 //
493 RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
494 RegisterC.Data = RtcRead (RTC_ADDRESS_REGISTER_C);
495
496 //
497 // Get the Time/Date/Daylight Savings values.
498 //
499 *Enabled = RegisterB.Bits.AIE;
500 if (*Enabled) {
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);
507 } else {
508 Time->Second = 0;
509 Time->Minute = 0;
510 Time->Hour = 0;
511 Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);
512 Time->Month = RtcRead (RTC_ADDRESS_MONTH);
513 Time->Year = RtcRead (RTC_ADDRESS_YEAR);
514 }
515
516 ConvertRtcTimeToEfiTime (Time, RegisterB);
517
518 Century = BcdToDecimal8 (RtcRead (RTC_ADDRESS_CENTURY));
519
520 Time->Year = (UINT16) (Century * 100 + Time->Year);
521
522 //
523 // Release RTC Lock.
524 //
525 EfiReleaseLock (&Global->RtcLock);
526
527 //
528 // Make sure all field values are in correct range
529 //
530 Status = RtcTimeFieldsValid (Time);
531 if (EFI_ERROR (Status)) {
532 return EFI_DEVICE_ERROR;
533 }
534
535 *Pending = RegisterC.Bits.AF;
536
537 return EFI_SUCCESS;
538 }
539
540 EFI_STATUS
541 EFIAPI
542 PcRtcSetWakeupTime (
543 IN BOOLEAN Enable,
544 OUT EFI_TIME *Time,
545 IN PC_RTC_MODULE_GLOBALS *Global
546 )
547 /*++
548
549 Routine Description:
550
551 Arguments:
552
553
554
555 Returns:
556 --*/
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
565 {
566 EFI_STATUS Status;
567 EFI_TIME RtcTime;
568 RTC_REGISTER_B RegisterB;
569 UINT8 Century;
570 EFI_TIME_CAPABILITIES Capabilities;
571
572 if (Enable) {
573
574 if (Time == NULL) {
575 return EFI_INVALID_PARAMETER;
576 }
577 //
578 // Make sure that the time fields are valid
579 //
580 Status = RtcTimeFieldsValid (Time);
581 if (EFI_ERROR (Status)) {
582 return EFI_INVALID_PARAMETER;
583 }
584 //
585 // Just support set alarm time within 24 hours
586 //
587 PcRtcGetTime (&RtcTime, &Capabilities, Global);
588 if (!IsWithinOneDay (&RtcTime, Time)) {
589 return EFI_UNSUPPORTED;
590 }
591 //
592 // Make a local copy of the time and date
593 //
594 CopyMem (&RtcTime, Time, sizeof (EFI_TIME));
595
596 }
597 //
598 // Acquire RTC Lock to make access to RTC atomic
599 //
600 EfiAcquireLock (&Global->RtcLock);
601
602 //
603 // Wait for up to 0.1 seconds for the RTC to be updated
604 //
605 Status = RtcWaitToUpdate (100000);
606 if (EFI_ERROR (Status)) {
607 EfiReleaseLock (&Global->RtcLock);
608 return EFI_DEVICE_ERROR;
609 }
610 //
611 // Read Register B, and inhibit updates of the RTC
612 //
613 RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);
614
615 RegisterB.Bits.SET = 1;
616 RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);
617
618 if (Enable) {
619 ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century);
620
621 //
622 // Set RTC alarm time
623 //
624 RtcWrite (RTC_ADDRESS_SECONDS_ALARM, RtcTime.Second);
625 RtcWrite (RTC_ADDRESS_MINUTES_ALARM, RtcTime.Minute);
626 RtcWrite (RTC_ADDRESS_HOURS_ALARM, RtcTime.Hour);
627
628 RegisterB.Bits.AIE = 1;
629
630 } else {
631 RegisterB.Bits.AIE = 0;
632 }
633 //
634 // Allow updates of the RTC registers
635 //
636 RegisterB.Bits.SET = 0;
637 RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);
638
639 //
640 // Release RTC Lock.
641 //
642 EfiReleaseLock (&Global->RtcLock);
643
644 return EFI_SUCCESS;
645 }
646
647 VOID
648 ConvertRtcTimeToEfiTime (
649 IN EFI_TIME *Time,
650 IN RTC_REGISTER_B RegisterB
651 )
652 /*++
653
654 Routine Description:
655
656 Arguments:
657
658
659
660 Returns:
661 --*/
662 // TODO: Time - add argument and description to function comment
663 // TODO: RegisterB - add argument and description to function comment
664 {
665 BOOLEAN PM;
666
667 if ((Time->Hour) & 0x80) {
668 PM = TRUE;
669 } else {
670 PM = FALSE;
671 }
672
673 Time->Hour = (UINT8) (Time->Hour & 0x7f);
674
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);
682 }
683 //
684 // If time is in 12 hour format, convert it to 24 hour format
685 //
686 if (RegisterB.Bits.MIL == 0) {
687 if (PM && Time->Hour < 12) {
688 Time->Hour = (UINT8) (Time->Hour + 12);
689 }
690
691 if (!PM && Time->Hour == 12) {
692 Time->Hour = 0;
693 }
694 }
695
696 Time->Nanosecond = 0;
697 Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;
698 Time->Daylight = 0;
699 }
700
701 EFI_STATUS
702 RtcWaitToUpdate (
703 UINTN Timeout
704 )
705 /*++
706
707 Routine Description:
708
709 Arguments:
710
711
712 Returns:
713 --*/
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
718 {
719 RTC_REGISTER_A RegisterA;
720 RTC_REGISTER_D RegisterD;
721
722 //
723 // See if the RTC is functioning correctly
724 //
725 RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D);
726
727 if (RegisterD.Bits.VRT == 0) {
728 return EFI_DEVICE_ERROR;
729 }
730 //
731 // Wait for up to 0.1 seconds for the RTC to be ready.
732 //
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);
738 Timeout--;
739 }
740
741 RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D);
742 if (Timeout == 0 || RegisterD.Bits.VRT == 0) {
743 return EFI_DEVICE_ERROR;
744 }
745
746 return EFI_SUCCESS;
747 }
748
749 EFI_STATUS
750 RtcTimeFieldsValid (
751 IN EFI_TIME *Time
752 )
753 /*++
754
755 Routine Description:
756
757 Arguments:
758
759 Returns:
760 --*/
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
764 {
765 if (Time->Year < 1998 ||
766 Time->Year > 2099 ||
767 Time->Month < 1 ||
768 Time->Month > 12 ||
769 (!DayValid (Time)) ||
770 Time->Hour > 23 ||
771 Time->Minute > 59 ||
772 Time->Second > 59 ||
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)))
776 ) {
777 return EFI_INVALID_PARAMETER;
778 }
779
780 return EFI_SUCCESS;
781 }
782
783 BOOLEAN
784 DayValid (
785 IN EFI_TIME *Time
786 )
787 /*++
788
789 Routine Description:
790
791 TODO: Add function description
792
793 Arguments:
794
795 Time - TODO: add argument description
796
797 Returns:
798
799 TODO: add return values
800
801 --*/
802 {
803
804
805 if (Time->Day < 1 ||
806 Time->Day > mDayOfMonth[Time->Month - 1] ||
807 (Time->Month == 2 && (!IsLeapYear (Time) && Time->Day > 28))
808 ) {
809 return FALSE;
810 }
811
812 return TRUE;
813 }
814
815 BOOLEAN
816 IsLeapYear (
817 IN EFI_TIME *Time
818 )
819 /*++
820
821 Routine Description:
822
823 TODO: Add function description
824
825 Arguments:
826
827 Time - TODO: add argument description
828
829 Returns:
830
831 TODO: add return values
832
833 --*/
834 {
835 if (Time->Year % 4 == 0) {
836 if (Time->Year % 100 == 0) {
837 if (Time->Year % 400 == 0) {
838 return TRUE;
839 } else {
840 return FALSE;
841 }
842 } else {
843 return TRUE;
844 }
845 } else {
846 return FALSE;
847 }
848 }
849
850 VOID
851 ConvertEfiTimeToRtcTime (
852 IN EFI_TIME *Time,
853 IN RTC_REGISTER_B RegisterB,
854 IN UINT8 *Century
855 )
856 /*++
857
858 Routine Description:
859
860 Arguments:
861
862
863 Returns:
864 --*/
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
868 {
869 BOOLEAN PM;
870
871 PM = TRUE;
872 //
873 // Adjust hour field if RTC in in 12 hour mode
874 //
875 if (RegisterB.Bits.MIL == 0) {
876 if (Time->Hour < 12) {
877 PM = FALSE;
878 }
879
880 if (Time->Hour >= 13) {
881 Time->Hour = (UINT8) (Time->Hour - 12);
882 } else if (Time->Hour == 0) {
883 Time->Hour = 12;
884 }
885 }
886 //
887 // Set the Time/Date/Daylight Savings values.
888 //
889 *Century = DecimaltoBcd ((UINT8) (Time->Year / 100));
890
891 Time->Year = (UINT16) (Time->Year % 100);
892
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);
900 }
901 //
902 // If we are in 12 hour mode and PM is set, then set bit 7 of the Hour field.
903 //
904 if (RegisterB.Bits.MIL == 0 && PM) {
905 Time->Hour = (UINT8) (Time->Hour | 0x80);
906 }
907 }
908
909 BOOLEAN
910 IsWithinOneDay (
911 IN EFI_TIME *From,
912 IN EFI_TIME *To
913 )
914 /*++
915
916 Routine Description:
917
918 Judge whether two days are adjacent.
919
920 Arguments:
921
922 From - the first day
923 To - the second day
924
925 Returns:
926
927 TRUE - The interval of two days are within one day.
928 FALSE - The interval of two days exceed ony day or parameter error.
929
930 --*/
931 {
932 BOOLEAN Adjacent = FALSE;
933
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)) {
938 Adjacent = TRUE;
939 }
940 } else if (From->Day == To->Day) {
941 if ((CompareHMS(From, To) <= 0)) {
942 Adjacent = TRUE;
943 }
944 }
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)) {
949 Adjacent = TRUE;
950 }
951 }
952 } else if (From->Day == mDayOfMonth[From->Month - 1]) {
953 if ((CompareHMS(From, To) >= 0)) {
954 Adjacent = TRUE;
955 }
956 }
957 }
958 } else if (((From->Year + 1) == To->Year) &&
959 (From->Month == 12) &&
960 (From->Day == 31) &&
961 (To->Month == 1) &&
962 (To->Day == 1)) {
963 if ((CompareHMS(From, To) >= 0)) {
964 Adjacent = TRUE;
965 }
966 }
967
968 return Adjacent;
969 }
970
971 UINT8
972 DecimaltoBcd (
973 IN UINT8 DecValue
974 )
975 /*++
976
977 Routine Description:
978
979 Arguments:
980
981 Returns:
982
983 --*/
984 // TODO: DecValue - add argument and description to function comment
985 {
986 UINTN High;
987 UINTN Low;
988
989 High = DecValue / 10;
990 Low = DecValue - (High * 10);
991
992 return (UINT8) (Low + (High << 4));
993 }