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