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