kern
annotate src/rtc.c @ 41:928b0ebfff4d
merged the timer/rtc/etc from the misc branch
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Tue, 14 Jun 2011 01:19:07 +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 } |