xref: /plan9/sys/src/9/pc/devrtc.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
13e12c5d1SDavid du Colombier #include	"u.h"
23e12c5d1SDavid du Colombier #include	"../port/lib.h"
33e12c5d1SDavid du Colombier #include	"mem.h"
43e12c5d1SDavid du Colombier #include	"dat.h"
53e12c5d1SDavid du Colombier #include	"fns.h"
63e12c5d1SDavid du Colombier #include	"../port/error.h"
73e12c5d1SDavid du Colombier 
83e12c5d1SDavid du Colombier /*
93e12c5d1SDavid du Colombier  *  real time clock and non-volatile ram
103e12c5d1SDavid du Colombier  */
113e12c5d1SDavid du Colombier 
123e12c5d1SDavid du Colombier enum {
133e12c5d1SDavid du Colombier 	Paddr=		0x70,	/* address port */
143e12c5d1SDavid du Colombier 	Pdata=		0x71,	/* data port */
153e12c5d1SDavid du Colombier 
163e12c5d1SDavid du Colombier 	Seconds=	0x00,
173e12c5d1SDavid du Colombier 	Minutes=	0x02,
183e12c5d1SDavid du Colombier 	Hours=		0x04,
193e12c5d1SDavid du Colombier 	Mday=		0x07,
203e12c5d1SDavid du Colombier 	Month=		0x08,
213e12c5d1SDavid du Colombier 	Year=		0x09,
223e12c5d1SDavid du Colombier 	Status=		0x0A,
233e12c5d1SDavid du Colombier 
24219b2ee8SDavid du Colombier 	Nvoff=		128,	/* where usable nvram lives */
25219b2ee8SDavid du Colombier 	Nvsize=		256,
26219b2ee8SDavid du Colombier 
273e12c5d1SDavid du Colombier 	Nbcd=		6,
283e12c5d1SDavid du Colombier };
293e12c5d1SDavid du Colombier 
303e12c5d1SDavid du Colombier typedef struct Rtc	Rtc;
313e12c5d1SDavid du Colombier struct Rtc
323e12c5d1SDavid du Colombier {
333e12c5d1SDavid du Colombier 	int	sec;
343e12c5d1SDavid du Colombier 	int	min;
353e12c5d1SDavid du Colombier 	int	hour;
363e12c5d1SDavid du Colombier 	int	mday;
373e12c5d1SDavid du Colombier 	int	mon;
383e12c5d1SDavid du Colombier 	int	year;
393e12c5d1SDavid du Colombier };
403e12c5d1SDavid du Colombier 
413e12c5d1SDavid du Colombier 
423e12c5d1SDavid du Colombier enum{
43*9a747e4fSDavid du Colombier 	Qdir = 0,
44*9a747e4fSDavid du Colombier 	Qrtc,
453e12c5d1SDavid du Colombier 	Qnvram,
463e12c5d1SDavid du Colombier };
473e12c5d1SDavid du Colombier 
483e12c5d1SDavid du Colombier Dirtab rtcdir[]={
49*9a747e4fSDavid du Colombier 	".",	{Qdir, 0, QTDIR},	0,	0555,
50219b2ee8SDavid du Colombier 	"nvram",	{Qnvram, 0},	Nvsize,	0664,
51219b2ee8SDavid du Colombier 	"rtc",		{Qrtc, 0},	0,	0664,
523e12c5d1SDavid du Colombier };
533e12c5d1SDavid du Colombier 
547dd7cddfSDavid du Colombier static ulong rtc2sec(Rtc*);
557dd7cddfSDavid du Colombier static void sec2rtc(ulong, Rtc*);
563e12c5d1SDavid du Colombier 
573e12c5d1SDavid du Colombier void
rtcinit(void)583e12c5d1SDavid du Colombier rtcinit(void)
593e12c5d1SDavid du Colombier {
607dd7cddfSDavid du Colombier 	if(ioalloc(Paddr, 2, 0, "rtc/nvr") < 0)
617dd7cddfSDavid du Colombier 		panic("rtcinit: ioalloc failed");
623e12c5d1SDavid du Colombier }
633e12c5d1SDavid du Colombier 
647dd7cddfSDavid du Colombier static Chan*
rtcattach(char * spec)653e12c5d1SDavid du Colombier rtcattach(char* spec)
663e12c5d1SDavid du Colombier {
673e12c5d1SDavid du Colombier 	return devattach('r', spec);
683e12c5d1SDavid du Colombier }
693e12c5d1SDavid du Colombier 
70*9a747e4fSDavid du Colombier static Walkqid*
rtcwalk(Chan * c,Chan * nc,char ** name,int nname)71*9a747e4fSDavid du Colombier rtcwalk(Chan* c, Chan *nc, char** name, int nname)
723e12c5d1SDavid du Colombier {
73*9a747e4fSDavid du Colombier 	return devwalk(c, nc, name, nname, rtcdir, nelem(rtcdir), devgen);
743e12c5d1SDavid du Colombier }
753e12c5d1SDavid du Colombier 
76*9a747e4fSDavid du Colombier static int
rtcstat(Chan * c,uchar * dp,int n)77*9a747e4fSDavid du Colombier rtcstat(Chan* c, uchar* dp, int n)
783e12c5d1SDavid du Colombier {
79*9a747e4fSDavid du Colombier 	return devstat(c, dp, n, rtcdir, nelem(rtcdir), devgen);
803e12c5d1SDavid du Colombier }
813e12c5d1SDavid du Colombier 
827dd7cddfSDavid du Colombier static Chan*
rtcopen(Chan * c,int omode)833e12c5d1SDavid du Colombier rtcopen(Chan* c, int omode)
843e12c5d1SDavid du Colombier {
853e12c5d1SDavid du Colombier 	omode = openmode(omode);
86*9a747e4fSDavid du Colombier 	switch((ulong)c->qid.path){
873e12c5d1SDavid du Colombier 	case Qrtc:
887dd7cddfSDavid du Colombier 		if(strcmp(up->user, eve)!=0 && omode!=OREAD)
893e12c5d1SDavid du Colombier 			error(Eperm);
903e12c5d1SDavid du Colombier 		break;
913e12c5d1SDavid du Colombier 	case Qnvram:
927dd7cddfSDavid du Colombier 		if(strcmp(up->user, eve)!=0)
933e12c5d1SDavid du Colombier 			error(Eperm);
943e12c5d1SDavid du Colombier 	}
957dd7cddfSDavid du Colombier 	return devopen(c, omode, rtcdir, nelem(rtcdir), devgen);
963e12c5d1SDavid du Colombier }
973e12c5d1SDavid du Colombier 
987dd7cddfSDavid du Colombier static void
rtcclose(Chan *)997dd7cddfSDavid du Colombier rtcclose(Chan*)
1003e12c5d1SDavid du Colombier {
1013e12c5d1SDavid du Colombier }
1023e12c5d1SDavid du Colombier 
1033e12c5d1SDavid du Colombier #define GETBCD(o) ((bcdclock[o]&0xf) + 10*(bcdclock[o]>>4))
1043e12c5d1SDavid du Colombier 
1057dd7cddfSDavid du Colombier static long
_rtctime(void)1067dd7cddfSDavid du Colombier _rtctime(void)
1073e12c5d1SDavid du Colombier {
1083e12c5d1SDavid du Colombier 	uchar bcdclock[Nbcd];
1093e12c5d1SDavid du Colombier 	Rtc rtc;
110bd389b36SDavid du Colombier 	int i;
1113e12c5d1SDavid du Colombier 
1127dd7cddfSDavid du Colombier 	/* don't do the read until the clock is no longer busy */
113bd389b36SDavid du Colombier 	for(i = 0; i < 10000; i++){
1143e12c5d1SDavid du Colombier 		outb(Paddr, Status);
1157dd7cddfSDavid du Colombier 		if(inb(Pdata) & 0x80)
1167dd7cddfSDavid du Colombier 			continue;
1177dd7cddfSDavid du Colombier 
1187dd7cddfSDavid du Colombier 		/* read clock values */
1193e12c5d1SDavid du Colombier 		outb(Paddr, Seconds);	bcdclock[0] = inb(Pdata);
1203e12c5d1SDavid du Colombier 		outb(Paddr, Minutes);	bcdclock[1] = inb(Pdata);
1213e12c5d1SDavid du Colombier 		outb(Paddr, Hours);	bcdclock[2] = inb(Pdata);
1223e12c5d1SDavid du Colombier 		outb(Paddr, Mday);	bcdclock[3] = inb(Pdata);
1233e12c5d1SDavid du Colombier 		outb(Paddr, Month);	bcdclock[4] = inb(Pdata);
1243e12c5d1SDavid du Colombier 		outb(Paddr, Year);	bcdclock[5] = inb(Pdata);
1253e12c5d1SDavid du Colombier 
1267dd7cddfSDavid du Colombier 		outb(Paddr, Status);
1277dd7cddfSDavid du Colombier 		if((inb(Pdata) & 0x80) == 0)
1287dd7cddfSDavid du Colombier 			break;
1297dd7cddfSDavid du Colombier 	}
1307dd7cddfSDavid du Colombier 
1313e12c5d1SDavid du Colombier 	/*
1323e12c5d1SDavid du Colombier 	 *  convert from BCD
1333e12c5d1SDavid du Colombier 	 */
1343e12c5d1SDavid du Colombier 	rtc.sec = GETBCD(0);
1353e12c5d1SDavid du Colombier 	rtc.min = GETBCD(1);
1363e12c5d1SDavid du Colombier 	rtc.hour = GETBCD(2);
1373e12c5d1SDavid du Colombier 	rtc.mday = GETBCD(3);
1383e12c5d1SDavid du Colombier 	rtc.mon = GETBCD(4);
1393e12c5d1SDavid du Colombier 	rtc.year = GETBCD(5);
1403e12c5d1SDavid du Colombier 
1413e12c5d1SDavid du Colombier 	/*
1423e12c5d1SDavid du Colombier 	 *  the world starts jan 1 1970
1433e12c5d1SDavid du Colombier 	 */
1443e12c5d1SDavid du Colombier 	if(rtc.year < 70)
1453e12c5d1SDavid du Colombier 		rtc.year += 2000;
1463e12c5d1SDavid du Colombier 	else
1473e12c5d1SDavid du Colombier 		rtc.year += 1900;
1483e12c5d1SDavid du Colombier 	return rtc2sec(&rtc);
1493e12c5d1SDavid du Colombier }
1503e12c5d1SDavid du Colombier 
1517dd7cddfSDavid du Colombier static Lock nvrtlock;
1527dd7cddfSDavid du Colombier 
1533e12c5d1SDavid du Colombier long
rtctime(void)1547dd7cddfSDavid du Colombier rtctime(void)
1553e12c5d1SDavid du Colombier {
1567dd7cddfSDavid du Colombier 	int i;
1577dd7cddfSDavid du Colombier 	long t, ot;
1587dd7cddfSDavid du Colombier 
1597dd7cddfSDavid du Colombier 	ilock(&nvrtlock);
1607dd7cddfSDavid du Colombier 
1617dd7cddfSDavid du Colombier 	/* loop till we get two reads in a row the same */
1627dd7cddfSDavid du Colombier 	t = _rtctime();
1637dd7cddfSDavid du Colombier 	for(i = 0; i < 100; i++){
1647dd7cddfSDavid du Colombier 		ot = t;
1657dd7cddfSDavid du Colombier 		t = _rtctime();
1667dd7cddfSDavid du Colombier 		if(ot == t)
1677dd7cddfSDavid du Colombier 			break;
1687dd7cddfSDavid du Colombier 	}
1697dd7cddfSDavid du Colombier 	if(i == 100) print("we are boofheads\n");
1707dd7cddfSDavid du Colombier 
1717dd7cddfSDavid du Colombier 	iunlock(&nvrtlock);
1727dd7cddfSDavid du Colombier 
1737dd7cddfSDavid du Colombier 	return t;
1747dd7cddfSDavid du Colombier }
1757dd7cddfSDavid du Colombier 
1767dd7cddfSDavid du Colombier static long
rtcread(Chan * c,void * buf,long n,vlong off)1777dd7cddfSDavid du Colombier rtcread(Chan* c, void* buf, long n, vlong off)
1787dd7cddfSDavid du Colombier {
1797dd7cddfSDavid du Colombier 	ulong t;
1807dd7cddfSDavid du Colombier 	char *a, *start;
1817dd7cddfSDavid du Colombier 	ulong offset = off;
1823e12c5d1SDavid du Colombier 
183*9a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR)
1847dd7cddfSDavid du Colombier 		return devdirread(c, buf, n, rtcdir, nelem(rtcdir), devgen);
1853e12c5d1SDavid du Colombier 
186*9a747e4fSDavid du Colombier 	switch((ulong)c->qid.path){
187219b2ee8SDavid du Colombier 	case Qrtc:
1883e12c5d1SDavid du Colombier 		t = rtctime();
1893e12c5d1SDavid du Colombier 		n = readnum(offset, buf, n, t, 12);
1903e12c5d1SDavid du Colombier 		return n;
191219b2ee8SDavid du Colombier 	case Qnvram:
1927dd7cddfSDavid du Colombier 		if(n == 0)
1937dd7cddfSDavid du Colombier 			return 0;
1947dd7cddfSDavid du Colombier 		if(n > Nvsize)
1957dd7cddfSDavid du Colombier 			n = Nvsize;
1967dd7cddfSDavid du Colombier 		a = start = smalloc(n);
1977dd7cddfSDavid du Colombier 
1987dd7cddfSDavid du Colombier 		ilock(&nvrtlock);
199219b2ee8SDavid du Colombier 		for(t = offset; t < offset + n; t++){
200219b2ee8SDavid du Colombier 			if(t >= Nvsize)
201219b2ee8SDavid du Colombier 				break;
202219b2ee8SDavid du Colombier 			outb(Paddr, Nvoff+t);
203219b2ee8SDavid du Colombier 			*a++ = inb(Pdata);
204219b2ee8SDavid du Colombier 		}
2057dd7cddfSDavid du Colombier 		iunlock(&nvrtlock);
2067dd7cddfSDavid du Colombier 
2077dd7cddfSDavid du Colombier 		if(waserror()){
2087dd7cddfSDavid du Colombier 			free(start);
2097dd7cddfSDavid du Colombier 			nexterror();
2107dd7cddfSDavid du Colombier 		}
2117dd7cddfSDavid du Colombier 		memmove(buf, start, t - offset);
212219b2ee8SDavid du Colombier 		poperror();
2137dd7cddfSDavid du Colombier 
2147dd7cddfSDavid du Colombier 		free(start);
215219b2ee8SDavid du Colombier 		return t - offset;
216219b2ee8SDavid du Colombier 	}
217219b2ee8SDavid du Colombier 	error(Ebadarg);
218219b2ee8SDavid du Colombier 	return 0;
2193e12c5d1SDavid du Colombier }
2203e12c5d1SDavid du Colombier 
2213e12c5d1SDavid du Colombier #define PUTBCD(n,o) bcdclock[o] = (n % 10) | (((n / 10) % 10)<<4)
2223e12c5d1SDavid du Colombier 
2237dd7cddfSDavid du Colombier static long
rtcwrite(Chan * c,void * buf,long n,vlong off)2247dd7cddfSDavid du Colombier rtcwrite(Chan* c, void* buf, long n, vlong off)
2253e12c5d1SDavid du Colombier {
226219b2ee8SDavid du Colombier 	int t;
2277dd7cddfSDavid du Colombier 	char *a, *start;
2283e12c5d1SDavid du Colombier 	Rtc rtc;
2293e12c5d1SDavid du Colombier 	ulong secs;
2303e12c5d1SDavid du Colombier 	uchar bcdclock[Nbcd];
2313e12c5d1SDavid du Colombier 	char *cp, *ep;
2327dd7cddfSDavid du Colombier 	ulong offset = off;
2333e12c5d1SDavid du Colombier 
2343e12c5d1SDavid du Colombier 	if(offset!=0)
2353e12c5d1SDavid du Colombier 		error(Ebadarg);
2363e12c5d1SDavid du Colombier 
237219b2ee8SDavid du Colombier 
238*9a747e4fSDavid du Colombier 	switch((ulong)c->qid.path){
239219b2ee8SDavid du Colombier 	case Qrtc:
2403e12c5d1SDavid du Colombier 		/*
2413e12c5d1SDavid du Colombier 		 *  read the time
2423e12c5d1SDavid du Colombier 		 */
2433e12c5d1SDavid du Colombier 		cp = ep = buf;
2443e12c5d1SDavid du Colombier 		ep += n;
2453e12c5d1SDavid du Colombier 		while(cp < ep){
2463e12c5d1SDavid du Colombier 			if(*cp>='0' && *cp<='9')
2473e12c5d1SDavid du Colombier 				break;
2483e12c5d1SDavid du Colombier 			cp++;
2493e12c5d1SDavid du Colombier 		}
2503e12c5d1SDavid du Colombier 		secs = strtoul(cp, 0, 0);
2513e12c5d1SDavid du Colombier 
2523e12c5d1SDavid du Colombier 		/*
2533e12c5d1SDavid du Colombier 		 *  convert to bcd
2543e12c5d1SDavid du Colombier 		 */
2553e12c5d1SDavid du Colombier 		sec2rtc(secs, &rtc);
2563e12c5d1SDavid du Colombier 		PUTBCD(rtc.sec, 0);
2573e12c5d1SDavid du Colombier 		PUTBCD(rtc.min, 1);
2583e12c5d1SDavid du Colombier 		PUTBCD(rtc.hour, 2);
2593e12c5d1SDavid du Colombier 		PUTBCD(rtc.mday, 3);
2603e12c5d1SDavid du Colombier 		PUTBCD(rtc.mon, 4);
2613e12c5d1SDavid du Colombier 		PUTBCD(rtc.year, 5);
2623e12c5d1SDavid du Colombier 
2633e12c5d1SDavid du Colombier 		/*
2643e12c5d1SDavid du Colombier 		 *  write the clock
2653e12c5d1SDavid du Colombier 		 */
2667dd7cddfSDavid du Colombier 		ilock(&nvrtlock);
2673e12c5d1SDavid du Colombier 		outb(Paddr, Seconds);	outb(Pdata, bcdclock[0]);
2683e12c5d1SDavid du Colombier 		outb(Paddr, Minutes);	outb(Pdata, bcdclock[1]);
2693e12c5d1SDavid du Colombier 		outb(Paddr, Hours);	outb(Pdata, bcdclock[2]);
2703e12c5d1SDavid du Colombier 		outb(Paddr, Mday);	outb(Pdata, bcdclock[3]);
2713e12c5d1SDavid du Colombier 		outb(Paddr, Month);	outb(Pdata, bcdclock[4]);
2723e12c5d1SDavid du Colombier 		outb(Paddr, Year);	outb(Pdata, bcdclock[5]);
2737dd7cddfSDavid du Colombier 		iunlock(&nvrtlock);
2743e12c5d1SDavid du Colombier 		return n;
275219b2ee8SDavid du Colombier 	case Qnvram:
2767dd7cddfSDavid du Colombier 		if(n == 0)
2777dd7cddfSDavid du Colombier 			return 0;
2787dd7cddfSDavid du Colombier 		if(n > Nvsize)
2797dd7cddfSDavid du Colombier 			n = Nvsize;
2807dd7cddfSDavid du Colombier 
2817dd7cddfSDavid du Colombier 		start = a = smalloc(n);
282219b2ee8SDavid du Colombier 		if(waserror()){
2837dd7cddfSDavid du Colombier 			free(start);
284219b2ee8SDavid du Colombier 			nexterror();
285219b2ee8SDavid du Colombier 		}
2867dd7cddfSDavid du Colombier 		memmove(a, buf, n);
2877dd7cddfSDavid du Colombier 		poperror();
2887dd7cddfSDavid du Colombier 
2897dd7cddfSDavid du Colombier 		ilock(&nvrtlock);
290219b2ee8SDavid du Colombier 		for(t = offset; t < offset + n; t++){
291219b2ee8SDavid du Colombier 			if(t >= Nvsize)
292219b2ee8SDavid du Colombier 				break;
293219b2ee8SDavid du Colombier 			outb(Paddr, Nvoff+t);
294219b2ee8SDavid du Colombier 			outb(Pdata, *a++);
295219b2ee8SDavid du Colombier 		}
2967dd7cddfSDavid du Colombier 		iunlock(&nvrtlock);
2977dd7cddfSDavid du Colombier 
2987dd7cddfSDavid du Colombier 		free(start);
299219b2ee8SDavid du Colombier 		return t - offset;
300219b2ee8SDavid du Colombier 	}
301219b2ee8SDavid du Colombier 	error(Ebadarg);
302219b2ee8SDavid du Colombier 	return 0;
3033e12c5d1SDavid du Colombier }
3043e12c5d1SDavid du Colombier 
3057dd7cddfSDavid du Colombier Dev rtcdevtab = {
3067dd7cddfSDavid du Colombier 	'r',
3077dd7cddfSDavid du Colombier 	"rtc",
3083e12c5d1SDavid du Colombier 
3097dd7cddfSDavid du Colombier 	devreset,
3107dd7cddfSDavid du Colombier 	rtcinit,
311*9a747e4fSDavid du Colombier 	devshutdown,
3127dd7cddfSDavid du Colombier 	rtcattach,
3137dd7cddfSDavid du Colombier 	rtcwalk,
3147dd7cddfSDavid du Colombier 	rtcstat,
3157dd7cddfSDavid du Colombier 	rtcopen,
3167dd7cddfSDavid du Colombier 	devcreate,
3177dd7cddfSDavid du Colombier 	rtcclose,
3187dd7cddfSDavid du Colombier 	rtcread,
3197dd7cddfSDavid du Colombier 	devbread,
3207dd7cddfSDavid du Colombier 	rtcwrite,
3217dd7cddfSDavid du Colombier 	devbwrite,
3227dd7cddfSDavid du Colombier 	devremove,
3237dd7cddfSDavid du Colombier 	devwstat,
3247dd7cddfSDavid du Colombier };
3253e12c5d1SDavid du Colombier 
3263e12c5d1SDavid du Colombier #define SEC2MIN 60L
3273e12c5d1SDavid du Colombier #define SEC2HOUR (60L*SEC2MIN)
3283e12c5d1SDavid du Colombier #define SEC2DAY (24L*SEC2HOUR)
3293e12c5d1SDavid du Colombier 
3303e12c5d1SDavid du Colombier /*
3313e12c5d1SDavid du Colombier  *  days per month plus days/year
3323e12c5d1SDavid du Colombier  */
3333e12c5d1SDavid du Colombier static	int	dmsize[] =
3343e12c5d1SDavid du Colombier {
3353e12c5d1SDavid du Colombier 	365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
3363e12c5d1SDavid du Colombier };
3373e12c5d1SDavid du Colombier static	int	ldmsize[] =
3383e12c5d1SDavid du Colombier {
3393e12c5d1SDavid du Colombier 	366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
3403e12c5d1SDavid du Colombier };
3413e12c5d1SDavid du Colombier 
3423e12c5d1SDavid du Colombier /*
3433e12c5d1SDavid du Colombier  *  return the days/month for the given year
3443e12c5d1SDavid du Colombier  */
3457dd7cddfSDavid du Colombier static int*
yrsize(int y)3467dd7cddfSDavid du Colombier yrsize(int y)
3473e12c5d1SDavid du Colombier {
3487dd7cddfSDavid du Colombier 	if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
3493e12c5d1SDavid du Colombier 		return ldmsize;
3503e12c5d1SDavid du Colombier 	else
3513e12c5d1SDavid du Colombier 		return dmsize;
3523e12c5d1SDavid du Colombier }
3533e12c5d1SDavid du Colombier 
3543e12c5d1SDavid du Colombier /*
3553e12c5d1SDavid du Colombier  *  compute seconds since Jan 1 1970
3563e12c5d1SDavid du Colombier  */
3577dd7cddfSDavid du Colombier static ulong
rtc2sec(Rtc * rtc)3583e12c5d1SDavid du Colombier rtc2sec(Rtc *rtc)
3593e12c5d1SDavid du Colombier {
3603e12c5d1SDavid du Colombier 	ulong secs;
3613e12c5d1SDavid du Colombier 	int i;
3623e12c5d1SDavid du Colombier 	int *d2m;
3633e12c5d1SDavid du Colombier 
3643e12c5d1SDavid du Colombier 	secs = 0;
3653e12c5d1SDavid du Colombier 
3663e12c5d1SDavid du Colombier 	/*
3673e12c5d1SDavid du Colombier 	 *  seconds per year
3683e12c5d1SDavid du Colombier 	 */
3693e12c5d1SDavid du Colombier 	for(i = 1970; i < rtc->year; i++){
3703e12c5d1SDavid du Colombier 		d2m = yrsize(i);
3713e12c5d1SDavid du Colombier 		secs += d2m[0] * SEC2DAY;
3723e12c5d1SDavid du Colombier 	}
3733e12c5d1SDavid du Colombier 
3743e12c5d1SDavid du Colombier 	/*
3753e12c5d1SDavid du Colombier 	 *  seconds per month
3763e12c5d1SDavid du Colombier 	 */
3773e12c5d1SDavid du Colombier 	d2m = yrsize(rtc->year);
3783e12c5d1SDavid du Colombier 	for(i = 1; i < rtc->mon; i++)
3793e12c5d1SDavid du Colombier 		secs += d2m[i] * SEC2DAY;
3803e12c5d1SDavid du Colombier 
3813e12c5d1SDavid du Colombier 	secs += (rtc->mday-1) * SEC2DAY;
3823e12c5d1SDavid du Colombier 	secs += rtc->hour * SEC2HOUR;
3833e12c5d1SDavid du Colombier 	secs += rtc->min * SEC2MIN;
3843e12c5d1SDavid du Colombier 	secs += rtc->sec;
3853e12c5d1SDavid du Colombier 
3863e12c5d1SDavid du Colombier 	return secs;
3873e12c5d1SDavid du Colombier }
3883e12c5d1SDavid du Colombier 
3893e12c5d1SDavid du Colombier /*
3903e12c5d1SDavid du Colombier  *  compute rtc from seconds since Jan 1 1970
3913e12c5d1SDavid du Colombier  */
3927dd7cddfSDavid du Colombier static void
sec2rtc(ulong secs,Rtc * rtc)3933e12c5d1SDavid du Colombier sec2rtc(ulong secs, Rtc *rtc)
3943e12c5d1SDavid du Colombier {
3953e12c5d1SDavid du Colombier 	int d;
3963e12c5d1SDavid du Colombier 	long hms, day;
3973e12c5d1SDavid du Colombier 	int *d2m;
3983e12c5d1SDavid du Colombier 
3993e12c5d1SDavid du Colombier 	/*
4003e12c5d1SDavid du Colombier 	 * break initial number into days
4013e12c5d1SDavid du Colombier 	 */
4023e12c5d1SDavid du Colombier 	hms = secs % SEC2DAY;
4033e12c5d1SDavid du Colombier 	day = secs / SEC2DAY;
4043e12c5d1SDavid du Colombier 	if(hms < 0) {
4053e12c5d1SDavid du Colombier 		hms += SEC2DAY;
4063e12c5d1SDavid du Colombier 		day -= 1;
4073e12c5d1SDavid du Colombier 	}
4083e12c5d1SDavid du Colombier 
4093e12c5d1SDavid du Colombier 	/*
4103e12c5d1SDavid du Colombier 	 * generate hours:minutes:seconds
4113e12c5d1SDavid du Colombier 	 */
4123e12c5d1SDavid du Colombier 	rtc->sec = hms % 60;
4133e12c5d1SDavid du Colombier 	d = hms / 60;
4143e12c5d1SDavid du Colombier 	rtc->min = d % 60;
4153e12c5d1SDavid du Colombier 	d /= 60;
4163e12c5d1SDavid du Colombier 	rtc->hour = d;
4173e12c5d1SDavid du Colombier 
4183e12c5d1SDavid du Colombier 	/*
4193e12c5d1SDavid du Colombier 	 * year number
4203e12c5d1SDavid du Colombier 	 */
4213e12c5d1SDavid du Colombier 	if(day >= 0)
4223e12c5d1SDavid du Colombier 		for(d = 1970; day >= *yrsize(d); d++)
4233e12c5d1SDavid du Colombier 			day -= *yrsize(d);
4243e12c5d1SDavid du Colombier 	else
4253e12c5d1SDavid du Colombier 		for (d = 1970; day < 0; d--)
4263e12c5d1SDavid du Colombier 			day += *yrsize(d-1);
4273e12c5d1SDavid du Colombier 	rtc->year = d;
4283e12c5d1SDavid du Colombier 
4293e12c5d1SDavid du Colombier 	/*
4303e12c5d1SDavid du Colombier 	 * generate month
4313e12c5d1SDavid du Colombier 	 */
4323e12c5d1SDavid du Colombier 	d2m = yrsize(rtc->year);
4333e12c5d1SDavid du Colombier 	for(d = 1; day >= d2m[d]; d++)
4343e12c5d1SDavid du Colombier 		day -= d2m[d];
4353e12c5d1SDavid du Colombier 	rtc->mday = day + 1;
4363e12c5d1SDavid du Colombier 	rtc->mon = d;
4373e12c5d1SDavid du Colombier 
4383e12c5d1SDavid du Colombier 	return;
4393e12c5d1SDavid du Colombier }
440bd389b36SDavid du Colombier 
441bd389b36SDavid du Colombier uchar
nvramread(int addr)4427dd7cddfSDavid du Colombier nvramread(int addr)
443bd389b36SDavid du Colombier {
4447dd7cddfSDavid du Colombier 	uchar data;
4457dd7cddfSDavid du Colombier 
4467dd7cddfSDavid du Colombier 	ilock(&nvrtlock);
4477dd7cddfSDavid du Colombier 	outb(Paddr, addr);
4487dd7cddfSDavid du Colombier 	data = inb(Pdata);
4497dd7cddfSDavid du Colombier 	iunlock(&nvrtlock);
4507dd7cddfSDavid du Colombier 
4517dd7cddfSDavid du Colombier 	return data;
4527dd7cddfSDavid du Colombier }
4537dd7cddfSDavid du Colombier 
4547dd7cddfSDavid du Colombier void
nvramwrite(int addr,uchar data)4557dd7cddfSDavid du Colombier nvramwrite(int addr, uchar data)
4567dd7cddfSDavid du Colombier {
4577dd7cddfSDavid du Colombier 	ilock(&nvrtlock);
4587dd7cddfSDavid du Colombier 	outb(Paddr, addr);
4597dd7cddfSDavid du Colombier 	outb(Pdata, data);
4607dd7cddfSDavid du Colombier 	iunlock(&nvrtlock);
461bd389b36SDavid du Colombier }
462