1*64136c1cSPekka Enberg #include "kvm/rtc.h" 2*64136c1cSPekka Enberg 3*64136c1cSPekka Enberg #include "kvm/ioport.h" 4*64136c1cSPekka Enberg #include "kvm/kvm.h" 5*64136c1cSPekka Enberg 6*64136c1cSPekka Enberg #include <time.h> 7*64136c1cSPekka Enberg 8*64136c1cSPekka Enberg static uint8_t cmos_index; 9*64136c1cSPekka Enberg 10*64136c1cSPekka Enberg #define CMOS_RTC_SECONDS 0x00 11*64136c1cSPekka Enberg #define CMOS_RTC_MINUTES 0x02 12*64136c1cSPekka Enberg #define CMOS_RTC_HOURS 0x04 13*64136c1cSPekka Enberg #define CMOS_RTC_DATE_OF_MONTH 0x07 14*64136c1cSPekka Enberg #define CMOS_RTC_MONTH 0x08 15*64136c1cSPekka Enberg #define CMOS_RTC_YEAR 0x09 16*64136c1cSPekka Enberg 17*64136c1cSPekka Enberg static inline unsigned char bin2bcd(unsigned val) 18*64136c1cSPekka Enberg { 19*64136c1cSPekka Enberg return ((val / 10) << 4) + val % 10; 20*64136c1cSPekka Enberg } 21*64136c1cSPekka Enberg 22*64136c1cSPekka Enberg static bool cmos_ram_data_in(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 23*64136c1cSPekka Enberg { 24*64136c1cSPekka Enberg struct tm *tm; 25*64136c1cSPekka Enberg time_t ti; 26*64136c1cSPekka Enberg 27*64136c1cSPekka Enberg time(&ti); 28*64136c1cSPekka Enberg 29*64136c1cSPekka Enberg tm = gmtime(&ti); 30*64136c1cSPekka Enberg 31*64136c1cSPekka Enberg switch (cmos_index) { 32*64136c1cSPekka Enberg case CMOS_RTC_SECONDS: 33*64136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_sec)); 34*64136c1cSPekka Enberg break; 35*64136c1cSPekka Enberg case CMOS_RTC_MINUTES: 36*64136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_min)); 37*64136c1cSPekka Enberg break; 38*64136c1cSPekka Enberg case CMOS_RTC_HOURS: 39*64136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_hour)); 40*64136c1cSPekka Enberg break; 41*64136c1cSPekka Enberg case CMOS_RTC_DATE_OF_MONTH: 42*64136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_mday)); 43*64136c1cSPekka Enberg break; 44*64136c1cSPekka Enberg case CMOS_RTC_MONTH: 45*64136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_mon + 1)); 46*64136c1cSPekka Enberg break; 47*64136c1cSPekka Enberg case CMOS_RTC_YEAR: 48*64136c1cSPekka Enberg ioport__write8(data, bin2bcd(tm->tm_year)); 49*64136c1cSPekka Enberg break; 50*64136c1cSPekka Enberg } 51*64136c1cSPekka Enberg 52*64136c1cSPekka Enberg return true; 53*64136c1cSPekka Enberg } 54*64136c1cSPekka Enberg 55*64136c1cSPekka Enberg static bool cmos_ram_data_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 56*64136c1cSPekka Enberg { 57*64136c1cSPekka Enberg return true; 58*64136c1cSPekka Enberg } 59*64136c1cSPekka Enberg 60*64136c1cSPekka Enberg static struct ioport_operations cmos_ram_data_ioport_ops = { 61*64136c1cSPekka Enberg .io_out = cmos_ram_data_out, 62*64136c1cSPekka Enberg .io_in = cmos_ram_data_in, 63*64136c1cSPekka Enberg }; 64*64136c1cSPekka Enberg 65*64136c1cSPekka Enberg static bool cmos_ram_index_out(struct kvm *self, uint16_t port, void *data, int size, uint32_t count) 66*64136c1cSPekka Enberg { 67*64136c1cSPekka Enberg uint8_t value; 68*64136c1cSPekka Enberg 69*64136c1cSPekka Enberg value = ioport__read8(data); 70*64136c1cSPekka Enberg 71*64136c1cSPekka Enberg self->nmi_disabled = value & (1UL << 7); 72*64136c1cSPekka Enberg 73*64136c1cSPekka Enberg cmos_index = value & ~(1UL << 7); 74*64136c1cSPekka Enberg 75*64136c1cSPekka Enberg return true; 76*64136c1cSPekka Enberg } 77*64136c1cSPekka Enberg 78*64136c1cSPekka Enberg static struct ioport_operations cmos_ram_index_ioport_ops = { 79*64136c1cSPekka Enberg .io_out = cmos_ram_index_out, 80*64136c1cSPekka Enberg }; 81*64136c1cSPekka Enberg 82*64136c1cSPekka Enberg void rtc__init(void) 83*64136c1cSPekka Enberg { 84*64136c1cSPekka Enberg /* PORT 0070-007F - CMOS RAM/RTC (REAL TIME CLOCK) */ 85*64136c1cSPekka Enberg ioport__register(0x0070, &cmos_ram_index_ioport_ops, 1); 86*64136c1cSPekka Enberg ioport__register(0x0071, &cmos_ram_data_ioport_ops, 1); 87*64136c1cSPekka Enberg } 88