xref: /reactos/hal/halx86/generic/cmos.c (revision d6d1efe7)
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 #if defined(ALLOC_PRAGMA) && !defined(_MINIHAL_)
17 #pragma alloc_text(INIT, HalpInitializeCmos)
18 #endif
19 
20 /* GLOBALS *******************************************************************/
21 
22 UCHAR HalpCmosCenturyOffset;
23 
24 /* PRIVATE FUNCTIONS *********************************************************/
25 
26 UCHAR
27 NTAPI
28 HalpReadCmos(IN UCHAR Reg)
29 {
30     /* Select the register */
31     WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, Reg);
32 
33     /* Query the value */
34     return READ_PORT_UCHAR(CMOS_DATA_PORT);
35 }
36 
37 VOID
38 NTAPI
39 HalpWriteCmos(IN UCHAR Reg,
40               IN UCHAR Value)
41 {
42     /* Select the register */
43     WRITE_PORT_UCHAR(CMOS_CONTROL_PORT, Reg);
44 
45     /* Write the value */
46     WRITE_PORT_UCHAR(CMOS_DATA_PORT, Value);
47 }
48 
49 ULONG
50 NTAPI
51 HalpGetCmosData(IN ULONG BusNumber,
52                 IN ULONG SlotNumber,
53                 IN PVOID Buffer,
54                 IN ULONG Length)
55 {
56     PUCHAR Ptr = (PUCHAR)Buffer;
57     ULONG Address = SlotNumber;
58     ULONG Len = Length;
59 
60     /* Do nothing if we don't have a length */
61     if (!Length) return 0;
62 
63     /* Acquire CMOS Lock */
64     HalpAcquireCmosSpinLock();
65 
66     /* Check if this is simple CMOS */
67     if (BusNumber == 0)
68     {
69         /* Loop the buffer up to 0xFF */
70         while ((Len > 0) && (Address < 0x100))
71         {
72             /* Read the data */
73             *Ptr = HalpReadCmos((UCHAR)Address);
74 
75             /* Update position and length */
76             Ptr++;
77             Address++;
78             Len--;
79         }
80     }
81     else if (BusNumber == 1)
82     {
83         /* Loop the buffer up to 0xFFFF */
84         while ((Len > 0) && (Address < 0x10000))
85         {
86             /* Write the data */
87             *Ptr = HalpReadCmos((UCHAR)Address);
88 
89             /* Update position and length */
90             Ptr++;
91             Address++;
92             Len--;
93         }
94     }
95 
96     /* Release CMOS Lock */
97     HalpReleaseCmosSpinLock();
98 
99     /* Return length read */
100     return Length - Len;
101 }
102 
103 ULONG
104 NTAPI
105 HalpSetCmosData(IN ULONG BusNumber,
106                 IN ULONG SlotNumber,
107                 IN 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 INIT_FUNCTION
158 VOID
159 NTAPI
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
176 HalGetEnvironmentVariable(IN PCH Name,
177                           IN USHORT ValueLength,
178                           IN PCH Value)
179 {
180     UCHAR Val;
181 
182     /* Only variable supported on x86 */
183     if (_stricmp(Name, "LastKnownGood")) return ENOENT;
184 
185     /* Acquire CMOS Lock */
186     HalpAcquireCmosSpinLock();
187 
188     /* Query the current value */
189     Val = HalpReadCmos(RTC_REGISTER_B) & 0x01;
190 
191     /* Release CMOS lock */
192     HalpReleaseCmosSpinLock();
193 
194     /* Check the flag */
195     if (Val)
196     {
197         /* Return false */
198         strncpy(Value, "FALSE", ValueLength);
199     }
200     else
201     {
202         /* Return true */
203         strncpy(Value, "TRUE", ValueLength);
204     }
205 
206     /* Return success */
207     return ESUCCESS;
208 }
209 
210 /*
211  * @implemented
212  */
213 ARC_STATUS
214 NTAPI
215 HalSetEnvironmentVariable(IN PCH Name,
216                           IN PCH Value)
217 {
218     UCHAR Val;
219 
220     /* Only variable supported on x86 */
221     if (_stricmp(Name, "LastKnownGood")) return ENOMEM;
222 
223     /* Check if this is true or false */
224     if (!_stricmp(Value, "TRUE"))
225     {
226         /* It's true, acquire CMOS lock */
227         HalpAcquireCmosSpinLock();
228 
229         /* Read the current value and add the flag */
230         Val = HalpReadCmos(RTC_REGISTER_B) | 1;
231     }
232     else if (!_stricmp(Value, "FALSE"))
233     {
234         /* It's false, acquire CMOS lock */
235         HalpAcquireCmosSpinLock();
236 
237         /* Read the current value and mask out  the flag */
238         Val = HalpReadCmos(RTC_REGISTER_B) & ~1;
239     }
240     else
241     {
242         /* Fail */
243         return ENOMEM;
244     }
245 
246     /* Write new value */
247     HalpWriteCmos(RTC_REGISTER_B, Val);
248 
249     /* Release the lock and return success */
250     HalpReleaseCmosSpinLock();
251     return ESUCCESS;
252 }
253 
254 /*
255  * @implemented
256  */
257 BOOLEAN
258 NTAPI
259 HalQueryRealTimeClock(OUT PTIME_FIELDS Time)
260 {
261     /* Acquire CMOS Lock */
262     HalpAcquireCmosSpinLock();
263 
264     /* Loop while update is in progress */
265     while ((HalpReadCmos(RTC_REGISTER_A)) & RTC_REG_A_UIP);
266 
267     /* Set the time data */
268     Time->Second = BCD_INT(HalpReadCmos(0));
269     Time->Minute = BCD_INT(HalpReadCmos(2));
270     Time->Hour = BCD_INT(HalpReadCmos(4));
271     Time->Weekday = BCD_INT(HalpReadCmos(6));
272     Time->Day = BCD_INT(HalpReadCmos(7));
273     Time->Month = BCD_INT(HalpReadCmos(8));
274     Time->Year = BCD_INT(HalpReadCmos(9));
275     Time->Milliseconds = 0;
276 
277     /* FIXME: Check century byte */
278 
279     /* Compensate for the century field */
280     Time->Year += (Time->Year > 80) ? 1900: 2000;
281 
282     /* Release CMOS lock */
283     HalpReleaseCmosSpinLock();
284 
285     /* Always return TRUE */
286     return TRUE;
287 }
288 
289 /*
290  * @implemented
291  */
292 BOOLEAN
293 NTAPI
294 HalSetRealTimeClock(IN PTIME_FIELDS Time)
295 {
296     /* Acquire CMOS Lock */
297     HalpAcquireCmosSpinLock();
298 
299     /* Loop while update is in progress */
300     while ((HalpReadCmos(RTC_REGISTER_A)) & RTC_REG_A_UIP);
301 
302     /* Write time fields to CMOS RTC */
303     HalpWriteCmos(0, INT_BCD(Time->Second));
304     HalpWriteCmos(2, INT_BCD(Time->Minute));
305     HalpWriteCmos(4, INT_BCD(Time->Hour));
306     HalpWriteCmos(6, INT_BCD(Time->Weekday));
307     HalpWriteCmos(7, INT_BCD(Time->Day));
308     HalpWriteCmos(8, INT_BCD(Time->Month));
309     HalpWriteCmos(9, INT_BCD(Time->Year % 100));
310 
311     /* FIXME: Set the century byte */
312 
313     /* Release CMOS lock */
314     HalpReleaseCmosSpinLock();
315 
316     /* Always return TRUE */
317     return TRUE;
318 }
319