xref: /plan9/sys/src/9/mtx/devrtc.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1*9a747e4fSDavid du Colombier /*
2*9a747e4fSDavid du Colombier  *	M48T59/559 Timekeeper
3*9a747e4fSDavid du Colombier  */
4*9a747e4fSDavid du Colombier #include	"u.h"
5*9a747e4fSDavid du Colombier #include	"../port/lib.h"
6*9a747e4fSDavid du Colombier #include	"mem.h"
7*9a747e4fSDavid du Colombier #include	"dat.h"
8*9a747e4fSDavid du Colombier #include	"fns.h"
9*9a747e4fSDavid du Colombier #include	"../port/error.h"
10*9a747e4fSDavid du Colombier 
11*9a747e4fSDavid du Colombier #include	"io.h"
12*9a747e4fSDavid du Colombier 
13*9a747e4fSDavid du Colombier enum{
14*9a747e4fSDavid du Colombier 	STB0 = 0x74,
15*9a747e4fSDavid du Colombier 	STB1 = 0x75,
16*9a747e4fSDavid du Colombier 	Data = 0x77,
17*9a747e4fSDavid du Colombier 
18*9a747e4fSDavid du Colombier 	NVOFF=	0,
19*9a747e4fSDavid du Colombier 	NVLEN=	0x1ff0,		/* length in bytes of NV RAM */
20*9a747e4fSDavid du Colombier 
21*9a747e4fSDavid du Colombier 	/*
22*9a747e4fSDavid du Colombier 	 *  register offsets into time of day clock
23*9a747e4fSDavid du Colombier 	 */
24*9a747e4fSDavid du Colombier 	NVflags=		0x1ff0,
25*9a747e4fSDavid du Colombier 	NVwatchdog=	0x1ff7,
26*9a747e4fSDavid du Colombier 	NVctl=		0x1ff8,
27*9a747e4fSDavid du Colombier 	NVsec,
28*9a747e4fSDavid du Colombier 	NVmin,
29*9a747e4fSDavid du Colombier 	NVhour,
30*9a747e4fSDavid du Colombier 	NVday,		/* (1 = Sun) */
31*9a747e4fSDavid du Colombier 	NVmday,		/* (1-31) */
32*9a747e4fSDavid du Colombier 	NVmon,		/* (1-12) */
33*9a747e4fSDavid du Colombier 	NVyear,		/* (0-99) */
34*9a747e4fSDavid du Colombier 
35*9a747e4fSDavid du Colombier 	/* NVctl */
36*9a747e4fSDavid du Colombier 	RTwrite = (1<<7),
37*9a747e4fSDavid du Colombier 	RTread = (1<<6),
38*9a747e4fSDavid du Colombier 	RTsign = (1<<5),
39*9a747e4fSDavid du Colombier 	RTcal = 0x1f,
40*9a747e4fSDavid du Colombier 
41*9a747e4fSDavid du Colombier 	/* NVwatchdog */
42*9a747e4fSDavid du Colombier 	WDsteer = (1<<7),		/* 0 -> intr, 1 -> reset */
43*9a747e4fSDavid du Colombier 	WDmult = (1<<2),		/* 5 bits of multiplier */
44*9a747e4fSDavid du Colombier 	WDres0 = (0<<0),		/* 1/16 sec resolution */
45*9a747e4fSDavid du Colombier 	WDres1 = (1<<0),		/* 1/4 sec resolution */
46*9a747e4fSDavid du Colombier 	WDres2 = (2<<0),		/* 1 sec resolution */
47*9a747e4fSDavid du Colombier 	WDres3 = (3<<0),		/* 4 sec resolution */
48*9a747e4fSDavid du Colombier 
49*9a747e4fSDavid du Colombier 	Qdir = 0,
50*9a747e4fSDavid du Colombier 	Qrtc,
51*9a747e4fSDavid du Colombier 	Qnvram,
52*9a747e4fSDavid du Colombier };
53*9a747e4fSDavid du Colombier 
54*9a747e4fSDavid du Colombier /*
55*9a747e4fSDavid du Colombier  *  broken down time
56*9a747e4fSDavid du Colombier  */
57*9a747e4fSDavid du Colombier typedef struct
58*9a747e4fSDavid du Colombier {
59*9a747e4fSDavid du Colombier 	int	sec;
60*9a747e4fSDavid du Colombier 	int	min;
61*9a747e4fSDavid du Colombier 	int	hour;
62*9a747e4fSDavid du Colombier 	int	mday;
63*9a747e4fSDavid du Colombier 	int	mon;
64*9a747e4fSDavid du Colombier 	int	year;
65*9a747e4fSDavid du Colombier } Rtc;
66*9a747e4fSDavid du Colombier 
67*9a747e4fSDavid du Colombier QLock	rtclock;		/* mutex on nvram operations */
68*9a747e4fSDavid du Colombier 
69*9a747e4fSDavid du Colombier static Dirtab rtcdir[]={
70*9a747e4fSDavid du Colombier 	".",		{Qdir, 0, QTDIR},	0,	DMDIR|0555,
71*9a747e4fSDavid du Colombier 	"rtc",		{Qrtc, 0},	0,	0644,
72*9a747e4fSDavid du Colombier 	"nvram",	{Qnvram, 0},	0,	0600,
73*9a747e4fSDavid du Colombier };
74*9a747e4fSDavid du Colombier 
75*9a747e4fSDavid du Colombier static ulong	rtc2sec(Rtc*);
76*9a747e4fSDavid du Colombier static void	sec2rtc(ulong, Rtc*);
77*9a747e4fSDavid du Colombier static void	setrtc(Rtc*);
78*9a747e4fSDavid du Colombier static void	nvcksum(void);
79*9a747e4fSDavid du Colombier static void	nvput(int, uchar);
80*9a747e4fSDavid du Colombier static uchar	nvget(int);
81*9a747e4fSDavid du Colombier 
82*9a747e4fSDavid du Colombier static Chan*
rtcattach(char * spec)83*9a747e4fSDavid du Colombier rtcattach(char *spec)
84*9a747e4fSDavid du Colombier {
85*9a747e4fSDavid du Colombier 	return devattach('r', spec);
86*9a747e4fSDavid du Colombier }
87*9a747e4fSDavid du Colombier 
88*9a747e4fSDavid du Colombier static Walkqid*
rtcwalk(Chan * c,Chan * nc,char ** name,int nname)89*9a747e4fSDavid du Colombier rtcwalk(Chan *c, Chan *nc, char **name, int nname)
90*9a747e4fSDavid du Colombier {
91*9a747e4fSDavid du Colombier 	return devwalk(c, nc, name, nname, rtcdir, nelem(rtcdir), devgen);
92*9a747e4fSDavid du Colombier }
93*9a747e4fSDavid du Colombier 
94*9a747e4fSDavid du Colombier static int
rtcstat(Chan * c,uchar * dp,int n)95*9a747e4fSDavid du Colombier rtcstat(Chan *c, uchar *dp, int n)
96*9a747e4fSDavid du Colombier {
97*9a747e4fSDavid du Colombier 	return devstat(c, dp, n, rtcdir, nelem(rtcdir), devgen);
98*9a747e4fSDavid du Colombier }
99*9a747e4fSDavid du Colombier 
100*9a747e4fSDavid du Colombier static Chan*
rtcopen(Chan * c,int omode)101*9a747e4fSDavid du Colombier rtcopen(Chan *c, int omode)
102*9a747e4fSDavid du Colombier {
103*9a747e4fSDavid du Colombier 	omode = openmode(omode);
104*9a747e4fSDavid du Colombier 	switch((ulong)c->qid.path){
105*9a747e4fSDavid du Colombier 	case Qrtc:
106*9a747e4fSDavid du Colombier 		if(strcmp(up->user, eve)!=0 && omode!=OREAD)
107*9a747e4fSDavid du Colombier 			error(Eperm);
108*9a747e4fSDavid du Colombier 		break;
109*9a747e4fSDavid du Colombier 	case Qnvram:
110*9a747e4fSDavid du Colombier 		if(strcmp(up->user, eve)!=0 || !cpuserver)
111*9a747e4fSDavid du Colombier 			error(Eperm);
112*9a747e4fSDavid du Colombier 	}
113*9a747e4fSDavid du Colombier 	return devopen(c, omode, rtcdir, nelem(rtcdir), devgen);
114*9a747e4fSDavid du Colombier }
115*9a747e4fSDavid du Colombier 
116*9a747e4fSDavid du Colombier static void
rtcclose(Chan *)117*9a747e4fSDavid du Colombier rtcclose(Chan*)
118*9a747e4fSDavid du Colombier {
119*9a747e4fSDavid du Colombier }
120*9a747e4fSDavid du Colombier 
121*9a747e4fSDavid du Colombier static long
rtcread(Chan * c,void * buf,long n,vlong off)122*9a747e4fSDavid du Colombier rtcread(Chan *c, void *buf, long n, vlong off)
123*9a747e4fSDavid du Colombier {
124*9a747e4fSDavid du Colombier 	char *p;
125*9a747e4fSDavid du Colombier 	ulong t;
126*9a747e4fSDavid du Colombier 	int i;
127*9a747e4fSDavid du Colombier 	ulong offset = off;
128*9a747e4fSDavid du Colombier 
129*9a747e4fSDavid du Colombier 	if(c->qid.type & QTDIR)
130*9a747e4fSDavid du Colombier 		return devdirread(c, buf, n, rtcdir, nelem(rtcdir), devgen);
131*9a747e4fSDavid du Colombier 
132*9a747e4fSDavid du Colombier 	switch((ulong)c->qid.path){
133*9a747e4fSDavid du Colombier 	case Qrtc:
134*9a747e4fSDavid du Colombier 		qlock(&rtclock);
135*9a747e4fSDavid du Colombier 		t = rtctime();
136*9a747e4fSDavid du Colombier 		qunlock(&rtclock);
137*9a747e4fSDavid du Colombier 		n = readnum(offset, buf, n, t, 12);
138*9a747e4fSDavid du Colombier 		return n;
139*9a747e4fSDavid du Colombier 	case Qnvram:
140*9a747e4fSDavid du Colombier 		offset += NVOFF;
141*9a747e4fSDavid du Colombier 		if(offset > NVLEN)
142*9a747e4fSDavid du Colombier 			return 0;
143*9a747e4fSDavid du Colombier 		if(n > NVLEN - offset)
144*9a747e4fSDavid du Colombier 			n = NVLEN - offset;
145*9a747e4fSDavid du Colombier 		p = buf;
146*9a747e4fSDavid du Colombier 		qlock(&rtclock);
147*9a747e4fSDavid du Colombier 		for(i = 0; i < n; i++)
148*9a747e4fSDavid du Colombier 			p[i] = nvget(i+offset);
149*9a747e4fSDavid du Colombier 		qunlock(&rtclock);
150*9a747e4fSDavid du Colombier 		return n;
151*9a747e4fSDavid du Colombier 	}
152*9a747e4fSDavid du Colombier 	error(Egreg);
153*9a747e4fSDavid du Colombier 	return -1;		/* never reached */
154*9a747e4fSDavid du Colombier }
155*9a747e4fSDavid du Colombier 
156*9a747e4fSDavid du Colombier static long
rtcwrite(Chan * c,void * buf,long n,vlong off)157*9a747e4fSDavid du Colombier rtcwrite(Chan *c, void *buf, long n, vlong off)
158*9a747e4fSDavid du Colombier {
159*9a747e4fSDavid du Colombier 	Rtc rtc;
160*9a747e4fSDavid du Colombier 	ulong secs;
161*9a747e4fSDavid du Colombier 	char *cp, *ep;
162*9a747e4fSDavid du Colombier 	int i;
163*9a747e4fSDavid du Colombier 	ulong offset = off;
164*9a747e4fSDavid du Colombier 
165*9a747e4fSDavid du Colombier 	switch((ulong)c->qid.path){
166*9a747e4fSDavid du Colombier 	case Qrtc:
167*9a747e4fSDavid du Colombier 		if(offset!=0)
168*9a747e4fSDavid du Colombier 			error(Ebadarg);
169*9a747e4fSDavid du Colombier 		/*
170*9a747e4fSDavid du Colombier 		 *  read the time
171*9a747e4fSDavid du Colombier 		 */
172*9a747e4fSDavid du Colombier 		cp = ep = buf;
173*9a747e4fSDavid du Colombier 		ep += n;
174*9a747e4fSDavid du Colombier 		while(cp < ep){
175*9a747e4fSDavid du Colombier 			if(*cp>='0' && *cp<='9')
176*9a747e4fSDavid du Colombier 				break;
177*9a747e4fSDavid du Colombier 			cp++;
178*9a747e4fSDavid du Colombier 		}
179*9a747e4fSDavid du Colombier 		secs = strtoul(cp, 0, 0);
180*9a747e4fSDavid du Colombier 		/*
181*9a747e4fSDavid du Colombier 		 *  convert to bcd
182*9a747e4fSDavid du Colombier 		 */
183*9a747e4fSDavid du Colombier 		sec2rtc(secs, &rtc);
184*9a747e4fSDavid du Colombier 		/*
185*9a747e4fSDavid du Colombier 		 * write it
186*9a747e4fSDavid du Colombier 		 */
187*9a747e4fSDavid du Colombier 		qlock(&rtclock);
188*9a747e4fSDavid du Colombier 		setrtc(&rtc);
189*9a747e4fSDavid du Colombier 		qunlock(&rtclock);
190*9a747e4fSDavid du Colombier 		return n;
191*9a747e4fSDavid du Colombier 	case Qnvram:
192*9a747e4fSDavid du Colombier 		offset += NVOFF;
193*9a747e4fSDavid du Colombier 		if(offset > NVLEN)
194*9a747e4fSDavid du Colombier 			return 0;
195*9a747e4fSDavid du Colombier 		if(n > NVLEN - offset)
196*9a747e4fSDavid du Colombier 			n = NVLEN - offset;
197*9a747e4fSDavid du Colombier 		qlock(&rtclock);
198*9a747e4fSDavid du Colombier 		for(i = 0; i < n; i++)
199*9a747e4fSDavid du Colombier 			nvput(i+offset, ((uchar*)buf)[i]);
200*9a747e4fSDavid du Colombier 		nvcksum();
201*9a747e4fSDavid du Colombier 		qunlock(&rtclock);
202*9a747e4fSDavid du Colombier 		return n;
203*9a747e4fSDavid du Colombier 	}
204*9a747e4fSDavid du Colombier 	error(Egreg);
205*9a747e4fSDavid du Colombier 	return -1;		/* never reached */
206*9a747e4fSDavid du Colombier }
207*9a747e4fSDavid du Colombier 
208*9a747e4fSDavid du Colombier long
rtcbwrite(Chan * c,Block * bp,ulong offset)209*9a747e4fSDavid du Colombier rtcbwrite(Chan *c, Block *bp, ulong offset)
210*9a747e4fSDavid du Colombier {
211*9a747e4fSDavid du Colombier 	return devbwrite(c, bp, offset);
212*9a747e4fSDavid du Colombier }
213*9a747e4fSDavid du Colombier 
214*9a747e4fSDavid du Colombier Dev rtcdevtab = {
215*9a747e4fSDavid du Colombier 	'r',
216*9a747e4fSDavid du Colombier 	"rtc",
217*9a747e4fSDavid du Colombier 
218*9a747e4fSDavid du Colombier 	devreset,
219*9a747e4fSDavid du Colombier 	devinit,
220*9a747e4fSDavid du Colombier 	devshutdown,
221*9a747e4fSDavid du Colombier 	rtcattach,
222*9a747e4fSDavid du Colombier 	rtcwalk,
223*9a747e4fSDavid du Colombier 	rtcstat,
224*9a747e4fSDavid du Colombier 	rtcopen,
225*9a747e4fSDavid du Colombier 	devcreate,
226*9a747e4fSDavid du Colombier 	rtcclose,
227*9a747e4fSDavid du Colombier 	rtcread,
228*9a747e4fSDavid du Colombier 	devbread,
229*9a747e4fSDavid du Colombier 	rtcwrite,
230*9a747e4fSDavid du Colombier 	devbwrite,
231*9a747e4fSDavid du Colombier 	devremove,
232*9a747e4fSDavid du Colombier 	devwstat,
233*9a747e4fSDavid du Colombier };
234*9a747e4fSDavid du Colombier 
235*9a747e4fSDavid du Colombier static void
nvput(int offset,uchar val)236*9a747e4fSDavid du Colombier nvput(int offset, uchar val)
237*9a747e4fSDavid du Colombier {
238*9a747e4fSDavid du Colombier 	outb(STB0, offset);
239*9a747e4fSDavid du Colombier 	outb(STB1, offset>>8);
240*9a747e4fSDavid du Colombier 	outb(Data, val);
241*9a747e4fSDavid du Colombier }
242*9a747e4fSDavid du Colombier 
243*9a747e4fSDavid du Colombier static uchar
nvget(int offset)244*9a747e4fSDavid du Colombier nvget(int offset)
245*9a747e4fSDavid du Colombier {
246*9a747e4fSDavid du Colombier 	outb(STB0, offset);
247*9a747e4fSDavid du Colombier 	outb(STB1, offset>>8);
248*9a747e4fSDavid du Colombier 	return inb(Data);
249*9a747e4fSDavid du Colombier }
250*9a747e4fSDavid du Colombier 
251*9a747e4fSDavid du Colombier static void
nvcksum(void)252*9a747e4fSDavid du Colombier nvcksum(void)
253*9a747e4fSDavid du Colombier {
254*9a747e4fSDavid du Colombier }
255*9a747e4fSDavid du Colombier 
256*9a747e4fSDavid du Colombier void
watchreset(void)257*9a747e4fSDavid du Colombier watchreset(void)
258*9a747e4fSDavid du Colombier {
259*9a747e4fSDavid du Colombier 	splhi();
260*9a747e4fSDavid du Colombier 	nvput(NVwatchdog, WDsteer|(1*WDmult)|WDres0);
261*9a747e4fSDavid du Colombier 	for(;;);
262*9a747e4fSDavid du Colombier }
263*9a747e4fSDavid du Colombier 
264*9a747e4fSDavid du Colombier static int
getbcd(int bcd)265*9a747e4fSDavid du Colombier getbcd(int bcd)
266*9a747e4fSDavid du Colombier {
267*9a747e4fSDavid du Colombier 	return (bcd&0x0f) + 10 * (bcd>>4);
268*9a747e4fSDavid du Colombier }
269*9a747e4fSDavid du Colombier 
270*9a747e4fSDavid du Colombier static int
putbcd(int val)271*9a747e4fSDavid du Colombier putbcd(int val)
272*9a747e4fSDavid du Colombier {
273*9a747e4fSDavid du Colombier 	return (val % 10) | (((val/10) % 10) << 4);
274*9a747e4fSDavid du Colombier }
275*9a747e4fSDavid du Colombier 
276*9a747e4fSDavid du Colombier long
rtctime(void)277*9a747e4fSDavid du Colombier rtctime(void)
278*9a747e4fSDavid du Colombier {
279*9a747e4fSDavid du Colombier 	int ctl;
280*9a747e4fSDavid du Colombier 	Rtc rtc;
281*9a747e4fSDavid du Colombier 
282*9a747e4fSDavid du Colombier 	/*
283*9a747e4fSDavid du Colombier 	 *  convert from BCD
284*9a747e4fSDavid du Colombier 	 */
285*9a747e4fSDavid du Colombier 	ctl = nvget(NVctl);
286*9a747e4fSDavid du Colombier 	ctl &= RTsign|RTcal;
287*9a747e4fSDavid du Colombier 	nvput(NVctl, ctl|RTread);
288*9a747e4fSDavid du Colombier 
289*9a747e4fSDavid du Colombier 	rtc.sec = getbcd(nvget(NVsec) & 0x7f);
290*9a747e4fSDavid du Colombier 	rtc.min = getbcd(nvget(NVmin));
291*9a747e4fSDavid du Colombier 	rtc.hour = getbcd(nvget(NVhour));
292*9a747e4fSDavid du Colombier 	rtc.mday = getbcd(nvget(NVmday));
293*9a747e4fSDavid du Colombier 	rtc.mon = getbcd(nvget(NVmon));
294*9a747e4fSDavid du Colombier 	rtc.year = getbcd(nvget(NVyear));
295*9a747e4fSDavid du Colombier 	if(rtc.year < 70)
296*9a747e4fSDavid du Colombier 		rtc.year += 2000;
297*9a747e4fSDavid du Colombier 	else
298*9a747e4fSDavid du Colombier 		rtc.year += 1900;
299*9a747e4fSDavid du Colombier 
300*9a747e4fSDavid du Colombier 	nvput(NVctl, ctl);
301*9a747e4fSDavid du Colombier 
302*9a747e4fSDavid du Colombier 	return rtc2sec(&rtc);
303*9a747e4fSDavid du Colombier }
304*9a747e4fSDavid du Colombier 
305*9a747e4fSDavid du Colombier static void
setrtc(Rtc * rtc)306*9a747e4fSDavid du Colombier setrtc(Rtc *rtc)
307*9a747e4fSDavid du Colombier {
308*9a747e4fSDavid du Colombier 	int ctl;
309*9a747e4fSDavid du Colombier 
310*9a747e4fSDavid du Colombier 	ctl = nvget(NVctl);
311*9a747e4fSDavid du Colombier 	ctl &= RTsign|RTcal;
312*9a747e4fSDavid du Colombier 	nvput(NVctl, ctl|RTwrite);
313*9a747e4fSDavid du Colombier 
314*9a747e4fSDavid du Colombier 	nvput(NVsec, putbcd(rtc->sec));
315*9a747e4fSDavid du Colombier 	nvput(NVmin, putbcd(rtc->min));
316*9a747e4fSDavid du Colombier 	nvput(NVhour, putbcd(rtc->hour));
317*9a747e4fSDavid du Colombier 	nvput(NVmday, putbcd(rtc->mday));
318*9a747e4fSDavid du Colombier 	nvput(NVmon, putbcd(rtc->mon));
319*9a747e4fSDavid du Colombier 	nvput(NVyear, putbcd(rtc->year % 100));
320*9a747e4fSDavid du Colombier 
321*9a747e4fSDavid du Colombier 	nvput(NVctl, ctl);
322*9a747e4fSDavid du Colombier }
323*9a747e4fSDavid du Colombier 
324*9a747e4fSDavid du Colombier #define SEC2MIN 60L
325*9a747e4fSDavid du Colombier #define SEC2HOUR (60L*SEC2MIN)
326*9a747e4fSDavid du Colombier #define SEC2DAY (24L*SEC2HOUR)
327*9a747e4fSDavid du Colombier 
328*9a747e4fSDavid du Colombier /*
329*9a747e4fSDavid du Colombier  *  days per month plus days/year
330*9a747e4fSDavid du Colombier  */
331*9a747e4fSDavid du Colombier static	int	dmsize[] =
332*9a747e4fSDavid du Colombier {
333*9a747e4fSDavid du Colombier 	365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
334*9a747e4fSDavid du Colombier };
335*9a747e4fSDavid du Colombier static	int	ldmsize[] =
336*9a747e4fSDavid du Colombier {
337*9a747e4fSDavid du Colombier 	366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
338*9a747e4fSDavid du Colombier };
339*9a747e4fSDavid du Colombier 
340*9a747e4fSDavid du Colombier /*
341*9a747e4fSDavid du Colombier  *  return the days/month for the given year
342*9a747e4fSDavid du Colombier  */
343*9a747e4fSDavid du Colombier static int *
yrsize(int y)344*9a747e4fSDavid du Colombier yrsize(int y)
345*9a747e4fSDavid du Colombier {
346*9a747e4fSDavid du Colombier 
347*9a747e4fSDavid du Colombier 	if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
348*9a747e4fSDavid du Colombier 		return ldmsize;
349*9a747e4fSDavid du Colombier 	else
350*9a747e4fSDavid du Colombier 		return dmsize;
351*9a747e4fSDavid du Colombier }
352*9a747e4fSDavid du Colombier 
353*9a747e4fSDavid du Colombier /*
354*9a747e4fSDavid du Colombier  *  compute seconds since Jan 1 1970
355*9a747e4fSDavid du Colombier  */
356*9a747e4fSDavid du Colombier static ulong
rtc2sec(Rtc * rtc)357*9a747e4fSDavid du Colombier rtc2sec(Rtc *rtc)
358*9a747e4fSDavid du Colombier {
359*9a747e4fSDavid du Colombier 	ulong secs;
360*9a747e4fSDavid du Colombier 	int i;
361*9a747e4fSDavid du Colombier 	int *d2m;
362*9a747e4fSDavid du Colombier 
363*9a747e4fSDavid du Colombier 	secs = 0;
364*9a747e4fSDavid du Colombier 
365*9a747e4fSDavid du Colombier 	/*
366*9a747e4fSDavid du Colombier 	 *  seconds per year
367*9a747e4fSDavid du Colombier 	 */
368*9a747e4fSDavid du Colombier 	for(i = 1970; i < rtc->year; i++){
369*9a747e4fSDavid du Colombier 		d2m = yrsize(i);
370*9a747e4fSDavid du Colombier 		secs += d2m[0] * SEC2DAY;
371*9a747e4fSDavid du Colombier 	}
372*9a747e4fSDavid du Colombier 
373*9a747e4fSDavid du Colombier 	/*
374*9a747e4fSDavid du Colombier 	 *  seconds per month
375*9a747e4fSDavid du Colombier 	 */
376*9a747e4fSDavid du Colombier 	d2m = yrsize(rtc->year);
377*9a747e4fSDavid du Colombier 	for(i = 1; i < rtc->mon; i++)
378*9a747e4fSDavid du Colombier 		secs += d2m[i] * SEC2DAY;
379*9a747e4fSDavid du Colombier 
380*9a747e4fSDavid du Colombier 	secs += (rtc->mday-1) * SEC2DAY;
381*9a747e4fSDavid du Colombier 	secs += rtc->hour * SEC2HOUR;
382*9a747e4fSDavid du Colombier 	secs += rtc->min * SEC2MIN;
383*9a747e4fSDavid du Colombier 	secs += rtc->sec;
384*9a747e4fSDavid du Colombier 
385*9a747e4fSDavid du Colombier 	return secs;
386*9a747e4fSDavid du Colombier }
387*9a747e4fSDavid du Colombier 
388*9a747e4fSDavid du Colombier /*
389*9a747e4fSDavid du Colombier  *  compute rtc from seconds since Jan 1 1970
390*9a747e4fSDavid du Colombier  */
391*9a747e4fSDavid du Colombier static void
sec2rtc(ulong secs,Rtc * rtc)392*9a747e4fSDavid du Colombier sec2rtc(ulong secs, Rtc *rtc)
393*9a747e4fSDavid du Colombier {
394*9a747e4fSDavid du Colombier 	int d;
395*9a747e4fSDavid du Colombier 	long hms, day;
396*9a747e4fSDavid du Colombier 	int *d2m;
397*9a747e4fSDavid du Colombier 
398*9a747e4fSDavid du Colombier 	/*
399*9a747e4fSDavid du Colombier 	 * break initial number into days
400*9a747e4fSDavid du Colombier 	 */
401*9a747e4fSDavid du Colombier 	hms = secs % SEC2DAY;
402*9a747e4fSDavid du Colombier 	day = secs / SEC2DAY;
403*9a747e4fSDavid du Colombier 	if(hms < 0) {
404*9a747e4fSDavid du Colombier 		hms += SEC2DAY;
405*9a747e4fSDavid du Colombier 		day -= 1;
406*9a747e4fSDavid du Colombier 	}
407*9a747e4fSDavid du Colombier 
408*9a747e4fSDavid du Colombier 	/*
409*9a747e4fSDavid du Colombier 	 * generate hours:minutes:seconds
410*9a747e4fSDavid du Colombier 	 */
411*9a747e4fSDavid du Colombier 	rtc->sec = hms % 60;
412*9a747e4fSDavid du Colombier 	d = hms / 60;
413*9a747e4fSDavid du Colombier 	rtc->min = d % 60;
414*9a747e4fSDavid du Colombier 	d /= 60;
415*9a747e4fSDavid du Colombier 	rtc->hour = d;
416*9a747e4fSDavid du Colombier 
417*9a747e4fSDavid du Colombier 	/*
418*9a747e4fSDavid du Colombier 	 * year number
419*9a747e4fSDavid du Colombier 	 */
420*9a747e4fSDavid du Colombier 	if(day >= 0)
421*9a747e4fSDavid du Colombier 		for(d = 1970; day >= *yrsize(d); d++)
422*9a747e4fSDavid du Colombier 			day -= *yrsize(d);
423*9a747e4fSDavid du Colombier 	else
424*9a747e4fSDavid du Colombier 		for (d = 1970; day < 0; d--)
425*9a747e4fSDavid du Colombier 			day += *yrsize(d-1);
426*9a747e4fSDavid du Colombier 	rtc->year = d;
427*9a747e4fSDavid du Colombier 
428*9a747e4fSDavid du Colombier 	/*
429*9a747e4fSDavid du Colombier 	 * generate month
430*9a747e4fSDavid du Colombier 	 */
431*9a747e4fSDavid du Colombier 	d2m = yrsize(rtc->year);
432*9a747e4fSDavid du Colombier 	for(d = 1; day >= d2m[d]; d++)
433*9a747e4fSDavid du Colombier 		day -= d2m[d];
434*9a747e4fSDavid du Colombier 	rtc->mday = day + 1;
435*9a747e4fSDavid du Colombier 	rtc->mon = d;
436*9a747e4fSDavid du Colombier 
437*9a747e4fSDavid du Colombier 	return;
438*9a747e4fSDavid du Colombier }
439