+
+BOOLEAN CmosInitialize(VOID)
+{
+ DWORD CmosSize = sizeof(CmosMemory);
+
+ /* File must not be opened before */
+ ASSERT(hCmosRam == INVALID_HANDLE_VALUE);
+
+ /* Clear the CMOS memory */
+ ZeroMemory(&CmosMemory, sizeof(CmosMemory));
+
+ /* Always open (and if needed, create) a RAM file with exclusive access */
+ SetLastError(0); // For debugging purposes
+ hCmosRam = CreateFileW(L"cmos.ram",
+ GENERIC_READ | GENERIC_WRITE,
+ 0,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL);
+ DPRINT1("CMOS opening %s ; GetLastError() = %u\n", hCmosRam != INVALID_HANDLE_VALUE ? "succeeded" : "failed", GetLastError());
+
+ if (hCmosRam != INVALID_HANDLE_VALUE)
+ {
+ BOOL Success = FALSE;
+
+ /* Attempt to fill the CMOS memory with the RAM file */
+ SetLastError(0); // For debugging purposes
+ Success = ReadFile(hCmosRam, &CmosMemory, CmosSize, &CmosSize, NULL);
+ if (CmosSize != sizeof(CmosMemory))
+ {
+ /* Bad CMOS Ram file. Reinitialize the CMOS memory. */
+ DPRINT1("Invalid CMOS file, read bytes %u, expected bytes %u\n", CmosSize, sizeof(CmosMemory));
+ ZeroMemory(&CmosMemory, sizeof(CmosMemory));
+ }
+ DPRINT1("CMOS loading %s ; GetLastError() = %u\n", Success ? "succeeded" : "failed", GetLastError());
+ SetFilePointer(hCmosRam, 0, NULL, FILE_BEGIN);
+ }
+
+ /* Overwrite some registers with default values */
+ CmosMemory.StatusRegA = CMOS_DEFAULT_STA;
+ CmosMemory.StatusRegB = CMOS_DEFAULT_STB;
+ CmosMemory.StatusRegC = 0x00;
+ CmosMemory.StatusRegD = CMOS_BATTERY_OK; // Our CMOS battery works perfectly forever.
+ CmosMemory.Diagnostics = 0x00; // Diagnostics must not find any errors.
+ CmosMemory.ShutdownStatus = 0x00;
+
+ return TRUE;
+}
+
+VOID CmosCleanup(VOID)
+{
+ DWORD CmosSize = sizeof(CmosMemory);
+
+ if (hCmosRam == INVALID_HANDLE_VALUE) return;
+
+ /* Flush the CMOS memory back to the RAM file and close it */
+ SetFilePointer(hCmosRam, 0, NULL, FILE_BEGIN);
+ WriteFile(hCmosRam, &CmosMemory, CmosSize, &CmosSize, NULL);
+
+ CloseHandle(hCmosRam);
+ hCmosRam = INVALID_HANDLE_VALUE;
+}
+
+/* EOF */