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