kern

annotate src/rtc.c @ 40:710739e33da8

- now read_rtc doesn't try to read weekday as it's probably wrong anyway, and doesn't set yearday either - mktime now fixes yearday and weekday - moved init_timer and init_rtc just before enabling the interrupts in main
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 12 Jun 2011 15:45:21 +0300
parents 2c401f69128e
children
rev   line source
nuclear@36 1 #include <stdio.h>
nuclear@36 2 #include <time.h>
nuclear@36 3 #include <asmops.h>
nuclear@37 4 #include "rtc.h"
nuclear@36 5
nuclear@36 6 /* CMOS I/O ports */
nuclear@36 7 #define PORT_CTL 0x70
nuclear@36 8 #define PORT_DATA 0x71
nuclear@36 9
nuclear@36 10 /* CMOS RTC registers */
nuclear@36 11 #define REG_SEC 0
nuclear@36 12 #define REG_ALARM_SEC 1
nuclear@36 13 #define REG_MIN 2
nuclear@36 14 #define REG_ALARM_MIN 3
nuclear@36 15 #define REG_HOUR 4
nuclear@36 16 #define REG_ALARM_HOUR 5
nuclear@36 17 #define REG_WEEKDAY 6
nuclear@36 18 #define REG_DAY 7
nuclear@36 19 #define REG_MONTH 8
nuclear@36 20 #define REG_YEAR 9
nuclear@36 21 #define REG_STATA 10
nuclear@36 22 #define REG_STATB 11
nuclear@36 23 #define REG_STATC 12
nuclear@36 24 #define REG_STATD 13
nuclear@36 25
nuclear@36 26 #define STATA_BUSY (1 << 7)
nuclear@36 27 #define STATB_24HR (1 << 1)
nuclear@36 28 #define STATB_BIN (1 << 2)
nuclear@36 29
nuclear@36 30 #define HOUR_PM_BIT (1 << 7)
nuclear@36 31
nuclear@36 32 #define BCD_TO_BIN(x) ((((x) >> 4) & 0xf) * 10 + ((x) & 0xf))
nuclear@36 33
nuclear@36 34 static void read_rtc(struct tm *tm);
nuclear@36 35 static int read_reg(int reg);
nuclear@36 36
nuclear@36 37
nuclear@36 38 void init_rtc(void)
nuclear@36 39 {
nuclear@36 40 struct tm tm;
nuclear@36 41
nuclear@36 42 read_rtc(&tm);
nuclear@37 43 start_time = mktime(&tm);
nuclear@37 44
nuclear@36 45 printf("System real-time clock: %s", asctime(&tm));
nuclear@36 46 }
nuclear@36 47
nuclear@37 48
nuclear@36 49 static void read_rtc(struct tm *tm)
nuclear@36 50 {
nuclear@36 51 int statb, pm;
nuclear@36 52
nuclear@36 53 /* wait for any clock updates to finish */
nuclear@36 54 while(read_reg(REG_STATA) & STATA_BUSY);
nuclear@36 55
nuclear@36 56 tm->tm_sec = read_reg(REG_SEC);
nuclear@36 57 tm->tm_min = read_reg(REG_MIN);
nuclear@36 58 tm->tm_hour = read_reg(REG_HOUR);
nuclear@36 59 tm->tm_mday = read_reg(REG_DAY);
nuclear@36 60 tm->tm_mon = read_reg(REG_MONTH);
nuclear@36 61 tm->tm_year = read_reg(REG_YEAR);
nuclear@36 62
nuclear@36 63 /* in 12hour mode, bit 7 means post-meridiem */
nuclear@36 64 pm = tm->tm_hour & HOUR_PM_BIT;
nuclear@36 65 tm->tm_hour &= ~HOUR_PM_BIT;
nuclear@36 66
nuclear@36 67 /* convert to binary if needed */
nuclear@36 68 statb = read_reg(REG_STATB);
nuclear@36 69 if(!(statb & STATB_BIN)) {
nuclear@36 70 tm->tm_sec = BCD_TO_BIN(tm->tm_sec);
nuclear@36 71 tm->tm_min = BCD_TO_BIN(tm->tm_min);
nuclear@36 72 tm->tm_hour = BCD_TO_BIN(tm->tm_hour);
nuclear@36 73 tm->tm_mday = BCD_TO_BIN(tm->tm_mday);
nuclear@36 74 tm->tm_mon = BCD_TO_BIN(tm->tm_mon);
nuclear@36 75 tm->tm_year = BCD_TO_BIN(tm->tm_year);
nuclear@36 76 }
nuclear@36 77
nuclear@36 78 /* make the year an offset from 1900 */
nuclear@36 79 if(tm->tm_year < 100) {
nuclear@36 80 tm->tm_year += 100;
nuclear@36 81 } else {
nuclear@36 82 tm->tm_year -= 1900;
nuclear@36 83 }
nuclear@36 84
nuclear@36 85 /* if tm_hour is in 12h mode, convert to 24h */
nuclear@36 86 if(!(statb & STATB_24HR)) {
nuclear@36 87 if(tm->tm_hour == 12) {
nuclear@36 88 tm->tm_hour = 0;
nuclear@36 89 }
nuclear@36 90 if(pm) {
nuclear@36 91 tm->tm_hour += 12;
nuclear@36 92 }
nuclear@36 93 }
nuclear@36 94
nuclear@36 95 tm->tm_mon -= 1; /* we want months to start from 0 */
nuclear@36 96 }
nuclear@36 97
nuclear@36 98 static int read_reg(int reg)
nuclear@36 99 {
nuclear@36 100 unsigned char val;
nuclear@36 101 outb(reg, PORT_CTL);
nuclear@36 102 iodelay();
nuclear@36 103 inb(val, PORT_DATA);
nuclear@36 104 iodelay();
nuclear@36 105 return val;
nuclear@36 106 }