xref: /inferno-os/os/js/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 #include	"io.h"
9*74a4d8c2SCharles.Forsyth 
10*74a4d8c2SCharles.Forsyth /*
11*74a4d8c2SCharles.Forsyth  * Mostek MK48T12-15 Zeropower/Timekeeper
12*74a4d8c2SCharles.Forsyth  * This driver is actually portable.
13*74a4d8c2SCharles.Forsyth  */
14*74a4d8c2SCharles.Forsyth typedef struct Rtc	Rtc;
15*74a4d8c2SCharles.Forsyth struct Rtc
16*74a4d8c2SCharles.Forsyth {
17*74a4d8c2SCharles.Forsyth 	int	sec;
18*74a4d8c2SCharles.Forsyth 	int	min;
19*74a4d8c2SCharles.Forsyth 	int	hour;
20*74a4d8c2SCharles.Forsyth 	int	wday;
21*74a4d8c2SCharles.Forsyth 	int	mday;
22*74a4d8c2SCharles.Forsyth 	int	mon;
23*74a4d8c2SCharles.Forsyth 	int	year;
24*74a4d8c2SCharles.Forsyth };
25*74a4d8c2SCharles.Forsyth 
26*74a4d8c2SCharles.Forsyth static uchar	rtcgencksum(void);
27*74a4d8c2SCharles.Forsyth static void	setrtc(Rtc *rtc);
28*74a4d8c2SCharles.Forsyth static long	rtctime(void);
29*74a4d8c2SCharles.Forsyth static int	*yrsize(int yr);
30*74a4d8c2SCharles.Forsyth static int	*yrsize(int yr);
31*74a4d8c2SCharles.Forsyth static ulong	rtc2sec(Rtc *rtc);
32*74a4d8c2SCharles.Forsyth static void	sec2rtc(ulong secs, Rtc *rtc);
33*74a4d8c2SCharles.Forsyth 
34*74a4d8c2SCharles.Forsyth static struct
35*74a4d8c2SCharles.Forsyth {
36*74a4d8c2SCharles.Forsyth 	uchar	*cksum;
37*74a4d8c2SCharles.Forsyth 	uchar	*ram;
38*74a4d8c2SCharles.Forsyth 	RTCdev	*rtc;
39*74a4d8c2SCharles.Forsyth }nvr;
40*74a4d8c2SCharles.Forsyth 
41*74a4d8c2SCharles.Forsyth enum{
42*74a4d8c2SCharles.Forsyth 	Qdir,
43*74a4d8c2SCharles.Forsyth 	Qrtc,
44*74a4d8c2SCharles.Forsyth 	Qnvram,
45*74a4d8c2SCharles.Forsyth };
46*74a4d8c2SCharles.Forsyth 
47*74a4d8c2SCharles.Forsyth QLock	rtclock;		/* mutex on clock operations */
48*74a4d8c2SCharles.Forsyth 
49*74a4d8c2SCharles.Forsyth static Dirtab rtcdir[]={
50*74a4d8c2SCharles.Forsyth 	".",		{Qdir, 0, QTDIR},	0,	0555,
51*74a4d8c2SCharles.Forsyth 	"rtc",		{Qrtc, 0},	0,		0666,
52*74a4d8c2SCharles.Forsyth 	"nvram",	{Qnvram, 0},	NVWRITE,	0666,
53*74a4d8c2SCharles.Forsyth };
54*74a4d8c2SCharles.Forsyth #define	NRTC	(sizeof(rtcdir)/sizeof(rtcdir[0]))
55*74a4d8c2SCharles.Forsyth 
56*74a4d8c2SCharles.Forsyth static void
rtcinit(void)57*74a4d8c2SCharles.Forsyth rtcinit(void)
58*74a4d8c2SCharles.Forsyth {
59*74a4d8c2SCharles.Forsyth 	KMap *k;
60*74a4d8c2SCharles.Forsyth 
61*74a4d8c2SCharles.Forsyth 	k = kmappa(NVR_CKSUM_PHYS, PTENOCACHE|PTEIO);
62*74a4d8c2SCharles.Forsyth 	nvr.cksum = (uchar*)VA(k);
63*74a4d8c2SCharles.Forsyth 
64*74a4d8c2SCharles.Forsyth 	k = kmappa(NVR_PHYS, PTENOCACHE|PTEIO);
65*74a4d8c2SCharles.Forsyth 	nvr.ram = (uchar*)VA(k);
66*74a4d8c2SCharles.Forsyth 	nvr.rtc = (RTCdev*)(VA(k)+RTCOFF);
67*74a4d8c2SCharles.Forsyth 
68*74a4d8c2SCharles.Forsyth 	rtcgencksum();
69*74a4d8c2SCharles.Forsyth }
70*74a4d8c2SCharles.Forsyth 
71*74a4d8c2SCharles.Forsyth static Chan*
rtcattach(char * spec)72*74a4d8c2SCharles.Forsyth rtcattach(char *spec)
73*74a4d8c2SCharles.Forsyth {
74*74a4d8c2SCharles.Forsyth 	return devattach('r',spec);
75*74a4d8c2SCharles.Forsyth }
76*74a4d8c2SCharles.Forsyth 
77*74a4d8c2SCharles.Forsyth static Walkqid*
rtcwalk(Chan * c,Chan * nc,char ** name,int nname)78*74a4d8c2SCharles.Forsyth rtcwalk(Chan *c, Chan *nc, char **name, int nname)
79*74a4d8c2SCharles.Forsyth {
80*74a4d8c2SCharles.Forsyth 	return devwalk(c, nc, name, nname, rtcdir, NRTC, devgen);
81*74a4d8c2SCharles.Forsyth }
82*74a4d8c2SCharles.Forsyth 
83*74a4d8c2SCharles.Forsyth static int
rtcstat(Chan * c,uchar * dp,int n)84*74a4d8c2SCharles.Forsyth rtcstat(Chan *c, uchar *dp, int n)
85*74a4d8c2SCharles.Forsyth {
86*74a4d8c2SCharles.Forsyth 	return devstat(c, dp, n, rtcdir, NRTC, devgen);
87*74a4d8c2SCharles.Forsyth }
88*74a4d8c2SCharles.Forsyth 
89*74a4d8c2SCharles.Forsyth static Chan*
rtcopen(Chan * c,int omode)90*74a4d8c2SCharles.Forsyth rtcopen(Chan *c, int omode)
91*74a4d8c2SCharles.Forsyth {
92*74a4d8c2SCharles.Forsyth 	omode = openmode(omode);
93*74a4d8c2SCharles.Forsyth 	switch((ulong)c->qid.path){
94*74a4d8c2SCharles.Forsyth 	case Qrtc:
95*74a4d8c2SCharles.Forsyth 		if(strcmp(up->env->user, eve)!=0 && omode!=OREAD)
96*74a4d8c2SCharles.Forsyth 			error(Eperm);
97*74a4d8c2SCharles.Forsyth 		break;
98*74a4d8c2SCharles.Forsyth 	case Qnvram:
99*74a4d8c2SCharles.Forsyth 		if(strcmp(up->env->user, eve)!=0)
100*74a4d8c2SCharles.Forsyth 			error(Eperm);
101*74a4d8c2SCharles.Forsyth 	}
102*74a4d8c2SCharles.Forsyth 	return devopen(c, omode, rtcdir, NRTC, devgen);
103*74a4d8c2SCharles.Forsyth }
104*74a4d8c2SCharles.Forsyth 
105*74a4d8c2SCharles.Forsyth static void
rtccreate(Chan * c,char * name,int omode,ulong perm)106*74a4d8c2SCharles.Forsyth rtccreate(Chan *c, char *name, int omode, ulong perm)
107*74a4d8c2SCharles.Forsyth {
108*74a4d8c2SCharles.Forsyth 	USED(c, name, omode, perm);
109*74a4d8c2SCharles.Forsyth 	error(Eperm);
110*74a4d8c2SCharles.Forsyth }
111*74a4d8c2SCharles.Forsyth 
112*74a4d8c2SCharles.Forsyth static void
rtcclose(Chan * c)113*74a4d8c2SCharles.Forsyth rtcclose(Chan *c)
114*74a4d8c2SCharles.Forsyth {
115*74a4d8c2SCharles.Forsyth 	USED(c);
116*74a4d8c2SCharles.Forsyth }
117*74a4d8c2SCharles.Forsyth 
118*74a4d8c2SCharles.Forsyth static long
rtcread(Chan * c,void * buf,long n,vlong offset)119*74a4d8c2SCharles.Forsyth rtcread(Chan *c, void *buf, long n, vlong offset)
120*74a4d8c2SCharles.Forsyth {
121*74a4d8c2SCharles.Forsyth 	ulong t, ot;
122*74a4d8c2SCharles.Forsyth 
123*74a4d8c2SCharles.Forsyth 	if(c->qid.type & QTDIR)
124*74a4d8c2SCharles.Forsyth 		return devdirread(c, buf, n, rtcdir, NRTC, devgen);
125*74a4d8c2SCharles.Forsyth 
126*74a4d8c2SCharles.Forsyth 	switch((ulong)c->qid.path){
127*74a4d8c2SCharles.Forsyth 	case Qrtc:
128*74a4d8c2SCharles.Forsyth 		qlock(&rtclock);
129*74a4d8c2SCharles.Forsyth 		t = rtctime();
130*74a4d8c2SCharles.Forsyth 		do{
131*74a4d8c2SCharles.Forsyth 			ot = t;
132*74a4d8c2SCharles.Forsyth 			t = rtctime();	/* make sure there's no skew */
133*74a4d8c2SCharles.Forsyth 		}while(t != ot);
134*74a4d8c2SCharles.Forsyth 		qunlock(&rtclock);
135*74a4d8c2SCharles.Forsyth 		n = readnum(offset, buf, n, t, 12);
136*74a4d8c2SCharles.Forsyth 		return n;
137*74a4d8c2SCharles.Forsyth 	case Qnvram:
138*74a4d8c2SCharles.Forsyth 		if(offset > NVREAD)
139*74a4d8c2SCharles.Forsyth 			return 0;
140*74a4d8c2SCharles.Forsyth 		if(n > NVREAD - offset)
141*74a4d8c2SCharles.Forsyth 			n = NVREAD - offset;
142*74a4d8c2SCharles.Forsyth 		qlock(&rtclock);
143*74a4d8c2SCharles.Forsyth 		memmove(buf, nvr.ram+offset, n);
144*74a4d8c2SCharles.Forsyth 		qunlock(&rtclock);
145*74a4d8c2SCharles.Forsyth 		return n;
146*74a4d8c2SCharles.Forsyth 	}
147*74a4d8c2SCharles.Forsyth 	error(Egreg);
148*74a4d8c2SCharles.Forsyth 	return 0;		/* not reached */
149*74a4d8c2SCharles.Forsyth }
150*74a4d8c2SCharles.Forsyth 
151*74a4d8c2SCharles.Forsyth /*
152*74a4d8c2SCharles.Forsyth  * XXX - Tad: fixme to generate the correct checksum
153*74a4d8c2SCharles.Forsyth  */
154*74a4d8c2SCharles.Forsyth static uchar
rtcgencksum(void)155*74a4d8c2SCharles.Forsyth rtcgencksum(void)
156*74a4d8c2SCharles.Forsyth {
157*74a4d8c2SCharles.Forsyth 	uchar cksum;
158*74a4d8c2SCharles.Forsyth 	int i;
159*74a4d8c2SCharles.Forsyth 	static uchar p1cksum = 0;
160*74a4d8c2SCharles.Forsyth 	static uchar p1cksumvalid=0;
161*74a4d8c2SCharles.Forsyth 
162*74a4d8c2SCharles.Forsyth 	if(!p1cksumvalid) {
163*74a4d8c2SCharles.Forsyth 		for(i=1; i < 0x1000 ; i++)
164*74a4d8c2SCharles.Forsyth 			p1cksum ^= nvr.cksum[i];
165*74a4d8c2SCharles.Forsyth 		p1cksumvalid = 1;
166*74a4d8c2SCharles.Forsyth 	}
167*74a4d8c2SCharles.Forsyth 
168*74a4d8c2SCharles.Forsyth 	cksum = p1cksum;
169*74a4d8c2SCharles.Forsyth 
170*74a4d8c2SCharles.Forsyth 	for(i=0; i < 0xfdf ; i++) {
171*74a4d8c2SCharles.Forsyth 		cksum ^= nvr.ram[i];
172*74a4d8c2SCharles.Forsyth 	}
173*74a4d8c2SCharles.Forsyth 
174*74a4d8c2SCharles.Forsyth 	return cksum;
175*74a4d8c2SCharles.Forsyth }
176*74a4d8c2SCharles.Forsyth 
177*74a4d8c2SCharles.Forsyth static long
rtcwrite(Chan * c,void * buf,long n,vlong offset)178*74a4d8c2SCharles.Forsyth rtcwrite(Chan *c, void *buf, long n, vlong offset)
179*74a4d8c2SCharles.Forsyth {
180*74a4d8c2SCharles.Forsyth 	Rtc rtc;
181*74a4d8c2SCharles.Forsyth 	ulong secs;
182*74a4d8c2SCharles.Forsyth 	char *cp, sbuf[32];
183*74a4d8c2SCharles.Forsyth 
184*74a4d8c2SCharles.Forsyth 	switch((ulong)c->qid.path){
185*74a4d8c2SCharles.Forsyth 	case Qrtc:
186*74a4d8c2SCharles.Forsyth 		/*
187*74a4d8c2SCharles.Forsyth 		 *  read the time
188*74a4d8c2SCharles.Forsyth 		 */
189*74a4d8c2SCharles.Forsyth 		if(offset != 0 || n >= sizeof(sbuf)-1)
190*74a4d8c2SCharles.Forsyth 			error(Ebadarg);
191*74a4d8c2SCharles.Forsyth 		memmove(sbuf, buf, n);
192*74a4d8c2SCharles.Forsyth 		sbuf[n] = '\0';
193*74a4d8c2SCharles.Forsyth 		cp = sbuf;
194*74a4d8c2SCharles.Forsyth 		while(*cp){
195*74a4d8c2SCharles.Forsyth 			if(*cp>='0' && *cp<='9')
196*74a4d8c2SCharles.Forsyth 				break;
197*74a4d8c2SCharles.Forsyth 			cp++;
198*74a4d8c2SCharles.Forsyth 		}
199*74a4d8c2SCharles.Forsyth 		secs = strtoul(cp, 0, 0);
200*74a4d8c2SCharles.Forsyth 		/*
201*74a4d8c2SCharles.Forsyth 		 *  convert to bcd
202*74a4d8c2SCharles.Forsyth 		 */
203*74a4d8c2SCharles.Forsyth 		sec2rtc(secs, &rtc);
204*74a4d8c2SCharles.Forsyth 		/*
205*74a4d8c2SCharles.Forsyth 		 * write it
206*74a4d8c2SCharles.Forsyth 		 */
207*74a4d8c2SCharles.Forsyth 		qlock(&rtclock);
208*74a4d8c2SCharles.Forsyth 		setrtc(&rtc);
209*74a4d8c2SCharles.Forsyth 		qunlock(&rtclock);
210*74a4d8c2SCharles.Forsyth 		return n;
211*74a4d8c2SCharles.Forsyth 	case Qnvram:
212*74a4d8c2SCharles.Forsyth 		if(offset > NVWRITE)
213*74a4d8c2SCharles.Forsyth 			return 0;
214*74a4d8c2SCharles.Forsyth 		if(n > NVWRITE - offset)
215*74a4d8c2SCharles.Forsyth 			n = NVWRITE - offset;
216*74a4d8c2SCharles.Forsyth 		qlock(&rtclock);
217*74a4d8c2SCharles.Forsyth 		memmove(nvr.ram+offset, buf, n);
218*74a4d8c2SCharles.Forsyth 		*nvr.cksum = rtcgencksum();
219*74a4d8c2SCharles.Forsyth 		qunlock(&rtclock);
220*74a4d8c2SCharles.Forsyth 		return n;
221*74a4d8c2SCharles.Forsyth 	}
222*74a4d8c2SCharles.Forsyth 	error(Egreg);
223*74a4d8c2SCharles.Forsyth 	return 0;		/* not reached */
224*74a4d8c2SCharles.Forsyth }
225*74a4d8c2SCharles.Forsyth 
226*74a4d8c2SCharles.Forsyth #define bcd2dec(bcd)	(((((bcd)>>4) & 0x0F) * 10) + ((bcd) & 0x0F))
227*74a4d8c2SCharles.Forsyth #define dec2bcd(dec)	((((dec)/10)<<4)|((dec)%10))
228*74a4d8c2SCharles.Forsyth 
229*74a4d8c2SCharles.Forsyth static void
setrtc(Rtc * rtc)230*74a4d8c2SCharles.Forsyth setrtc(Rtc *rtc)
231*74a4d8c2SCharles.Forsyth {
232*74a4d8c2SCharles.Forsyth 	struct RTCdev *dev;
233*74a4d8c2SCharles.Forsyth 
234*74a4d8c2SCharles.Forsyth 	dev = nvr.rtc;
235*74a4d8c2SCharles.Forsyth 	dev->control |= RTCWRITE;
236*74a4d8c2SCharles.Forsyth 	wbflush();
237*74a4d8c2SCharles.Forsyth 	dev->year = dec2bcd(rtc->year % 100);
238*74a4d8c2SCharles.Forsyth 	dev->mon = dec2bcd(rtc->mon);
239*74a4d8c2SCharles.Forsyth 	dev->mday = dec2bcd(rtc->mday);
240*74a4d8c2SCharles.Forsyth 	dev->hour = dec2bcd(rtc->hour);
241*74a4d8c2SCharles.Forsyth 	dev->min = dec2bcd(rtc->min);
242*74a4d8c2SCharles.Forsyth 	dev->sec = dec2bcd(rtc->sec);
243*74a4d8c2SCharles.Forsyth 	wbflush();
244*74a4d8c2SCharles.Forsyth 	dev->control &= ~RTCWRITE;
245*74a4d8c2SCharles.Forsyth 	wbflush();
246*74a4d8c2SCharles.Forsyth }
247*74a4d8c2SCharles.Forsyth 
248*74a4d8c2SCharles.Forsyth static long
rtctime(void)249*74a4d8c2SCharles.Forsyth rtctime(void)
250*74a4d8c2SCharles.Forsyth {
251*74a4d8c2SCharles.Forsyth 	struct RTCdev *dev;
252*74a4d8c2SCharles.Forsyth 	Rtc rtc;
253*74a4d8c2SCharles.Forsyth 
254*74a4d8c2SCharles.Forsyth 	dev = nvr.rtc;
255*74a4d8c2SCharles.Forsyth 	dev->control |= RTCREAD;
256*74a4d8c2SCharles.Forsyth 	wbflush();
257*74a4d8c2SCharles.Forsyth 	rtc.sec = bcd2dec(dev->sec) & 0x7F;
258*74a4d8c2SCharles.Forsyth 	rtc.min = bcd2dec(dev->min & 0x7F);
259*74a4d8c2SCharles.Forsyth 	rtc.hour = bcd2dec(dev->hour & 0x3F);
260*74a4d8c2SCharles.Forsyth 	rtc.mday = bcd2dec(dev->mday & 0x3F);
261*74a4d8c2SCharles.Forsyth 	rtc.mon = bcd2dec(dev->mon & 0x3F);
262*74a4d8c2SCharles.Forsyth 	rtc.year = bcd2dec(dev->year);
263*74a4d8c2SCharles.Forsyth 	dev->control &= ~RTCREAD;
264*74a4d8c2SCharles.Forsyth 	wbflush();
265*74a4d8c2SCharles.Forsyth 
266*74a4d8c2SCharles.Forsyth 	if (rtc.mon < 1 || rtc.mon > 12)
267*74a4d8c2SCharles.Forsyth 		return 0;
268*74a4d8c2SCharles.Forsyth 	/*
269*74a4d8c2SCharles.Forsyth 	 *  the world starts Jan 1 1970
270*74a4d8c2SCharles.Forsyth 	 */
271*74a4d8c2SCharles.Forsyth 	if(rtc.year < 70)
272*74a4d8c2SCharles.Forsyth 		rtc.year += 2000;
273*74a4d8c2SCharles.Forsyth 	else
274*74a4d8c2SCharles.Forsyth 		rtc.year += 1900;
275*74a4d8c2SCharles.Forsyth 
276*74a4d8c2SCharles.Forsyth 	return rtc2sec(&rtc);
277*74a4d8c2SCharles.Forsyth }
278*74a4d8c2SCharles.Forsyth 
279*74a4d8c2SCharles.Forsyth #define SEC2MIN 60L
280*74a4d8c2SCharles.Forsyth #define SEC2HOUR (60L*SEC2MIN)
281*74a4d8c2SCharles.Forsyth #define SEC2DAY (24L*SEC2HOUR)
282*74a4d8c2SCharles.Forsyth 
283*74a4d8c2SCharles.Forsyth /*
284*74a4d8c2SCharles.Forsyth  *  days per month plus days/year
285*74a4d8c2SCharles.Forsyth  */
286*74a4d8c2SCharles.Forsyth static	int	dmsize[] =
287*74a4d8c2SCharles.Forsyth {
288*74a4d8c2SCharles.Forsyth 	365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
289*74a4d8c2SCharles.Forsyth };
290*74a4d8c2SCharles.Forsyth static	int	ldmsize[] =
291*74a4d8c2SCharles.Forsyth {
292*74a4d8c2SCharles.Forsyth 	366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
293*74a4d8c2SCharles.Forsyth };
294*74a4d8c2SCharles.Forsyth 
295*74a4d8c2SCharles.Forsyth /*
296*74a4d8c2SCharles.Forsyth  *  return the days/month for the given year
297*74a4d8c2SCharles.Forsyth  */
298*74a4d8c2SCharles.Forsyth static int *
yrsize(int yr)299*74a4d8c2SCharles.Forsyth yrsize(int yr)
300*74a4d8c2SCharles.Forsyth {
301*74a4d8c2SCharles.Forsyth 	if((yr % 4) == 0)
302*74a4d8c2SCharles.Forsyth 		return ldmsize;
303*74a4d8c2SCharles.Forsyth 	else
304*74a4d8c2SCharles.Forsyth 		return dmsize;
305*74a4d8c2SCharles.Forsyth }
306*74a4d8c2SCharles.Forsyth 
307*74a4d8c2SCharles.Forsyth /*
308*74a4d8c2SCharles.Forsyth  *  compute seconds since Jan 1 1970
309*74a4d8c2SCharles.Forsyth  */
310*74a4d8c2SCharles.Forsyth static ulong
rtc2sec(Rtc * rtc)311*74a4d8c2SCharles.Forsyth rtc2sec(Rtc *rtc)
312*74a4d8c2SCharles.Forsyth {
313*74a4d8c2SCharles.Forsyth 	ulong secs;
314*74a4d8c2SCharles.Forsyth 	int i;
315*74a4d8c2SCharles.Forsyth 	int *d2m;
316*74a4d8c2SCharles.Forsyth 
317*74a4d8c2SCharles.Forsyth 	secs = 0;
318*74a4d8c2SCharles.Forsyth 
319*74a4d8c2SCharles.Forsyth 	/*
320*74a4d8c2SCharles.Forsyth 	 *  seconds per year
321*74a4d8c2SCharles.Forsyth 	 */
322*74a4d8c2SCharles.Forsyth 	for(i = 1970; i < rtc->year; i++){
323*74a4d8c2SCharles.Forsyth 		d2m = yrsize(i);
324*74a4d8c2SCharles.Forsyth 		secs += d2m[0] * SEC2DAY;
325*74a4d8c2SCharles.Forsyth 	}
326*74a4d8c2SCharles.Forsyth 
327*74a4d8c2SCharles.Forsyth 	/*
328*74a4d8c2SCharles.Forsyth 	 *  seconds per month
329*74a4d8c2SCharles.Forsyth 	 */
330*74a4d8c2SCharles.Forsyth 	d2m = yrsize(rtc->year);
331*74a4d8c2SCharles.Forsyth 	for(i = 1; i < rtc->mon; i++)
332*74a4d8c2SCharles.Forsyth 		secs += d2m[i] * SEC2DAY;
333*74a4d8c2SCharles.Forsyth 
334*74a4d8c2SCharles.Forsyth 	secs += (rtc->mday-1) * SEC2DAY;
335*74a4d8c2SCharles.Forsyth 	secs += rtc->hour * SEC2HOUR;
336*74a4d8c2SCharles.Forsyth 	secs += rtc->min * SEC2MIN;
337*74a4d8c2SCharles.Forsyth 	secs += rtc->sec;
338*74a4d8c2SCharles.Forsyth 
339*74a4d8c2SCharles.Forsyth 	return secs;
340*74a4d8c2SCharles.Forsyth }
341*74a4d8c2SCharles.Forsyth 
342*74a4d8c2SCharles.Forsyth /*
343*74a4d8c2SCharles.Forsyth  *  compute rtc from seconds since Jan 1 1970
344*74a4d8c2SCharles.Forsyth  */
345*74a4d8c2SCharles.Forsyth static void
sec2rtc(ulong secs,Rtc * rtc)346*74a4d8c2SCharles.Forsyth sec2rtc(ulong secs, Rtc *rtc)
347*74a4d8c2SCharles.Forsyth {
348*74a4d8c2SCharles.Forsyth 	int d;
349*74a4d8c2SCharles.Forsyth 	long hms, day;
350*74a4d8c2SCharles.Forsyth 	int *d2m;
351*74a4d8c2SCharles.Forsyth 
352*74a4d8c2SCharles.Forsyth 	/*
353*74a4d8c2SCharles.Forsyth 	 * break initial number into days
354*74a4d8c2SCharles.Forsyth 	 */
355*74a4d8c2SCharles.Forsyth 	hms = secs % SEC2DAY;
356*74a4d8c2SCharles.Forsyth 	day = secs / SEC2DAY;
357*74a4d8c2SCharles.Forsyth 	if(hms < 0) {
358*74a4d8c2SCharles.Forsyth 		hms += SEC2DAY;
359*74a4d8c2SCharles.Forsyth 		day -= 1;
360*74a4d8c2SCharles.Forsyth 	}
361*74a4d8c2SCharles.Forsyth 
362*74a4d8c2SCharles.Forsyth 	/*
363*74a4d8c2SCharles.Forsyth 	 * generate hours:minutes:seconds
364*74a4d8c2SCharles.Forsyth 	 */
365*74a4d8c2SCharles.Forsyth 	rtc->sec = hms % 60;
366*74a4d8c2SCharles.Forsyth 	d = hms / 60;
367*74a4d8c2SCharles.Forsyth 	rtc->min = d % 60;
368*74a4d8c2SCharles.Forsyth 	d /= 60;
369*74a4d8c2SCharles.Forsyth 	rtc->hour = d;
370*74a4d8c2SCharles.Forsyth 
371*74a4d8c2SCharles.Forsyth 	/*
372*74a4d8c2SCharles.Forsyth 	 * year number
373*74a4d8c2SCharles.Forsyth 	 */
374*74a4d8c2SCharles.Forsyth 	if(day >= 0)
375*74a4d8c2SCharles.Forsyth 		for(d = 1970; day >= *yrsize(d); d++)
376*74a4d8c2SCharles.Forsyth 			day -= *yrsize(d);
377*74a4d8c2SCharles.Forsyth 	else
378*74a4d8c2SCharles.Forsyth 		for (d = 1970; day < 0; d--)
379*74a4d8c2SCharles.Forsyth 			day += *yrsize(d-1);
380*74a4d8c2SCharles.Forsyth 	rtc->year = d;
381*74a4d8c2SCharles.Forsyth 
382*74a4d8c2SCharles.Forsyth 	/*
383*74a4d8c2SCharles.Forsyth 	 * generate month
384*74a4d8c2SCharles.Forsyth 	 */
385*74a4d8c2SCharles.Forsyth 	d2m = yrsize(rtc->year);
386*74a4d8c2SCharles.Forsyth 	for(d = 1; day >= d2m[d]; d++)
387*74a4d8c2SCharles.Forsyth 		day -= d2m[d];
388*74a4d8c2SCharles.Forsyth 	rtc->mday = day + 1;
389*74a4d8c2SCharles.Forsyth 	rtc->mon = d;
390*74a4d8c2SCharles.Forsyth 
391*74a4d8c2SCharles.Forsyth 	return;
392*74a4d8c2SCharles.Forsyth }
393*74a4d8c2SCharles.Forsyth 
394*74a4d8c2SCharles.Forsyth Dev rtcdevtab = {
395*74a4d8c2SCharles.Forsyth 	'r',
396*74a4d8c2SCharles.Forsyth 	"rtc",
397*74a4d8c2SCharles.Forsyth 
398*74a4d8c2SCharles.Forsyth 	devreset,
399*74a4d8c2SCharles.Forsyth 	rtcinit,
400*74a4d8c2SCharles.Forsyth 	devshutdown,
401*74a4d8c2SCharles.Forsyth 	rtcattach,
402*74a4d8c2SCharles.Forsyth 	rtcwalk,
403*74a4d8c2SCharles.Forsyth 	rtcstat,
404*74a4d8c2SCharles.Forsyth 	rtcopen,
405*74a4d8c2SCharles.Forsyth 	rtccreate,
406*74a4d8c2SCharles.Forsyth 	rtcclose,
407*74a4d8c2SCharles.Forsyth 	rtcread,
408*74a4d8c2SCharles.Forsyth 	devbread,
409*74a4d8c2SCharles.Forsyth 	rtcwrite,
410*74a4d8c2SCharles.Forsyth 	devbwrite,
411*74a4d8c2SCharles.Forsyth 	devremove,
412*74a4d8c2SCharles.Forsyth 	devwstat,
413*74a4d8c2SCharles.Forsyth };
414