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