[HAL]: Okay, this one was my fault, forgot to built the nasty-ass HALMPS. Move the...
[reactos.git] / reactos / hal / halx86 / generic / cmos.c
1 /*
2 * PROJECT: ReactOS HAL
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: hal/halx86/generic/cmos.c
5 * PURPOSE: CMOS Access Routines (Real Time Clock and LastKnownGood)
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Eric Kohl
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <hal.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 KSPIN_LOCK HalpSystemHardwareLock;
19 UCHAR HalpCmosCenturyOffset;
20 ULONG HalpSystemHardwareFlags;
21
22 /* PRIVATE FUNCTIONS **********************************************************/
23
24 VOID
25 NTAPI
26 HalpAcquireSystemHardwareSpinLock(VOID)
27 {
28 ULONG Flags;
29
30 /* Get flags and disable interrupts */
31 Flags = __readeflags();
32 _disable();
33
34 /* Acquire the lock */
35 KxAcquireSpinLock(&HalpSystemHardwareLock);
36
37 /* We have the lock, save the flags now */
38 HalpSystemHardwareFlags = Flags;
39 }
40
41 VOID
42 NTAPI
43 HalpReleaseCmosSpinLock(VOID)
44 {
45 ULONG Flags;
46
47 /* Get the flags */
48 Flags = HalpSystemHardwareFlags;
49
50 /* Release the lock */
51 KxReleaseSpinLock(&HalpSystemHardwareLock);
52
53 /* Restore the flags */
54 __writeeflags(Flags);
55 }
56
57 FORCEINLINE
58 UCHAR
59 HalpReadCmos(IN UCHAR Reg)
60 {
61 /* Select the register */
62 WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, Reg);
63
64 /* Query the value */
65 return READ_PORT_UCHAR(CMOS_DATA_PORT);
66 }
67
68 FORCEINLINE
69 VOID
70 HalpWriteCmos(IN UCHAR Reg,
71 IN UCHAR Value)
72 {
73 /* Select the register */
74 WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, Reg);
75
76 /* Write the value */
77 WRITE_PORT_UCHAR(CMOS_DATA_PORT, Value);
78 }
79
80 ULONG
81 NTAPI
82 HalpGetCmosData(IN ULONG BusNumber,
83 IN ULONG SlotNumber,
84 IN PVOID Buffer,
85 IN ULONG Length)
86 {
87 PUCHAR Ptr = (PUCHAR)Buffer;
88 ULONG Address = SlotNumber;
89 ULONG Len = Length;
90
91 /* Do nothing if we don't have a length */
92 if (!Length) return 0;
93
94 /* Acquire CMOS Lock */
95 HalpAcquireSystemHardwareSpinLock();
96
97 /* Check if this is simple CMOS */
98 if (BusNumber == 0)
99 {
100 /* Loop the buffer up to 0xFF */
101 while ((Len > 0) && (Address < 0x100))
102 {
103 /* Read the data */
104 *Ptr = HalpReadCmos((UCHAR)Address);
105
106 /* Update position and length */
107 Ptr++;
108 Address++;
109 Len--;
110 }
111 }
112 else if (BusNumber == 1)
113 {
114 /* Loop the buffer up to 0xFFFF */
115 while ((Len > 0) && (Address < 0x10000))
116 {
117 /* Write the data */
118 *Ptr = HalpReadCmos((UCHAR)Address);
119
120 /* Update position and length */
121 Ptr++;
122 Address++;
123 Len--;
124 }
125 }
126
127 /* Release CMOS Lock */
128 HalpReleaseCmosSpinLock();
129
130 /* Return length read */
131 return Length - Len;
132 }
133
134 ULONG
135 NTAPI
136 HalpSetCmosData(IN ULONG BusNumber,
137 IN ULONG SlotNumber,
138 IN PVOID Buffer,
139 IN ULONG Length)
140 {
141 PUCHAR Ptr = (PUCHAR)Buffer;
142 ULONG Address = SlotNumber;
143 ULONG Len = Length;
144
145 /* Do nothing if we don't have a length */
146 if (!Length) return 0;
147
148 /* Acquire CMOS Lock */
149 HalpAcquireSystemHardwareSpinLock();
150
151 /* Check if this is simple CMOS */
152 if (BusNumber == 0)
153 {
154 /* Loop the buffer up to 0xFF */
155 while ((Len > 0) && (Address < 0x100))
156 {
157 /* Write the data */
158 HalpWriteCmos((UCHAR)Address, *Ptr);
159
160 /* Update position and length */
161 Ptr++;
162 Address++;
163 Len--;
164 }
165 }
166 else if (BusNumber == 1)
167 {
168 /* Loop the buffer up to 0xFFFF */
169 while ((Len > 0) && (Address < 0x10000))
170 {
171 /* Write the data */
172 HalpWriteCmos((UCHAR)Address, *Ptr);
173
174 /* Update position and length */
175 Ptr++;
176 Address++;
177 Len--;
178 }
179 }
180
181 /* Release CMOS Lock */
182 HalpReleaseCmosSpinLock();
183
184 /* Return length read */
185 return Length - Len;
186 }
187
188 VOID
189 NTAPI
190 HalpInitializeCmos(VOID)
191 {
192 /* Set default century offset byte */
193 HalpCmosCenturyOffset = 50;
194
195 /* No support for EISA or MCA */
196 ASSERT(HalpBusType == MACHINE_TYPE_ISA);
197 }
198
199 /* PUBLIC FUNCTIONS **********************************************************/
200
201 /*
202 * @implemented
203 */
204 ARC_STATUS
205 NTAPI
206 HalGetEnvironmentVariable(IN PCH Name,
207 IN USHORT ValueLength,
208 IN PCH Value)
209 {
210 UCHAR Val;
211
212 /* Only variable supported on x86 */
213 if (_stricmp(Name, "LastKnownGood")) return ENOENT;
214
215 /* Acquire CMOS Lock */
216 HalpAcquireSystemHardwareSpinLock();
217
218 /* Query the current value */
219 Val = HalpReadCmos(RTC_REGISTER_B) & 0x01;
220
221 /* Release CMOS lock */
222 HalpReleaseCmosSpinLock();
223
224 /* Check the flag */
225 if (Val)
226 {
227 /* Return false */
228 strncpy(Value, "FALSE", ValueLength);
229 }
230 else
231 {
232 /* Return true */
233 strncpy(Value, "TRUE", ValueLength);
234 }
235
236 /* Return success */
237 return ESUCCESS;
238 }
239
240 /*
241 * @implemented
242 */
243 ARC_STATUS
244 NTAPI
245 HalSetEnvironmentVariable(IN PCH Name,
246 IN PCH Value)
247 {
248 UCHAR Val;
249
250 /* Only variable supported on x86 */
251 if (_stricmp(Name, "LastKnownGood")) return ENOMEM;
252
253 /* Check if this is true or false */
254 if (!_stricmp(Value, "TRUE"))
255 {
256 /* It's true, acquire CMOS lock */
257 HalpAcquireSystemHardwareSpinLock();
258
259 /* Read the current value and add the flag */
260 Val = HalpReadCmos(RTC_REGISTER_B) | 1;
261 }
262 else if (!_stricmp(Value, "FALSE"))
263 {
264 /* It's false, acquire CMOS lock */
265 HalpAcquireSystemHardwareSpinLock();
266
267 /* Read the current value and mask out the flag */
268 Val = HalpReadCmos(RTC_REGISTER_B) & ~1;
269 }
270 else
271 {
272 /* Fail */
273 return ENOMEM;
274 }
275
276 /* Write new value */
277 HalpWriteCmos(RTC_REGISTER_B, Val);
278
279 /* Release the lock and return success */
280 HalpReleaseCmosSpinLock();
281 return ESUCCESS;
282 }
283
284 /*
285 * @implemented
286 */
287 BOOLEAN
288 NTAPI
289 HalQueryRealTimeClock(OUT PTIME_FIELDS Time)
290 {
291 /* Acquire CMOS Lock */
292 HalpAcquireSystemHardwareSpinLock();
293
294 /* Loop while update is in progress */
295 while ((HalpReadCmos(RTC_REGISTER_A)) & RTC_REG_A_UIP);
296
297 /* Set the time data */
298 Time->Second = BCD_INT(HalpReadCmos(0));
299 Time->Minute = BCD_INT(HalpReadCmos(2));
300 Time->Hour = BCD_INT(HalpReadCmos(4));
301 Time->Weekday = BCD_INT(HalpReadCmos(6));
302 Time->Day = BCD_INT(HalpReadCmos(7));
303 Time->Month = BCD_INT(HalpReadCmos(8));
304 Time->Year = BCD_INT(HalpReadCmos(9));
305 Time->Milliseconds = 0;
306
307 /* FIXME: Check century byte */
308
309 /* Compensate for the century field */
310 Time->Year += (Time->Year > 80) ? 1900: 2000;
311
312 /* Release CMOS lock */
313 HalpReleaseCmosSpinLock();
314
315 /* Always return TRUE */
316 return TRUE;
317 }
318
319 /*
320 * @implemented
321 */
322 BOOLEAN
323 NTAPI
324 HalSetRealTimeClock(IN PTIME_FIELDS Time)
325 {
326 /* Acquire CMOS Lock */
327 HalpAcquireSystemHardwareSpinLock();
328
329 /* Loop while update is in progress */
330 while ((HalpReadCmos(RTC_REGISTER_A)) & RTC_REG_A_UIP);
331
332 /* Write time fields to CMOS RTC */
333 HalpWriteCmos(0, INT_BCD(Time->Second));
334 HalpWriteCmos(2, INT_BCD(Time->Minute));
335 HalpWriteCmos(4, INT_BCD(Time->Hour));
336 HalpWriteCmos(6, INT_BCD(Time->Weekday));
337 HalpWriteCmos(7, INT_BCD(Time->Day));
338 HalpWriteCmos(8, INT_BCD(Time->Month));
339 HalpWriteCmos(9, INT_BCD(Time->Year % 100));
340
341 /* FIXME: Set the century byte */
342
343 /* Release CMOS lock */
344 HalpReleaseCmosSpinLock();
345
346 /* Always return TRUE */
347 return TRUE;
348 }