:pserver:cvsanon@mok.lvcm.com:/CVS/ReactOS reactos
[reactos.git] / hal / halx86 / time.c
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS kernel
4  * FILE:            ntoskrnl/hal/x86/time.c
5  * PURPOSE:         Getting time information
6  * UPDATE HISTORY:
7  */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <ddk/ntddk.h>
12 #include <string.h>
13 #include <mps.h>
14 #include <bus.h>
15
16 #define NDEBUG
17 #include <internal/debug.h>
18
19 /* MACROS and CONSTANTS ******************************************************/
20
21 /* macro BCD_INT : convert bcd to int */
22 #define BCD_INT(bcd) (((bcd & 0xf0) >> 4) * 10 + (bcd &0x0f))
23
24 /* macro INT_BCD : convert int to bcd */
25 #define INT_BCD(int) (((int / 10) << 4) + (int % 10))
26
27
28 #define RTC_REGISTER_A   0x0A
29 #define   RTC_REG_A_UIP  0x80  /* Update In Progress bit */
30
31 #define RTC_REGISTER_B   0x0B
32
33 #define RTC_REGISTER_CENTURY   0x32
34
35
36 /* FUNCTIONS *****************************************************************/
37
38
39 static UCHAR
40 HalpQueryCMOS(UCHAR Reg)
41 {
42   UCHAR Val;
43   ULONG Flags;
44
45   Reg |= 0x80;
46   pushfl(Flags);
47   __asm__("cli\n");  // AP unsure as to whether to do this here
48   WRITE_PORT_UCHAR((PUCHAR)0x70, Reg);
49   Val = READ_PORT_UCHAR((PUCHAR)0x71);
50   WRITE_PORT_UCHAR((PUCHAR)0x70, 0);
51   popfl(Flags);
52
53   return(Val);
54 }
55
56
57 static VOID
58 HalpSetCMOS(UCHAR Reg,
59             UCHAR Val)
60 {
61   ULONG Flags;
62
63   Reg |= 0x80;
64   pushfl(Flags);
65   __asm__("cli\n");  // AP unsure as to whether to do this here
66   WRITE_PORT_UCHAR((PUCHAR)0x70, Reg);
67   WRITE_PORT_UCHAR((PUCHAR)0x71, Val);
68   WRITE_PORT_UCHAR((PUCHAR)0x70, 0);
69   popfl(Flags);
70 }
71
72
73 static UCHAR
74 HalpQueryECMOS(USHORT Reg)
75 {
76   UCHAR Val;
77   ULONG Flags;
78
79   pushfl(Flags);
80   __asm__("cli\n");  // AP unsure as to whether to do this here
81   WRITE_PORT_UCHAR((PUCHAR)0x74, (UCHAR)(Reg & 0x00FF));
82   WRITE_PORT_UCHAR((PUCHAR)0x75, (UCHAR)(Reg>>8));
83   Val = READ_PORT_UCHAR((PUCHAR)0x76);
84   popfl(Flags);
85
86   return(Val);
87 }
88
89
90 static VOID
91 HalpSetECMOS(USHORT Reg,
92              UCHAR Val)
93 {
94   ULONG Flags;
95
96   pushfl(Flags);
97   __asm__("cli\n");  // AP unsure as to whether to do this here
98   WRITE_PORT_UCHAR((PUCHAR)0x74, (UCHAR)(Reg & 0x00FF));
99   WRITE_PORT_UCHAR((PUCHAR)0x75, (UCHAR)(Reg>>8));
100   WRITE_PORT_UCHAR((PUCHAR)0x76, Val);
101   popfl(Flags);
102 }
103
104
105 VOID STDCALL
106 HalQueryRealTimeClock(PTIME_FIELDS Time)
107 {
108     /* check 'Update In Progress' bit */
109     while (HalpQueryCMOS (RTC_REGISTER_A) & RTC_REG_A_UIP)
110         ;
111
112     Time->Second = BCD_INT(HalpQueryCMOS (0));
113     Time->Minute = BCD_INT(HalpQueryCMOS (2));
114     Time->Hour = BCD_INT(HalpQueryCMOS (4));
115     Time->Weekday = BCD_INT(HalpQueryCMOS (6));
116     Time->Day = BCD_INT(HalpQueryCMOS (7));
117     Time->Month = BCD_INT(HalpQueryCMOS (8));
118     Time->Year = BCD_INT(HalpQueryCMOS (9));
119
120     if (Time->Year > 80)
121         Time->Year += 1900;
122     else
123         Time->Year += 2000;
124
125 #if 0
126     /* Century */
127     Time->Year += BCD_INT(HalpQueryCMOS (RTC_REGISTER_CENTURY)) * 100;
128 #endif
129
130 #ifndef NDEBUG
131     DbgPrint ("HalQueryRealTimeClock() %d:%d:%d %d/%d/%d\n",
132               Time->Hour,
133               Time->Minute,
134               Time->Second,
135               Time->Day,
136               Time->Month,
137               Time->Year
138              );
139 #endif
140
141     Time->Milliseconds = 0;
142 }
143
144
145 VOID STDCALL
146 HalSetRealTimeClock(PTIME_FIELDS Time)
147 {
148     /* check 'Update In Progress' bit */
149     while (HalpQueryCMOS (RTC_REGISTER_A) & RTC_REG_A_UIP)
150         ;
151
152     HalpSetCMOS (0, INT_BCD(Time->Second));
153     HalpSetCMOS (2, INT_BCD(Time->Minute));
154     HalpSetCMOS (4, INT_BCD(Time->Hour));
155     HalpSetCMOS (6, INT_BCD(Time->Weekday));
156     HalpSetCMOS (7, INT_BCD(Time->Day));
157     HalpSetCMOS (8, INT_BCD(Time->Month));
158     HalpSetCMOS (9, INT_BCD(Time->Year % 100));
159
160 #if 0
161     /* Century */
162     HalpSetCMOS (RTC_REGISTER_CENTURY, INT_BCD(Time->Year / 100));
163 #endif
164 }
165
166
167 BOOLEAN STDCALL
168 HalGetEnvironmentVariable(PCH Name,
169                           PCH Value,
170                           USHORT ValueLength)
171 {
172    if (_stricmp(Name, "LastKnownGood") != 0)
173      {
174         return FALSE;
175      }
176
177    if (HalpQueryCMOS(RTC_REGISTER_B) & 0x01)
178      {
179         strncpy(Value, "FALSE", ValueLength);
180      }
181    else
182      {
183         strncpy(Value, "TRUE", ValueLength);
184      }
185
186    return TRUE;
187 }
188
189
190 BOOLEAN STDCALL
191 HalSetEnvironmentVariable(PCH Name,
192                           PCH Value)
193 {
194   UCHAR Val;
195
196   if (_stricmp(Name, "LastKnownGood") != 0)
197     return FALSE;
198
199   Val = HalpQueryCMOS(RTC_REGISTER_B);
200
201   if (_stricmp(Value, "TRUE") == 0)
202     HalpSetCMOS(RTC_REGISTER_B, Val | 0x01);
203   else if (_stricmp(Value, "FALSE") == 0)
204     HalpSetCMOS(RTC_REGISTER_B, Val & ~0x01);
205   else
206     return FALSE;
207
208    return TRUE;
209 }
210
211
212 ULONG STDCALL
213 HalpGetCmosData(PBUS_HANDLER BusHandler,
214                 ULONG BusNumber,
215                 ULONG SlotNumber,
216                 PVOID Buffer,
217                 ULONG Offset,
218                 ULONG Length)
219 {
220   PUCHAR Ptr = Buffer;
221   ULONG Address = SlotNumber;
222   ULONG Len = Length;
223
224   DPRINT("HalpGetCmosData() called.\n");
225   DPRINT("  BusNumber %lu\n", BusNumber);
226   DPRINT("  SlotNumber %lu\n", SlotNumber);
227   DPRINT("  Offset 0x%lx\n", Offset);
228   DPRINT("  Length 0x%lx\n", Length);
229
230   if (Length == 0)
231     return 0;
232
233   if (BusNumber == 0)
234     {
235       /* CMOS */
236       while ((Len > 0) && (Address < 0x100))
237         {
238           *Ptr = HalpQueryCMOS((UCHAR)Address);
239           Ptr = Ptr + 1;
240           Address++;
241           Len--;
242         }
243     }
244   else if (BusNumber == 1)
245     {
246       /* Extended CMOS */
247       while ((Len > 0) && (Address < 0x1000))
248         {
249           *Ptr = HalpQueryECMOS((USHORT)Address);
250           Ptr = Ptr + 1;
251           Address++;
252           Len--;
253         }
254     }
255
256   return(Length - Len);
257 }
258
259
260 ULONG STDCALL
261 HalpSetCmosData(PBUS_HANDLER BusHandler,
262                 ULONG BusNumber,
263                 ULONG SlotNumber,
264                 PVOID Buffer,
265                 ULONG Offset,
266                 ULONG Length)
267 {
268   PUCHAR Ptr = (PUCHAR)Buffer;
269   ULONG Address = SlotNumber;
270   ULONG Len = Length;
271
272   DPRINT("HalpSetCmosData() called.\n");
273   DPRINT("  BusNumber %lu\n", BusNumber);
274   DPRINT("  SlotNumber %lu\n", SlotNumber);
275   DPRINT("  Offset 0x%lx\n", Offset);
276   DPRINT("  Length 0x%lx\n", Length);
277
278   if (Length == 0)
279     return 0;
280
281   if (BusNumber == 0)
282     {
283       /* CMOS */
284       while ((Len > 0) && (Address < 0x100))
285         {
286           HalpSetCMOS((UCHAR)Address, *Ptr);
287           Ptr = Ptr + 1;
288           Address++;
289           Len--;
290         }
291     }
292   else if (BusNumber == 1)
293     {
294       /* Extended CMOS */
295       while ((Len > 0) && (Address < 0x1000))
296         {
297           HalpSetECMOS((USHORT)Address, *Ptr);
298           Ptr = Ptr + 1;
299           Address++;
300           Len--;
301         }
302     }
303
304   return(Length - Len);
305 }
306
307 /* EOF */