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