kern
annotate src/rtc.c @ 36:e70b1ab9613e
- added cmos rtc code
- added time/date functions in klibc
- implemented an iowait macro with output to 0x80
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Fri, 10 Jun 2011 05:33:38 +0300 |
parents | |
children | 2c401f69128e |
rev | line source |
---|---|
nuclear@36 | 1 #include <stdio.h> |
nuclear@36 | 2 #include <time.h> |
nuclear@36 | 3 #include <asmops.h> |
nuclear@36 | 4 |
nuclear@36 | 5 /* CMOS I/O ports */ |
nuclear@36 | 6 #define PORT_CTL 0x70 |
nuclear@36 | 7 #define PORT_DATA 0x71 |
nuclear@36 | 8 |
nuclear@36 | 9 /* CMOS RTC registers */ |
nuclear@36 | 10 #define REG_SEC 0 |
nuclear@36 | 11 #define REG_ALARM_SEC 1 |
nuclear@36 | 12 #define REG_MIN 2 |
nuclear@36 | 13 #define REG_ALARM_MIN 3 |
nuclear@36 | 14 #define REG_HOUR 4 |
nuclear@36 | 15 #define REG_ALARM_HOUR 5 |
nuclear@36 | 16 #define REG_WEEKDAY 6 |
nuclear@36 | 17 #define REG_DAY 7 |
nuclear@36 | 18 #define REG_MONTH 8 |
nuclear@36 | 19 #define REG_YEAR 9 |
nuclear@36 | 20 #define REG_STATA 10 |
nuclear@36 | 21 #define REG_STATB 11 |
nuclear@36 | 22 #define REG_STATC 12 |
nuclear@36 | 23 #define REG_STATD 13 |
nuclear@36 | 24 |
nuclear@36 | 25 #define STATA_BUSY (1 << 7) |
nuclear@36 | 26 #define STATB_24HR (1 << 1) |
nuclear@36 | 27 #define STATB_BIN (1 << 2) |
nuclear@36 | 28 |
nuclear@36 | 29 #define HOUR_PM_BIT (1 << 7) |
nuclear@36 | 30 |
nuclear@36 | 31 #define BCD_TO_BIN(x) ((((x) >> 4) & 0xf) * 10 + ((x) & 0xf)) |
nuclear@36 | 32 |
nuclear@36 | 33 static void read_rtc(struct tm *tm); |
nuclear@36 | 34 static int read_reg(int reg); |
nuclear@36 | 35 |
nuclear@36 | 36 static unsigned long start_time; |
nuclear@36 | 37 |
nuclear@36 | 38 |
nuclear@36 | 39 void init_rtc(void) |
nuclear@36 | 40 { |
nuclear@36 | 41 struct tm tm; |
nuclear@36 | 42 |
nuclear@36 | 43 read_rtc(&tm); |
nuclear@36 | 44 printf("System real-time clock: %s", asctime(&tm)); |
nuclear@36 | 45 printf("time_t: %ld\n", mktime(&tm)); |
nuclear@36 | 46 } |
nuclear@36 | 47 |
nuclear@36 | 48 static void read_rtc(struct tm *tm) |
nuclear@36 | 49 { |
nuclear@36 | 50 int statb, pm; |
nuclear@36 | 51 |
nuclear@36 | 52 /* wait for any clock updates to finish */ |
nuclear@36 | 53 while(read_reg(REG_STATA) & STATA_BUSY); |
nuclear@36 | 54 |
nuclear@36 | 55 tm->tm_sec = read_reg(REG_SEC); |
nuclear@36 | 56 tm->tm_min = read_reg(REG_MIN); |
nuclear@36 | 57 tm->tm_hour = read_reg(REG_HOUR); |
nuclear@36 | 58 tm->tm_mday = read_reg(REG_DAY); |
nuclear@36 | 59 tm->tm_mon = read_reg(REG_MONTH); |
nuclear@36 | 60 tm->tm_year = read_reg(REG_YEAR); |
nuclear@36 | 61 tm->tm_wday = read_reg(REG_WEEKDAY); |
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 tm->tm_wday = BCD_TO_BIN(tm->tm_wday); |
nuclear@36 | 77 } |
nuclear@36 | 78 |
nuclear@36 | 79 /* make the year an offset from 1900 */ |
nuclear@36 | 80 if(tm->tm_year < 100) { |
nuclear@36 | 81 tm->tm_year += 100; |
nuclear@36 | 82 } else { |
nuclear@36 | 83 tm->tm_year -= 1900; |
nuclear@36 | 84 } |
nuclear@36 | 85 |
nuclear@36 | 86 /* if tm_hour is in 12h mode, convert to 24h */ |
nuclear@36 | 87 if(!(statb & STATB_24HR)) { |
nuclear@36 | 88 if(tm->tm_hour == 12) { |
nuclear@36 | 89 tm->tm_hour = 0; |
nuclear@36 | 90 } |
nuclear@36 | 91 if(pm) { |
nuclear@36 | 92 tm->tm_hour += 12; |
nuclear@36 | 93 } |
nuclear@36 | 94 } |
nuclear@36 | 95 |
nuclear@36 | 96 tm->tm_mon -= 1; /* we want months to start from 0 */ |
nuclear@36 | 97 tm->tm_wday -= 1; /* we want weekdays to start from 0 */ |
nuclear@36 | 98 tm->tm_yday = day_of_year(tm->tm_year + 1900, tm->tm_mon, tm->tm_mday - 1); |
nuclear@36 | 99 } |
nuclear@36 | 100 |
nuclear@36 | 101 static int read_reg(int reg) |
nuclear@36 | 102 { |
nuclear@36 | 103 unsigned char val; |
nuclear@36 | 104 outb(reg, PORT_CTL); |
nuclear@36 | 105 iodelay(); |
nuclear@36 | 106 inb(val, PORT_DATA); |
nuclear@36 | 107 iodelay(); |
nuclear@36 | 108 return val; |
nuclear@36 | 109 } |