xref: /inferno-os/os/pc/devrtc.c (revision 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a)
1*74a4d8c2SCharles.Forsyth #include	"u.h"
2*74a4d8c2SCharles.Forsyth #include	"../port/lib.h"
3*74a4d8c2SCharles.Forsyth #include	"mem.h"
4*74a4d8c2SCharles.Forsyth #include	"dat.h"
5*74a4d8c2SCharles.Forsyth #include	"fns.h"
6*74a4d8c2SCharles.Forsyth #include	"../port/error.h"
7*74a4d8c2SCharles.Forsyth 
8*74a4d8c2SCharles.Forsyth /*
9*74a4d8c2SCharles.Forsyth  *  real time clock and non-volatile ram
10*74a4d8c2SCharles.Forsyth  */
11*74a4d8c2SCharles.Forsyth 
12*74a4d8c2SCharles.Forsyth enum {
13*74a4d8c2SCharles.Forsyth 	Paddr=		0x70,	/* address port */
14*74a4d8c2SCharles.Forsyth 	Pdata=		0x71,	/* data port */
15*74a4d8c2SCharles.Forsyth 
16*74a4d8c2SCharles.Forsyth 	Seconds=	0x00,
17*74a4d8c2SCharles.Forsyth 	Minutes=	0x02,
18*74a4d8c2SCharles.Forsyth 	Hours=		0x04,
19*74a4d8c2SCharles.Forsyth 	Mday=		0x07,
20*74a4d8c2SCharles.Forsyth 	Month=		0x08,
21*74a4d8c2SCharles.Forsyth 	Year=		0x09,
22*74a4d8c2SCharles.Forsyth 	Status=		0x0A,
23*74a4d8c2SCharles.Forsyth 
24*74a4d8c2SCharles.Forsyth 	Nvoff=		128,	/* where usable nvram lives */
25*74a4d8c2SCharles.Forsyth 	Nvsize=		256,
26*74a4d8c2SCharles.Forsyth 
27*74a4d8c2SCharles.Forsyth 	Nbcd=		6,
28*74a4d8c2SCharles.Forsyth };
29*74a4d8c2SCharles.Forsyth 
30*74a4d8c2SCharles.Forsyth typedef struct Rtc	Rtc;
31*74a4d8c2SCharles.Forsyth struct Rtc
32*74a4d8c2SCharles.Forsyth {
33*74a4d8c2SCharles.Forsyth 	int	sec;
34*74a4d8c2SCharles.Forsyth 	int	min;
35*74a4d8c2SCharles.Forsyth 	int	hour;
36*74a4d8c2SCharles.Forsyth 	int	mday;
37*74a4d8c2SCharles.Forsyth 	int	mon;
38*74a4d8c2SCharles.Forsyth 	int	year;
39*74a4d8c2SCharles.Forsyth };
40*74a4d8c2SCharles.Forsyth 
41*74a4d8c2SCharles.Forsyth 
42*74a4d8c2SCharles.Forsyth enum{
43*74a4d8c2SCharles.Forsyth 	Qdir = 0,
44*74a4d8c2SCharles.Forsyth 	Qrtc,
45*74a4d8c2SCharles.Forsyth 	Qnvram,
46*74a4d8c2SCharles.Forsyth };
47*74a4d8c2SCharles.Forsyth 
48*74a4d8c2SCharles.Forsyth Dirtab rtcdir[]={
49*74a4d8c2SCharles.Forsyth 	".",	{Qdir, 0, QTDIR},	0,	0555,
50*74a4d8c2SCharles.Forsyth 	"nvram",	{Qnvram, 0},	Nvsize,	0664,
51*74a4d8c2SCharles.Forsyth 	"rtc",		{Qrtc, 0},	0,	0664,
52*74a4d8c2SCharles.Forsyth };
53*74a4d8c2SCharles.Forsyth 
54*74a4d8c2SCharles.Forsyth static ulong rtc2sec(Rtc*);
55*74a4d8c2SCharles.Forsyth static void sec2rtc(ulong, Rtc*);
56*74a4d8c2SCharles.Forsyth 
57*74a4d8c2SCharles.Forsyth void
rtcinit(void)58*74a4d8c2SCharles.Forsyth rtcinit(void)
59*74a4d8c2SCharles.Forsyth {
60*74a4d8c2SCharles.Forsyth 	if(ioalloc(Paddr, 2, 0, "rtc/nvr") < 0)
61*74a4d8c2SCharles.Forsyth 		panic("rtcinit: ioalloc failed");
62*74a4d8c2SCharles.Forsyth }
63*74a4d8c2SCharles.Forsyth 
64*74a4d8c2SCharles.Forsyth static Chan*
rtcattach(char * spec)65*74a4d8c2SCharles.Forsyth rtcattach(char* spec)
66*74a4d8c2SCharles.Forsyth {
67*74a4d8c2SCharles.Forsyth 	return devattach('r', spec);
68*74a4d8c2SCharles.Forsyth }
69*74a4d8c2SCharles.Forsyth 
70*74a4d8c2SCharles.Forsyth static Walkqid*
rtcwalk(Chan * c,Chan * nc,char ** name,int nname)71*74a4d8c2SCharles.Forsyth rtcwalk(Chan* c, Chan *nc, char** name, int nname)
72*74a4d8c2SCharles.Forsyth {
73*74a4d8c2SCharles.Forsyth 	return devwalk(c, nc, name, nname, rtcdir, nelem(rtcdir), devgen);
74*74a4d8c2SCharles.Forsyth }
75*74a4d8c2SCharles.Forsyth 
76*74a4d8c2SCharles.Forsyth static int
rtcstat(Chan * c,uchar * dp,int n)77*74a4d8c2SCharles.Forsyth rtcstat(Chan* c, uchar* dp, int n)
78*74a4d8c2SCharles.Forsyth {
79*74a4d8c2SCharles.Forsyth 	return devstat(c, dp, n, rtcdir, nelem(rtcdir), devgen);
80*74a4d8c2SCharles.Forsyth }
81*74a4d8c2SCharles.Forsyth 
82*74a4d8c2SCharles.Forsyth static Chan*
rtcopen(Chan * c,int omode)83*74a4d8c2SCharles.Forsyth rtcopen(Chan* c, int omode)
84*74a4d8c2SCharles.Forsyth {
85*74a4d8c2SCharles.Forsyth 	omode = openmode(omode);
86*74a4d8c2SCharles.Forsyth 	switch((ulong)c->qid.path){
87*74a4d8c2SCharles.Forsyth 	case Qrtc:
88*74a4d8c2SCharles.Forsyth 		if(strcmp(up->env->user, eve)!=0 && omode!=OREAD)
89*74a4d8c2SCharles.Forsyth 			error(Eperm);
90*74a4d8c2SCharles.Forsyth 		break;
91*74a4d8c2SCharles.Forsyth 	case Qnvram:
92*74a4d8c2SCharles.Forsyth 		if(strcmp(up->env->user, eve)!=0)
93*74a4d8c2SCharles.Forsyth 			error(Eperm);
94*74a4d8c2SCharles.Forsyth 	}
95*74a4d8c2SCharles.Forsyth 	return devopen(c, omode, rtcdir, nelem(rtcdir), devgen);
96*74a4d8c2SCharles.Forsyth }
97*74a4d8c2SCharles.Forsyth 
98*74a4d8c2SCharles.Forsyth static void
rtcclose(Chan *)99*74a4d8c2SCharles.Forsyth rtcclose(Chan*)
100*74a4d8c2SCharles.Forsyth {
101*74a4d8c2SCharles.Forsyth }
102*74a4d8c2SCharles.Forsyth 
103*74a4d8c2SCharles.Forsyth #define GETBCD(o) ((bcdclock[o]&0xf) + 10*(bcdclock[o]>>4))
104*74a4d8c2SCharles.Forsyth 
105*74a4d8c2SCharles.Forsyth static long
_rtctime(void)106*74a4d8c2SCharles.Forsyth _rtctime(void)
107*74a4d8c2SCharles.Forsyth {
108*74a4d8c2SCharles.Forsyth 	uchar bcdclock[Nbcd];
109*74a4d8c2SCharles.Forsyth 	Rtc rtc;
110*74a4d8c2SCharles.Forsyth 	int i;
111*74a4d8c2SCharles.Forsyth 
112*74a4d8c2SCharles.Forsyth 	/* don't do the read until the clock is no longer busy */
113*74a4d8c2SCharles.Forsyth 	for(i = 0; i < 10000; i++){
114*74a4d8c2SCharles.Forsyth 		outb(Paddr, Status);
115*74a4d8c2SCharles.Forsyth 		if(inb(Pdata) & 0x80)
116*74a4d8c2SCharles.Forsyth 			continue;
117*74a4d8c2SCharles.Forsyth 
118*74a4d8c2SCharles.Forsyth 		/* read clock values */
119*74a4d8c2SCharles.Forsyth 		outb(Paddr, Seconds);	bcdclock[0] = inb(Pdata);
120*74a4d8c2SCharles.Forsyth 		outb(Paddr, Minutes);	bcdclock[1] = inb(Pdata);
121*74a4d8c2SCharles.Forsyth 		outb(Paddr, Hours);	bcdclock[2] = inb(Pdata);
122*74a4d8c2SCharles.Forsyth 		outb(Paddr, Mday);	bcdclock[3] = inb(Pdata);
123*74a4d8c2SCharles.Forsyth 		outb(Paddr, Month);	bcdclock[4] = inb(Pdata);
124*74a4d8c2SCharles.Forsyth 		outb(Paddr, Year);	bcdclock[5] = inb(Pdata);
125*74a4d8c2SCharles.Forsyth 
126*74a4d8c2SCharles.Forsyth 		outb(Paddr, Status);
127*74a4d8c2SCharles.Forsyth 		if((inb(Pdata) & 0x80) == 0)
128*74a4d8c2SCharles.Forsyth 			break;
129*74a4d8c2SCharles.Forsyth 	}
130*74a4d8c2SCharles.Forsyth 
131*74a4d8c2SCharles.Forsyth 	/*
132*74a4d8c2SCharles.Forsyth 	 *  convert from BCD
133*74a4d8c2SCharles.Forsyth 	 */
134*74a4d8c2SCharles.Forsyth 	rtc.sec = GETBCD(0);
135*74a4d8c2SCharles.Forsyth 	rtc.min = GETBCD(1);
136*74a4d8c2SCharles.Forsyth 	rtc.hour = GETBCD(2);
137*74a4d8c2SCharles.Forsyth 	rtc.mday = GETBCD(3);
138*74a4d8c2SCharles.Forsyth 	rtc.mon = GETBCD(4);
139*74a4d8c2SCharles.Forsyth 	rtc.year = GETBCD(5);
140*74a4d8c2SCharles.Forsyth 
141*74a4d8c2SCharles.Forsyth 	/*
142*74a4d8c2SCharles.Forsyth 	 *  the world starts jan 1 1970
143*74a4d8c2SCharles.Forsyth 	 */
144*74a4d8c2SCharles.Forsyth 	if(rtc.year < 70)
145*74a4d8c2SCharles.Forsyth 		rtc.year += 2000;
146*74a4d8c2SCharles.Forsyth 	else
147*74a4d8c2SCharles.Forsyth 		rtc.year += 1900;
148*74a4d8c2SCharles.Forsyth 	return rtc2sec(&rtc);
149*74a4d8c2SCharles.Forsyth }
150*74a4d8c2SCharles.Forsyth 
151*74a4d8c2SCharles.Forsyth static Lock nvrtlock;
152*74a4d8c2SCharles.Forsyth 
153*74a4d8c2SCharles.Forsyth long
rtctime(void)154*74a4d8c2SCharles.Forsyth rtctime(void)
155*74a4d8c2SCharles.Forsyth {
156*74a4d8c2SCharles.Forsyth 	int i;
157*74a4d8c2SCharles.Forsyth 	long t, ot;
158*74a4d8c2SCharles.Forsyth 
159*74a4d8c2SCharles.Forsyth 	ilock(&nvrtlock);
160*74a4d8c2SCharles.Forsyth 
161*74a4d8c2SCharles.Forsyth 	/* loop till we get two reads in a row the same */
162*74a4d8c2SCharles.Forsyth 	t = _rtctime();
163*74a4d8c2SCharles.Forsyth 	for(i = 0; i < 100; i++){
164*74a4d8c2SCharles.Forsyth 		ot = t;
165*74a4d8c2SCharles.Forsyth 		t = _rtctime();
166*74a4d8c2SCharles.Forsyth 		if(ot == t)
167*74a4d8c2SCharles.Forsyth 			break;
168*74a4d8c2SCharles.Forsyth 	}
169*74a4d8c2SCharles.Forsyth 	if(i == 100) print("we are boofheads\n");
170*74a4d8c2SCharles.Forsyth 
171*74a4d8c2SCharles.Forsyth 	iunlock(&nvrtlock);
172*74a4d8c2SCharles.Forsyth 
173*74a4d8c2SCharles.Forsyth 	return t;
174*74a4d8c2SCharles.Forsyth }
175*74a4d8c2SCharles.Forsyth 
176*74a4d8c2SCharles.Forsyth static long
rtcread(Chan * c,void * buf,long n,vlong off)177*74a4d8c2SCharles.Forsyth rtcread(Chan* c, void* buf, long n, vlong off)
178*74a4d8c2SCharles.Forsyth {
179*74a4d8c2SCharles.Forsyth 	ulong t;
180*74a4d8c2SCharles.Forsyth 	char *a, *start;
181*74a4d8c2SCharles.Forsyth 	ulong offset = off;
182*74a4d8c2SCharles.Forsyth 
183*74a4d8c2SCharles.Forsyth 	if(c->qid.type & QTDIR)
184*74a4d8c2SCharles.Forsyth 		return devdirread(c, buf, n, rtcdir, nelem(rtcdir), devgen);
185*74a4d8c2SCharles.Forsyth 
186*74a4d8c2SCharles.Forsyth 	switch((ulong)c->qid.path){
187*74a4d8c2SCharles.Forsyth 	case Qrtc:
188*74a4d8c2SCharles.Forsyth 		t = rtctime();
189*74a4d8c2SCharles.Forsyth 		n = readnum(offset, buf, n, t, 12);
190*74a4d8c2SCharles.Forsyth 		return n;
191*74a4d8c2SCharles.Forsyth 	case Qnvram:
192*74a4d8c2SCharles.Forsyth 		if(n == 0)
193*74a4d8c2SCharles.Forsyth 			return 0;
194*74a4d8c2SCharles.Forsyth 		if(n > Nvsize)
195*74a4d8c2SCharles.Forsyth 			n = Nvsize;
196*74a4d8c2SCharles.Forsyth 		a = start = smalloc(n);
197*74a4d8c2SCharles.Forsyth 
198*74a4d8c2SCharles.Forsyth 		ilock(&nvrtlock);
199*74a4d8c2SCharles.Forsyth 		for(t = offset; t < offset + n; t++){
200*74a4d8c2SCharles.Forsyth 			if(t >= Nvsize)
201*74a4d8c2SCharles.Forsyth 				break;
202*74a4d8c2SCharles.Forsyth 			outb(Paddr, Nvoff+t);
203*74a4d8c2SCharles.Forsyth 			*a++ = inb(Pdata);
204*74a4d8c2SCharles.Forsyth 		}
205*74a4d8c2SCharles.Forsyth 		iunlock(&nvrtlock);
206*74a4d8c2SCharles.Forsyth 
207*74a4d8c2SCharles.Forsyth 		if(waserror()){
208*74a4d8c2SCharles.Forsyth 			free(start);
209*74a4d8c2SCharles.Forsyth 			nexterror();
210*74a4d8c2SCharles.Forsyth 		}
211*74a4d8c2SCharles.Forsyth 		memmove(buf, start, t - offset);
212*74a4d8c2SCharles.Forsyth 		poperror();
213*74a4d8c2SCharles.Forsyth 
214*74a4d8c2SCharles.Forsyth 		free(start);
215*74a4d8c2SCharles.Forsyth 		return t - offset;
216*74a4d8c2SCharles.Forsyth 	}
217*74a4d8c2SCharles.Forsyth 	error(Ebadarg);
218*74a4d8c2SCharles.Forsyth 	return 0;
219*74a4d8c2SCharles.Forsyth }
220*74a4d8c2SCharles.Forsyth 
221*74a4d8c2SCharles.Forsyth #define PUTBCD(n,o) bcdclock[o] = (n % 10) | (((n / 10) % 10)<<4)
222*74a4d8c2SCharles.Forsyth 
223*74a4d8c2SCharles.Forsyth static long
rtcwrite(Chan * c,void * buf,long n,vlong off)224*74a4d8c2SCharles.Forsyth rtcwrite(Chan* c, void* buf, long n, vlong off)
225*74a4d8c2SCharles.Forsyth {
226*74a4d8c2SCharles.Forsyth 	int t;
227*74a4d8c2SCharles.Forsyth 	char *a, *start;
228*74a4d8c2SCharles.Forsyth 	Rtc rtc;
229*74a4d8c2SCharles.Forsyth 	ulong secs;
230*74a4d8c2SCharles.Forsyth 	uchar bcdclock[Nbcd];
231*74a4d8c2SCharles.Forsyth 	char *cp, *ep;
232*74a4d8c2SCharles.Forsyth 	ulong offset = off;
233*74a4d8c2SCharles.Forsyth 
234*74a4d8c2SCharles.Forsyth 	if(offset!=0)
235*74a4d8c2SCharles.Forsyth 		error(Ebadarg);
236*74a4d8c2SCharles.Forsyth 
237*74a4d8c2SCharles.Forsyth 
238*74a4d8c2SCharles.Forsyth 	switch((ulong)c->qid.path){
239*74a4d8c2SCharles.Forsyth 	case Qrtc:
240*74a4d8c2SCharles.Forsyth 		/*
241*74a4d8c2SCharles.Forsyth 		 *  read the time
242*74a4d8c2SCharles.Forsyth 		 */
243*74a4d8c2SCharles.Forsyth 		cp = ep = buf;
244*74a4d8c2SCharles.Forsyth 		ep += n;
245*74a4d8c2SCharles.Forsyth 		while(cp < ep){
246*74a4d8c2SCharles.Forsyth 			if(*cp>='0' && *cp<='9')
247*74a4d8c2SCharles.Forsyth 				break;
248*74a4d8c2SCharles.Forsyth 			cp++;
249*74a4d8c2SCharles.Forsyth 		}
250*74a4d8c2SCharles.Forsyth 		secs = strtoul(cp, 0, 0);
251*74a4d8c2SCharles.Forsyth 
252*74a4d8c2SCharles.Forsyth 		/*
253*74a4d8c2SCharles.Forsyth 		 *  convert to bcd
254*74a4d8c2SCharles.Forsyth 		 */
255*74a4d8c2SCharles.Forsyth 		sec2rtc(secs, &rtc);
256*74a4d8c2SCharles.Forsyth 		PUTBCD(rtc.sec, 0);
257*74a4d8c2SCharles.Forsyth 		PUTBCD(rtc.min, 1);
258*74a4d8c2SCharles.Forsyth 		PUTBCD(rtc.hour, 2);
259*74a4d8c2SCharles.Forsyth 		PUTBCD(rtc.mday, 3);
260*74a4d8c2SCharles.Forsyth 		PUTBCD(rtc.mon, 4);
261*74a4d8c2SCharles.Forsyth 		PUTBCD(rtc.year, 5);
262*74a4d8c2SCharles.Forsyth 
263*74a4d8c2SCharles.Forsyth 		/*
264*74a4d8c2SCharles.Forsyth 		 *  write the clock
265*74a4d8c2SCharles.Forsyth 		 */
266*74a4d8c2SCharles.Forsyth 		ilock(&nvrtlock);
267*74a4d8c2SCharles.Forsyth 		outb(Paddr, Seconds);	outb(Pdata, bcdclock[0]);
268*74a4d8c2SCharles.Forsyth 		outb(Paddr, Minutes);	outb(Pdata, bcdclock[1]);
269*74a4d8c2SCharles.Forsyth 		outb(Paddr, Hours);	outb(Pdata, bcdclock[2]);
270*74a4d8c2SCharles.Forsyth 		outb(Paddr, Mday);	outb(Pdata, bcdclock[3]);
271*74a4d8c2SCharles.Forsyth 		outb(Paddr, Month);	outb(Pdata, bcdclock[4]);
272*74a4d8c2SCharles.Forsyth 		outb(Paddr, Year);	outb(Pdata, bcdclock[5]);
273*74a4d8c2SCharles.Forsyth 		iunlock(&nvrtlock);
274*74a4d8c2SCharles.Forsyth 		return n;
275*74a4d8c2SCharles.Forsyth 	case Qnvram:
276*74a4d8c2SCharles.Forsyth 		if(n == 0)
277*74a4d8c2SCharles.Forsyth 			return 0;
278*74a4d8c2SCharles.Forsyth 		if(n > Nvsize)
279*74a4d8c2SCharles.Forsyth 			n = Nvsize;
280*74a4d8c2SCharles.Forsyth 
281*74a4d8c2SCharles.Forsyth 		start = a = smalloc(n);
282*74a4d8c2SCharles.Forsyth 		if(waserror()){
283*74a4d8c2SCharles.Forsyth 			free(start);
284*74a4d8c2SCharles.Forsyth 			nexterror();
285*74a4d8c2SCharles.Forsyth 		}
286*74a4d8c2SCharles.Forsyth 		memmove(a, buf, n);
287*74a4d8c2SCharles.Forsyth 		poperror();
288*74a4d8c2SCharles.Forsyth 
289*74a4d8c2SCharles.Forsyth 		ilock(&nvrtlock);
290*74a4d8c2SCharles.Forsyth 		for(t = offset; t < offset + n; t++){
291*74a4d8c2SCharles.Forsyth 			if(t >= Nvsize)
292*74a4d8c2SCharles.Forsyth 				break;
293*74a4d8c2SCharles.Forsyth 			outb(Paddr, Nvoff+t);
294*74a4d8c2SCharles.Forsyth 			outb(Pdata, *a++);
295*74a4d8c2SCharles.Forsyth 		}
296*74a4d8c2SCharles.Forsyth 		iunlock(&nvrtlock);
297*74a4d8c2SCharles.Forsyth 
298*74a4d8c2SCharles.Forsyth 		free(start);
299*74a4d8c2SCharles.Forsyth 		return t - offset;
300*74a4d8c2SCharles.Forsyth 	}
301*74a4d8c2SCharles.Forsyth 	error(Ebadarg);
302*74a4d8c2SCharles.Forsyth 	return 0;
303*74a4d8c2SCharles.Forsyth }
304*74a4d8c2SCharles.Forsyth 
305*74a4d8c2SCharles.Forsyth Dev rtcdevtab = {
306*74a4d8c2SCharles.Forsyth 	'r',
307*74a4d8c2SCharles.Forsyth 	"rtc",
308*74a4d8c2SCharles.Forsyth 
309*74a4d8c2SCharles.Forsyth 	devreset,
310*74a4d8c2SCharles.Forsyth 	rtcinit,
311*74a4d8c2SCharles.Forsyth 	devshutdown,
312*74a4d8c2SCharles.Forsyth 	rtcattach,
313*74a4d8c2SCharles.Forsyth 	rtcwalk,
314*74a4d8c2SCharles.Forsyth 	rtcstat,
315*74a4d8c2SCharles.Forsyth 	rtcopen,
316*74a4d8c2SCharles.Forsyth 	devcreate,
317*74a4d8c2SCharles.Forsyth 	rtcclose,
318*74a4d8c2SCharles.Forsyth 	rtcread,
319*74a4d8c2SCharles.Forsyth 	devbread,
320*74a4d8c2SCharles.Forsyth 	rtcwrite,
321*74a4d8c2SCharles.Forsyth 	devbwrite,
322*74a4d8c2SCharles.Forsyth 	devremove,
323*74a4d8c2SCharles.Forsyth 	devwstat,
324*74a4d8c2SCharles.Forsyth };
325*74a4d8c2SCharles.Forsyth 
326*74a4d8c2SCharles.Forsyth #define SEC2MIN 60L
327*74a4d8c2SCharles.Forsyth #define SEC2HOUR (60L*SEC2MIN)
328*74a4d8c2SCharles.Forsyth #define SEC2DAY (24L*SEC2HOUR)
329*74a4d8c2SCharles.Forsyth 
330*74a4d8c2SCharles.Forsyth /*
331*74a4d8c2SCharles.Forsyth  *  days per month plus days/year
332*74a4d8c2SCharles.Forsyth  */
333*74a4d8c2SCharles.Forsyth static	int	dmsize[] =
334*74a4d8c2SCharles.Forsyth {
335*74a4d8c2SCharles.Forsyth 	365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
336*74a4d8c2SCharles.Forsyth };
337*74a4d8c2SCharles.Forsyth static	int	ldmsize[] =
338*74a4d8c2SCharles.Forsyth {
339*74a4d8c2SCharles.Forsyth 	366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
340*74a4d8c2SCharles.Forsyth };
341*74a4d8c2SCharles.Forsyth 
342*74a4d8c2SCharles.Forsyth /*
343*74a4d8c2SCharles.Forsyth  *  return the days/month for the given year
344*74a4d8c2SCharles.Forsyth  */
345*74a4d8c2SCharles.Forsyth static int*
yrsize(int y)346*74a4d8c2SCharles.Forsyth yrsize(int y)
347*74a4d8c2SCharles.Forsyth {
348*74a4d8c2SCharles.Forsyth 	if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
349*74a4d8c2SCharles.Forsyth 		return ldmsize;
350*74a4d8c2SCharles.Forsyth 	else
351*74a4d8c2SCharles.Forsyth 		return dmsize;
352*74a4d8c2SCharles.Forsyth }
353*74a4d8c2SCharles.Forsyth 
354*74a4d8c2SCharles.Forsyth /*
355*74a4d8c2SCharles.Forsyth  *  compute seconds since Jan 1 1970
356*74a4d8c2SCharles.Forsyth  */
357*74a4d8c2SCharles.Forsyth static ulong
rtc2sec(Rtc * rtc)358*74a4d8c2SCharles.Forsyth rtc2sec(Rtc *rtc)
359*74a4d8c2SCharles.Forsyth {
360*74a4d8c2SCharles.Forsyth 	ulong secs;
361*74a4d8c2SCharles.Forsyth 	int i;
362*74a4d8c2SCharles.Forsyth 	int *d2m;
363*74a4d8c2SCharles.Forsyth 
364*74a4d8c2SCharles.Forsyth 	secs = 0;
365*74a4d8c2SCharles.Forsyth 
366*74a4d8c2SCharles.Forsyth 	/*
367*74a4d8c2SCharles.Forsyth 	 *  seconds per year
368*74a4d8c2SCharles.Forsyth 	 */
369*74a4d8c2SCharles.Forsyth 	for(i = 1970; i < rtc->year; i++){
370*74a4d8c2SCharles.Forsyth 		d2m = yrsize(i);
371*74a4d8c2SCharles.Forsyth 		secs += d2m[0] * SEC2DAY;
372*74a4d8c2SCharles.Forsyth 	}
373*74a4d8c2SCharles.Forsyth 
374*74a4d8c2SCharles.Forsyth 	/*
375*74a4d8c2SCharles.Forsyth 	 *  seconds per month
376*74a4d8c2SCharles.Forsyth 	 */
377*74a4d8c2SCharles.Forsyth 	d2m = yrsize(rtc->year);
378*74a4d8c2SCharles.Forsyth 	for(i = 1; i < rtc->mon; i++)
379*74a4d8c2SCharles.Forsyth 		secs += d2m[i] * SEC2DAY;
380*74a4d8c2SCharles.Forsyth 
381*74a4d8c2SCharles.Forsyth 	secs += (rtc->mday-1) * SEC2DAY;
382*74a4d8c2SCharles.Forsyth 	secs += rtc->hour * SEC2HOUR;
383*74a4d8c2SCharles.Forsyth 	secs += rtc->min * SEC2MIN;
384*74a4d8c2SCharles.Forsyth 	secs += rtc->sec;
385*74a4d8c2SCharles.Forsyth 
386*74a4d8c2SCharles.Forsyth 	return secs;
387*74a4d8c2SCharles.Forsyth }
388*74a4d8c2SCharles.Forsyth 
389*74a4d8c2SCharles.Forsyth /*
390*74a4d8c2SCharles.Forsyth  *  compute rtc from seconds since Jan 1 1970
391*74a4d8c2SCharles.Forsyth  */
392*74a4d8c2SCharles.Forsyth static void
sec2rtc(ulong secs,Rtc * rtc)393*74a4d8c2SCharles.Forsyth sec2rtc(ulong secs, Rtc *rtc)
394*74a4d8c2SCharles.Forsyth {
395*74a4d8c2SCharles.Forsyth 	int d;
396*74a4d8c2SCharles.Forsyth 	long hms, day;
397*74a4d8c2SCharles.Forsyth 	int *d2m;
398*74a4d8c2SCharles.Forsyth 
399*74a4d8c2SCharles.Forsyth 	/*
400*74a4d8c2SCharles.Forsyth 	 * break initial number into days
401*74a4d8c2SCharles.Forsyth 	 */
402*74a4d8c2SCharles.Forsyth 	hms = secs % SEC2DAY;
403*74a4d8c2SCharles.Forsyth 	day = secs / SEC2DAY;
404*74a4d8c2SCharles.Forsyth 	if(hms < 0) {
405*74a4d8c2SCharles.Forsyth 		hms += SEC2DAY;
406*74a4d8c2SCharles.Forsyth 		day -= 1;
407*74a4d8c2SCharles.Forsyth 	}
408*74a4d8c2SCharles.Forsyth 
409*74a4d8c2SCharles.Forsyth 	/*
410*74a4d8c2SCharles.Forsyth 	 * generate hours:minutes:seconds
411*74a4d8c2SCharles.Forsyth 	 */
412*74a4d8c2SCharles.Forsyth 	rtc->sec = hms % 60;
413*74a4d8c2SCharles.Forsyth 	d = hms / 60;
414*74a4d8c2SCharles.Forsyth 	rtc->min = d % 60;
415*74a4d8c2SCharles.Forsyth 	d /= 60;
416*74a4d8c2SCharles.Forsyth 	rtc->hour = d;
417*74a4d8c2SCharles.Forsyth 
418*74a4d8c2SCharles.Forsyth 	/*
419*74a4d8c2SCharles.Forsyth 	 * year number
420*74a4d8c2SCharles.Forsyth 	 */
421*74a4d8c2SCharles.Forsyth 	if(day >= 0)
422*74a4d8c2SCharles.Forsyth 		for(d = 1970; day >= *yrsize(d); d++)
423*74a4d8c2SCharles.Forsyth 			day -= *yrsize(d);
424*74a4d8c2SCharles.Forsyth 	else
425*74a4d8c2SCharles.Forsyth 		for (d = 1970; day < 0; d--)
426*74a4d8c2SCharles.Forsyth 			day += *yrsize(d-1);
427*74a4d8c2SCharles.Forsyth 	rtc->year = d;
428*74a4d8c2SCharles.Forsyth 
429*74a4d8c2SCharles.Forsyth 	/*
430*74a4d8c2SCharles.Forsyth 	 * generate month
431*74a4d8c2SCharles.Forsyth 	 */
432*74a4d8c2SCharles.Forsyth 	d2m = yrsize(rtc->year);
433*74a4d8c2SCharles.Forsyth 	for(d = 1; day >= d2m[d]; d++)
434*74a4d8c2SCharles.Forsyth 		day -= d2m[d];
435*74a4d8c2SCharles.Forsyth 	rtc->mday = day + 1;
436*74a4d8c2SCharles.Forsyth 	rtc->mon = d;
437*74a4d8c2SCharles.Forsyth 
438*74a4d8c2SCharles.Forsyth 	return;
439*74a4d8c2SCharles.Forsyth }
440*74a4d8c2SCharles.Forsyth 
441*74a4d8c2SCharles.Forsyth uchar
nvramread(int addr)442*74a4d8c2SCharles.Forsyth nvramread(int addr)
443*74a4d8c2SCharles.Forsyth {
444*74a4d8c2SCharles.Forsyth 	uchar data;
445*74a4d8c2SCharles.Forsyth 
446*74a4d8c2SCharles.Forsyth 	ilock(&nvrtlock);
447*74a4d8c2SCharles.Forsyth 	outb(Paddr, addr);
448*74a4d8c2SCharles.Forsyth 	data = inb(Pdata);
449*74a4d8c2SCharles.Forsyth 	iunlock(&nvrtlock);
450*74a4d8c2SCharles.Forsyth 
451*74a4d8c2SCharles.Forsyth 	return data;
452*74a4d8c2SCharles.Forsyth }
453*74a4d8c2SCharles.Forsyth 
454*74a4d8c2SCharles.Forsyth void
nvramwrite(int addr,uchar data)455*74a4d8c2SCharles.Forsyth nvramwrite(int addr, uchar data)
456*74a4d8c2SCharles.Forsyth {
457*74a4d8c2SCharles.Forsyth 	ilock(&nvrtlock);
458*74a4d8c2SCharles.Forsyth 	outb(Paddr, addr);
459*74a4d8c2SCharles.Forsyth 	outb(Pdata, data);
460*74a4d8c2SCharles.Forsyth 	iunlock(&nvrtlock);
461*74a4d8c2SCharles.Forsyth }
462