2 #include "../port/lib.h"
6 #include "../port/error.h"
9 * real time clock and non-volatile ram
13 Paddr= 0x70, /* address port */
14 Pdata= 0x71, /* data port */
24 Nvoff= 128, /* where usable nvram lives */
30 typedef struct Rtc Rtc;
49 ".", {Qdir, 0, QTDIR}, 0, 0555,
50 "nvram", {Qnvram, 0}, Nvsize, 0664,
51 "rtc", {Qrtc, 0}, 0, 0664,
54 static ulong rtc2sec(Rtc*);
55 static void sec2rtc(ulong, Rtc*);
60 if(ioalloc(Paddr, 2, 0, "rtc/nvr") < 0)
61 panic("rtcinit: ioalloc failed");
67 return devattach('r', spec);
71 rtcwalk(Chan* c, Chan *nc, char** name, int nname)
73 return devwalk(c, nc, name, nname, rtcdir, nelem(rtcdir), devgen);
77 rtcstat(Chan* c, uchar* dp, int n)
79 return devstat(c, dp, n, rtcdir, nelem(rtcdir), devgen);
83 rtcopen(Chan* c, int omode)
85 omode = openmode(omode);
86 switch((ulong)c->qid.path){
88 if(strcmp(up->user, eve)!=0 && omode!=OREAD)
92 if(strcmp(up->user, eve)!=0)
95 return devopen(c, omode, rtcdir, nelem(rtcdir), devgen);
103 #define GETBCD(o) ((bcdclock[o]&0xf) + 10*(bcdclock[o]>>4))
108 uchar bcdclock[Nbcd];
112 /* don't do the read until the clock is no longer busy */
113 for(i = 0; i < 10000; i++){
115 if(inb(Pdata) & 0x80)
118 /* read clock values */
119 outb(Paddr, Seconds); bcdclock[0] = inb(Pdata);
120 outb(Paddr, Minutes); bcdclock[1] = inb(Pdata);
121 outb(Paddr, Hours); bcdclock[2] = inb(Pdata);
122 outb(Paddr, Mday); bcdclock[3] = inb(Pdata);
123 outb(Paddr, Month); bcdclock[4] = inb(Pdata);
124 outb(Paddr, Year); bcdclock[5] = inb(Pdata);
127 if((inb(Pdata) & 0x80) == 0)
136 rtc.hour = GETBCD(2);
137 rtc.mday = GETBCD(3);
139 rtc.year = GETBCD(5);
142 * the world starts jan 1 1970
148 return rtc2sec(&rtc);
151 static Lock nvrtlock;
161 /* loop till we get two reads in a row the same */
163 for(i = 0; i < 100; i++){
169 if(i == 100) print("we are boofheads\n");
177 rtcread(Chan* c, void* buf, long n, vlong off)
183 if(c->qid.type & QTDIR)
184 return devdirread(c, buf, n, rtcdir, nelem(rtcdir), devgen);
186 switch((ulong)c->qid.path){
189 n = readnum(offset, buf, n, t, 12);
196 a = start = smalloc(n);
199 for(t = offset; t < offset + n; t++){
202 outb(Paddr, Nvoff+t);
211 memmove(buf, start, t - offset);
221 #define PUTBCD(n,o) bcdclock[o] = (n % 10) | (((n / 10) % 10)<<4)
224 rtcwrite(Chan* c, void* buf, long n, vlong off)
230 uchar bcdclock[Nbcd];
238 switch((ulong)c->qid.path){
246 if(*cp>='0' && *cp<='9')
250 secs = strtoul(cp, 0, 0);
267 outb(Paddr, Seconds); outb(Pdata, bcdclock[0]);
268 outb(Paddr, Minutes); outb(Pdata, bcdclock[1]);
269 outb(Paddr, Hours); outb(Pdata, bcdclock[2]);
270 outb(Paddr, Mday); outb(Pdata, bcdclock[3]);
271 outb(Paddr, Month); outb(Pdata, bcdclock[4]);
272 outb(Paddr, Year); outb(Pdata, bcdclock[5]);
281 start = a = smalloc(n);
290 for(t = offset; t < offset + n; t++){
293 outb(Paddr, Nvoff+t);
327 #define SEC2HOUR (60L*SEC2MIN)
328 #define SEC2DAY (24L*SEC2HOUR)
331 * days per month plus days/year
333 static int dmsize[] =
335 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
337 static int ldmsize[] =
339 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
343 * return the days/month for the given year
348 if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
355 * compute seconds since Jan 1 1970
369 for(i = 1970; i < rtc->year; i++){
371 secs += d2m[0] * SEC2DAY;
377 d2m = yrsize(rtc->year);
378 for(i = 1; i < rtc->mon; i++)
379 secs += d2m[i] * SEC2DAY;
381 secs += (rtc->mday-1) * SEC2DAY;
382 secs += rtc->hour * SEC2HOUR;
383 secs += rtc->min * SEC2MIN;
390 * compute rtc from seconds since Jan 1 1970
393 sec2rtc(ulong secs, Rtc *rtc)
400 * break initial number into days
402 hms = secs % SEC2DAY;
403 day = secs / SEC2DAY;
410 * generate hours:minutes:seconds
422 for(d = 1970; day >= *yrsize(d); d++)
425 for (d = 1970; day < 0; d--)
432 d2m = yrsize(rtc->year);
433 for(d = 1; day >= d2m[d]; d++)
455 nvramwrite(int addr, uchar data)