Ditto for HAL
[reactos.git] / reactos / hal / halx86 / generic / 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 <hal.h>
12 #define NDEBUG
13 #include <debug.h>
14
15
16 /* MACROS and CONSTANTS ******************************************************/
17
18 /* macro BCD_INT : convert bcd to int */
19 #define BCD_INT(bcd) (((bcd & 0xf0) >> 4) * 10 + (bcd &0x0f))
20
21 /* macro INT_BCD : convert int to bcd */
22 #define INT_BCD(int) (((int / 10) << 4) + (int % 10))
23
24
25 #define RTC_REGISTER_A 0x0A
26 #define RTC_REG_A_UIP 0x80 /* Update In Progress bit */
27
28 #define RTC_REGISTER_B 0x0B
29
30 #define RTC_REGISTER_CENTURY 0x32
31
32 /* GLOBALS ******************************************************************/
33
34 static KSPIN_LOCK CmosLock = {0};
35
36 /* FUNCTIONS *****************************************************************/
37
38
39 static UCHAR
40 HalpQueryCMOS(UCHAR Reg)
41 {
42 UCHAR Val;
43 ULONG Flags;
44
45 Reg |= 0x80;
46
47 /* save flags and disable interrupts */
48 Ki386SaveFlags(Flags);
49 Ki386DisableInterrupts();
50
51 WRITE_PORT_UCHAR((PUCHAR)0x70, Reg);
52 Val = READ_PORT_UCHAR((PUCHAR)0x71);
53 WRITE_PORT_UCHAR((PUCHAR)0x70, 0);
54
55 /* restore flags */
56 Ki386RestoreFlags(Flags);
57
58 return(Val);
59 }
60
61
62 static VOID
63 HalpSetCMOS(UCHAR Reg,
64 UCHAR Val)
65 {
66 ULONG Flags;
67
68 Reg |= 0x80;
69
70 /* save flags and disable interrupts */
71 Ki386SaveFlags(Flags);
72 Ki386DisableInterrupts();
73
74 WRITE_PORT_UCHAR((PUCHAR)0x70, Reg);
75 WRITE_PORT_UCHAR((PUCHAR)0x71, Val);
76 WRITE_PORT_UCHAR((PUCHAR)0x70, 0);
77
78 /* restore flags */
79 Ki386RestoreFlags(Flags);
80 }
81
82
83 static UCHAR
84 HalpQueryECMOS(USHORT Reg)
85 {
86 UCHAR Val;
87 ULONG Flags;
88
89 /* save flags and disable interrupts */
90 Ki386SaveFlags(Flags);
91 Ki386DisableInterrupts();
92
93 WRITE_PORT_UCHAR((PUCHAR)0x74, (UCHAR)(Reg & 0x00FF));
94 WRITE_PORT_UCHAR((PUCHAR)0x75, (UCHAR)(Reg>>8));
95 Val = READ_PORT_UCHAR((PUCHAR)0x76);
96
97 /* restore flags */
98 Ki386RestoreFlags(Flags);
99
100 return(Val);
101 }
102
103
104 static VOID
105 HalpSetECMOS(USHORT Reg,
106 UCHAR Val)
107 {
108 ULONG Flags;
109
110 /* save flags and disable interrupts */
111 Ki386SaveFlags(Flags);
112 Ki386DisableInterrupts();
113
114 WRITE_PORT_UCHAR((PUCHAR)0x74, (UCHAR)(Reg & 0x00FF));
115 WRITE_PORT_UCHAR((PUCHAR)0x75, (UCHAR)(Reg>>8));
116 WRITE_PORT_UCHAR((PUCHAR)0x76, Val);
117
118 /* restore flags */
119 Ki386RestoreFlags(Flags);
120 }
121
122
123 VOID STDCALL
124 HalQueryRealTimeClock(PTIME_FIELDS Time)
125 {
126 KIRQL oldIrql;
127
128 KeAcquireSpinLock(&CmosLock, &oldIrql);
129
130 /* check 'Update In Progress' bit */
131 while (HalpQueryCMOS (RTC_REGISTER_A) & RTC_REG_A_UIP);
132
133 Time->Second = BCD_INT(HalpQueryCMOS (0));
134 Time->Minute = BCD_INT(HalpQueryCMOS (2));
135 Time->Hour = BCD_INT(HalpQueryCMOS (4));
136 Time->Weekday = BCD_INT(HalpQueryCMOS (6));
137 Time->Day = BCD_INT(HalpQueryCMOS (7));
138 Time->Month = BCD_INT(HalpQueryCMOS (8));
139 Time->Year = BCD_INT(HalpQueryCMOS (9));
140
141 if (Time->Year > 80)
142 Time->Year += 1900;
143 else
144 Time->Year += 2000;
145
146 #if 0
147 /* Century */
148 Time->Year += BCD_INT(HalpQueryCMOS (RTC_REGISTER_CENTURY)) * 100;
149 #endif
150
151 KeReleaseSpinLock(&CmosLock, oldIrql);
152
153 #ifndef NDEBUG
154 DbgPrint ("HalQueryRealTimeClock() %d:%d:%d %d/%d/%d\n",
155 Time->Hour,
156 Time->Minute,
157 Time->Second,
158 Time->Day,
159 Time->Month,
160 Time->Year
161 );
162 #endif
163
164 Time->Milliseconds = 0;
165 }
166
167
168 VOID STDCALL
169 HalSetRealTimeClock(PTIME_FIELDS Time)
170 {
171 KIRQL oldIrql;
172
173 KeAcquireSpinLock(&CmosLock, &oldIrql);
174
175 /* check 'Update In Progress' bit */
176 while (HalpQueryCMOS (RTC_REGISTER_A) & RTC_REG_A_UIP);
177
178 HalpSetCMOS (0, (UCHAR)INT_BCD(Time->Second));
179 HalpSetCMOS (2, (UCHAR)INT_BCD(Time->Minute));
180 HalpSetCMOS (4, (UCHAR)INT_BCD(Time->Hour));
181 HalpSetCMOS (6, (UCHAR)INT_BCD(Time->Weekday));
182 HalpSetCMOS (7, (UCHAR)INT_BCD(Time->Day));
183 HalpSetCMOS (8, (UCHAR)INT_BCD(Time->Month));
184 HalpSetCMOS (9, (UCHAR)INT_BCD(Time->Year % 100));
185
186 #if 0
187 /* Century */
188 HalpSetCMOS (RTC_REGISTER_CENTURY, INT_BCD(Time->Year / 100));
189 #endif
190 KeReleaseSpinLock(&CmosLock, oldIrql);
191
192 }
193
194
195 BOOLEAN STDCALL
196 HalGetEnvironmentVariable(PCH Name,
197 PCH Value,
198 USHORT ValueLength)
199 {
200 KIRQL oldIrql;
201
202
203 if (_stricmp(Name, "LastKnownGood") != 0)
204 {
205 return FALSE;
206 }
207
208 KeAcquireSpinLock(&CmosLock, &oldIrql);
209 if (HalpQueryCMOS(RTC_REGISTER_B) & 0x01)
210 {
211 strncpy(Value, "FALSE", ValueLength);
212 }
213 else
214 {
215 strncpy(Value, "TRUE", ValueLength);
216 }
217 KeReleaseSpinLock(&CmosLock, oldIrql);
218
219 return TRUE;
220 }
221
222
223 BOOLEAN STDCALL
224 HalSetEnvironmentVariable(PCH Name,
225 PCH Value)
226 {
227 UCHAR Val;
228 KIRQL oldIrql;
229 BOOLEAN result = TRUE;
230
231 if (_stricmp(Name, "LastKnownGood") != 0)
232 return FALSE;
233
234 KeAcquireSpinLock(&CmosLock, &oldIrql);
235
236 Val = HalpQueryCMOS(RTC_REGISTER_B);
237
238 if (_stricmp(Value, "TRUE") == 0)
239 HalpSetCMOS(RTC_REGISTER_B, (UCHAR)(Val | 0x01));
240 else if (_stricmp(Value, "FALSE") == 0)
241 HalpSetCMOS(RTC_REGISTER_B, (UCHAR)(Val & ~0x01));
242 else
243 result = FALSE;
244
245 KeReleaseSpinLock(&CmosLock, oldIrql);
246
247 return result;
248 }
249
250
251 ULONG STDCALL
252 HalpGetCmosData(PBUS_HANDLER BusHandler,
253 ULONG BusNumber,
254 ULONG SlotNumber,
255 PVOID Buffer,
256 ULONG Offset,
257 ULONG Length)
258 {
259 PUCHAR Ptr = Buffer;
260 ULONG Address = SlotNumber;
261 ULONG Len = Length;
262 KIRQL oldIrql;
263
264 DPRINT("HalpGetCmosData() called.\n");
265 DPRINT(" BusNumber %lu\n", BusNumber);
266 DPRINT(" SlotNumber %lu\n", SlotNumber);
267 DPRINT(" Offset 0x%lx\n", Offset);
268 DPRINT(" Length 0x%lx\n", Length);
269
270 if (Length == 0)
271 return 0;
272
273 if (BusNumber == 0)
274 {
275 /* CMOS */
276 KeAcquireSpinLock(&CmosLock, &oldIrql);
277 while ((Len > 0) && (Address < 0x100))
278 {
279 *Ptr = HalpQueryCMOS((UCHAR)Address);
280 Ptr = Ptr + 1;
281 Address++;
282 Len--;
283 }
284 KeReleaseSpinLock(&CmosLock, oldIrql);
285 }
286 else if (BusNumber == 1)
287 {
288 /* Extended CMOS */
289 KeAcquireSpinLock(&CmosLock, &oldIrql);
290 while ((Len > 0) && (Address < 0x1000))
291 {
292 *Ptr = HalpQueryECMOS((USHORT)Address);
293 Ptr = Ptr + 1;
294 Address++;
295 Len--;
296 }
297 KeReleaseSpinLock(&CmosLock, oldIrql);
298 }
299
300 return(Length - Len);
301 }
302
303
304 ULONG STDCALL
305 HalpSetCmosData(PBUS_HANDLER BusHandler,
306 ULONG BusNumber,
307 ULONG SlotNumber,
308 PVOID Buffer,
309 ULONG Offset,
310 ULONG Length)
311 {
312 PUCHAR Ptr = (PUCHAR)Buffer;
313 ULONG Address = SlotNumber;
314 ULONG Len = Length;
315 KIRQL oldIrql;
316
317 DPRINT("HalpSetCmosData() called.\n");
318 DPRINT(" BusNumber %lu\n", BusNumber);
319 DPRINT(" SlotNumber %lu\n", SlotNumber);
320 DPRINT(" Offset 0x%lx\n", Offset);
321 DPRINT(" Length 0x%lx\n", Length);
322
323 if (Length == 0)
324 return 0;
325
326 if (BusNumber == 0)
327 {
328 /* CMOS */
329 KeAcquireSpinLock(&CmosLock, &oldIrql);
330 while ((Len > 0) && (Address < 0x100))
331 {
332 HalpSetCMOS((UCHAR)Address, *Ptr);
333 Ptr = Ptr + 1;
334 Address++;
335 Len--;
336 }
337 KeReleaseSpinLock(&CmosLock, oldIrql);
338 }
339 else if (BusNumber == 1)
340 {
341 /* Extended CMOS */
342 KeAcquireSpinLock(&CmosLock, &oldIrql);
343 while ((Len > 0) && (Address < 0x1000))
344 {
345 HalpSetECMOS((USHORT)Address, *Ptr);
346 Ptr = Ptr + 1;
347 Address++;
348 Len--;
349 }
350 KeReleaseSpinLock(&CmosLock, oldIrql);
351 }
352
353 return(Length - Len);
354 }
355
356 /* EOF */