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