111 lines
2.8 KiB
C
111 lines
2.8 KiB
C
#include <amd64/io.h>
|
|
#include <amd64/rtc.h>
|
|
#include <libk/std.h>
|
|
#include <limine/requests.h>
|
|
#include <sys/debug.h>
|
|
#include <sys/spin.h>
|
|
#include <sys/stall.h>
|
|
#include <time.h>
|
|
#include <uacpi/acpi.h>
|
|
#include <uacpi/status.h>
|
|
#include <uacpi/tables.h>
|
|
#include <uacpi/uacpi.h>
|
|
|
|
#define RTC_CMOS_ADDR 0x70
|
|
#define RTC_CMOS_DATA 0x71
|
|
|
|
static uint8_t rtc_century;
|
|
#define RTC_SEC 0x00
|
|
#define RTC_SEC_ALARM 0x01
|
|
#define RTC_MIN 0x02
|
|
#define RTC_MIN_ALARM 0x03
|
|
#define RTC_HOUR 0x04
|
|
#define RTC_HOUR_ALARM 0x05
|
|
#define RTC_WEEK_DAY 0x06
|
|
#define RTC_DAY 0x07
|
|
#define RTC_MONTH 0x08
|
|
#define RTC_YEAR 0x09
|
|
#define RTC_REG_A 0x0A
|
|
#define RTC_REG_B 0x0B
|
|
#define RTC_REG_C 0x0C
|
|
#define RTC_REG_D 0x0D
|
|
|
|
#define RTC_REG_A_UIP (1 << 7)
|
|
|
|
#define RTC_REG_B_HOURFMT (1 << 1)
|
|
#define RTC_REG_B_DATAMODE (1 << 2)
|
|
|
|
static uint8_t rtc_read (uint8_t addr) {
|
|
outb (RTC_CMOS_ADDR, RTC_REG_A);
|
|
while (inb (RTC_CMOS_DATA) & RTC_REG_A_UIP)
|
|
;
|
|
outb (RTC_CMOS_ADDR, addr);
|
|
return inb (RTC_CMOS_DATA);
|
|
}
|
|
|
|
static void rtc_write (uint8_t addr, uint8_t value) {
|
|
outb (RTC_CMOS_ADDR, addr);
|
|
outb (RTC_CMOS_DATA, value);
|
|
}
|
|
|
|
static uint8_t rtc_bcd_to_bin (uint8_t value) { return (value & 0xF) + (value >> 4) * 10; }
|
|
|
|
static uint8_t rtc_bin_to_bcd (uint8_t value) { return ((value / 10) << 4) + (value % 10); }
|
|
|
|
void rtc_init (void) {
|
|
struct uacpi_table fadt_table;
|
|
uacpi_status status = uacpi_table_find_by_signature (ACPI_FADT_SIGNATURE, &fadt_table);
|
|
if (status != UACPI_STATUS_OK) {
|
|
DEBUG ("Could not find FADT table!\n");
|
|
spin ();
|
|
}
|
|
|
|
struct acpi_fadt* fadt = (struct acpi_fadt*)fadt_table.virt_addr;
|
|
|
|
rtc_century = fadt->century;
|
|
}
|
|
|
|
void rtc_date_time (struct date_time* date_time) {
|
|
if (rtc_read (RTC_REG_A) & RTC_REG_A_UIP)
|
|
stall_ms (1);
|
|
|
|
uint8_t sec = rtc_read (RTC_SEC);
|
|
uint8_t min = rtc_read (RTC_MIN);
|
|
uint8_t hour = rtc_read (RTC_HOUR);
|
|
uint8_t weekday = rtc_read (RTC_WEEK_DAY);
|
|
uint8_t day = rtc_read (RTC_DAY);
|
|
uint8_t month = rtc_read (RTC_MONTH);
|
|
uint8_t year = rtc_read (RTC_YEAR);
|
|
uint8_t century = rtc_century != 0 ? rtc_read (rtc_century) : 0;
|
|
|
|
uint8_t b = rtc_read (RTC_REG_B);
|
|
|
|
/* BCD */
|
|
if ((~b) & RTC_REG_B_DATAMODE) {
|
|
sec = rtc_bcd_to_bin (sec);
|
|
min = rtc_bcd_to_bin (min);
|
|
hour = rtc_bcd_to_bin (hour);
|
|
day = rtc_bcd_to_bin (day);
|
|
month = rtc_bcd_to_bin (month);
|
|
year = rtc_bcd_to_bin (year);
|
|
if (rtc_century != 0)
|
|
century = rtc_bcd_to_bin (century);
|
|
}
|
|
|
|
weekday--;
|
|
|
|
int full_year;
|
|
if (rtc_century != 0)
|
|
full_year = (century * 100) + year;
|
|
else
|
|
full_year = (year < 80) ? (2000 + year) : (1900 + year);
|
|
|
|
date_time->sec = sec;
|
|
date_time->min = min;
|
|
date_time->hour = hour;
|
|
date_time->day = day;
|
|
date_time->weekday = weekday;
|
|
date_time->month = month;
|
|
date_time->year = full_year;
|
|
}
|