]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/PcatRealTimeClockRuntimeDxe/PcRtc.c
Fixed one bug when runtime test. The root cause is that ICC compiler will convert...
[mirror_edk2.git] / MdeModulePkg / Universal / PcatRealTimeClockRuntimeDxe / PcRtc.c
1 /*++
2
3 Copyright (c) 2006 - 2007 Intel Corporation. <BR>
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
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];
1033 BOOLEAN Adjacent;
1034
1035 DayOfMonth[0] = 31;
1036 DayOfMonth[1] = 29;
1037 DayOfMonth[2] = 31;
1038 DayOfMonth[3] = 30;
1039 DayOfMonth[4] = 31;
1040 DayOfMonth[5] = 30;
1041 DayOfMonth[6] = 31;
1042 DayOfMonth[7] = 31;
1043 DayOfMonth[8] = 30;
1044 DayOfMonth[9] = 31;
1045 DayOfMonth[10] = 30;
1046 DayOfMonth[11] = 31;
1047
1048 Adjacent = FALSE;
1049
1050 if (From->Year == To->Year) {
1051 if (From->Month == To->Month) {
1052 if ((From->Day + 1) == To->Day) {
1053 if ((CompareHMS(From, To) >= 0)) {
1054 Adjacent = TRUE;
1055 }
1056 } else if (From->Day == To->Day) {
1057 if ((CompareHMS(From, To) <= 0)) {
1058 Adjacent = TRUE;
1059 }
1060 }
1061 } else if (((From->Month + 1) == To->Month) && (To->Day == 1)) {
1062 if ((From->Month == 2) && !IsLeapYear(From)) {
1063 if (From->Day == 28) {
1064 if ((CompareHMS(From, To) >= 0)) {
1065 Adjacent = TRUE;
1066 }
1067 }
1068 } else if (From->Day == DayOfMonth[From->Month - 1]) {
1069 if ((CompareHMS(From, To) >= 0)) {
1070 Adjacent = TRUE;
1071 }
1072 }
1073 }
1074 } else if (((From->Year + 1) == To->Year) &&
1075 (From->Month == 12) &&
1076 (From->Day == 31) &&
1077 (To->Month == 1) &&
1078 (To->Day == 1)) {
1079 if ((CompareHMS(From, To) >= 0)) {
1080 Adjacent = TRUE;
1081 }
1082 }
1083
1084 return Adjacent;
1085 }
1086