//----------------------------------------------------------------------------// // GNU GPL OS/K // // // // Desc: Interrupt related functions // // // // // // Copyright © 2018-2019 The OS/K Team // // // // This file is part of OS/K. // // // // OS/K is free software: you can redistribute it and/or modify // // it under the terms of the GNU General Public License as published by // // the Free Software Foundation, either version 3 of the License, or // // any later version. // // // // OS/K is distributed in the hope that it will be useful, // // but WITHOUT ANY WARRANTY//without even the implied warranty of // // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // // GNU General Public License for more details. // // // // You should have received a copy of the GNU General Public License // // along with OS/K. If not, see . // //----------------------------------------------------------------------------// #include #include #include #include static ulong IoRtcTicks = 0; static uchar RtcRate = 0x05; //2048Hz static Time_t IoRtcOriginTime; static Time_t IoRtcTime; static char time24or12Mode; static void GetTimeFromRtc(void) { Time_t lastTime; char updateInProgress = 1; while(updateInProgress) { // wait while the RTC updates its value IoWriteByteOnPort(0x70, 0x0A); updateInProgress = (IoReadByteFromPort(0x71) & 0x80); } IoWriteByteOnPort(0x70, 0x0); IoRtcOriginTime.sec = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x02); IoRtcOriginTime.min = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x04); IoRtcOriginTime.hour = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x06); IoRtcOriginTime.weekday = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x07); IoRtcOriginTime.day = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x08); IoRtcOriginTime.month = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x09); IoRtcOriginTime.year = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x32); IoRtcOriginTime.century = IoReadByteFromPort(0x71); // Now while we don't get the same value, read the registers (ensure data are valid) do { lastTime.sec = IoRtcOriginTime.sec; lastTime.min = IoRtcOriginTime.min; lastTime.hour = IoRtcOriginTime.hour; lastTime.weekday = IoRtcOriginTime.weekday; lastTime.day = IoRtcOriginTime.day; lastTime.month = IoRtcOriginTime.month; lastTime.year = IoRtcOriginTime.year; lastTime.century = IoRtcOriginTime.century; while(updateInProgress) { // wait while the RTC updates its value IoWriteByteOnPort(0x70, 0x0A); updateInProgress = (IoReadByteFromPort(0x71) & 0x80); } IoWriteByteOnPort(0x70, 0x0); IoRtcOriginTime.sec = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x02); IoRtcOriginTime.min = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x04); IoRtcOriginTime.hour = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x06); IoRtcOriginTime.weekday = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x07); IoRtcOriginTime.day = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x08); IoRtcOriginTime.month = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x09); IoRtcOriginTime.year = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x32); IoRtcOriginTime.century = IoReadByteFromPort(0x71); } while ( (lastTime.sec != IoRtcOriginTime.sec) || (lastTime.min != IoRtcOriginTime.min) || (lastTime.hour != IoRtcOriginTime.hour) || (lastTime.weekday != IoRtcOriginTime.weekday) || (lastTime.day != IoRtcOriginTime.day) || (lastTime.month != IoRtcOriginTime.month) || (lastTime.year != IoRtcOriginTime.year) || (lastTime.century != IoRtcOriginTime.century) ); IoWriteByteOnPort(0x70, 0x0B); time24or12Mode = IoReadByteFromPort(0x71); // Convert to binary if it is necessary if (!(time24or12Mode & 0x04)) { IoRtcOriginTime.sec = (IoRtcOriginTime.sec & 0x0F) + ((IoRtcOriginTime.sec / 16) * 10); IoRtcOriginTime.min = (IoRtcOriginTime.min & 0x0F) + ((IoRtcOriginTime.min / 16) * 10); IoRtcOriginTime.hour = ( (IoRtcOriginTime.hour & 0x0F) + (((IoRtcOriginTime.hour & 0x70) / 16) * 10) ) | (IoRtcOriginTime.hour & 0x80); IoRtcOriginTime.day = (IoRtcOriginTime.day & 0x0F) + ((IoRtcOriginTime.day / 16) * 10); IoRtcOriginTime.month = (IoRtcOriginTime.month & 0x0F) + ((IoRtcOriginTime.month / 16) * 10); IoRtcOriginTime.year = (IoRtcOriginTime.year & 0x0F) + ((IoRtcOriginTime.year / 16) * 10); IoRtcOriginTime.century = (IoRtcOriginTime.century & 0x0F) + ((IoRtcOriginTime.century / 16) * 10); IoRtcOriginTime.weekday = (IoRtcOriginTime.weekday & 0x0F) + ((IoRtcOriginTime.weekday / 16) * 10); } // Convert 12 to 24 hour if necessary if (!(time24or12Mode & 0x02) && (IoRtcOriginTime.hour & 0x80)) { IoRtcOriginTime.hour = ((IoRtcOriginTime.hour & 0x7)+ 10) % 24; } IoRtcTime.sec = IoRtcOriginTime.sec; IoRtcTime.min = IoRtcOriginTime.min; IoRtcTime.hour = IoRtcOriginTime.hour; IoRtcTime.weekday = IoRtcOriginTime.weekday; IoRtcTime.day = IoRtcOriginTime.day; IoRtcTime.month = IoRtcOriginTime.month; IoRtcTime.year = IoRtcOriginTime.year; IoRtcTime.century = IoRtcOriginTime.century; } void RtcHandler(ISRFrame_t *regs) { //bprintf(BStdOut, " *RTC - "); IoWriteByteOnPort(0x70, 0x0C); // Selects status reg C IoReadByteFromPort(0x71); // Flush IoRtcTicks++; IoSendEOItoPIC(0x28); //bprintf(BStdOut, " - EOI* "); } void IoPrintRtcTime(void) { Time_t* RtcTime = IoGetRtcTime(); KernLog("[RTC Time] %02d/%02d/%04d ; %02d:%02d:%02d\n", RtcTime->day, RtcTime->month, RtcTime->year + RtcTime->century*100, RtcTime->hour, RtcTime->min, RtcTime->sec ); } // FIXME XXX FIXME char* IoGetRtcTimeChar(void) { Time_t* RtcTime = IoGetRtcTime(); char* timeChar = ""; sprintf(timeChar, "[RTC Time] %d/%d/%d ; %d:%d:%d\n", RtcTime->day, RtcTime->month, RtcTime->year + RtcTime->century*100, RtcTime->hour, RtcTime->min, RtcTime->sec ); return timeChar; } // END OF FIXME XXX FIXME static void UpdateRtcTime(void) { ulong frequency = 32768 >> (RtcRate-1); uchar minRemain, hourRemain, dayRemain; IoRtcTime.sec = (uchar)(((ulong)IoRtcOriginTime.sec + (IoRtcTicks / frequency)) % 60); minRemain = (uchar)(((ulong)IoRtcOriginTime.sec + (IoRtcTicks / frequency)) / 60); IoRtcTime.min = (uchar)(((ulong)IoRtcOriginTime.min + minRemain) % 60); hourRemain = (uchar)(((ulong)IoRtcOriginTime.min + minRemain) / 60); IoRtcTime.hour = (uchar)(((ulong)IoRtcOriginTime.hour + hourRemain) % 24); dayRemain = (uchar)(((ulong)IoRtcOriginTime.hour + hourRemain) / 24); if (dayRemain) { KeStartPanic("[RTC Time] We must shutdown this computer for your safety.\n"); } } Time_t* IoGetRtcTime(void) { UpdateRtcTime(); return &IoRtcTime; } ulong IoGetRtcTicks(void) { return IoRtcTicks; } void IoEnableRtc(void) { ulong flags = KePauseIRQs(); char readedInterruptConfig; char readedRegister; char readedIrqs; IdtRegisterIrq(RtcHandler, 0x28, 0x8E); // Setting up the register control and interrupt rates DebugLog("[RTC Time] Interrupt frequency set to %d Hz\n", 32768 >> (RtcRate-1)); IoWriteByteOnPort(0x70, 0x8B); readedRegister = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x8B); // Because reading flushes IoWriteByteOnPort(0x71, readedRegister | 0x40); IoWriteByteOnPort(0x70, 0x8A); readedInterruptConfig = IoReadByteFromPort(0x71); IoWriteByteOnPort(0x70, 0x8A); // Because reading flushes IoWriteByteOnPort(0x71, (readedInterruptConfig & 0xF0) | RtcRate); IoWriteByteOnPort(0x70, 0x0C); IoReadByteFromPort(0x71); // Flush // Setting up the IRQs readedIrqs = IoReadByteFromPort(0xA1); IoWriteByteOnPort(0xA1, 0xFE & readedIrqs); // Enables IRQ on PIC 2 readedIrqs = IoReadByteFromPort(0x21); IoWriteByteOnPort(0x21, 0xFB & readedIrqs); // Enables IRQ on PIC 1 // Clean-up IoWriteByteOnPort(0x70, 0x0C); // Select status reg C IoReadByteFromPort(0x71); // Flush GetTimeFromRtc(); KeRestoreIRQs(flags); IoEnableNMI(); }