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