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