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 +}