kernel/time.c (view raw)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109
#include "time.h"
#include "assembly.h"
#include "interrupts.h"
#include "pic.h"
#include "core.h"
#include "alarm.h"
#define RTC_COMMAND 0x70
#define RTC_DATA 0x71
#define RTC_READY 0x80
#define RTC_REGISTER_A 0x0A
#define RTC_REGISTER_B 0x0B
#define RTC_REGISTER_C 0x0C
#define RTC_REGISTER_D 0x0D
#define RTC_GET_SECONDS 0x00
#define RTC_GET_MINUTES 0x02
#define RTC_GET_HOURS 0x04
#define RTC_GET_DAY 0x07
#define RTC_GET_MONTH 0x08
#define RTC_GET_YEAR 0x09
#define RTC_DISABLE_NMI 0x80
#define RTC_ENABLE_NMI 0x00
#define RTC_ENABLE_INT8 0x40
int ticks = 0;
void time_tick(void) {
ticks++;
}
int time_get_ticks(void) {
return ticks;
}
static uint8_t rtc_get(uint8_t reg) {
outb(reg, RTC_COMMAND);
/*nop();
nop();
nop();
nop();*/
uint8_t res = inb(RTC_DATA);
return res;
}
static uint8_t from_BCD(uint8_t bcd_value) {
return (bcd_value >> 4) * 10 + (bcd_value & 0x0F);
}
static void rtc_set(uint8_t reg, uint8_t value) {
outb(reg, RTC_COMMAND);
/*nop();
nop();
nop();
nop();*/
outb(value, RTC_DATA);
}
int time_now(datetime_t *buffer) {
buffer->year = 2000 + from_BCD(rtc_get(RTC_GET_YEAR));
buffer->month = from_BCD(rtc_get(RTC_GET_MONTH));
buffer->day = from_BCD(rtc_get(RTC_GET_DAY));
buffer->hour = from_BCD(rtc_get(RTC_GET_HOURS));
buffer->minute = from_BCD(rtc_get(RTC_GET_MINUTES));
buffer->second = from_BCD(rtc_get(RTC_GET_SECONDS));
return 0;
}
INTERRUPT(rtc_interrupt, frame) {
(void)frame;
time_tick();
alarm_tick();
rtc_get(RTC_REGISTER_C);
pic2_eoi();
}
int time_init(void) {
install_interrupt(PIC2_IRQ(0x00), rtc_interrupt, 0x18, INT_GATE);
// disable all interrupts
cli();
uint8_t reg_a = rtc_get(RTC_REGISTER_A | RTC_DISABLE_NMI);
rtc_set(RTC_REGISTER_A | RTC_DISABLE_NMI, (reg_a & 0xF0) | RTC_INT_RATE);
uint8_t reg_b = rtc_get(RTC_REGISTER_B | RTC_DISABLE_NMI);
rtc_set(RTC_REGISTER_B | RTC_DISABLE_NMI, reg_b | RTC_ENABLE_INT8);
reg_b = rtc_get(RTC_REGISTER_B);
rtc_get(RTC_REGISTER_C);
rtc_get(RTC_REGISTER_D);
// enable interrupts again
sti();
pic_unmask_interrupt(8);
return 0;
}