]> git.proxmox.com Git - mirror_edk2.git/blame - DuetPkg/PcRtc/RealTimeClock.c
1, Enable USB boot for R9's Duet.
[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
e188a609 156 //RTC_REGISTER_C RegisterC;\r
c69dd9df 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
e188a609 183 //RegisterC.Data = RtcRead (RTC_ADDRESS_REGISTER_C);\r
c69dd9df 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
e25803f0 194 // KEN: BUGBUG following wait action will cause failure under vmware environment.\r
195 //\r
196 //Status = RtcWaitToUpdate (100000);\r
197 //if (EFI_ERROR (Status)) {\r
198 // EfiReleaseLock (&Global->RtcLock);\r
199 // return EFI_DEVICE_ERROR;\r
200 //}\r
c69dd9df 201 //\r
202 // Get the Time/Date/Daylight Savings values.\r
203 //\r
204 Time.Second = RtcRead (RTC_ADDRESS_SECONDS);\r
205 Time.Minute = RtcRead (RTC_ADDRESS_MINUTES);\r
206 Time.Hour = RtcRead (RTC_ADDRESS_HOURS);\r
207 Time.Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);\r
208 Time.Month = RtcRead (RTC_ADDRESS_MONTH);\r
209 Time.Year = RtcRead (RTC_ADDRESS_YEAR);\r
210\r
211 ConvertRtcTimeToEfiTime (&Time, RegisterB);\r
212\r
213 if (RtcTestCenturyRegister () == EFI_SUCCESS) {\r
214 Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f));\r
215 } else {\r
216 Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY));\r
217 }\r
218\r
219 Time.Year = (UINT16) (Century * 100 + Time.Year);\r
220\r
221 //\r
222 // Set RTC configuration after get original time\r
223 //\r
224 RtcWrite (RTC_ADDRESS_REGISTER_B, RTC_INIT_REGISTER_B);\r
225\r
226 //\r
227 // Release RTC Lock.\r
228 //\r
229 EfiReleaseLock (&Global->RtcLock);\r
230\r
231 //\r
232 // Validate time fields\r
233 //\r
234 Status = RtcTimeFieldsValid (&Time);\r
235 if (EFI_ERROR (Status)) {\r
236 Time.Second = RTC_INIT_SECOND;\r
237 Time.Minute = RTC_INIT_MINUTE;\r
238 Time.Hour = RTC_INIT_HOUR;\r
239 Time.Day = RTC_INIT_DAY;\r
240 Time.Month = RTC_INIT_MONTH;\r
241 Time.Year = RTC_INIT_YEAR;\r
242 }\r
243 //\r
244 // Reset time value according to new RTC configuration\r
245 //\r
246 PcRtcSetTime (&Time, Global);\r
247\r
248 return EFI_SUCCESS;\r
249}\r
250\r
251EFI_STATUS\r
252PcRtcGetTime (\r
253 OUT EFI_TIME *Time,\r
254 IN EFI_TIME_CAPABILITIES *Capabilities,\r
255 IN PC_RTC_MODULE_GLOBALS *Global\r
256 )\r
257/*++\r
258\r
259Routine Description:\r
260\r
261 Arguments:\r
262\r
263 Returns: \r
264--*/\r
265// TODO: Time - add argument and description to function comment\r
266// TODO: Capabilities - add argument and description to function comment\r
267// TODO: Global - add argument and description to function comment\r
268// TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
269// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
270// TODO: EFI_SUCCESS - add return value to function comment\r
271{\r
272 EFI_STATUS Status;\r
273 RTC_REGISTER_B RegisterB;\r
274 UINT8 Century;\r
e188a609 275 //UINTN BufferSize;\r
c69dd9df 276\r
277 //\r
278 // Check parameters for null pointer\r
279 //\r
280 if (Time == NULL) {\r
281 return EFI_INVALID_PARAMETER;\r
282\r
283 }\r
284 //\r
285 // Acquire RTC Lock to make access to RTC atomic\r
286 //\r
287 EfiAcquireLock (&Global->RtcLock);\r
288\r
289 //\r
290 // Wait for up to 0.1 seconds for the RTC to be updated\r
291 //\r
292 Status = RtcWaitToUpdate (100000);\r
293 if (EFI_ERROR (Status)) {\r
294 EfiReleaseLock (&Global->RtcLock);\r
295 return Status;\r
296 }\r
297 //\r
298 // Read Register B\r
299 //\r
300 RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);\r
301\r
302 //\r
303 // Get the Time/Date/Daylight Savings values.\r
304 //\r
305 Time->Second = RtcRead (RTC_ADDRESS_SECONDS);\r
306 Time->Minute = RtcRead (RTC_ADDRESS_MINUTES);\r
307 Time->Hour = RtcRead (RTC_ADDRESS_HOURS);\r
308 Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);\r
309 Time->Month = RtcRead (RTC_ADDRESS_MONTH);\r
310 Time->Year = RtcRead (RTC_ADDRESS_YEAR);\r
311\r
312 ConvertRtcTimeToEfiTime (Time, RegisterB);\r
313\r
314 if (RtcTestCenturyRegister () == EFI_SUCCESS) {\r
315 Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f));\r
316 } else {\r
317 Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY));\r
318 }\r
319\r
320 Time->Year = (UINT16) (Century * 100 + Time->Year);\r
321\r
322 //\r
323 // Release RTC Lock.\r
324 //\r
325 EfiReleaseLock (&Global->RtcLock);\r
326\r
327 //\r
328 // Get the variable that containts the TimeZone and Daylight fields\r
329 //\r
330 Time->TimeZone = Global->SavedTimeZone;\r
331 Time->Daylight = Global->Daylight;\r
332\r
e188a609 333 //BufferSize = sizeof (INT16) + sizeof (UINT8);\r
c69dd9df 334\r
335 //\r
336 // Make sure all field values are in correct range\r
337 //\r
338 Status = RtcTimeFieldsValid (Time);\r
339 if (EFI_ERROR (Status)) {\r
340 return EFI_DEVICE_ERROR;\r
341 }\r
342 //\r
343 // Fill in Capabilities if it was passed in\r
344 //\r
345 if (Capabilities) {\r
346 Capabilities->Resolution = 1;\r
347 //\r
348 // 1 hertz\r
349 //\r
350 Capabilities->Accuracy = 50000000;\r
351 //\r
352 // 50 ppm\r
353 //\r
354 Capabilities->SetsToZero = FALSE;\r
355 }\r
356\r
357 return EFI_SUCCESS;\r
358}\r
359\r
360EFI_STATUS\r
361PcRtcSetTime (\r
362 IN EFI_TIME *Time,\r
363 IN PC_RTC_MODULE_GLOBALS *Global\r
364 )\r
365/*++\r
366\r
367Routine Description:\r
368\r
369 Arguments:\r
370\r
371 Returns: \r
372--*/\r
373// TODO: Time - add argument and description to function comment\r
374// TODO: Global - add argument and description to function comment\r
375// TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
376{\r
377 EFI_STATUS Status;\r
378 EFI_TIME RtcTime;\r
379 RTC_REGISTER_B RegisterB;\r
380 UINT8 Century;\r
381\r
382 if (Time == NULL) {\r
383 return EFI_INVALID_PARAMETER;\r
384 }\r
385 //\r
386 // Make sure that the time fields are valid\r
387 //\r
388 Status = RtcTimeFieldsValid (Time);\r
389 if (EFI_ERROR (Status)) {\r
390 return Status;\r
391 }\r
392\r
393 CopyMem (&RtcTime, Time, sizeof (EFI_TIME));\r
394\r
395 //\r
396 // Acquire RTC Lock to make access to RTC atomic\r
397 //\r
398 EfiAcquireLock (&Global->RtcLock);\r
399\r
400 //\r
401 // Wait for up to 0.1 seconds for the RTC to be updated\r
402 //\r
403 Status = RtcWaitToUpdate (100000);\r
404 if (EFI_ERROR (Status)) {\r
405 EfiReleaseLock (&Global->RtcLock);\r
406 return Status;\r
407 }\r
408 //\r
409 // Read Register B, and inhibit updates of the RTC\r
410 //\r
411 RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);\r
412 RegisterB.Bits.SET = 1;\r
413 RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
414\r
415 ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century);\r
416\r
417 RtcWrite (RTC_ADDRESS_SECONDS, RtcTime.Second);\r
418 RtcWrite (RTC_ADDRESS_MINUTES, RtcTime.Minute);\r
419 RtcWrite (RTC_ADDRESS_HOURS, RtcTime.Hour);\r
420 RtcWrite (RTC_ADDRESS_DAY_OF_THE_MONTH, RtcTime.Day);\r
421 RtcWrite (RTC_ADDRESS_MONTH, RtcTime.Month);\r
422 RtcWrite (RTC_ADDRESS_YEAR, (UINT8) RtcTime.Year);\r
423 if (RtcTestCenturyRegister () == EFI_SUCCESS) {\r
424 Century = (UINT8) ((Century & 0x7f) | (RtcRead (RTC_ADDRESS_CENTURY) & 0x80));\r
425 }\r
426\r
427 RtcWrite (RTC_ADDRESS_CENTURY, Century);\r
428\r
429 //\r
430 // Allow updates of the RTC registers\r
431 //\r
432 RegisterB.Bits.SET = 0;\r
433 RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
434\r
435 //\r
436 // Release RTC Lock.\r
437 //\r
438 EfiReleaseLock (&Global->RtcLock);\r
439\r
440 //\r
441 // Set the variable that containts the TimeZone and Daylight fields\r
442 //\r
443 Global->SavedTimeZone = Time->TimeZone;\r
444 Global->Daylight = Time->Daylight;\r
445 return Status;\r
446}\r
447\r
448EFI_STATUS\r
449EFIAPI\r
450PcRtcGetWakeupTime (\r
451 OUT BOOLEAN *Enabled,\r
452 OUT BOOLEAN *Pending,\r
453 OUT EFI_TIME *Time,\r
454 IN PC_RTC_MODULE_GLOBALS *Global\r
455 )\r
456/*++\r
457\r
458Routine Description:\r
459\r
460 Arguments:\r
461\r
462 \r
463\r
464Returns: \r
465--*/\r
466// TODO: Enabled - add argument and description to function comment\r
467// TODO: Pending - add argument and description to function comment\r
468// TODO: Time - add argument and description to function comment\r
469// TODO: Global - add argument and description to function comment\r
470// TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
471// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
472// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
473// TODO: EFI_SUCCESS - add return value to function comment\r
474{\r
475 EFI_STATUS Status;\r
476 RTC_REGISTER_B RegisterB;\r
477 RTC_REGISTER_C RegisterC;\r
478 UINT8 Century;\r
479\r
480 //\r
481 // Check paramters for null pointers\r
482 //\r
483 if ((Enabled == NULL) || (Pending == NULL) || (Time == NULL)) {\r
484 return EFI_INVALID_PARAMETER;\r
485\r
486 }\r
487 //\r
488 // Acquire RTC Lock to make access to RTC atomic\r
489 //\r
490 EfiAcquireLock (&Global->RtcLock);\r
491\r
492 //\r
493 // Wait for up to 0.1 seconds for the RTC to be updated\r
494 //\r
495 Status = RtcWaitToUpdate (100000);\r
496 if (EFI_ERROR (Status)) {\r
497 EfiReleaseLock (&Global->RtcLock);\r
498 return EFI_DEVICE_ERROR;\r
499 }\r
500 //\r
501 // Read Register B and Register C\r
502 //\r
503 RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);\r
504 RegisterC.Data = RtcRead (RTC_ADDRESS_REGISTER_C);\r
505\r
506 //\r
507 // Get the Time/Date/Daylight Savings values.\r
508 //\r
509 *Enabled = RegisterB.Bits.AIE;\r
510 if (*Enabled) {\r
511 Time->Second = RtcRead (RTC_ADDRESS_SECONDS_ALARM);\r
512 Time->Minute = RtcRead (RTC_ADDRESS_MINUTES_ALARM);\r
513 Time->Hour = RtcRead (RTC_ADDRESS_HOURS_ALARM);\r
514 Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);\r
515 Time->Month = RtcRead (RTC_ADDRESS_MONTH);\r
516 Time->Year = RtcRead (RTC_ADDRESS_YEAR);\r
517 } else {\r
518 Time->Second = 0;\r
519 Time->Minute = 0;\r
520 Time->Hour = 0;\r
521 Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);\r
522 Time->Month = RtcRead (RTC_ADDRESS_MONTH);\r
523 Time->Year = RtcRead (RTC_ADDRESS_YEAR);\r
524 }\r
525\r
526 ConvertRtcTimeToEfiTime (Time, RegisterB);\r
527\r
528 if (RtcTestCenturyRegister () == EFI_SUCCESS) {\r
529 Century = BcdToDecimal ((UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f));\r
530 } else {\r
531 Century = BcdToDecimal (RtcRead (RTC_ADDRESS_CENTURY));\r
532 }\r
533\r
534 Time->Year = (UINT16) (Century * 100 + Time->Year);\r
535\r
536 //\r
537 // Release RTC Lock.\r
538 //\r
539 EfiReleaseLock (&Global->RtcLock);\r
540\r
541 //\r
542 // Make sure all field values are in correct range\r
543 //\r
544 Status = RtcTimeFieldsValid (Time);\r
545 if (EFI_ERROR (Status)) {\r
546 return EFI_DEVICE_ERROR;\r
547 }\r
548\r
549 *Pending = RegisterC.Bits.AF;\r
550\r
551 return EFI_SUCCESS;\r
552}\r
553\r
554EFI_STATUS\r
555EFIAPI\r
556PcRtcSetWakeupTime (\r
557 IN BOOLEAN Enable,\r
558 OUT EFI_TIME *Time,\r
559 IN PC_RTC_MODULE_GLOBALS *Global\r
560 )\r
561/*++\r
562\r
563Routine Description:\r
564\r
565 Arguments:\r
566\r
567 \r
568\r
569Returns: \r
570--*/\r
571// TODO: Enable - add argument and description to function comment\r
572// TODO: Time - add argument and description to function comment\r
573// TODO: Global - add argument and description to function comment\r
574// TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
575// TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
576// TODO: EFI_UNSUPPORTED - add return value to function comment\r
577// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
578// TODO: EFI_SUCCESS - add return value to function comment\r
579{\r
580 EFI_STATUS Status;\r
581 EFI_TIME RtcTime;\r
582 RTC_REGISTER_B RegisterB;\r
583 UINT8 Century;\r
584 EFI_TIME_CAPABILITIES Capabilities;\r
585\r
586 if (Enable) {\r
587\r
588 if (Time == NULL) {\r
589 return EFI_INVALID_PARAMETER;\r
590 }\r
591 //\r
592 // Make sure that the time fields are valid\r
593 //\r
594 Status = RtcTimeFieldsValid (Time);\r
595 if (EFI_ERROR (Status)) {\r
596 return EFI_INVALID_PARAMETER;\r
597 }\r
598 //\r
599 // Just support set alarm time within 24 hours\r
600 //\r
601 PcRtcGetTime (&RtcTime, &Capabilities, Global);\r
602 if (!IsWithinOneDay (&RtcTime, Time)) {\r
603 return EFI_UNSUPPORTED;\r
604 }\r
605 //\r
606 // Make a local copy of the time and date\r
607 //\r
608 CopyMem (&RtcTime, Time, sizeof (EFI_TIME));\r
609\r
610 }\r
611 //\r
612 // Acquire RTC Lock to make access to RTC atomic\r
613 //\r
614 EfiAcquireLock (&Global->RtcLock);\r
615\r
616 //\r
617 // Wait for up to 0.1 seconds for the RTC to be updated\r
618 //\r
619 Status = RtcWaitToUpdate (100000);\r
620 if (EFI_ERROR (Status)) {\r
621 EfiReleaseLock (&Global->RtcLock);\r
622 return EFI_DEVICE_ERROR;\r
623 }\r
624 //\r
625 // Read Register B, and inhibit updates of the RTC\r
626 //\r
627 RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);\r
628\r
629 RegisterB.Bits.SET = 1;\r
630 RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
631\r
632 if (Enable) {\r
633 ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century);\r
634\r
635 //\r
636 // Set RTC alarm time\r
637 //\r
638 RtcWrite (RTC_ADDRESS_SECONDS_ALARM, RtcTime.Second);\r
639 RtcWrite (RTC_ADDRESS_MINUTES_ALARM, RtcTime.Minute);\r
640 RtcWrite (RTC_ADDRESS_HOURS_ALARM, RtcTime.Hour);\r
641\r
642 RegisterB.Bits.AIE = 1;\r
643\r
644 } else {\r
645 RegisterB.Bits.AIE = 0;\r
646 }\r
647 //\r
648 // Allow updates of the RTC registers\r
649 //\r
650 RegisterB.Bits.SET = 0;\r
651 RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
652\r
653 //\r
654 // Release RTC Lock.\r
655 //\r
656 EfiReleaseLock (&Global->RtcLock);\r
657\r
658 return EFI_SUCCESS;\r
659}\r
660\r
661UINT8\r
662BcdToDecimal (\r
663 IN UINT8 BcdValue\r
664 )\r
665/*++\r
666\r
667Routine Description:\r
668\r
669 Arguments:\r
670\r
671 \r
672\r
673Returns: \r
674--*/\r
675// TODO: BcdValue - add argument and description to function comment\r
676{\r
677 UINTN High;\r
678 UINTN Low;\r
679\r
680 High = BcdValue >> 4;\r
681 Low = BcdValue - (High << 4);\r
682\r
683 return (UINT8) (Low + (High * 10));\r
684}\r
685\r
686EFI_STATUS\r
687RtcTestCenturyRegister (\r
688 VOID\r
689 )\r
690/*++\r
691\r
692Routine Description:\r
693\r
694 Arguments:\r
695\r
696 \r
697\r
698Returns: \r
699--*/\r
700// TODO: EFI_SUCCESS - add return value to function comment\r
701// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
702{\r
703 UINT8 Century;\r
704 UINT8 Temp;\r
705\r
706 Century = RtcRead (RTC_ADDRESS_CENTURY);\r
707 //\r
708 // RtcWrite (RTC_ADDRESS_CENTURY, 0x00);\r
709 //\r
710 Temp = (UINT8) (RtcRead (RTC_ADDRESS_CENTURY) & 0x7f);\r
711 RtcWrite (RTC_ADDRESS_CENTURY, Century);\r
712 if (Temp == 0x19 || Temp == 0x20) {\r
713 return EFI_SUCCESS;\r
714 }\r
715\r
716 return EFI_DEVICE_ERROR;\r
717}\r
718\r
719VOID\r
720ConvertRtcTimeToEfiTime (\r
721 IN EFI_TIME *Time,\r
722 IN RTC_REGISTER_B RegisterB\r
723 )\r
724/*++\r
725\r
726Routine Description:\r
727\r
728 Arguments:\r
729\r
730 \r
731\r
732Returns: \r
733--*/\r
734// TODO: Time - add argument and description to function comment\r
735// TODO: RegisterB - add argument and description to function comment\r
736{\r
737 BOOLEAN PM;\r
738\r
739 if ((Time->Hour) & 0x80) {\r
740 PM = TRUE;\r
741 } else {\r
742 PM = FALSE;\r
743 }\r
744\r
745 Time->Hour = (UINT8) (Time->Hour & 0x7f);\r
746\r
747 if (RegisterB.Bits.DM == 0) {\r
748 Time->Year = BcdToDecimal ((UINT8) Time->Year);\r
749 Time->Month = BcdToDecimal (Time->Month);\r
750 Time->Day = BcdToDecimal (Time->Day);\r
751 Time->Hour = BcdToDecimal (Time->Hour);\r
752 Time->Minute = BcdToDecimal (Time->Minute);\r
753 Time->Second = BcdToDecimal (Time->Second);\r
754 }\r
755 //\r
756 // If time is in 12 hour format, convert it to 24 hour format\r
757 //\r
758 if (RegisterB.Bits.MIL == 0) {\r
759 if (PM && Time->Hour < 12) {\r
760 Time->Hour = (UINT8) (Time->Hour + 12);\r
761 }\r
762\r
763 if (!PM && Time->Hour == 12) {\r
764 Time->Hour = 0;\r
765 }\r
766 }\r
767\r
768 Time->Nanosecond = 0;\r
769 Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
770 Time->Daylight = 0;\r
771}\r
772\r
773EFI_STATUS\r
774RtcWaitToUpdate (\r
775 UINTN Timeout\r
776 )\r
777/*++\r
778\r
779Routine Description:\r
780\r
781 Arguments:\r
782 \r
783\r
784Returns: \r
785--*/\r
786// TODO: Timeout - add argument and description to function comment\r
787// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
788// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
789// TODO: EFI_SUCCESS - add return value to function comment\r
790{\r
791 RTC_REGISTER_A RegisterA;\r
792 RTC_REGISTER_D RegisterD;\r
793\r
794 //\r
795 // See if the RTC is functioning correctly\r
796 //\r
797 RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D);\r
798\r
799 if (RegisterD.Bits.VRT == 0) {\r
800 return EFI_DEVICE_ERROR;\r
801 }\r
802 //\r
803 // Wait for up to 0.1 seconds for the RTC to be ready.\r
804 //\r
805 Timeout = (Timeout / 10) + 1;\r
806 RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A);\r
807 while (RegisterA.Bits.UIP == 1 && Timeout > 0) {\r
808 MicroSecondDelay (10);\r
809 RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A);\r
810 Timeout--;\r
811 }\r
812\r
813 RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D);\r
814 if (Timeout == 0 || RegisterD.Bits.VRT == 0) {\r
815 return EFI_DEVICE_ERROR;\r
816 }\r
817\r
818 return EFI_SUCCESS;\r
819}\r
820\r
821EFI_STATUS\r
822RtcTimeFieldsValid (\r
823 IN EFI_TIME *Time\r
824 )\r
825/*++\r
826\r
827Routine Description:\r
828\r
829 Arguments:\r
830 \r
831 Returns: \r
832--*/\r
833// TODO: Time - add argument and description to function comment\r
834// TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
835// TODO: EFI_SUCCESS - add return value to function comment\r
836{\r
837 if (Time->Year < 1998 ||\r
838 Time->Year > 2099 ||\r
839 Time->Month < 1 ||\r
840 Time->Month > 12 ||\r
841 (!DayValid (Time)) ||\r
842 Time->Hour > 23 ||\r
843 Time->Minute > 59 ||\r
844 Time->Second > 59 ||\r
845 Time->Nanosecond > 999999999 ||\r
846 (!(Time->TimeZone == EFI_UNSPECIFIED_TIMEZONE || (Time->TimeZone >= -1440 && Time->TimeZone <= 1440))) ||\r
847 (Time->Daylight & (~(EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT)))\r
848 ) {\r
849 return EFI_INVALID_PARAMETER;\r
850 }\r
851\r
852 return EFI_SUCCESS;\r
853}\r
854\r
855BOOLEAN\r
856DayValid (\r
857 IN EFI_TIME *Time\r
858 )\r
859/*++\r
860\r
861Routine Description:\r
862\r
863 TODO: Add function description\r
864\r
865Arguments:\r
866\r
867 Time - TODO: add argument description\r
868\r
869Returns:\r
870\r
871 TODO: add return values\r
872\r
873--*/\r
874{\r
875\r
876 INTN DayOfMonth[12] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };\r
877\r
878 if (Time->Day < 1 ||\r
879 Time->Day > DayOfMonth[Time->Month - 1] ||\r
880 (Time->Month == 2 && (!IsLeapYear (Time) && Time->Day > 28))\r
881 ) {\r
882 return FALSE;\r
883 }\r
884\r
885 return TRUE;\r
886}\r
887\r
888BOOLEAN\r
889IsLeapYear (\r
890 IN EFI_TIME *Time\r
891 )\r
892/*++\r
893\r
894Routine Description:\r
895\r
896 TODO: Add function description\r
897\r
898Arguments:\r
899\r
900 Time - TODO: add argument description\r
901\r
902Returns:\r
903\r
904 TODO: add return values\r
905\r
906--*/\r
907{\r
908 if (Time->Year % 4 == 0) {\r
909 if (Time->Year % 100 == 0) {\r
910 if (Time->Year % 400 == 0) {\r
911 return TRUE;\r
912 } else {\r
913 return FALSE;\r
914 }\r
915 } else {\r
916 return TRUE;\r
917 }\r
918 } else {\r
919 return FALSE;\r
920 }\r
921}\r
922\r
923VOID\r
924ConvertEfiTimeToRtcTime (\r
925 IN EFI_TIME *Time,\r
926 IN RTC_REGISTER_B RegisterB,\r
927 IN UINT8 *Century\r
928 )\r
929/*++\r
930\r
931Routine Description:\r
932\r
933 Arguments:\r
934\r
935\r
936Returns: \r
937--*/\r
938// TODO: Time - add argument and description to function comment\r
939// TODO: RegisterB - add argument and description to function comment\r
940// TODO: Century - add argument and description to function comment\r
941{\r
942 BOOLEAN PM;\r
943\r
944 PM = TRUE;\r
945 //\r
946 // Adjust hour field if RTC in in 12 hour mode\r
947 //\r
948 if (RegisterB.Bits.MIL == 0) {\r
949 if (Time->Hour < 12) {\r
950 PM = FALSE;\r
951 }\r
952\r
953 if (Time->Hour >= 13) {\r
954 Time->Hour = (UINT8) (Time->Hour - 12);\r
955 } else if (Time->Hour == 0) {\r
956 Time->Hour = 12;\r
957 }\r
958 }\r
959 //\r
960 // Set the Time/Date/Daylight Savings values.\r
961 //\r
962 *Century = DecimaltoBcd ((UINT8) (Time->Year / 100));\r
963\r
964 Time->Year = (UINT16) (Time->Year % 100);\r
965\r
966 if (RegisterB.Bits.DM == 0) {\r
967 Time->Year = DecimaltoBcd ((UINT8) Time->Year);\r
968 Time->Month = DecimaltoBcd (Time->Month);\r
969 Time->Day = DecimaltoBcd (Time->Day);\r
970 Time->Hour = DecimaltoBcd (Time->Hour);\r
971 Time->Minute = DecimaltoBcd (Time->Minute);\r
972 Time->Second = DecimaltoBcd (Time->Second);\r
973 }\r
974 //\r
975 // If we are in 12 hour mode and PM is set, then set bit 7 of the Hour field.\r
976 //\r
977 if (RegisterB.Bits.MIL == 0 && PM) {\r
978 Time->Hour = (UINT8) (Time->Hour | 0x80);\r
979 }\r
980}\r
981 \r
982BOOLEAN \r
983IsWithinOneDay (\r
984 IN EFI_TIME *From,\r
985 IN EFI_TIME *To\r
986 )\r
987/*++\r
988\r
989Routine Description:\r
990\r
991 Judge whether two days are adjacent.\r
992\r
993Arguments:\r
994\r
995 From - the first day\r
996 To - the second day\r
997\r
998Returns:\r
999\r
1000 TRUE - The interval of two days are within one day.\r
1001 FALSE - The interval of two days exceed ony day or parameter error.\r
1002\r
1003--*/\r
1004{\r
1005 UINT8 DayOfMonth[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};\r
1006 BOOLEAN Adjacent = FALSE;\r
1007\r
1008 if (From->Year == To->Year) {\r
1009 if (From->Month == To->Month) {\r
1010 if ((From->Day + 1) == To->Day) {\r
1011 if ((CompareHMS(From, To) >= 0)) {\r
1012 Adjacent = TRUE;\r
1013 }\r
1014 } else if (From->Day == To->Day) {\r
1015 if ((CompareHMS(From, To) <= 0)) {\r
1016 Adjacent = TRUE;\r
1017 }\r
1018 }\r
1019 } else if (((From->Month + 1) == To->Month) && (To->Day == 1)) {\r
1020 if ((From->Month == 2) && !IsLeapYear(From)) {\r
1021 if (From->Day == 28) {\r
1022 if ((CompareHMS(From, To) >= 0)) {\r
1023 Adjacent = TRUE;\r
1024 } \r
1025 }\r
1026 } else if (From->Day == DayOfMonth[From->Month - 1]) {\r
1027 if ((CompareHMS(From, To) >= 0)) {\r
1028 Adjacent = TRUE;\r
1029 }\r
1030 }\r
1031 }\r
1032 } else if (((From->Year + 1) == To->Year) &&\r
1033 (From->Month == 12) &&\r
1034 (From->Day == 31) &&\r
1035 (To->Month == 1) &&\r
1036 (To->Day == 1)) {\r
1037 if ((CompareHMS(From, To) >= 0)) {\r
1038 Adjacent = TRUE;\r
1039 }\r
1040 }\r
1041\r
1042 return Adjacent;\r
1043}\r
1044\r
1045UINT8\r
1046DecimaltoBcd (\r
1047 IN UINT8 DecValue\r
1048 )\r
1049/*++\r
1050\r
1051Routine Description:\r
1052\r
1053 Arguments: \r
1054\r
1055Returns: \r
1056\r
1057--*/\r
1058// TODO: DecValue - add argument and description to function comment\r
1059{\r
1060 UINTN High;\r
1061 UINTN Low;\r
1062\r
1063 High = DecValue / 10;\r
1064 Low = DecValue - (High * 10);\r
1065\r
1066 return (UINT8) (Low + (High << 4));\r
1067}\r