Read RTC date and time
This commit is contained in:
parent
4081a220ef
commit
7c8744d1e0
112
src/hulk/rtc.d
112
src/hulk/rtc.d
@ -13,32 +13,67 @@ struct rtc
|
|||||||
|
|
||||||
private enum ubyte DISABLE_NMI = 0x80u;
|
private enum ubyte DISABLE_NMI = 0x80u;
|
||||||
|
|
||||||
private enum ubyte SR_A = 0xAu;
|
private enum ubyte REG_RTC_SECONDS = 0x0u;
|
||||||
private enum ubyte SR_B = 0xBu;
|
private enum ubyte REG_RTC_MINUTES = 0x2u;
|
||||||
private enum ubyte SR_C = 0xCu;
|
private enum ubyte REG_RTC_HOURS = 0x4u;
|
||||||
|
private enum ubyte REG_RTC_DAY = 0x7u;
|
||||||
|
private enum ubyte REG_RTC_MONTH = 0x8u;
|
||||||
|
private enum ubyte REG_RTC_YEAR = 0x9u;
|
||||||
|
private enum ubyte REG_SR_A = 0xAu;
|
||||||
|
private enum ubyte REG_SR_B = 0xBu;
|
||||||
|
private enum ubyte REG_SR_C = 0xCu;
|
||||||
|
|
||||||
|
private enum ubyte SR_A_RTC_UPDATE_IN_PROGRESS = 0x80u;
|
||||||
|
private enum ubyte SR_B_24HOUR = 0x02u;
|
||||||
|
private enum ubyte SR_B_BINARY = 0x04u;
|
||||||
private enum ubyte SR_B_ENABLE_IRQ = 0x40u;
|
private enum ubyte SR_B_ENABLE_IRQ = 0x40u;
|
||||||
|
|
||||||
|
private static __gshared bool rtc_24hour_mode;
|
||||||
|
private static __gshared bool rtc_binary_mode;
|
||||||
|
|
||||||
|
static struct time
|
||||||
|
{
|
||||||
|
public ubyte year;
|
||||||
|
public ubyte month;
|
||||||
|
public ubyte day;
|
||||||
|
public ubyte hour;
|
||||||
|
public ubyte minute;
|
||||||
|
public ubyte second;
|
||||||
|
}
|
||||||
|
|
||||||
public static void initialize()
|
public static void initialize()
|
||||||
{
|
{
|
||||||
/* Enable IRQ 8 to receive RTC interrupts. */
|
time t = read_rtc_time();
|
||||||
out8(PORT_SELECT, DISABLE_NMI | SR_B);
|
klog.writefln("System time is 20%02u-%02u-%02u %02u:%02u:%02u",
|
||||||
ubyte sr_b = in8(PORT_DATA);
|
t.year, t.month, t.day, t.hour, t.minute, t.second);
|
||||||
out8(PORT_SELECT, DISABLE_NMI | SR_B);
|
|
||||||
out8(PORT_DATA, sr_b | SR_B_ENABLE_IRQ);
|
|
||||||
|
|
||||||
out8(PORT_SELECT, DISABLE_NMI | SR_A);
|
/* Enable IRQ 8 to receive RTC interrupts. */
|
||||||
klog.writefln("SR_A = 0x%x", in8(PORT_DATA));
|
ubyte sr_b = read_register(REG_SR_B, true);
|
||||||
|
write_register(REG_SR_B, sr_b | SR_B_ENABLE_IRQ, true);
|
||||||
|
|
||||||
|
rtc_24hour_mode = (sr_b & SR_B_24HOUR) != 0u;
|
||||||
|
rtc_binary_mode = (sr_b & SR_B_BINARY) != 0u;
|
||||||
|
|
||||||
/* Send EOI to enable more RTC interrupts and re-enable NMIs. */
|
/* Send EOI to enable more RTC interrupts and re-enable NMIs. */
|
||||||
eoi();
|
eoi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ubyte read_register(ubyte register, bool disable_nmi = false)
|
||||||
|
{
|
||||||
|
out8(PORT_SELECT, register | (disable_nmi ? DISABLE_NMI : 0u));
|
||||||
|
return in8(PORT_DATA);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void write_register(ubyte register, ubyte value, bool disable_nmi = false)
|
||||||
|
{
|
||||||
|
out8(PORT_SELECT, register | (disable_nmi ? DISABLE_NMI : 0u));
|
||||||
|
out8(PORT_DATA, value);
|
||||||
|
}
|
||||||
|
|
||||||
private static void eoi()
|
private static void eoi()
|
||||||
{
|
{
|
||||||
/* Read from status register C to clear the interrupt. */
|
/* Read from status register C to clear the interrupt. */
|
||||||
out8(PORT_SELECT, SR_C);
|
read_register(REG_SR_C);
|
||||||
in8(PORT_DATA);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void isr()
|
public static void isr()
|
||||||
@ -53,4 +88,57 @@ struct rtc
|
|||||||
}
|
}
|
||||||
eoi();
|
eoi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static time read_rtc_time()
|
||||||
|
{
|
||||||
|
time[2] times;
|
||||||
|
size_t reads;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
times[reads & 1] = read_rtc_time_unsafe();
|
||||||
|
reads++;
|
||||||
|
} while ((reads < 2u) || (times[0] != times[1]));
|
||||||
|
return times[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
private static time read_rtc_time_unsafe()
|
||||||
|
{
|
||||||
|
time t;
|
||||||
|
while ((read_register(REG_SR_A) & SR_A_RTC_UPDATE_IN_PROGRESS) != 0u)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
t.year = read_rtc_time_register(REG_RTC_YEAR);
|
||||||
|
t.month = read_rtc_time_register(REG_RTC_MONTH);
|
||||||
|
t.day = read_rtc_time_register(REG_RTC_DAY);
|
||||||
|
t.hour = read_register(REG_RTC_HOURS);
|
||||||
|
t.minute = read_rtc_time_register(REG_RTC_MINUTES);
|
||||||
|
t.second = read_rtc_time_register(REG_RTC_SECONDS);
|
||||||
|
if (!rtc_24hour_mode)
|
||||||
|
{
|
||||||
|
ubyte pm = (t.hour & 0x80u) >> 7u;
|
||||||
|
t.hour &= 0x7Fu;
|
||||||
|
if (!rtc_binary_mode)
|
||||||
|
{
|
||||||
|
t.hour = bcd_to_binary(t.hour);
|
||||||
|
}
|
||||||
|
/* Hour is in 12-hour format; convert to 24-hour format. */
|
||||||
|
t.hour = cast(ubyte)((t.hour % 12u) + pm * 12u);
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ubyte read_rtc_time_register(ubyte register)
|
||||||
|
{
|
||||||
|
ubyte value = read_register(register);
|
||||||
|
if (!rtc_binary_mode)
|
||||||
|
{
|
||||||
|
value = bcd_to_binary(value);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ubyte bcd_to_binary(ubyte bcd)
|
||||||
|
{
|
||||||
|
return (bcd & 0xFu) + ((bcd & 0xF0u) >> 4u) * 10u;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user