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