kern
changeset 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 | 06172322fb76 |
children | 2c401f69128e |
files | src/asmops.h src/klibc/time.c src/klibc/time.h src/main.c src/rtc.c src/rtc.h |
diffstat | 6 files changed, 215 insertions(+), 0 deletions(-) [+] |
line diff
1.1 --- a/src/asmops.h Thu Jun 09 05:09:49 2011 +0300 1.2 +++ b/src/asmops.h Fri Jun 10 05:33:38 2011 +0300 1.3 @@ -32,4 +32,6 @@ 1.4 "outl %0, %1\n\t" \ 1.5 :: "a" ((unsigned long)(src)), "dN" ((unsigned short)(port))) 1.6 1.7 +#define iodelay() outb(0, 0x80) 1.8 + 1.9 #endif /* ASMOPS_H_ */
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 2.2 +++ b/src/klibc/time.c Fri Jun 10 05:33:38 2011 +0300 2.3 @@ -0,0 +1,70 @@ 2.4 +#include <stdio.h> 2.5 +#include "time.h" 2.6 + 2.7 +#define MINSEC 60 2.8 +#define HOURSEC (60 * MINSEC) 2.9 +#define DAYSEC (24 * HOURSEC) 2.10 + 2.11 +static int is_leap_year(int yr); 2.12 + 2.13 + 2.14 +static char *wday[] = { 2.15 + "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" 2.16 +}; 2.17 +static char *mon[] = { 2.18 + "Jan", "Feb", "Mar", "Apr", "May", "Jun", 2.19 + "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" 2.20 +}; 2.21 + 2.22 + 2.23 +char *asctime(struct tm *tm) 2.24 +{ 2.25 + static char buf[64]; 2.26 + 2.27 + sprintf(buf, "%s %s %d %02d:%02d:%02d %d\n", wday[tm->tm_wday], 2.28 + mon[tm->tm_mon], tm->tm_mday, tm->tm_hour, tm->tm_min, 2.29 + tm->tm_sec, tm->tm_year + 1900); 2.30 + return buf; 2.31 +} 2.32 + 2.33 +time_t mktime(struct tm *tm) 2.34 +{ 2.35 + int i, num_years = tm->tm_year - 70; 2.36 + int year = 1970; 2.37 + int days = day_of_year(tm->tm_year + 1900, tm->tm_mon, tm->tm_mday - 1); 2.38 + 2.39 + for(i=0; i<num_years; i++) { 2.40 + days += is_leap_year(year++) ? 366 : 365; 2.41 + } 2.42 + 2.43 + return (time_t)days * DAYSEC + tm->tm_hour * HOURSEC + 2.44 + tm->tm_min * MINSEC + tm->tm_sec; 2.45 +} 2.46 + 2.47 +int day_of_year(int year, int mon, int day) 2.48 +{ 2.49 + static int commdays[] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 2.50 + static int leapdays[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}; 2.51 + int *mdays, i, yday; 2.52 + 2.53 + mdays = is_leap_year(year) ? leapdays : commdays; 2.54 + 2.55 + yday = day; 2.56 + for(i=0; i<mon; i++) { 2.57 + yday += mdays[i]; 2.58 + } 2.59 + return yday; 2.60 +} 2.61 + 2.62 +static int is_leap_year(int yr) 2.63 +{ 2.64 + /* exceptions first */ 2.65 + if(yr % 400 == 0) { 2.66 + return 1; 2.67 + } 2.68 + if(yr % 100 == 0) { 2.69 + return 0; 2.70 + } 2.71 + /* standard case */ 2.72 + return yr % 4 == 0; 2.73 +}
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 3.2 +++ b/src/klibc/time.h Fri Jun 10 05:33:38 2011 +0300 3.3 @@ -0,0 +1,25 @@ 3.4 +#ifndef _TIME_H_ 3.5 +#define _TIME_H_ 3.6 + 3.7 +typedef long time_t; 3.8 + 3.9 +struct tm { 3.10 + int tm_sec; 3.11 + int tm_min; 3.12 + int tm_hour; 3.13 + int tm_mday; 3.14 + int tm_mon; 3.15 + int tm_year; 3.16 + int tm_wday; 3.17 + int tm_yday; 3.18 + int tm_isdst; 3.19 +}; 3.20 + 3.21 +char *asctime(struct tm *tm); 3.22 +time_t mktime(struct tm *tm); 3.23 + 3.24 +/* non-standard helpers */ 3.25 +int day_of_year(int year, int mon, int day); 3.26 + 3.27 + 3.28 +#endif /* _TIME_H_ */
4.1 --- a/src/main.c Thu Jun 09 05:09:49 2011 +0300 4.2 +++ b/src/main.c Fri Jun 10 05:33:38 2011 +0300 4.3 @@ -5,6 +5,7 @@ 4.4 #include "asmops.h" 4.5 #include "segm.h" 4.6 #include "intr.h" 4.7 +#include "rtc.h" 4.8 #include "timer.h" 4.9 #include "mem.h" 4.10 #include "vm.h" 4.11 @@ -54,6 +55,7 @@ 4.12 init_segm(); 4.13 init_intr(); 4.14 4.15 + init_rtc(); 4.16 init_timer(); 4.17 4.18 /* initialize the physical memory manager */
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/rtc.c Fri Jun 10 05:33:38 2011 +0300 5.3 @@ -0,0 +1,109 @@ 5.4 +#include <stdio.h> 5.5 +#include <time.h> 5.6 +#include <asmops.h> 5.7 + 5.8 +/* CMOS I/O ports */ 5.9 +#define PORT_CTL 0x70 5.10 +#define PORT_DATA 0x71 5.11 + 5.12 +/* CMOS RTC registers */ 5.13 +#define REG_SEC 0 5.14 +#define REG_ALARM_SEC 1 5.15 +#define REG_MIN 2 5.16 +#define REG_ALARM_MIN 3 5.17 +#define REG_HOUR 4 5.18 +#define REG_ALARM_HOUR 5 5.19 +#define REG_WEEKDAY 6 5.20 +#define REG_DAY 7 5.21 +#define REG_MONTH 8 5.22 +#define REG_YEAR 9 5.23 +#define REG_STATA 10 5.24 +#define REG_STATB 11 5.25 +#define REG_STATC 12 5.26 +#define REG_STATD 13 5.27 + 5.28 +#define STATA_BUSY (1 << 7) 5.29 +#define STATB_24HR (1 << 1) 5.30 +#define STATB_BIN (1 << 2) 5.31 + 5.32 +#define HOUR_PM_BIT (1 << 7) 5.33 + 5.34 +#define BCD_TO_BIN(x) ((((x) >> 4) & 0xf) * 10 + ((x) & 0xf)) 5.35 + 5.36 +static void read_rtc(struct tm *tm); 5.37 +static int read_reg(int reg); 5.38 + 5.39 +static unsigned long start_time; 5.40 + 5.41 + 5.42 +void init_rtc(void) 5.43 +{ 5.44 + struct tm tm; 5.45 + 5.46 + read_rtc(&tm); 5.47 + printf("System real-time clock: %s", asctime(&tm)); 5.48 + printf("time_t: %ld\n", mktime(&tm)); 5.49 +} 5.50 + 5.51 +static void read_rtc(struct tm *tm) 5.52 +{ 5.53 + int statb, pm; 5.54 + 5.55 + /* wait for any clock updates to finish */ 5.56 + while(read_reg(REG_STATA) & STATA_BUSY); 5.57 + 5.58 + tm->tm_sec = read_reg(REG_SEC); 5.59 + tm->tm_min = read_reg(REG_MIN); 5.60 + tm->tm_hour = read_reg(REG_HOUR); 5.61 + tm->tm_mday = read_reg(REG_DAY); 5.62 + tm->tm_mon = read_reg(REG_MONTH); 5.63 + tm->tm_year = read_reg(REG_YEAR); 5.64 + tm->tm_wday = read_reg(REG_WEEKDAY); 5.65 + 5.66 + /* in 12hour mode, bit 7 means post-meridiem */ 5.67 + pm = tm->tm_hour & HOUR_PM_BIT; 5.68 + tm->tm_hour &= ~HOUR_PM_BIT; 5.69 + 5.70 + /* convert to binary if needed */ 5.71 + statb = read_reg(REG_STATB); 5.72 + if(!(statb & STATB_BIN)) { 5.73 + tm->tm_sec = BCD_TO_BIN(tm->tm_sec); 5.74 + tm->tm_min = BCD_TO_BIN(tm->tm_min); 5.75 + tm->tm_hour = BCD_TO_BIN(tm->tm_hour); 5.76 + tm->tm_mday = BCD_TO_BIN(tm->tm_mday); 5.77 + tm->tm_mon = BCD_TO_BIN(tm->tm_mon); 5.78 + tm->tm_year = BCD_TO_BIN(tm->tm_year); 5.79 + tm->tm_wday = BCD_TO_BIN(tm->tm_wday); 5.80 + } 5.81 + 5.82 + /* make the year an offset from 1900 */ 5.83 + if(tm->tm_year < 100) { 5.84 + tm->tm_year += 100; 5.85 + } else { 5.86 + tm->tm_year -= 1900; 5.87 + } 5.88 + 5.89 + /* if tm_hour is in 12h mode, convert to 24h */ 5.90 + if(!(statb & STATB_24HR)) { 5.91 + if(tm->tm_hour == 12) { 5.92 + tm->tm_hour = 0; 5.93 + } 5.94 + if(pm) { 5.95 + tm->tm_hour += 12; 5.96 + } 5.97 + } 5.98 + 5.99 + tm->tm_mon -= 1; /* we want months to start from 0 */ 5.100 + tm->tm_wday -= 1; /* we want weekdays to start from 0 */ 5.101 + tm->tm_yday = day_of_year(tm->tm_year + 1900, tm->tm_mon, tm->tm_mday - 1); 5.102 +} 5.103 + 5.104 +static int read_reg(int reg) 5.105 +{ 5.106 + unsigned char val; 5.107 + outb(reg, PORT_CTL); 5.108 + iodelay(); 5.109 + inb(val, PORT_DATA); 5.110 + iodelay(); 5.111 + return val; 5.112 +}