nuclear@36: #include nuclear@36: #include nuclear@36: #include nuclear@37: #include "rtc.h" nuclear@36: nuclear@36: /* CMOS I/O ports */ nuclear@36: #define PORT_CTL 0x70 nuclear@36: #define PORT_DATA 0x71 nuclear@36: nuclear@36: /* CMOS RTC registers */ nuclear@36: #define REG_SEC 0 nuclear@36: #define REG_ALARM_SEC 1 nuclear@36: #define REG_MIN 2 nuclear@36: #define REG_ALARM_MIN 3 nuclear@36: #define REG_HOUR 4 nuclear@36: #define REG_ALARM_HOUR 5 nuclear@36: #define REG_WEEKDAY 6 nuclear@36: #define REG_DAY 7 nuclear@36: #define REG_MONTH 8 nuclear@36: #define REG_YEAR 9 nuclear@36: #define REG_STATA 10 nuclear@36: #define REG_STATB 11 nuclear@36: #define REG_STATC 12 nuclear@36: #define REG_STATD 13 nuclear@36: nuclear@36: #define STATA_BUSY (1 << 7) nuclear@36: #define STATB_24HR (1 << 1) nuclear@36: #define STATB_BIN (1 << 2) nuclear@36: nuclear@36: #define HOUR_PM_BIT (1 << 7) nuclear@36: nuclear@36: #define BCD_TO_BIN(x) ((((x) >> 4) & 0xf) * 10 + ((x) & 0xf)) nuclear@36: nuclear@36: static void read_rtc(struct tm *tm); nuclear@36: static int read_reg(int reg); nuclear@36: nuclear@36: nuclear@36: void init_rtc(void) nuclear@36: { nuclear@36: struct tm tm; nuclear@36: nuclear@36: read_rtc(&tm); nuclear@37: start_time = mktime(&tm); nuclear@37: nuclear@36: printf("System real-time clock: %s", asctime(&tm)); nuclear@36: } nuclear@36: nuclear@37: nuclear@36: static void read_rtc(struct tm *tm) nuclear@36: { nuclear@36: int statb, pm; nuclear@36: nuclear@36: /* wait for any clock updates to finish */ nuclear@36: while(read_reg(REG_STATA) & STATA_BUSY); nuclear@36: nuclear@36: tm->tm_sec = read_reg(REG_SEC); nuclear@36: tm->tm_min = read_reg(REG_MIN); nuclear@36: tm->tm_hour = read_reg(REG_HOUR); nuclear@36: tm->tm_mday = read_reg(REG_DAY); nuclear@36: tm->tm_mon = read_reg(REG_MONTH); nuclear@36: tm->tm_year = read_reg(REG_YEAR); nuclear@36: nuclear@36: /* in 12hour mode, bit 7 means post-meridiem */ nuclear@36: pm = tm->tm_hour & HOUR_PM_BIT; nuclear@36: tm->tm_hour &= ~HOUR_PM_BIT; nuclear@36: nuclear@36: /* convert to binary if needed */ nuclear@36: statb = read_reg(REG_STATB); nuclear@36: if(!(statb & STATB_BIN)) { nuclear@36: tm->tm_sec = BCD_TO_BIN(tm->tm_sec); nuclear@36: tm->tm_min = BCD_TO_BIN(tm->tm_min); nuclear@36: tm->tm_hour = BCD_TO_BIN(tm->tm_hour); nuclear@36: tm->tm_mday = BCD_TO_BIN(tm->tm_mday); nuclear@36: tm->tm_mon = BCD_TO_BIN(tm->tm_mon); nuclear@36: tm->tm_year = BCD_TO_BIN(tm->tm_year); nuclear@36: } nuclear@36: nuclear@36: /* make the year an offset from 1900 */ nuclear@36: if(tm->tm_year < 100) { nuclear@36: tm->tm_year += 100; nuclear@36: } else { nuclear@36: tm->tm_year -= 1900; nuclear@36: } nuclear@36: nuclear@36: /* if tm_hour is in 12h mode, convert to 24h */ nuclear@36: if(!(statb & STATB_24HR)) { nuclear@36: if(tm->tm_hour == 12) { nuclear@36: tm->tm_hour = 0; nuclear@36: } nuclear@36: if(pm) { nuclear@36: tm->tm_hour += 12; nuclear@36: } nuclear@36: } nuclear@36: nuclear@36: tm->tm_mon -= 1; /* we want months to start from 0 */ nuclear@36: } nuclear@36: nuclear@36: static int read_reg(int reg) nuclear@36: { nuclear@36: unsigned char val; nuclear@36: outb(reg, PORT_CTL); nuclear@36: iodelay(); nuclear@36: inb(val, PORT_DATA); nuclear@36: iodelay(); nuclear@36: return val; nuclear@36: }