13e12c5d1SDavid du Colombier #include "u.h" 23e12c5d1SDavid du Colombier #include "../port/lib.h" 33e12c5d1SDavid du Colombier #include "mem.h" 43e12c5d1SDavid du Colombier #include "dat.h" 53e12c5d1SDavid du Colombier #include "fns.h" 63e12c5d1SDavid du Colombier #include "../port/error.h" 73e12c5d1SDavid du Colombier #include "devtab.h" 83e12c5d1SDavid du Colombier 93e12c5d1SDavid du Colombier /* 103e12c5d1SDavid du Colombier * real time clock and non-volatile ram 113e12c5d1SDavid du Colombier */ 123e12c5d1SDavid du Colombier 133e12c5d1SDavid du Colombier enum { 143e12c5d1SDavid du Colombier Paddr= 0x70, /* address port */ 153e12c5d1SDavid du Colombier Pdata= 0x71, /* data port */ 163e12c5d1SDavid du Colombier 173e12c5d1SDavid du Colombier Seconds= 0x00, 183e12c5d1SDavid du Colombier Minutes= 0x02, 193e12c5d1SDavid du Colombier Hours= 0x04, 203e12c5d1SDavid du Colombier Mday= 0x07, 213e12c5d1SDavid du Colombier Month= 0x08, 223e12c5d1SDavid du Colombier Year= 0x09, 233e12c5d1SDavid du Colombier Status= 0x0A, 243e12c5d1SDavid du Colombier 25*219b2ee8SDavid du Colombier Nvoff= 128, /* where usable nvram lives */ 26*219b2ee8SDavid du Colombier Nvsize= 256, 27*219b2ee8SDavid du Colombier 283e12c5d1SDavid du Colombier Nbcd= 6, 293e12c5d1SDavid du Colombier }; 303e12c5d1SDavid du Colombier 313e12c5d1SDavid du Colombier typedef struct Rtc Rtc; 323e12c5d1SDavid du Colombier struct Rtc 333e12c5d1SDavid du Colombier { 343e12c5d1SDavid du Colombier int sec; 353e12c5d1SDavid du Colombier int min; 363e12c5d1SDavid du Colombier int hour; 373e12c5d1SDavid du Colombier int mday; 383e12c5d1SDavid du Colombier int mon; 393e12c5d1SDavid du Colombier int year; 403e12c5d1SDavid du Colombier }; 413e12c5d1SDavid du Colombier 423e12c5d1SDavid du Colombier QLock rtclock; /* mutex on clock operations */ 433e12c5d1SDavid du Colombier 443e12c5d1SDavid du Colombier enum{ 453e12c5d1SDavid du Colombier Qrtc = 1, 463e12c5d1SDavid du Colombier Qnvram, 473e12c5d1SDavid du Colombier }; 483e12c5d1SDavid du Colombier 49*219b2ee8SDavid du Colombier #define NRTC 2 503e12c5d1SDavid du Colombier Dirtab rtcdir[]={ 51*219b2ee8SDavid du Colombier "nvram", {Qnvram, 0}, Nvsize, 0664, 52*219b2ee8SDavid du Colombier "rtc", {Qrtc, 0}, 0, 0664, 533e12c5d1SDavid du Colombier }; 543e12c5d1SDavid du Colombier 553e12c5d1SDavid du Colombier ulong rtc2sec(Rtc*); 563e12c5d1SDavid du Colombier void sec2rtc(ulong, Rtc*); 573e12c5d1SDavid du Colombier int *yrsize(int); 583e12c5d1SDavid du Colombier 593e12c5d1SDavid du Colombier void 603e12c5d1SDavid du Colombier rtcreset(void) 613e12c5d1SDavid du Colombier { 623e12c5d1SDavid du Colombier } 633e12c5d1SDavid du Colombier 643e12c5d1SDavid du Colombier void 653e12c5d1SDavid du Colombier rtcinit(void) 663e12c5d1SDavid du Colombier { 673e12c5d1SDavid du Colombier } 683e12c5d1SDavid du Colombier 693e12c5d1SDavid du Colombier Chan* 703e12c5d1SDavid du Colombier rtcattach(char *spec) 713e12c5d1SDavid du Colombier { 723e12c5d1SDavid du Colombier return devattach('r', spec); 733e12c5d1SDavid du Colombier } 743e12c5d1SDavid du Colombier 753e12c5d1SDavid du Colombier Chan* 763e12c5d1SDavid du Colombier rtcclone(Chan *c, Chan *nc) 773e12c5d1SDavid du Colombier { 783e12c5d1SDavid du Colombier return devclone(c, nc); 793e12c5d1SDavid du Colombier } 803e12c5d1SDavid du Colombier 813e12c5d1SDavid du Colombier int 823e12c5d1SDavid du Colombier rtcwalk(Chan *c, char *name) 833e12c5d1SDavid du Colombier { 843e12c5d1SDavid du Colombier return devwalk(c, name, rtcdir, NRTC, devgen); 853e12c5d1SDavid du Colombier } 863e12c5d1SDavid du Colombier 873e12c5d1SDavid du Colombier void 883e12c5d1SDavid du Colombier rtcstat(Chan *c, char *dp) 893e12c5d1SDavid du Colombier { 903e12c5d1SDavid du Colombier devstat(c, dp, rtcdir, NRTC, devgen); 913e12c5d1SDavid du Colombier } 923e12c5d1SDavid du Colombier 933e12c5d1SDavid du Colombier Chan* 943e12c5d1SDavid du Colombier rtcopen(Chan *c, int omode) 953e12c5d1SDavid du Colombier { 963e12c5d1SDavid du Colombier omode = openmode(omode); 973e12c5d1SDavid du Colombier switch(c->qid.path){ 983e12c5d1SDavid du Colombier case Qrtc: 993e12c5d1SDavid du Colombier if(strcmp(u->p->user, eve)!=0 && omode!=OREAD) 1003e12c5d1SDavid du Colombier error(Eperm); 1013e12c5d1SDavid du Colombier break; 1023e12c5d1SDavid du Colombier case Qnvram: 103*219b2ee8SDavid du Colombier if(strcmp(u->p->user, eve)!=0) 1043e12c5d1SDavid du Colombier error(Eperm); 1053e12c5d1SDavid du Colombier } 1063e12c5d1SDavid du Colombier return devopen(c, omode, rtcdir, NRTC, devgen); 1073e12c5d1SDavid du Colombier } 1083e12c5d1SDavid du Colombier 1093e12c5d1SDavid du Colombier void 1103e12c5d1SDavid du Colombier rtccreate(Chan *c, char *name, int omode, ulong perm) 1113e12c5d1SDavid du Colombier { 1123e12c5d1SDavid du Colombier USED(c, name, omode, perm); 1133e12c5d1SDavid du Colombier error(Eperm); 1143e12c5d1SDavid du Colombier } 1153e12c5d1SDavid du Colombier 1163e12c5d1SDavid du Colombier void 1173e12c5d1SDavid du Colombier rtcclose(Chan *c) 1183e12c5d1SDavid du Colombier { 1193e12c5d1SDavid du Colombier USED(c); 1203e12c5d1SDavid du Colombier } 1213e12c5d1SDavid du Colombier 1223e12c5d1SDavid du Colombier #define GETBCD(o) ((bcdclock[o]&0xf) + 10*(bcdclock[o]>>4)) 1233e12c5d1SDavid du Colombier 1243e12c5d1SDavid du Colombier long 1253e12c5d1SDavid du Colombier rtctime(void) 1263e12c5d1SDavid du Colombier { 1273e12c5d1SDavid du Colombier uchar bcdclock[Nbcd]; 1283e12c5d1SDavid du Colombier Rtc rtc; 129bd389b36SDavid du Colombier int i; 1303e12c5d1SDavid du Colombier 131bd389b36SDavid du Colombier for(i = 0; i < 10000; i++){ 1323e12c5d1SDavid du Colombier outb(Paddr, Status); 133bd389b36SDavid du Colombier if((inb(Pdata) & 1) == 0) 134bd389b36SDavid du Colombier break; 135bd389b36SDavid du Colombier } 1363e12c5d1SDavid du Colombier outb(Paddr, Seconds); bcdclock[0] = inb(Pdata); 1373e12c5d1SDavid du Colombier outb(Paddr, Minutes); bcdclock[1] = inb(Pdata); 1383e12c5d1SDavid du Colombier outb(Paddr, Hours); bcdclock[2] = inb(Pdata); 1393e12c5d1SDavid du Colombier outb(Paddr, Mday); bcdclock[3] = inb(Pdata); 1403e12c5d1SDavid du Colombier outb(Paddr, Month); bcdclock[4] = inb(Pdata); 1413e12c5d1SDavid du Colombier outb(Paddr, Year); bcdclock[5] = inb(Pdata); 1423e12c5d1SDavid du Colombier 1433e12c5d1SDavid du Colombier /* 1443e12c5d1SDavid du Colombier * convert from BCD 1453e12c5d1SDavid du Colombier */ 1463e12c5d1SDavid du Colombier rtc.sec = GETBCD(0); 1473e12c5d1SDavid du Colombier rtc.min = GETBCD(1); 1483e12c5d1SDavid du Colombier rtc.hour = GETBCD(2); 1493e12c5d1SDavid du Colombier rtc.mday = GETBCD(3); 1503e12c5d1SDavid du Colombier rtc.mon = GETBCD(4); 1513e12c5d1SDavid du Colombier rtc.year = GETBCD(5); 1523e12c5d1SDavid du Colombier 1533e12c5d1SDavid du Colombier /* 1543e12c5d1SDavid du Colombier * the world starts jan 1 1970 1553e12c5d1SDavid du Colombier */ 1563e12c5d1SDavid du Colombier if(rtc.year < 70) 1573e12c5d1SDavid du Colombier rtc.year += 2000; 1583e12c5d1SDavid du Colombier else 1593e12c5d1SDavid du Colombier rtc.year += 1900; 1603e12c5d1SDavid du Colombier return rtc2sec(&rtc); 1613e12c5d1SDavid du Colombier } 1623e12c5d1SDavid du Colombier 1633e12c5d1SDavid du Colombier long 1643e12c5d1SDavid du Colombier rtcread(Chan *c, void *buf, long n, ulong offset) 1653e12c5d1SDavid du Colombier { 1663e12c5d1SDavid du Colombier ulong t, ot; 167*219b2ee8SDavid du Colombier char *a; 1683e12c5d1SDavid du Colombier 1693e12c5d1SDavid du Colombier if(c->qid.path & CHDIR) 1703e12c5d1SDavid du Colombier return devdirread(c, buf, n, rtcdir, NRTC, devgen); 1713e12c5d1SDavid du Colombier 172*219b2ee8SDavid du Colombier switch(c->qid.path){ 173*219b2ee8SDavid du Colombier case Qrtc: 1743e12c5d1SDavid du Colombier qlock(&rtclock); 1753e12c5d1SDavid du Colombier t = rtctime(); 1763e12c5d1SDavid du Colombier do{ 1773e12c5d1SDavid du Colombier ot = t; 1783e12c5d1SDavid du Colombier t = rtctime(); /* make sure there's no skew */ 1793e12c5d1SDavid du Colombier }while(t != ot); 1803e12c5d1SDavid du Colombier qunlock(&rtclock); 1813e12c5d1SDavid du Colombier n = readnum(offset, buf, n, t, 12); 1823e12c5d1SDavid du Colombier return n; 183*219b2ee8SDavid du Colombier case Qnvram: 184*219b2ee8SDavid du Colombier a = buf; 185*219b2ee8SDavid du Colombier if(waserror()){ 186*219b2ee8SDavid du Colombier qunlock(&rtclock); 187*219b2ee8SDavid du Colombier nexterror(); 188*219b2ee8SDavid du Colombier } 189*219b2ee8SDavid du Colombier qlock(&rtclock); 190*219b2ee8SDavid du Colombier for(t = offset; t < offset + n; t++){ 191*219b2ee8SDavid du Colombier if(t >= Nvsize) 192*219b2ee8SDavid du Colombier break; 193*219b2ee8SDavid du Colombier outb(Paddr, Nvoff+t); 194*219b2ee8SDavid du Colombier delay(1); 195*219b2ee8SDavid du Colombier *a++ = inb(Pdata); 196*219b2ee8SDavid du Colombier } 197*219b2ee8SDavid du Colombier qunlock(&rtclock); 198*219b2ee8SDavid du Colombier poperror(); 199*219b2ee8SDavid du Colombier return t - offset; 200*219b2ee8SDavid du Colombier } 201*219b2ee8SDavid du Colombier error(Ebadarg); 202*219b2ee8SDavid du Colombier return 0; 2033e12c5d1SDavid du Colombier } 2043e12c5d1SDavid du Colombier 2053e12c5d1SDavid du Colombier #define PUTBCD(n,o) bcdclock[o] = (n % 10) | (((n / 10) % 10)<<4) 2063e12c5d1SDavid du Colombier 2073e12c5d1SDavid du Colombier long 2083e12c5d1SDavid du Colombier rtcwrite(Chan *c, void *buf, long n, ulong offset) 2093e12c5d1SDavid du Colombier { 210*219b2ee8SDavid du Colombier int t; 211*219b2ee8SDavid du Colombier char *a; 2123e12c5d1SDavid du Colombier Rtc rtc; 2133e12c5d1SDavid du Colombier ulong secs; 2143e12c5d1SDavid du Colombier uchar bcdclock[Nbcd]; 2153e12c5d1SDavid du Colombier char *cp, *ep; 2163e12c5d1SDavid du Colombier 2173e12c5d1SDavid du Colombier USED(c); 2183e12c5d1SDavid du Colombier if(offset!=0) 2193e12c5d1SDavid du Colombier error(Ebadarg); 2203e12c5d1SDavid du Colombier 221*219b2ee8SDavid du Colombier 222*219b2ee8SDavid du Colombier switch(c->qid.path){ 223*219b2ee8SDavid du Colombier case Qrtc: 2243e12c5d1SDavid du Colombier /* 2253e12c5d1SDavid du Colombier * read the time 2263e12c5d1SDavid du Colombier */ 2273e12c5d1SDavid du Colombier cp = ep = buf; 2283e12c5d1SDavid du Colombier ep += n; 2293e12c5d1SDavid du Colombier while(cp < ep){ 2303e12c5d1SDavid du Colombier if(*cp>='0' && *cp<='9') 2313e12c5d1SDavid du Colombier break; 2323e12c5d1SDavid du Colombier cp++; 2333e12c5d1SDavid du Colombier } 2343e12c5d1SDavid du Colombier secs = strtoul(cp, 0, 0); 2353e12c5d1SDavid du Colombier 2363e12c5d1SDavid du Colombier /* 2373e12c5d1SDavid du Colombier * convert to bcd 2383e12c5d1SDavid du Colombier */ 2393e12c5d1SDavid du Colombier sec2rtc(secs, &rtc); 2403e12c5d1SDavid du Colombier PUTBCD(rtc.sec, 0); 2413e12c5d1SDavid du Colombier PUTBCD(rtc.min, 1); 2423e12c5d1SDavid du Colombier PUTBCD(rtc.hour, 2); 2433e12c5d1SDavid du Colombier PUTBCD(rtc.mday, 3); 2443e12c5d1SDavid du Colombier PUTBCD(rtc.mon, 4); 2453e12c5d1SDavid du Colombier PUTBCD(rtc.year, 5); 2463e12c5d1SDavid du Colombier 2473e12c5d1SDavid du Colombier /* 2483e12c5d1SDavid du Colombier * write the clock 2493e12c5d1SDavid du Colombier */ 2503e12c5d1SDavid du Colombier qlock(&rtclock); 2513e12c5d1SDavid du Colombier outb(Paddr, Seconds); outb(Pdata, bcdclock[0]); 2523e12c5d1SDavid du Colombier outb(Paddr, Minutes); outb(Pdata, bcdclock[1]); 2533e12c5d1SDavid du Colombier outb(Paddr, Hours); outb(Pdata, bcdclock[2]); 2543e12c5d1SDavid du Colombier outb(Paddr, Mday); outb(Pdata, bcdclock[3]); 2553e12c5d1SDavid du Colombier outb(Paddr, Month); outb(Pdata, bcdclock[4]); 2563e12c5d1SDavid du Colombier outb(Paddr, Year); outb(Pdata, bcdclock[5]); 2573e12c5d1SDavid du Colombier qunlock(&rtclock); 2583e12c5d1SDavid du Colombier return n; 259*219b2ee8SDavid du Colombier case Qnvram: 260*219b2ee8SDavid du Colombier a = buf; 261*219b2ee8SDavid du Colombier if(waserror()){ 262*219b2ee8SDavid du Colombier qunlock(&rtclock); 263*219b2ee8SDavid du Colombier nexterror(); 264*219b2ee8SDavid du Colombier } 265*219b2ee8SDavid du Colombier qlock(&rtclock); 266*219b2ee8SDavid du Colombier for(t = offset; t < offset + n; t++){ 267*219b2ee8SDavid du Colombier if(t >= Nvsize) 268*219b2ee8SDavid du Colombier break; 269*219b2ee8SDavid du Colombier outb(Paddr, Nvoff+t); 270*219b2ee8SDavid du Colombier outb(Pdata, *a++); 271*219b2ee8SDavid du Colombier } 272*219b2ee8SDavid du Colombier qunlock(&rtclock); 273*219b2ee8SDavid du Colombier poperror(); 274*219b2ee8SDavid du Colombier return t - offset; 275*219b2ee8SDavid du Colombier } 276*219b2ee8SDavid du Colombier error(Ebadarg); 277*219b2ee8SDavid du Colombier return 0; 2783e12c5d1SDavid du Colombier } 2793e12c5d1SDavid du Colombier 2803e12c5d1SDavid du Colombier void 2813e12c5d1SDavid du Colombier rtcremove(Chan *c) 2823e12c5d1SDavid du Colombier { 2833e12c5d1SDavid du Colombier USED(c); 2843e12c5d1SDavid du Colombier error(Eperm); 2853e12c5d1SDavid du Colombier } 2863e12c5d1SDavid du Colombier 2873e12c5d1SDavid du Colombier void 2883e12c5d1SDavid du Colombier rtcwstat(Chan *c, char *dp) 2893e12c5d1SDavid du Colombier { 2903e12c5d1SDavid du Colombier USED(c, dp); 2913e12c5d1SDavid du Colombier error(Eperm); 2923e12c5d1SDavid du Colombier } 2933e12c5d1SDavid du Colombier 2943e12c5d1SDavid du Colombier #define SEC2MIN 60L 2953e12c5d1SDavid du Colombier #define SEC2HOUR (60L*SEC2MIN) 2963e12c5d1SDavid du Colombier #define SEC2DAY (24L*SEC2HOUR) 2973e12c5d1SDavid du Colombier 2983e12c5d1SDavid du Colombier /* 2993e12c5d1SDavid du Colombier * days per month plus days/year 3003e12c5d1SDavid du Colombier */ 3013e12c5d1SDavid du Colombier static int dmsize[] = 3023e12c5d1SDavid du Colombier { 3033e12c5d1SDavid du Colombier 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 3043e12c5d1SDavid du Colombier }; 3053e12c5d1SDavid du Colombier static int ldmsize[] = 3063e12c5d1SDavid du Colombier { 3073e12c5d1SDavid du Colombier 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 3083e12c5d1SDavid du Colombier }; 3093e12c5d1SDavid du Colombier 3103e12c5d1SDavid du Colombier /* 3113e12c5d1SDavid du Colombier * return the days/month for the given year 3123e12c5d1SDavid du Colombier */ 3133e12c5d1SDavid du Colombier int * 3143e12c5d1SDavid du Colombier yrsize(int yr) 3153e12c5d1SDavid du Colombier { 3163e12c5d1SDavid du Colombier if((yr % 4) == 0) 3173e12c5d1SDavid du Colombier return ldmsize; 3183e12c5d1SDavid du Colombier else 3193e12c5d1SDavid du Colombier return dmsize; 3203e12c5d1SDavid du Colombier } 3213e12c5d1SDavid du Colombier 3223e12c5d1SDavid du Colombier /* 3233e12c5d1SDavid du Colombier * compute seconds since Jan 1 1970 3243e12c5d1SDavid du Colombier */ 3253e12c5d1SDavid du Colombier ulong 3263e12c5d1SDavid du Colombier rtc2sec(Rtc *rtc) 3273e12c5d1SDavid du Colombier { 3283e12c5d1SDavid du Colombier ulong secs; 3293e12c5d1SDavid du Colombier int i; 3303e12c5d1SDavid du Colombier int *d2m; 3313e12c5d1SDavid du Colombier 3323e12c5d1SDavid du Colombier secs = 0; 3333e12c5d1SDavid du Colombier 3343e12c5d1SDavid du Colombier /* 3353e12c5d1SDavid du Colombier * seconds per year 3363e12c5d1SDavid du Colombier */ 3373e12c5d1SDavid du Colombier for(i = 1970; i < rtc->year; i++){ 3383e12c5d1SDavid du Colombier d2m = yrsize(i); 3393e12c5d1SDavid du Colombier secs += d2m[0] * SEC2DAY; 3403e12c5d1SDavid du Colombier } 3413e12c5d1SDavid du Colombier 3423e12c5d1SDavid du Colombier /* 3433e12c5d1SDavid du Colombier * seconds per month 3443e12c5d1SDavid du Colombier */ 3453e12c5d1SDavid du Colombier d2m = yrsize(rtc->year); 3463e12c5d1SDavid du Colombier for(i = 1; i < rtc->mon; i++) 3473e12c5d1SDavid du Colombier secs += d2m[i] * SEC2DAY; 3483e12c5d1SDavid du Colombier 3493e12c5d1SDavid du Colombier secs += (rtc->mday-1) * SEC2DAY; 3503e12c5d1SDavid du Colombier secs += rtc->hour * SEC2HOUR; 3513e12c5d1SDavid du Colombier secs += rtc->min * SEC2MIN; 3523e12c5d1SDavid du Colombier secs += rtc->sec; 3533e12c5d1SDavid du Colombier 3543e12c5d1SDavid du Colombier return secs; 3553e12c5d1SDavid du Colombier } 3563e12c5d1SDavid du Colombier 3573e12c5d1SDavid du Colombier /* 3583e12c5d1SDavid du Colombier * compute rtc from seconds since Jan 1 1970 3593e12c5d1SDavid du Colombier */ 3603e12c5d1SDavid du Colombier void 3613e12c5d1SDavid du Colombier sec2rtc(ulong secs, Rtc *rtc) 3623e12c5d1SDavid du Colombier { 3633e12c5d1SDavid du Colombier int d; 3643e12c5d1SDavid du Colombier long hms, day; 3653e12c5d1SDavid du Colombier int *d2m; 3663e12c5d1SDavid du Colombier 3673e12c5d1SDavid du Colombier /* 3683e12c5d1SDavid du Colombier * break initial number into days 3693e12c5d1SDavid du Colombier */ 3703e12c5d1SDavid du Colombier hms = secs % SEC2DAY; 3713e12c5d1SDavid du Colombier day = secs / SEC2DAY; 3723e12c5d1SDavid du Colombier if(hms < 0) { 3733e12c5d1SDavid du Colombier hms += SEC2DAY; 3743e12c5d1SDavid du Colombier day -= 1; 3753e12c5d1SDavid du Colombier } 3763e12c5d1SDavid du Colombier 3773e12c5d1SDavid du Colombier /* 3783e12c5d1SDavid du Colombier * generate hours:minutes:seconds 3793e12c5d1SDavid du Colombier */ 3803e12c5d1SDavid du Colombier rtc->sec = hms % 60; 3813e12c5d1SDavid du Colombier d = hms / 60; 3823e12c5d1SDavid du Colombier rtc->min = d % 60; 3833e12c5d1SDavid du Colombier d /= 60; 3843e12c5d1SDavid du Colombier rtc->hour = d; 3853e12c5d1SDavid du Colombier 3863e12c5d1SDavid du Colombier /* 3873e12c5d1SDavid du Colombier * year number 3883e12c5d1SDavid du Colombier */ 3893e12c5d1SDavid du Colombier if(day >= 0) 3903e12c5d1SDavid du Colombier for(d = 1970; day >= *yrsize(d); d++) 3913e12c5d1SDavid du Colombier day -= *yrsize(d); 3923e12c5d1SDavid du Colombier else 3933e12c5d1SDavid du Colombier for (d = 1970; day < 0; d--) 3943e12c5d1SDavid du Colombier day += *yrsize(d-1); 3953e12c5d1SDavid du Colombier rtc->year = d; 3963e12c5d1SDavid du Colombier 3973e12c5d1SDavid du Colombier /* 3983e12c5d1SDavid du Colombier * generate month 3993e12c5d1SDavid du Colombier */ 4003e12c5d1SDavid du Colombier d2m = yrsize(rtc->year); 4013e12c5d1SDavid du Colombier for(d = 1; day >= d2m[d]; d++) 4023e12c5d1SDavid du Colombier day -= d2m[d]; 4033e12c5d1SDavid du Colombier rtc->mday = day + 1; 4043e12c5d1SDavid du Colombier rtc->mon = d; 4053e12c5d1SDavid du Colombier 4063e12c5d1SDavid du Colombier return; 4073e12c5d1SDavid du Colombier } 408bd389b36SDavid du Colombier 409bd389b36SDavid du Colombier uchar 410bd389b36SDavid du Colombier nvramread(int offset) 411bd389b36SDavid du Colombier { 412bd389b36SDavid du Colombier outb(Paddr, offset); 413*219b2ee8SDavid du Colombier delay(1); 414bd389b36SDavid du Colombier return inb(Pdata); 415bd389b36SDavid du Colombier } 416