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