Fixed one bug when runtime test. The root cause is that ICC compiler will convert...
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Universal / PcatRealTimeClockRuntimeDxe / PcRtc.c
1 /*++\r
2 \r
3 Copyright (c) 2006 - 2007 Intel Corporation. <BR>\r
4 All rights reserved. This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution.  The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php\r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 \r
12 \r
13 \r
14 Module Name:\r
15 \r
16   PcRtc.c\r
17 \r
18 Abstract:\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
26 STATIC\r
27 INTN\r
28 CompareHMS (\r
29   IN EFI_TIME   *From,\r
30   IN EFI_TIME   *To\r
31   );\r
32 \r
33 STATIC\r
34 BOOLEAN\r
35 IsWithinOneDay (\r
36   IN EFI_TIME   *From,\r
37   IN EFI_TIME   *To\r
38   );\r
39 \r
40 STATIC\r
41 UINT8\r
42 RtcRead (\r
43   IN  UINT8 Address\r
44   )\r
45 /*++\r
46 \r
47 Routine Description:\r
48 \r
49   GC_TODO: Add function description\r
50 \r
51 Arguments:\r
52 \r
53   Address - GC_TODO: add argument description\r
54 \r
55 Returns:\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
65 STATIC\r
66 VOID\r
67 RtcWrite (\r
68   IN  UINT8   Address,\r
69   IN  UINT8   Data\r
70   )\r
71 /*++\r
72 \r
73 Routine Description:\r
74 \r
75   GC_TODO: Add function description\r
76 \r
77 Arguments:\r
78 \r
79   Address - GC_TODO: add argument description\r
80   Data    - GC_TODO: add argument description\r
81 \r
82 Returns:\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
92 EFI_STATUS\r
93 PcRtcInit (\r
94   IN PC_RTC_MODULE_GLOBALS  *Global\r
95   )\r
96 /*++\r
97 \r
98 Routine Description:\r
99 \r
100   GC_TODO: Add function description\r
101 \r
102 Arguments:\r
103 \r
104   Global  - GC_TODO: add argument description\r
105 \r
106 Returns:\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
218 EFI_STATUS\r
219 PcRtcGetTime (\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
226 Routine 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
334 EFI_STATUS\r
335 PcRtcSetTime (\r
336   IN EFI_TIME                *Time,\r
337   IN PC_RTC_MODULE_GLOBALS   *Global\r
338   )\r
339 /*++\r
340 \r
341 Routine 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
432 EFI_STATUS\r
433 PcRtcGetWakeupTime (\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
441 Routine Description:\r
442 \r
443   Arguments:\r
444 \r
445 \r
446 \r
447 Returns:\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
547 EFI_STATUS\r
548 PcRtcSetWakeupTime (\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
555 Routine Description:\r
556 \r
557   Arguments:\r
558 \r
559 \r
560 \r
561 Returns:\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
663 EFI_STATUS\r
664 RtcTestCenturyRegister (\r
665   VOID\r
666   )\r
667 /*++\r
668 \r
669 Routine Description:\r
670 \r
671   Arguments:\r
672 \r
673 \r
674 \r
675 Returns:\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
696 VOID\r
697 ConvertRtcTimeToEfiTime (\r
698   IN EFI_TIME       *Time,\r
699   IN RTC_REGISTER_B RegisterB\r
700   )\r
701 /*++\r
702 \r
703 Routine Description:\r
704 \r
705   Arguments:\r
706 \r
707 \r
708 \r
709 Returns:\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
750 EFI_STATUS\r
751 RtcWaitToUpdate (\r
752   UINTN Timeout\r
753   )\r
754 /*++\r
755 \r
756 Routine Description:\r
757 \r
758   Arguments:\r
759 \r
760 \r
761 Returns:\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
798 EFI_STATUS\r
799 RtcTimeFieldsValid (\r
800   IN EFI_TIME *Time\r
801   )\r
802 /*++\r
803 \r
804 Routine 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
832 BOOLEAN\r
833 DayValid (\r
834   IN  EFI_TIME  *Time\r
835   )\r
836 /*++\r
837 \r
838 Routine Description:\r
839 \r
840   GC_TODO: Add function description\r
841 \r
842 Arguments:\r
843 \r
844   Time  - GC_TODO: add argument description\r
845 \r
846 Returns:\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
877 BOOLEAN\r
878 IsLeapYear (\r
879   IN EFI_TIME   *Time\r
880   )\r
881 /*++\r
882 \r
883 Routine Description:\r
884 \r
885   GC_TODO: Add function description\r
886 \r
887 Arguments:\r
888 \r
889   Time  - GC_TODO: add argument description\r
890 \r
891 Returns:\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
912 VOID\r
913 ConvertEfiTimeToRtcTime (\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
920 Routine Description:\r
921 \r
922   Arguments:\r
923 \r
924 \r
925 Returns:\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
971 STATIC\r
972 INTN\r
973 CompareHMS (\r
974   IN EFI_TIME   *From,\r
975   IN EFI_TIME   *To\r
976   )\r
977 /*++\r
978 \r
979 Routine 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
984 Arguments:\r
985 \r
986   From  -   the first time\r
987   To    -   the second time\r
988 \r
989 Returns:\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
1008 STATIC\r
1009 BOOLEAN\r
1010 IsWithinOneDay (\r
1011   IN EFI_TIME  *From,\r
1012   IN EFI_TIME  *To\r
1013   )\r
1014 /*++\r
1015 \r
1016 Routine Description:\r
1017 \r
1018   Judge whether two days are adjacent.\r
1019 \r
1020 Arguments:\r
1021 \r
1022   From  -   the first day\r
1023   To    -   the second day\r
1024 \r
1025 Returns:\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];\r
1033   BOOLEAN Adjacent;\r
1034 \r
1035   DayOfMonth[0] = 31;\r
1036   DayOfMonth[1] = 29;\r
1037   DayOfMonth[2] = 31;\r
1038   DayOfMonth[3] = 30;\r
1039   DayOfMonth[4] = 31;\r
1040   DayOfMonth[5] = 30;\r
1041   DayOfMonth[6] = 31;\r
1042   DayOfMonth[7] = 31;\r
1043   DayOfMonth[8] = 30;\r
1044   DayOfMonth[9] = 31;\r
1045   DayOfMonth[10] = 30;\r
1046   DayOfMonth[11] = 31;\r
1047 \r
1048   Adjacent = FALSE;\r
1049 \r
1050   if (From->Year == To->Year) {\r
1051     if (From->Month == To->Month) {\r
1052       if ((From->Day + 1) == To->Day) {\r
1053         if ((CompareHMS(From, To) >= 0)) {\r
1054           Adjacent = TRUE;\r
1055         }\r
1056       } else if (From->Day == To->Day) {\r
1057         if ((CompareHMS(From, To) <= 0)) {\r
1058           Adjacent = TRUE;\r
1059         }\r
1060       }\r
1061     } else if (((From->Month + 1) == To->Month) && (To->Day == 1)) {\r
1062       if ((From->Month == 2) && !IsLeapYear(From)) {\r
1063         if (From->Day == 28) {\r
1064           if ((CompareHMS(From, To) >= 0)) {\r
1065             Adjacent = TRUE;\r
1066           }\r
1067         }\r
1068       } else if (From->Day == DayOfMonth[From->Month - 1]) {\r
1069         if ((CompareHMS(From, To) >= 0)) {\r
1070            Adjacent = TRUE;\r
1071         }\r
1072       }\r
1073     }\r
1074   } else if (((From->Year + 1) == To->Year) &&\r
1075              (From->Month == 12) &&\r
1076              (From->Day   == 31) &&\r
1077              (To->Month   == 1)  &&\r
1078              (To->Day     == 1)) {\r
1079     if ((CompareHMS(From, To) >= 0)) {\r
1080       Adjacent = TRUE;\r
1081     }\r
1082   }\r
1083 \r
1084   return Adjacent;\r
1085 }\r
1086 \r