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