kern
diff 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 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/rtc.c Fri Jun 10 05:33:38 2011 +0300 1.3 @@ -0,0 +1,109 @@ 1.4 +#include <stdio.h> 1.5 +#include <time.h> 1.6 +#include <asmops.h> 1.7 + 1.8 +/* CMOS I/O ports */ 1.9 +#define PORT_CTL 0x70 1.10 +#define PORT_DATA 0x71 1.11 + 1.12 +/* CMOS RTC registers */ 1.13 +#define REG_SEC 0 1.14 +#define REG_ALARM_SEC 1 1.15 +#define REG_MIN 2 1.16 +#define REG_ALARM_MIN 3 1.17 +#define REG_HOUR 4 1.18 +#define REG_ALARM_HOUR 5 1.19 +#define REG_WEEKDAY 6 1.20 +#define REG_DAY 7 1.21 +#define REG_MONTH 8 1.22 +#define REG_YEAR 9 1.23 +#define REG_STATA 10 1.24 +#define REG_STATB 11 1.25 +#define REG_STATC 12 1.26 +#define REG_STATD 13 1.27 + 1.28 +#define STATA_BUSY (1 << 7) 1.29 +#define STATB_24HR (1 << 1) 1.30 +#define STATB_BIN (1 << 2) 1.31 + 1.32 +#define HOUR_PM_BIT (1 << 7) 1.33 + 1.34 +#define BCD_TO_BIN(x) ((((x) >> 4) & 0xf) * 10 + ((x) & 0xf)) 1.35 + 1.36 +static void read_rtc(struct tm *tm); 1.37 +static int read_reg(int reg); 1.38 + 1.39 +static unsigned long start_time; 1.40 + 1.41 + 1.42 +void init_rtc(void) 1.43 +{ 1.44 + struct tm tm; 1.45 + 1.46 + read_rtc(&tm); 1.47 + printf("System real-time clock: %s", asctime(&tm)); 1.48 + printf("time_t: %ld\n", mktime(&tm)); 1.49 +} 1.50 + 1.51 +static void read_rtc(struct tm *tm) 1.52 +{ 1.53 + int statb, pm; 1.54 + 1.55 + /* wait for any clock updates to finish */ 1.56 + while(read_reg(REG_STATA) & STATA_BUSY); 1.57 + 1.58 + tm->tm_sec = read_reg(REG_SEC); 1.59 + tm->tm_min = read_reg(REG_MIN); 1.60 + tm->tm_hour = read_reg(REG_HOUR); 1.61 + tm->tm_mday = read_reg(REG_DAY); 1.62 + tm->tm_mon = read_reg(REG_MONTH); 1.63 + tm->tm_year = read_reg(REG_YEAR); 1.64 + tm->tm_wday = read_reg(REG_WEEKDAY); 1.65 + 1.66 + /* in 12hour mode, bit 7 means post-meridiem */ 1.67 + pm = tm->tm_hour & HOUR_PM_BIT; 1.68 + tm->tm_hour &= ~HOUR_PM_BIT; 1.69 + 1.70 + /* convert to binary if needed */ 1.71 + statb = read_reg(REG_STATB); 1.72 + if(!(statb & STATB_BIN)) { 1.73 + tm->tm_sec = BCD_TO_BIN(tm->tm_sec); 1.74 + tm->tm_min = BCD_TO_BIN(tm->tm_min); 1.75 + tm->tm_hour = BCD_TO_BIN(tm->tm_hour); 1.76 + tm->tm_mday = BCD_TO_BIN(tm->tm_mday); 1.77 + tm->tm_mon = BCD_TO_BIN(tm->tm_mon); 1.78 + tm->tm_year = BCD_TO_BIN(tm->tm_year); 1.79 + tm->tm_wday = BCD_TO_BIN(tm->tm_wday); 1.80 + } 1.81 + 1.82 + /* make the year an offset from 1900 */ 1.83 + if(tm->tm_year < 100) { 1.84 + tm->tm_year += 100; 1.85 + } else { 1.86 + tm->tm_year -= 1900; 1.87 + } 1.88 + 1.89 + /* if tm_hour is in 12h mode, convert to 24h */ 1.90 + if(!(statb & STATB_24HR)) { 1.91 + if(tm->tm_hour == 12) { 1.92 + tm->tm_hour = 0; 1.93 + } 1.94 + if(pm) { 1.95 + tm->tm_hour += 12; 1.96 + } 1.97 + } 1.98 + 1.99 + tm->tm_mon -= 1; /* we want months to start from 0 */ 1.100 + tm->tm_wday -= 1; /* we want weekdays to start from 0 */ 1.101 + tm->tm_yday = day_of_year(tm->tm_year + 1900, tm->tm_mon, tm->tm_mday - 1); 1.102 +} 1.103 + 1.104 +static int read_reg(int reg) 1.105 +{ 1.106 + unsigned char val; 1.107 + outb(reg, PORT_CTL); 1.108 + iodelay(); 1.109 + inb(val, PORT_DATA); 1.110 + iodelay(); 1.111 + return val; 1.112 +}