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