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 }