]> git.proxmox.com Git - mirror_edk2.git/blame - PcAtChipsetPkg/PcRtc/RealTimeClock.c
supply comments on data structure to follow spec.
[mirror_edk2.git] / PcAtChipsetPkg / 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
269c0ba2 44\r
45INTN mDayOfMonth[12] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};\r
c69dd9df 46 \r
47UINT8\r
48RtcRead (\r
49 IN UINT8 Address\r
50 )\r
51/*++\r
52\r
53Routine Description:\r
54\r
55 TODO: Add function description\r
56\r
57Arguments:\r
58\r
59 Address - TODO: add argument description\r
60\r
61Returns:\r
62\r
63 TODO: add return values\r
64\r
65--*/\r
66{\r
67 IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8) (Address | (UINT8) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & 0x80)));\r
68 return IoRead8 (PCAT_RTC_DATA_REGISTER);\r
69}\r
70\r
71INTN\r
72CompareHMS (\r
73 IN EFI_TIME *From,\r
74 IN EFI_TIME *To\r
75 )\r
76/*++\r
77\r
78Routine Description: \r
79\r
80 Compare the Hour, Minute and Second of the 'From' time and the 'To' time.\r
81 Only compare H/M/S in EFI_TIME and ignore other fields here. \r
82\r
83Arguments:\r
84\r
85 From - the first time\r
86 To - the second time \r
87\r
88Returns:\r
89\r
90 >0 : The H/M/S of the 'From' time is later than those of 'To' time\r
91 ==0 : The H/M/S of the 'From' time is same as those of 'To' time\r
92 <0 : The H/M/S of the 'From' time is earlier than those of 'To' time\r
93\r
94--*/\r
95\r
96{\r
97 if ((From->Hour > To->Hour) ||\r
98 ((From->Hour == To->Hour) && (From->Minute > To->Minute)) ||\r
99 ((From->Hour == To->Hour) && (From->Minute == To->Minute) && (From->Second > To->Second))) {\r
100 return 1; \r
101 } else if ((From->Hour == To->Hour) && (From->Minute == To->Minute) && (From->Second == To->Second)) {\r
102 return 0;\r
103 } else {\r
104 return -1;\r
105 }\r
106}\r
107\r
108VOID\r
109RtcWrite (\r
110 IN UINT8 Address,\r
111 IN UINT8 Data\r
112 )\r
113/*++\r
114\r
115Routine Description:\r
116\r
117 TODO: Add function description\r
118\r
119Arguments:\r
120\r
121 Address - TODO: add argument description\r
122 Data - TODO: add argument description\r
123\r
124Returns:\r
125\r
126 TODO: add return values\r
127\r
128--*/\r
129{\r
130 IoWrite8 (PCAT_RTC_ADDRESS_REGISTER, (UINT8) (Address | (UINT8) (IoRead8 (PCAT_RTC_ADDRESS_REGISTER) & 0x80)));\r
131 IoWrite8 (PCAT_RTC_DATA_REGISTER, Data);\r
132}\r
133\r
134EFI_STATUS\r
135PcRtcInit (\r
136 IN PC_RTC_MODULE_GLOBALS *Global\r
137 )\r
138/*++\r
139\r
140Routine Description:\r
141\r
142 TODO: Add function description\r
143\r
144Arguments:\r
145\r
146 Global - TODO: add argument description\r
147\r
148Returns:\r
149\r
150 EFI_DEVICE_ERROR - TODO: Add description for return value\r
151 EFI_SUCCESS - TODO: Add description for return value\r
152\r
153--*/\r
154{\r
155 EFI_STATUS Status;\r
156 RTC_REGISTER_A RegisterA;\r
157 RTC_REGISTER_B RegisterB;\r
e188a609 158 //RTC_REGISTER_C RegisterC;\r
c69dd9df 159 RTC_REGISTER_D RegisterD;\r
160 UINT8 Century;\r
161 EFI_TIME Time;\r
162\r
163 //\r
164 // Acquire RTC Lock to make access to RTC atomic\r
165 //\r
166 EfiAcquireLock (&Global->RtcLock);\r
167\r
168 //\r
169 // Initialize RTC Register\r
170 //\r
171 // Make sure Division Chain is properly configured,\r
172 // or RTC clock won't "tick" -- time won't increment\r
173 //\r
174 RegisterA.Data = RTC_INIT_REGISTER_A;\r
175 RtcWrite (RTC_ADDRESS_REGISTER_A, RegisterA.Data);\r
176\r
177 //\r
178 // Read Register B\r
179 //\r
180 RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);\r
181\r
182 //\r
183 // Clear RTC flag register\r
184 //\r
e188a609 185 //RegisterC.Data = RtcRead (RTC_ADDRESS_REGISTER_C);\r
c69dd9df 186\r
187 //\r
188 // Clear RTC register D\r
189 //\r
190 RegisterD.Data = RTC_INIT_REGISTER_D;\r
191 RtcWrite (RTC_ADDRESS_REGISTER_D, RegisterD.Data);\r
192\r
193 //\r
194 // Wait for up to 0.1 seconds for the RTC to be updated\r
195 //\r
e25803f0 196 // KEN: BUGBUG following wait action will cause failure under vmware environment.\r
197 //\r
198 //Status = RtcWaitToUpdate (100000);\r
199 //if (EFI_ERROR (Status)) {\r
200 // EfiReleaseLock (&Global->RtcLock);\r
201 // return EFI_DEVICE_ERROR;\r
202 //}\r
c69dd9df 203 //\r
204 // Get the Time/Date/Daylight Savings values.\r
205 //\r
206 Time.Second = RtcRead (RTC_ADDRESS_SECONDS);\r
207 Time.Minute = RtcRead (RTC_ADDRESS_MINUTES);\r
208 Time.Hour = RtcRead (RTC_ADDRESS_HOURS);\r
209 Time.Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);\r
210 Time.Month = RtcRead (RTC_ADDRESS_MONTH);\r
211 Time.Year = RtcRead (RTC_ADDRESS_YEAR);\r
212\r
213 ConvertRtcTimeToEfiTime (&Time, RegisterB);\r
214\r
aa4d03f7 215 Century = BcdToDecimal8 (RtcRead (RTC_ADDRESS_CENTURY));\r
c69dd9df 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
e188a609 273 //UINTN BufferSize;\r
c69dd9df 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
aa4d03f7 312 Century = BcdToDecimal8 (RtcRead (RTC_ADDRESS_CENTURY));\r
c69dd9df 313\r
314 Time->Year = (UINT16) (Century * 100 + Time->Year);\r
315\r
316 //\r
317 // Release RTC Lock.\r
318 //\r
319 EfiReleaseLock (&Global->RtcLock);\r
320\r
321 //\r
322 // Get the variable that containts the TimeZone and Daylight fields\r
323 //\r
324 Time->TimeZone = Global->SavedTimeZone;\r
325 Time->Daylight = Global->Daylight;\r
326\r
e188a609 327 //BufferSize = sizeof (INT16) + sizeof (UINT8);\r
c69dd9df 328\r
329 //\r
330 // Make sure all field values are in correct range\r
331 //\r
332 Status = RtcTimeFieldsValid (Time);\r
333 if (EFI_ERROR (Status)) {\r
334 return EFI_DEVICE_ERROR;\r
335 }\r
336 //\r
337 // Fill in Capabilities if it was passed in\r
338 //\r
339 if (Capabilities) {\r
340 Capabilities->Resolution = 1;\r
341 //\r
342 // 1 hertz\r
343 //\r
344 Capabilities->Accuracy = 50000000;\r
345 //\r
346 // 50 ppm\r
347 //\r
348 Capabilities->SetsToZero = FALSE;\r
349 }\r
350\r
351 return EFI_SUCCESS;\r
352}\r
353\r
354EFI_STATUS\r
355PcRtcSetTime (\r
356 IN EFI_TIME *Time,\r
357 IN PC_RTC_MODULE_GLOBALS *Global\r
358 )\r
359/*++\r
360\r
361Routine Description:\r
362\r
363 Arguments:\r
364\r
365 Returns: \r
366--*/\r
367// TODO: Time - add argument and description to function comment\r
368// TODO: Global - add argument and description to function comment\r
369// TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
370{\r
371 EFI_STATUS Status;\r
372 EFI_TIME RtcTime;\r
373 RTC_REGISTER_B RegisterB;\r
374 UINT8 Century;\r
375\r
376 if (Time == NULL) {\r
377 return EFI_INVALID_PARAMETER;\r
378 }\r
379 //\r
380 // Make sure that the time fields are valid\r
381 //\r
382 Status = RtcTimeFieldsValid (Time);\r
383 if (EFI_ERROR (Status)) {\r
384 return Status;\r
385 }\r
386\r
387 CopyMem (&RtcTime, Time, sizeof (EFI_TIME));\r
388\r
389 //\r
390 // Acquire RTC Lock to make access to RTC atomic\r
391 //\r
392 EfiAcquireLock (&Global->RtcLock);\r
393\r
394 //\r
395 // Wait for up to 0.1 seconds for the RTC to be updated\r
396 //\r
397 Status = RtcWaitToUpdate (100000);\r
398 if (EFI_ERROR (Status)) {\r
399 EfiReleaseLock (&Global->RtcLock);\r
400 return Status;\r
401 }\r
402 //\r
403 // Read Register B, and inhibit updates of the RTC\r
404 //\r
405 RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);\r
406 RegisterB.Bits.SET = 1;\r
407 RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
408\r
409 ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century);\r
410\r
411 RtcWrite (RTC_ADDRESS_SECONDS, RtcTime.Second);\r
412 RtcWrite (RTC_ADDRESS_MINUTES, RtcTime.Minute);\r
413 RtcWrite (RTC_ADDRESS_HOURS, RtcTime.Hour);\r
414 RtcWrite (RTC_ADDRESS_DAY_OF_THE_MONTH, RtcTime.Day);\r
415 RtcWrite (RTC_ADDRESS_MONTH, RtcTime.Month);\r
416 RtcWrite (RTC_ADDRESS_YEAR, (UINT8) RtcTime.Year);\r
c69dd9df 417 RtcWrite (RTC_ADDRESS_CENTURY, Century);\r
418\r
419 //\r
420 // Allow updates of the RTC registers\r
421 //\r
422 RegisterB.Bits.SET = 0;\r
423 RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
424\r
425 //\r
426 // Release RTC Lock.\r
427 //\r
428 EfiReleaseLock (&Global->RtcLock);\r
429\r
430 //\r
431 // Set the variable that containts the TimeZone and Daylight fields\r
432 //\r
433 Global->SavedTimeZone = Time->TimeZone;\r
434 Global->Daylight = Time->Daylight;\r
435 return Status;\r
436}\r
437\r
438EFI_STATUS\r
439EFIAPI\r
440PcRtcGetWakeupTime (\r
441 OUT BOOLEAN *Enabled,\r
442 OUT BOOLEAN *Pending,\r
443 OUT EFI_TIME *Time,\r
444 IN PC_RTC_MODULE_GLOBALS *Global\r
445 )\r
446/*++\r
447\r
448Routine Description:\r
449\r
450 Arguments:\r
451\r
452 \r
453\r
454Returns: \r
455--*/\r
456// TODO: Enabled - add argument and description to function comment\r
457// TODO: Pending - add argument and description to function comment\r
458// TODO: Time - add argument and description to function comment\r
459// TODO: Global - add argument and description to function comment\r
460// TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
461// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
462// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
463// TODO: EFI_SUCCESS - add return value to function comment\r
464{\r
465 EFI_STATUS Status;\r
466 RTC_REGISTER_B RegisterB;\r
467 RTC_REGISTER_C RegisterC;\r
468 UINT8 Century;\r
469\r
470 //\r
471 // Check paramters for null pointers\r
472 //\r
473 if ((Enabled == NULL) || (Pending == NULL) || (Time == NULL)) {\r
474 return EFI_INVALID_PARAMETER;\r
475\r
476 }\r
477 //\r
478 // Acquire RTC Lock to make access to RTC atomic\r
479 //\r
480 EfiAcquireLock (&Global->RtcLock);\r
481\r
482 //\r
483 // Wait for up to 0.1 seconds for the RTC to be updated\r
484 //\r
485 Status = RtcWaitToUpdate (100000);\r
486 if (EFI_ERROR (Status)) {\r
487 EfiReleaseLock (&Global->RtcLock);\r
488 return EFI_DEVICE_ERROR;\r
489 }\r
490 //\r
491 // Read Register B and Register C\r
492 //\r
493 RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);\r
494 RegisterC.Data = RtcRead (RTC_ADDRESS_REGISTER_C);\r
495\r
496 //\r
497 // Get the Time/Date/Daylight Savings values.\r
498 //\r
499 *Enabled = RegisterB.Bits.AIE;\r
500 if (*Enabled) {\r
501 Time->Second = RtcRead (RTC_ADDRESS_SECONDS_ALARM);\r
502 Time->Minute = RtcRead (RTC_ADDRESS_MINUTES_ALARM);\r
503 Time->Hour = RtcRead (RTC_ADDRESS_HOURS_ALARM);\r
504 Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);\r
505 Time->Month = RtcRead (RTC_ADDRESS_MONTH);\r
506 Time->Year = RtcRead (RTC_ADDRESS_YEAR);\r
507 } else {\r
508 Time->Second = 0;\r
509 Time->Minute = 0;\r
510 Time->Hour = 0;\r
511 Time->Day = RtcRead (RTC_ADDRESS_DAY_OF_THE_MONTH);\r
512 Time->Month = RtcRead (RTC_ADDRESS_MONTH);\r
513 Time->Year = RtcRead (RTC_ADDRESS_YEAR);\r
514 }\r
515\r
516 ConvertRtcTimeToEfiTime (Time, RegisterB);\r
517\r
aa4d03f7 518 Century = BcdToDecimal8 (RtcRead (RTC_ADDRESS_CENTURY));\r
c69dd9df 519\r
520 Time->Year = (UINT16) (Century * 100 + Time->Year);\r
521\r
522 //\r
523 // Release RTC Lock.\r
524 //\r
525 EfiReleaseLock (&Global->RtcLock);\r
526\r
527 //\r
528 // Make sure all field values are in correct range\r
529 //\r
530 Status = RtcTimeFieldsValid (Time);\r
531 if (EFI_ERROR (Status)) {\r
532 return EFI_DEVICE_ERROR;\r
533 }\r
534\r
535 *Pending = RegisterC.Bits.AF;\r
536\r
537 return EFI_SUCCESS;\r
538}\r
539\r
540EFI_STATUS\r
541EFIAPI\r
542PcRtcSetWakeupTime (\r
543 IN BOOLEAN Enable,\r
544 OUT EFI_TIME *Time,\r
545 IN PC_RTC_MODULE_GLOBALS *Global\r
546 )\r
547/*++\r
548\r
549Routine Description:\r
550\r
551 Arguments:\r
552\r
553 \r
554\r
555Returns: \r
556--*/\r
557// TODO: Enable - add argument and description to function comment\r
558// TODO: Time - add argument and description to function comment\r
559// TODO: Global - add argument and description to function comment\r
560// TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
561// TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
562// TODO: EFI_UNSUPPORTED - add return value to function comment\r
563// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
564// TODO: EFI_SUCCESS - add return value to function comment\r
565{\r
566 EFI_STATUS Status;\r
567 EFI_TIME RtcTime;\r
568 RTC_REGISTER_B RegisterB;\r
569 UINT8 Century;\r
570 EFI_TIME_CAPABILITIES Capabilities;\r
571\r
572 if (Enable) {\r
573\r
574 if (Time == NULL) {\r
575 return EFI_INVALID_PARAMETER;\r
576 }\r
577 //\r
578 // Make sure that the time fields are valid\r
579 //\r
580 Status = RtcTimeFieldsValid (Time);\r
581 if (EFI_ERROR (Status)) {\r
582 return EFI_INVALID_PARAMETER;\r
583 }\r
584 //\r
585 // Just support set alarm time within 24 hours\r
586 //\r
587 PcRtcGetTime (&RtcTime, &Capabilities, Global);\r
588 if (!IsWithinOneDay (&RtcTime, Time)) {\r
589 return EFI_UNSUPPORTED;\r
590 }\r
591 //\r
592 // Make a local copy of the time and date\r
593 //\r
594 CopyMem (&RtcTime, Time, sizeof (EFI_TIME));\r
595\r
596 }\r
597 //\r
598 // Acquire RTC Lock to make access to RTC atomic\r
599 //\r
600 EfiAcquireLock (&Global->RtcLock);\r
601\r
602 //\r
603 // Wait for up to 0.1 seconds for the RTC to be updated\r
604 //\r
605 Status = RtcWaitToUpdate (100000);\r
606 if (EFI_ERROR (Status)) {\r
607 EfiReleaseLock (&Global->RtcLock);\r
608 return EFI_DEVICE_ERROR;\r
609 }\r
610 //\r
611 // Read Register B, and inhibit updates of the RTC\r
612 //\r
613 RegisterB.Data = RtcRead (RTC_ADDRESS_REGISTER_B);\r
614\r
615 RegisterB.Bits.SET = 1;\r
616 RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
617\r
618 if (Enable) {\r
619 ConvertEfiTimeToRtcTime (&RtcTime, RegisterB, &Century);\r
620\r
621 //\r
622 // Set RTC alarm time\r
623 //\r
624 RtcWrite (RTC_ADDRESS_SECONDS_ALARM, RtcTime.Second);\r
625 RtcWrite (RTC_ADDRESS_MINUTES_ALARM, RtcTime.Minute);\r
626 RtcWrite (RTC_ADDRESS_HOURS_ALARM, RtcTime.Hour);\r
627\r
628 RegisterB.Bits.AIE = 1;\r
629\r
630 } else {\r
631 RegisterB.Bits.AIE = 0;\r
632 }\r
633 //\r
634 // Allow updates of the RTC registers\r
635 //\r
636 RegisterB.Bits.SET = 0;\r
637 RtcWrite (RTC_ADDRESS_REGISTER_B, RegisterB.Data);\r
638\r
639 //\r
640 // Release RTC Lock.\r
641 //\r
642 EfiReleaseLock (&Global->RtcLock);\r
643\r
644 return EFI_SUCCESS;\r
645}\r
646\r
c69dd9df 647VOID\r
648ConvertRtcTimeToEfiTime (\r
649 IN EFI_TIME *Time,\r
650 IN RTC_REGISTER_B RegisterB\r
651 )\r
652/*++\r
653\r
654Routine Description:\r
655\r
656 Arguments:\r
657\r
658 \r
659\r
660Returns: \r
661--*/\r
662// TODO: Time - add argument and description to function comment\r
663// TODO: RegisterB - add argument and description to function comment\r
664{\r
665 BOOLEAN PM;\r
666\r
667 if ((Time->Hour) & 0x80) {\r
668 PM = TRUE;\r
669 } else {\r
670 PM = FALSE;\r
671 }\r
672\r
673 Time->Hour = (UINT8) (Time->Hour & 0x7f);\r
674\r
675 if (RegisterB.Bits.DM == 0) {\r
aa4d03f7 676 Time->Year = BcdToDecimal8 ((UINT8) Time->Year);\r
677 Time->Month = BcdToDecimal8 (Time->Month);\r
678 Time->Day = BcdToDecimal8 (Time->Day);\r
679 Time->Hour = BcdToDecimal8 (Time->Hour);\r
680 Time->Minute = BcdToDecimal8 (Time->Minute);\r
681 Time->Second = BcdToDecimal8 (Time->Second);\r
c69dd9df 682 }\r
683 //\r
684 // If time is in 12 hour format, convert it to 24 hour format\r
685 //\r
686 if (RegisterB.Bits.MIL == 0) {\r
687 if (PM && Time->Hour < 12) {\r
688 Time->Hour = (UINT8) (Time->Hour + 12);\r
689 }\r
690\r
691 if (!PM && Time->Hour == 12) {\r
692 Time->Hour = 0;\r
693 }\r
694 }\r
695\r
696 Time->Nanosecond = 0;\r
697 Time->TimeZone = EFI_UNSPECIFIED_TIMEZONE;\r
698 Time->Daylight = 0;\r
699}\r
700\r
701EFI_STATUS\r
702RtcWaitToUpdate (\r
703 UINTN Timeout\r
704 )\r
705/*++\r
706\r
707Routine Description:\r
708\r
709 Arguments:\r
710 \r
711\r
712Returns: \r
713--*/\r
714// TODO: Timeout - add argument and description to function comment\r
715// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
716// TODO: EFI_DEVICE_ERROR - add return value to function comment\r
717// TODO: EFI_SUCCESS - add return value to function comment\r
718{\r
719 RTC_REGISTER_A RegisterA;\r
720 RTC_REGISTER_D RegisterD;\r
721\r
722 //\r
723 // See if the RTC is functioning correctly\r
724 //\r
725 RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D);\r
726\r
727 if (RegisterD.Bits.VRT == 0) {\r
728 return EFI_DEVICE_ERROR;\r
729 }\r
730 //\r
731 // Wait for up to 0.1 seconds for the RTC to be ready.\r
732 //\r
733 Timeout = (Timeout / 10) + 1;\r
734 RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A);\r
735 while (RegisterA.Bits.UIP == 1 && Timeout > 0) {\r
736 MicroSecondDelay (10);\r
737 RegisterA.Data = RtcRead (RTC_ADDRESS_REGISTER_A);\r
738 Timeout--;\r
739 }\r
740\r
741 RegisterD.Data = RtcRead (RTC_ADDRESS_REGISTER_D);\r
742 if (Timeout == 0 || RegisterD.Bits.VRT == 0) {\r
743 return EFI_DEVICE_ERROR;\r
744 }\r
745\r
746 return EFI_SUCCESS;\r
747}\r
748\r
749EFI_STATUS\r
750RtcTimeFieldsValid (\r
751 IN EFI_TIME *Time\r
752 )\r
753/*++\r
754\r
755Routine Description:\r
756\r
757 Arguments:\r
758 \r
759 Returns: \r
760--*/\r
761// TODO: Time - add argument and description to function comment\r
762// TODO: EFI_INVALID_PARAMETER - add return value to function comment\r
763// TODO: EFI_SUCCESS - add return value to function comment\r
764{\r
765 if (Time->Year < 1998 ||\r
766 Time->Year > 2099 ||\r
767 Time->Month < 1 ||\r
768 Time->Month > 12 ||\r
769 (!DayValid (Time)) ||\r
770 Time->Hour > 23 ||\r
771 Time->Minute > 59 ||\r
772 Time->Second > 59 ||\r
773 Time->Nanosecond > 999999999 ||\r
774 (!(Time->TimeZone == EFI_UNSPECIFIED_TIMEZONE || (Time->TimeZone >= -1440 && Time->TimeZone <= 1440))) ||\r
775 (Time->Daylight & (~(EFI_TIME_ADJUST_DAYLIGHT | EFI_TIME_IN_DAYLIGHT)))\r
776 ) {\r
777 return EFI_INVALID_PARAMETER;\r
778 }\r
779\r
780 return EFI_SUCCESS;\r
781}\r
782\r
783BOOLEAN\r
784DayValid (\r
785 IN EFI_TIME *Time\r
786 )\r
787/*++\r
788\r
789Routine Description:\r
790\r
791 TODO: Add function description\r
792\r
793Arguments:\r
794\r
795 Time - TODO: add argument description\r
796\r
797Returns:\r
798\r
799 TODO: add return values\r
800\r
801--*/\r
802{\r
803\r
c69dd9df 804\r
805 if (Time->Day < 1 ||\r
269c0ba2 806 Time->Day > mDayOfMonth[Time->Month - 1] ||\r
c69dd9df 807 (Time->Month == 2 && (!IsLeapYear (Time) && Time->Day > 28))\r
808 ) {\r
809 return FALSE;\r
810 }\r
811\r
812 return TRUE;\r
813}\r
814\r
815BOOLEAN\r
816IsLeapYear (\r
817 IN EFI_TIME *Time\r
818 )\r
819/*++\r
820\r
821Routine Description:\r
822\r
823 TODO: Add function description\r
824\r
825Arguments:\r
826\r
827 Time - TODO: add argument description\r
828\r
829Returns:\r
830\r
831 TODO: add return values\r
832\r
833--*/\r
834{\r
835 if (Time->Year % 4 == 0) {\r
836 if (Time->Year % 100 == 0) {\r
837 if (Time->Year % 400 == 0) {\r
838 return TRUE;\r
839 } else {\r
840 return FALSE;\r
841 }\r
842 } else {\r
843 return TRUE;\r
844 }\r
845 } else {\r
846 return FALSE;\r
847 }\r
848}\r
849\r
850VOID\r
851ConvertEfiTimeToRtcTime (\r
852 IN EFI_TIME *Time,\r
853 IN RTC_REGISTER_B RegisterB,\r
854 IN UINT8 *Century\r
855 )\r
856/*++\r
857\r
858Routine Description:\r
859\r
860 Arguments:\r
861\r
862\r
863Returns: \r
864--*/\r
865// TODO: Time - add argument and description to function comment\r
866// TODO: RegisterB - add argument and description to function comment\r
867// TODO: Century - add argument and description to function comment\r
868{\r
869 BOOLEAN PM;\r
870\r
871 PM = TRUE;\r
872 //\r
873 // Adjust hour field if RTC in in 12 hour mode\r
874 //\r
875 if (RegisterB.Bits.MIL == 0) {\r
876 if (Time->Hour < 12) {\r
877 PM = FALSE;\r
878 }\r
879\r
880 if (Time->Hour >= 13) {\r
881 Time->Hour = (UINT8) (Time->Hour - 12);\r
882 } else if (Time->Hour == 0) {\r
883 Time->Hour = 12;\r
884 }\r
885 }\r
886 //\r
887 // Set the Time/Date/Daylight Savings values.\r
888 //\r
889 *Century = DecimaltoBcd ((UINT8) (Time->Year / 100));\r
890\r
891 Time->Year = (UINT16) (Time->Year % 100);\r
892\r
893 if (RegisterB.Bits.DM == 0) {\r
894 Time->Year = DecimaltoBcd ((UINT8) Time->Year);\r
895 Time->Month = DecimaltoBcd (Time->Month);\r
896 Time->Day = DecimaltoBcd (Time->Day);\r
897 Time->Hour = DecimaltoBcd (Time->Hour);\r
898 Time->Minute = DecimaltoBcd (Time->Minute);\r
899 Time->Second = DecimaltoBcd (Time->Second);\r
900 }\r
901 //\r
902 // If we are in 12 hour mode and PM is set, then set bit 7 of the Hour field.\r
903 //\r
904 if (RegisterB.Bits.MIL == 0 && PM) {\r
905 Time->Hour = (UINT8) (Time->Hour | 0x80);\r
906 }\r
907}\r
908 \r
909BOOLEAN \r
910IsWithinOneDay (\r
911 IN EFI_TIME *From,\r
912 IN EFI_TIME *To\r
913 )\r
914/*++\r
915\r
916Routine Description:\r
917\r
918 Judge whether two days are adjacent.\r
919\r
920Arguments:\r
921\r
922 From - the first day\r
923 To - the second day\r
924\r
925Returns:\r
926\r
927 TRUE - The interval of two days are within one day.\r
928 FALSE - The interval of two days exceed ony day or parameter error.\r
929\r
930--*/\r
931{\r
c69dd9df 932 BOOLEAN Adjacent = FALSE;\r
933\r
934 if (From->Year == To->Year) {\r
935 if (From->Month == To->Month) {\r
936 if ((From->Day + 1) == To->Day) {\r
937 if ((CompareHMS(From, To) >= 0)) {\r
938 Adjacent = TRUE;\r
939 }\r
940 } else if (From->Day == To->Day) {\r
941 if ((CompareHMS(From, To) <= 0)) {\r
942 Adjacent = TRUE;\r
943 }\r
944 }\r
945 } else if (((From->Month + 1) == To->Month) && (To->Day == 1)) {\r
946 if ((From->Month == 2) && !IsLeapYear(From)) {\r
947 if (From->Day == 28) {\r
948 if ((CompareHMS(From, To) >= 0)) {\r
949 Adjacent = TRUE;\r
950 } \r
951 }\r
269c0ba2 952 } else if (From->Day == mDayOfMonth[From->Month - 1]) {\r
c69dd9df 953 if ((CompareHMS(From, To) >= 0)) {\r
954 Adjacent = TRUE;\r
955 }\r
956 }\r
957 }\r
958 } else if (((From->Year + 1) == To->Year) &&\r
959 (From->Month == 12) &&\r
960 (From->Day == 31) &&\r
961 (To->Month == 1) &&\r
962 (To->Day == 1)) {\r
963 if ((CompareHMS(From, To) >= 0)) {\r
964 Adjacent = TRUE;\r
965 }\r
966 }\r
967\r
968 return Adjacent;\r
969}\r
970\r
971UINT8\r
972DecimaltoBcd (\r
973 IN UINT8 DecValue\r
974 )\r
975/*++\r
976\r
977Routine Description:\r
978\r
979 Arguments: \r
980\r
981Returns: \r
982\r
983--*/\r
984// TODO: DecValue - add argument and description to function comment\r
985{\r
986 UINTN High;\r
987 UINTN Low;\r
988\r
989 High = DecValue / 10;\r
990 Low = DecValue - (High * 10);\r
991\r
992 return (UINT8) (Low + (High << 4));\r
993}\r