2 * M48T59/559 Timekeeper
5 #include "../port/lib.h"
9 #include "../port/error.h"
19 NVLEN= 0x1ff0, /* length in bytes of NV RAM */
22 * register offsets into time of day clock
30 NVday, /* (1 = Sun) */
42 WDsteer = (1<<7), /* 0 -> intr, 1 -> reset */
43 WDmult = (1<<2), /* 5 bits of multiplier */
44 WDres0 = (0<<0), /* 1/16 sec resolution */
45 WDres1 = (1<<0), /* 1/4 sec resolution */
46 WDres2 = (2<<0), /* 1 sec resolution */
47 WDres3 = (3<<0), /* 4 sec resolution */
67 QLock rtclock; /* mutex on nvram operations */
69 static Dirtab rtcdir[]={
70 ".", {Qdir, 0, QTDIR}, 0, DMDIR|0555,
71 "rtc", {Qrtc, 0}, 0, 0644,
72 "nvram", {Qnvram, 0}, 0, 0600,
75 static ulong rtc2sec(Rtc*);
76 static void sec2rtc(ulong, Rtc*);
77 static void setrtc(Rtc*);
78 static void nvcksum(void);
79 static void nvput(int, uchar);
80 static uchar nvget(int);
85 return devattach('r', spec);
89 rtcwalk(Chan *c, Chan *nc, char **name, int nname)
91 return devwalk(c, nc, name, nname, rtcdir, nelem(rtcdir), devgen);
95 rtcstat(Chan *c, uchar *dp, int n)
97 return devstat(c, dp, n, rtcdir, nelem(rtcdir), devgen);
101 rtcopen(Chan *c, int omode)
103 omode = openmode(omode);
104 switch((ulong)c->qid.path){
106 if(strcmp(up->user, eve)!=0 && omode!=OREAD)
110 if(strcmp(up->user, eve)!=0 || !cpuserver)
113 return devopen(c, omode, rtcdir, nelem(rtcdir), devgen);
122 rtcread(Chan *c, void *buf, long n, vlong off)
129 if(c->qid.type & QTDIR)
130 return devdirread(c, buf, n, rtcdir, nelem(rtcdir), devgen);
132 switch((ulong)c->qid.path){
137 n = readnum(offset, buf, n, t, 12);
143 if(n > NVLEN - offset)
147 for(i = 0; i < n; i++)
148 p[i] = nvget(i+offset);
153 return -1; /* never reached */
157 rtcwrite(Chan *c, void *buf, long n, vlong off)
165 switch((ulong)c->qid.path){
175 if(*cp>='0' && *cp<='9')
179 secs = strtoul(cp, 0, 0);
195 if(n > NVLEN - offset)
198 for(i = 0; i < n; i++)
199 nvput(i+offset, ((uchar*)buf)[i]);
205 return -1; /* never reached */
209 rtcbwrite(Chan *c, Block *bp, ulong offset)
211 return devbwrite(c, bp, offset);
236 nvput(int offset, uchar val)
239 outb(STB1, offset>>8);
247 outb(STB1, offset>>8);
260 nvput(NVwatchdog, WDsteer|(1*WDmult)|WDres0);
267 return (bcd&0x0f) + 10 * (bcd>>4);
273 return (val % 10) | (((val/10) % 10) << 4);
287 nvput(NVctl, ctl|RTread);
289 rtc.sec = getbcd(nvget(NVsec) & 0x7f);
290 rtc.min = getbcd(nvget(NVmin));
291 rtc.hour = getbcd(nvget(NVhour));
292 rtc.mday = getbcd(nvget(NVmday));
293 rtc.mon = getbcd(nvget(NVmon));
294 rtc.year = getbcd(nvget(NVyear));
302 return rtc2sec(&rtc);
312 nvput(NVctl, ctl|RTwrite);
314 nvput(NVsec, putbcd(rtc->sec));
315 nvput(NVmin, putbcd(rtc->min));
316 nvput(NVhour, putbcd(rtc->hour));
317 nvput(NVmday, putbcd(rtc->mday));
318 nvput(NVmon, putbcd(rtc->mon));
319 nvput(NVyear, putbcd(rtc->year % 100));
325 #define SEC2HOUR (60L*SEC2MIN)
326 #define SEC2DAY (24L*SEC2HOUR)
329 * days per month plus days/year
331 static int dmsize[] =
333 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
335 static int ldmsize[] =
337 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
341 * return the days/month for the given year
347 if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
354 * compute seconds since Jan 1 1970
368 for(i = 1970; i < rtc->year; i++){
370 secs += d2m[0] * SEC2DAY;
376 d2m = yrsize(rtc->year);
377 for(i = 1; i < rtc->mon; i++)
378 secs += d2m[i] * SEC2DAY;
380 secs += (rtc->mday-1) * SEC2DAY;
381 secs += rtc->hour * SEC2HOUR;
382 secs += rtc->min * SEC2MIN;
389 * compute rtc from seconds since Jan 1 1970
392 sec2rtc(ulong secs, Rtc *rtc)
399 * break initial number into days
401 hms = secs % SEC2DAY;
402 day = secs / SEC2DAY;
409 * generate hours:minutes:seconds
421 for(d = 1970; day >= *yrsize(d); d++)
424 for (d = 1970; day < 0; d--)
431 d2m = yrsize(rtc->year);
432 for(d = 1; day >= d2m[d]; d++)