xref: /plan9-contrib/sys/src/9k/386/devrtc.c (revision b04d1ba28d50c54914fe11ad5f62d5599a9aae00)
19ef1f84bSDavid du Colombier #include	"u.h"
29ef1f84bSDavid du Colombier #include	"../port/lib.h"
39ef1f84bSDavid du Colombier #include	"mem.h"
49ef1f84bSDavid du Colombier #include	"dat.h"
59ef1f84bSDavid du Colombier #include	"fns.h"
69ef1f84bSDavid du Colombier #include	"../port/error.h"
79ef1f84bSDavid du Colombier 
89ef1f84bSDavid du Colombier /*
99ef1f84bSDavid du Colombier  *  real time clock and non-volatile ram
109ef1f84bSDavid du Colombier  */
119ef1f84bSDavid du Colombier 
129ef1f84bSDavid du Colombier enum {
139ef1f84bSDavid du Colombier 	Addr=		0x70,	/* address port */
149ef1f84bSDavid du Colombier 	Data=		0x71,	/* data port */
159ef1f84bSDavid du Colombier 
169ef1f84bSDavid du Colombier 	Seconds=	0x00,
179ef1f84bSDavid du Colombier 	Minutes=	0x02,
189ef1f84bSDavid du Colombier 	Hours=		0x04,
199ef1f84bSDavid du Colombier 	Mday=		0x07,
209ef1f84bSDavid du Colombier 	Month=		0x08,
219ef1f84bSDavid du Colombier 	Year=		0x09,
229ef1f84bSDavid du Colombier 	Status=		0x0A,
239ef1f84bSDavid du Colombier 
249ef1f84bSDavid du Colombier 	Nvoff=		128,	/* where usable nvram lives */
259ef1f84bSDavid du Colombier 	Nvsize=		256,
269ef1f84bSDavid du Colombier 
279ef1f84bSDavid du Colombier 	Nbcd=		6,
289ef1f84bSDavid du Colombier };
299ef1f84bSDavid du Colombier 
309ef1f84bSDavid du Colombier typedef struct Rtc	Rtc;
319ef1f84bSDavid du Colombier struct Rtc
329ef1f84bSDavid du Colombier {
339ef1f84bSDavid du Colombier 	int	sec;
349ef1f84bSDavid du Colombier 	int	min;
359ef1f84bSDavid du Colombier 	int	hour;
369ef1f84bSDavid du Colombier 	int	mday;
379ef1f84bSDavid du Colombier 	int	mon;
389ef1f84bSDavid du Colombier 	int	year;
399ef1f84bSDavid du Colombier };
409ef1f84bSDavid du Colombier 
419ef1f84bSDavid du Colombier 
429ef1f84bSDavid du Colombier enum{
439ef1f84bSDavid du Colombier 	Qdir = 0,
449ef1f84bSDavid du Colombier 	Qrtc,
459ef1f84bSDavid du Colombier 	Qnvram,
469ef1f84bSDavid du Colombier };
479ef1f84bSDavid du Colombier 
489ef1f84bSDavid du Colombier Dirtab rtcdir[]={
499ef1f84bSDavid du Colombier 	".",	{Qdir, 0, QTDIR},	0,	0555,
509ef1f84bSDavid du Colombier 	"nvram",	{Qnvram, 0},	Nvsize,	0664,
519ef1f84bSDavid du Colombier 	"rtc",		{Qrtc, 0},	0,	0664,
529ef1f84bSDavid du Colombier };
539ef1f84bSDavid du Colombier 
549ef1f84bSDavid du Colombier static ulong rtc2sec(Rtc*);
559ef1f84bSDavid du Colombier static void sec2rtc(ulong, Rtc*);
569ef1f84bSDavid du Colombier 
579ef1f84bSDavid du Colombier void
rtcinit(void)589ef1f84bSDavid du Colombier rtcinit(void)
599ef1f84bSDavid du Colombier {
609ef1f84bSDavid du Colombier 	if(ioalloc(Addr, 2, 0, "rtc/nvr") < 0)
619ef1f84bSDavid du Colombier 		panic("rtcinit: ioalloc failed");
629ef1f84bSDavid du Colombier }
639ef1f84bSDavid du Colombier 
649ef1f84bSDavid du Colombier static Chan*
rtcattach(char * spec)659ef1f84bSDavid du Colombier rtcattach(char* spec)
669ef1f84bSDavid du Colombier {
679ef1f84bSDavid du Colombier 	return devattach('r', spec);
689ef1f84bSDavid du Colombier }
699ef1f84bSDavid du Colombier 
709ef1f84bSDavid du Colombier static Walkqid*
rtcwalk(Chan * c,Chan * nc,char ** name,int nname)719ef1f84bSDavid du Colombier rtcwalk(Chan* c, Chan *nc, char** name, int nname)
729ef1f84bSDavid du Colombier {
739ef1f84bSDavid du Colombier 	return devwalk(c, nc, name, nname, rtcdir, nelem(rtcdir), devgen);
749ef1f84bSDavid du Colombier }
759ef1f84bSDavid du Colombier 
769ef1f84bSDavid du Colombier static long
rtcstat(Chan * c,uchar * dp,long n)779ef1f84bSDavid du Colombier rtcstat(Chan* c, uchar* dp, long n)
789ef1f84bSDavid du Colombier {
799ef1f84bSDavid du Colombier 	return devstat(c, dp, n, rtcdir, nelem(rtcdir), devgen);
809ef1f84bSDavid du Colombier }
819ef1f84bSDavid du Colombier 
829ef1f84bSDavid du Colombier static Chan*
rtcopen(Chan * c,int omode)839ef1f84bSDavid du Colombier rtcopen(Chan* c, int omode)
849ef1f84bSDavid du Colombier {
859ef1f84bSDavid du Colombier 	omode = openmode(omode);
869ef1f84bSDavid du Colombier 	switch((ulong)c->qid.path){
879ef1f84bSDavid du Colombier 	case Qrtc:
889ef1f84bSDavid du Colombier 		if(strcmp(up->user, eve)!=0 && omode!=OREAD)
899ef1f84bSDavid du Colombier 			error(Eperm);
909ef1f84bSDavid du Colombier 		break;
919ef1f84bSDavid du Colombier 	case Qnvram:
929ef1f84bSDavid du Colombier 		if(strcmp(up->user, eve)!=0)
939ef1f84bSDavid du Colombier 			error(Eperm);
949ef1f84bSDavid du Colombier 	}
959ef1f84bSDavid du Colombier 	return devopen(c, omode, rtcdir, nelem(rtcdir), devgen);
969ef1f84bSDavid du Colombier }
979ef1f84bSDavid du Colombier 
989ef1f84bSDavid du Colombier static void
rtcclose(Chan *)999ef1f84bSDavid du Colombier rtcclose(Chan*)
1009ef1f84bSDavid du Colombier {
1019ef1f84bSDavid du Colombier }
1029ef1f84bSDavid du Colombier 
1039ef1f84bSDavid du Colombier #define GETBCD(o) ((bcdclock[o]&0xf) + 10*(bcdclock[o]>>4))
1049ef1f84bSDavid du Colombier 
1059ef1f84bSDavid du Colombier static long
rtcextract(void)1069ef1f84bSDavid du Colombier rtcextract(void)
1079ef1f84bSDavid du Colombier {
1089ef1f84bSDavid du Colombier 	uchar bcdclock[Nbcd];
1099ef1f84bSDavid du Colombier 	Rtc rtc;
1109ef1f84bSDavid du Colombier 	int i;
1119ef1f84bSDavid du Colombier 
1129ef1f84bSDavid du Colombier 	/* don't do the read until the clock is no longer busy */
1139ef1f84bSDavid du Colombier 	for(i = 0; i < 10000; i++){
1149ef1f84bSDavid du Colombier 		outb(Addr, Status);
1159ef1f84bSDavid du Colombier 		if(inb(Data) & 0x80)
1169ef1f84bSDavid du Colombier 			continue;
1179ef1f84bSDavid du Colombier 
1189ef1f84bSDavid du Colombier 		/* read clock values */
1199ef1f84bSDavid du Colombier 		outb(Addr, Seconds);	bcdclock[0] = inb(Data);
1209ef1f84bSDavid du Colombier 		outb(Addr, Minutes);	bcdclock[1] = inb(Data);
1219ef1f84bSDavid du Colombier 		outb(Addr, Hours);	bcdclock[2] = inb(Data);
1229ef1f84bSDavid du Colombier 		outb(Addr, Mday);	bcdclock[3] = inb(Data);
1239ef1f84bSDavid du Colombier 		outb(Addr, Month);	bcdclock[4] = inb(Data);
1249ef1f84bSDavid du Colombier 		outb(Addr, Year);	bcdclock[5] = inb(Data);
1259ef1f84bSDavid du Colombier 
1269ef1f84bSDavid du Colombier 		outb(Addr, Status);
1279ef1f84bSDavid du Colombier 		if((inb(Data) & 0x80) == 0)
1289ef1f84bSDavid du Colombier 			break;
1299ef1f84bSDavid du Colombier 	}
1309ef1f84bSDavid du Colombier 
1319ef1f84bSDavid du Colombier 	/*
1329ef1f84bSDavid du Colombier 	 *  convert from BCD
1339ef1f84bSDavid du Colombier 	 */
1349ef1f84bSDavid du Colombier 	rtc.sec = GETBCD(0);
1359ef1f84bSDavid du Colombier 	rtc.min = GETBCD(1);
1369ef1f84bSDavid du Colombier 	rtc.hour = GETBCD(2);
1379ef1f84bSDavid du Colombier 	rtc.mday = GETBCD(3);
1389ef1f84bSDavid du Colombier 	rtc.mon = GETBCD(4);
1399ef1f84bSDavid du Colombier 	rtc.year = GETBCD(5);
1409ef1f84bSDavid du Colombier 
1419ef1f84bSDavid du Colombier 	/*
1429ef1f84bSDavid du Colombier 	 *  the world starts jan 1 1970
1439ef1f84bSDavid du Colombier 	 */
1449ef1f84bSDavid du Colombier 	if(rtc.year < 70)
1459ef1f84bSDavid du Colombier 		rtc.year += 2000;
1469ef1f84bSDavid du Colombier 	else
1479ef1f84bSDavid du Colombier 		rtc.year += 1900;
1489ef1f84bSDavid du Colombier 	return rtc2sec(&rtc);
1499ef1f84bSDavid du Colombier }
1509ef1f84bSDavid du Colombier 
1519ef1f84bSDavid du Colombier static Lock nvrtlock;
1529ef1f84bSDavid du Colombier 
1539ef1f84bSDavid du Colombier long
rtctime(void)1549ef1f84bSDavid du Colombier rtctime(void)
1559ef1f84bSDavid du Colombier {
1569ef1f84bSDavid du Colombier 	int i;
1579ef1f84bSDavid du Colombier 	long t, ot;
1589ef1f84bSDavid du Colombier 
1599ef1f84bSDavid du Colombier 	ilock(&nvrtlock);
1609ef1f84bSDavid du Colombier 
1619ef1f84bSDavid du Colombier 	/* loop till we get two reads in a row the same */
1629ef1f84bSDavid du Colombier 	t = rtcextract();
1639ef1f84bSDavid du Colombier 	for(i = 0; i < 100; i++){
164*b04d1ba2SDavid du Colombier 		ot = t;
165*b04d1ba2SDavid du Colombier 		t = rtcextract();
1669ef1f84bSDavid du Colombier 		if(ot == t)
1679ef1f84bSDavid du Colombier 			break;
1689ef1f84bSDavid du Colombier 	}
1699ef1f84bSDavid du Colombier 	iunlock(&nvrtlock);
1709ef1f84bSDavid du Colombier 
1719ef1f84bSDavid du Colombier 	if(i == 100) print("we are boofheads\n");
1729ef1f84bSDavid du Colombier 
1739ef1f84bSDavid du Colombier 	return t;
1749ef1f84bSDavid du Colombier }
1759ef1f84bSDavid du Colombier 
1769ef1f84bSDavid du Colombier static long
rtcread(Chan * c,void * buf,long n,vlong off)1779ef1f84bSDavid du Colombier rtcread(Chan* c, void* buf, long n, vlong off)
1789ef1f84bSDavid du Colombier {
1799ef1f84bSDavid du Colombier 	ulong t;
1809ef1f84bSDavid du Colombier 	char *a, *start;
1819ef1f84bSDavid du Colombier 	ulong offset = off;
1829ef1f84bSDavid du Colombier 
1839ef1f84bSDavid du Colombier 	if(c->qid.type & QTDIR)
1849ef1f84bSDavid du Colombier 		return devdirread(c, buf, n, rtcdir, nelem(rtcdir), devgen);
1859ef1f84bSDavid du Colombier 
1869ef1f84bSDavid du Colombier 	switch((ulong)c->qid.path){
1879ef1f84bSDavid du Colombier 	case Qrtc:
1889ef1f84bSDavid du Colombier 		t = rtctime();
1899ef1f84bSDavid du Colombier 		n = readnum(offset, buf, n, t, 12);
1909ef1f84bSDavid du Colombier 		return n;
1919ef1f84bSDavid du Colombier 	case Qnvram:
1929ef1f84bSDavid du Colombier 		if(n == 0)
1939ef1f84bSDavid du Colombier 			return 0;
1949ef1f84bSDavid du Colombier 		if(n > Nvsize)
1959ef1f84bSDavid du Colombier 			n = Nvsize;
1969ef1f84bSDavid du Colombier 		a = start = smalloc(n);
1979ef1f84bSDavid du Colombier 
1989ef1f84bSDavid du Colombier 		ilock(&nvrtlock);
1999ef1f84bSDavid du Colombier 		for(t = offset; t < offset + n; t++){
2009ef1f84bSDavid du Colombier 			if(t >= Nvsize)
2019ef1f84bSDavid du Colombier 				break;
2029ef1f84bSDavid du Colombier 			outb(Addr, Nvoff+t);
2039ef1f84bSDavid du Colombier 			*a++ = inb(Data);
2049ef1f84bSDavid du Colombier 		}
2059ef1f84bSDavid du Colombier 		iunlock(&nvrtlock);
2069ef1f84bSDavid du Colombier 
2079ef1f84bSDavid du Colombier 		if(waserror()){
2089ef1f84bSDavid du Colombier 			free(start);
2099ef1f84bSDavid du Colombier 			nexterror();
2109ef1f84bSDavid du Colombier 		}
2119ef1f84bSDavid du Colombier 		memmove(buf, start, t - offset);
2129ef1f84bSDavid du Colombier 		poperror();
2139ef1f84bSDavid du Colombier 
2149ef1f84bSDavid du Colombier 		free(start);
2159ef1f84bSDavid du Colombier 		return t - offset;
2169ef1f84bSDavid du Colombier 	}
2179ef1f84bSDavid du Colombier 	error(Ebadarg);
2189ef1f84bSDavid du Colombier 	return 0;
2199ef1f84bSDavid du Colombier }
2209ef1f84bSDavid du Colombier 
2219ef1f84bSDavid du Colombier #define PUTBCD(n,o) bcdclock[o] = (n % 10) | (((n / 10) % 10)<<4)
2229ef1f84bSDavid du Colombier 
2239ef1f84bSDavid du Colombier static long
rtcwrite(Chan * c,void * buf,long n,vlong off)2249ef1f84bSDavid du Colombier rtcwrite(Chan* c, void* buf, long n, vlong off)
2259ef1f84bSDavid du Colombier {
2269ef1f84bSDavid du Colombier 	int t;
2279ef1f84bSDavid du Colombier 	char *a, *start;
2289ef1f84bSDavid du Colombier 	Rtc rtc;
2299ef1f84bSDavid du Colombier 	ulong secs;
2309ef1f84bSDavid du Colombier 	uchar bcdclock[Nbcd];
2319ef1f84bSDavid du Colombier 	char *cp, *ep;
2329ef1f84bSDavid du Colombier 	ulong offset = off;
2339ef1f84bSDavid du Colombier 
2349ef1f84bSDavid du Colombier 	if(offset!=0)
2359ef1f84bSDavid du Colombier 		error(Ebadarg);
2369ef1f84bSDavid du Colombier 
2379ef1f84bSDavid du Colombier 
2389ef1f84bSDavid du Colombier 	switch((ulong)c->qid.path){
2399ef1f84bSDavid du Colombier 	case Qrtc:
2409ef1f84bSDavid du Colombier 		/*
2419ef1f84bSDavid du Colombier 		 *  read the time
2429ef1f84bSDavid du Colombier 		 */
2439ef1f84bSDavid du Colombier 		cp = ep = buf;
2449ef1f84bSDavid du Colombier 		ep += n;
2459ef1f84bSDavid du Colombier 		while(cp < ep){
2469ef1f84bSDavid du Colombier 			if(*cp>='0' && *cp<='9')
2479ef1f84bSDavid du Colombier 				break;
2489ef1f84bSDavid du Colombier 			cp++;
2499ef1f84bSDavid du Colombier 		}
2509ef1f84bSDavid du Colombier 		secs = strtoul(cp, 0, 0);
2519ef1f84bSDavid du Colombier 
2529ef1f84bSDavid du Colombier 		/*
2539ef1f84bSDavid du Colombier 		 *  convert to bcd
2549ef1f84bSDavid du Colombier 		 */
2559ef1f84bSDavid du Colombier 		sec2rtc(secs, &rtc);
2569ef1f84bSDavid du Colombier 		PUTBCD(rtc.sec, 0);
2579ef1f84bSDavid du Colombier 		PUTBCD(rtc.min, 1);
2589ef1f84bSDavid du Colombier 		PUTBCD(rtc.hour, 2);
2599ef1f84bSDavid du Colombier 		PUTBCD(rtc.mday, 3);
2609ef1f84bSDavid du Colombier 		PUTBCD(rtc.mon, 4);
2619ef1f84bSDavid du Colombier 		PUTBCD(rtc.year, 5);
2629ef1f84bSDavid du Colombier 
2639ef1f84bSDavid du Colombier 		/*
2649ef1f84bSDavid du Colombier 		 *  write the clock
2659ef1f84bSDavid du Colombier 		 */
2669ef1f84bSDavid du Colombier 		ilock(&nvrtlock);
2679ef1f84bSDavid du Colombier 		outb(Addr, Seconds);	outb(Data, bcdclock[0]);
2689ef1f84bSDavid du Colombier 		outb(Addr, Minutes);	outb(Data, bcdclock[1]);
2699ef1f84bSDavid du Colombier 		outb(Addr, Hours);	outb(Data, bcdclock[2]);
2709ef1f84bSDavid du Colombier 		outb(Addr, Mday);	outb(Data, bcdclock[3]);
2719ef1f84bSDavid du Colombier 		outb(Addr, Month);	outb(Data, bcdclock[4]);
2729ef1f84bSDavid du Colombier 		outb(Addr, Year);	outb(Data, bcdclock[5]);
2739ef1f84bSDavid du Colombier 		iunlock(&nvrtlock);
2749ef1f84bSDavid du Colombier 		return n;
2759ef1f84bSDavid du Colombier 	case Qnvram:
2769ef1f84bSDavid du Colombier 		if(n == 0)
2779ef1f84bSDavid du Colombier 			return 0;
2789ef1f84bSDavid du Colombier 		if(n > Nvsize)
2799ef1f84bSDavid du Colombier 			n = Nvsize;
2809ef1f84bSDavid du Colombier 
2819ef1f84bSDavid du Colombier 		start = a = smalloc(n);
2829ef1f84bSDavid du Colombier 		if(waserror()){
2839ef1f84bSDavid du Colombier 			free(start);
2849ef1f84bSDavid du Colombier 			nexterror();
2859ef1f84bSDavid du Colombier 		}
2869ef1f84bSDavid du Colombier 		memmove(a, buf, n);
2879ef1f84bSDavid du Colombier 		poperror();
2889ef1f84bSDavid du Colombier 
2899ef1f84bSDavid du Colombier 		ilock(&nvrtlock);
2909ef1f84bSDavid du Colombier 		for(t = offset; t < offset + n; t++){
2919ef1f84bSDavid du Colombier 			if(t >= Nvsize)
2929ef1f84bSDavid du Colombier 				break;
2939ef1f84bSDavid du Colombier 			outb(Addr, Nvoff+t);
2949ef1f84bSDavid du Colombier 			outb(Data, *a++);
2959ef1f84bSDavid du Colombier 		}
2969ef1f84bSDavid du Colombier 		iunlock(&nvrtlock);
2979ef1f84bSDavid du Colombier 
2989ef1f84bSDavid du Colombier 		free(start);
2999ef1f84bSDavid du Colombier 		return t - offset;
3009ef1f84bSDavid du Colombier 	}
3019ef1f84bSDavid du Colombier 	error(Ebadarg);
3029ef1f84bSDavid du Colombier 	return 0;
3039ef1f84bSDavid du Colombier }
3049ef1f84bSDavid du Colombier 
3059ef1f84bSDavid du Colombier Dev rtcdevtab = {
3069ef1f84bSDavid du Colombier 	'r',
3079ef1f84bSDavid du Colombier 	"rtc",
3089ef1f84bSDavid du Colombier 
3099ef1f84bSDavid du Colombier 	devreset,
3109ef1f84bSDavid du Colombier 	rtcinit,
3119ef1f84bSDavid du Colombier 	devshutdown,
3129ef1f84bSDavid du Colombier 	rtcattach,
3139ef1f84bSDavid du Colombier 	rtcwalk,
3149ef1f84bSDavid du Colombier 	rtcstat,
3159ef1f84bSDavid du Colombier 	rtcopen,
3169ef1f84bSDavid du Colombier 	devcreate,
3179ef1f84bSDavid du Colombier 	rtcclose,
3189ef1f84bSDavid du Colombier 	rtcread,
3199ef1f84bSDavid du Colombier 	devbread,
3209ef1f84bSDavid du Colombier 	rtcwrite,
3219ef1f84bSDavid du Colombier 	devbwrite,
3229ef1f84bSDavid du Colombier 	devremove,
3239ef1f84bSDavid du Colombier 	devwstat,
3249ef1f84bSDavid du Colombier };
3259ef1f84bSDavid du Colombier 
3269ef1f84bSDavid du Colombier #define SEC2MIN 60L
3279ef1f84bSDavid du Colombier #define SEC2HOUR (60L*SEC2MIN)
3289ef1f84bSDavid du Colombier #define SEC2DAY (24L*SEC2HOUR)
3299ef1f84bSDavid du Colombier 
3309ef1f84bSDavid du Colombier /*
3319ef1f84bSDavid du Colombier  *  days per month plus days/year
3329ef1f84bSDavid du Colombier  */
3339ef1f84bSDavid du Colombier static	int	dmsize[] =
3349ef1f84bSDavid du Colombier {
3359ef1f84bSDavid du Colombier 	365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
3369ef1f84bSDavid du Colombier };
3379ef1f84bSDavid du Colombier static	int	ldmsize[] =
3389ef1f84bSDavid du Colombier {
3399ef1f84bSDavid du Colombier 	366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
3409ef1f84bSDavid du Colombier };
3419ef1f84bSDavid du Colombier 
3429ef1f84bSDavid du Colombier /*
3439ef1f84bSDavid du Colombier  *  return the days/month for the given year
3449ef1f84bSDavid du Colombier  */
3459ef1f84bSDavid du Colombier static int*
yrsize(int y)3469ef1f84bSDavid du Colombier yrsize(int y)
3479ef1f84bSDavid du Colombier {
3489ef1f84bSDavid du Colombier 	if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
3499ef1f84bSDavid du Colombier 		return ldmsize;
3509ef1f84bSDavid du Colombier 	else
3519ef1f84bSDavid du Colombier 		return dmsize;
3529ef1f84bSDavid du Colombier }
3539ef1f84bSDavid du Colombier 
3549ef1f84bSDavid du Colombier /*
3559ef1f84bSDavid du Colombier  *  compute seconds since Jan 1 1970
3569ef1f84bSDavid du Colombier  */
3579ef1f84bSDavid du Colombier static ulong
rtc2sec(Rtc * rtc)3589ef1f84bSDavid du Colombier rtc2sec(Rtc *rtc)
3599ef1f84bSDavid du Colombier {
3609ef1f84bSDavid du Colombier 	ulong secs;
3619ef1f84bSDavid du Colombier 	int i;
3629ef1f84bSDavid du Colombier 	int *d2m;
3639ef1f84bSDavid du Colombier 
3649ef1f84bSDavid du Colombier 	secs = 0;
3659ef1f84bSDavid du Colombier 
3669ef1f84bSDavid du Colombier 	/*
3679ef1f84bSDavid du Colombier 	 *  seconds per year
3689ef1f84bSDavid du Colombier 	 */
3699ef1f84bSDavid du Colombier 	for(i = 1970; i < rtc->year; i++){
3709ef1f84bSDavid du Colombier 		d2m = yrsize(i);
3719ef1f84bSDavid du Colombier 		secs += d2m[0] * SEC2DAY;
3729ef1f84bSDavid du Colombier 	}
3739ef1f84bSDavid du Colombier 
3749ef1f84bSDavid du Colombier 	/*
3759ef1f84bSDavid du Colombier 	 *  seconds per month
3769ef1f84bSDavid du Colombier 	 */
3779ef1f84bSDavid du Colombier 	d2m = yrsize(rtc->year);
3789ef1f84bSDavid du Colombier 	for(i = 1; i < rtc->mon; i++)
3799ef1f84bSDavid du Colombier 		secs += d2m[i] * SEC2DAY;
3809ef1f84bSDavid du Colombier 
3819ef1f84bSDavid du Colombier 	secs += (rtc->mday-1) * SEC2DAY;
3829ef1f84bSDavid du Colombier 	secs += rtc->hour * SEC2HOUR;
3839ef1f84bSDavid du Colombier 	secs += rtc->min * SEC2MIN;
3849ef1f84bSDavid du Colombier 	secs += rtc->sec;
3859ef1f84bSDavid du Colombier 
3869ef1f84bSDavid du Colombier 	return secs;
3879ef1f84bSDavid du Colombier }
3889ef1f84bSDavid du Colombier 
3899ef1f84bSDavid du Colombier /*
3909ef1f84bSDavid du Colombier  *  compute rtc from seconds since Jan 1 1970
3919ef1f84bSDavid du Colombier  */
3929ef1f84bSDavid du Colombier static void
sec2rtc(ulong secs,Rtc * rtc)3939ef1f84bSDavid du Colombier sec2rtc(ulong secs, Rtc *rtc)
3949ef1f84bSDavid du Colombier {
3959ef1f84bSDavid du Colombier 	int d;
3969ef1f84bSDavid du Colombier 	long hms, day;
3979ef1f84bSDavid du Colombier 	int *d2m;
3989ef1f84bSDavid du Colombier 
3999ef1f84bSDavid du Colombier 	/*
4009ef1f84bSDavid du Colombier 	 * break initial number into days
4019ef1f84bSDavid du Colombier 	 */
4029ef1f84bSDavid du Colombier 	hms = secs % SEC2DAY;
4039ef1f84bSDavid du Colombier 	day = secs / SEC2DAY;
4049ef1f84bSDavid du Colombier 	if(hms < 0) {
4059ef1f84bSDavid du Colombier 		hms += SEC2DAY;
4069ef1f84bSDavid du Colombier 		day -= 1;
4079ef1f84bSDavid du Colombier 	}
4089ef1f84bSDavid du Colombier 
4099ef1f84bSDavid du Colombier 	/*
4109ef1f84bSDavid du Colombier 	 * generate hours:minutes:seconds
4119ef1f84bSDavid du Colombier 	 */
4129ef1f84bSDavid du Colombier 	rtc->sec = hms % 60;
4139ef1f84bSDavid du Colombier 	d = hms / 60;
4149ef1f84bSDavid du Colombier 	rtc->min = d % 60;
4159ef1f84bSDavid du Colombier 	d /= 60;
4169ef1f84bSDavid du Colombier 	rtc->hour = d;
4179ef1f84bSDavid du Colombier 
4189ef1f84bSDavid du Colombier 	/*
4199ef1f84bSDavid du Colombier 	 * year number
4209ef1f84bSDavid du Colombier 	 */
4219ef1f84bSDavid du Colombier 	if(day >= 0)
4229ef1f84bSDavid du Colombier 		for(d = 1970; day >= *yrsize(d); d++)
4239ef1f84bSDavid du Colombier 			day -= *yrsize(d);
4249ef1f84bSDavid du Colombier 	else
4259ef1f84bSDavid du Colombier 		for (d = 1970; day < 0; d--)
4269ef1f84bSDavid du Colombier 			day += *yrsize(d-1);
4279ef1f84bSDavid du Colombier 	rtc->year = d;
4289ef1f84bSDavid du Colombier 
4299ef1f84bSDavid du Colombier 	/*
4309ef1f84bSDavid du Colombier 	 * generate month
4319ef1f84bSDavid du Colombier 	 */
4329ef1f84bSDavid du Colombier 	d2m = yrsize(rtc->year);
4339ef1f84bSDavid du Colombier 	for(d = 1; day >= d2m[d]; d++)
4349ef1f84bSDavid du Colombier 		day -= d2m[d];
4359ef1f84bSDavid du Colombier 	rtc->mday = day + 1;
4369ef1f84bSDavid du Colombier 	rtc->mon = d;
4379ef1f84bSDavid du Colombier 
4389ef1f84bSDavid du Colombier 	return;
4399ef1f84bSDavid du Colombier }
4409ef1f84bSDavid du Colombier 
4419ef1f84bSDavid du Colombier uchar
nvramread(int addr)4429ef1f84bSDavid du Colombier nvramread(int addr)
4439ef1f84bSDavid du Colombier {
4449ef1f84bSDavid du Colombier 	uchar data;
4459ef1f84bSDavid du Colombier 
4469ef1f84bSDavid du Colombier 	ilock(&nvrtlock);
4479ef1f84bSDavid du Colombier 	outb(Addr, addr);
4489ef1f84bSDavid du Colombier 	data = inb(Data);
4499ef1f84bSDavid du Colombier 	iunlock(&nvrtlock);
4509ef1f84bSDavid du Colombier 
4519ef1f84bSDavid du Colombier 	return data;
4529ef1f84bSDavid du Colombier }
4539ef1f84bSDavid du Colombier 
4549ef1f84bSDavid du Colombier void
nvramwrite(int addr,uchar data)4559ef1f84bSDavid du Colombier nvramwrite(int addr, uchar data)
4569ef1f84bSDavid du Colombier {
4579ef1f84bSDavid du Colombier 	ilock(&nvrtlock);
4589ef1f84bSDavid du Colombier 	outb(Addr, addr);
4599ef1f84bSDavid du Colombier 	outb(Data, data);
4609ef1f84bSDavid du Colombier 	iunlock(&nvrtlock);
4619ef1f84bSDavid du Colombier }
462