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