|
|
1.1 ! root 1: #include "u.h" ! 2: #include "../port/lib.h" ! 3: #include "mem.h" ! 4: #include "dat.h" ! 5: #include "fns.h" ! 6: #include "../port/error.h" ! 7: #include "devtab.h" ! 8: ! 9: /* ! 10: * real time clock and non-volatile ram ! 11: */ ! 12: ! 13: enum { ! 14: Paddr= 0x70, /* address port */ ! 15: Pdata= 0x71, /* data port */ ! 16: ! 17: Seconds= 0x00, ! 18: Minutes= 0x02, ! 19: Hours= 0x04, ! 20: Mday= 0x07, ! 21: Month= 0x08, ! 22: Year= 0x09, ! 23: Status= 0x0A, ! 24: ! 25: Nvoff= 128, /* where usable nvram lives */ ! 26: Nvsize= 256, ! 27: ! 28: Nbcd= 6, ! 29: }; ! 30: ! 31: typedef struct Rtc Rtc; ! 32: struct Rtc ! 33: { ! 34: int sec; ! 35: int min; ! 36: int hour; ! 37: int mday; ! 38: int mon; ! 39: int year; ! 40: }; ! 41: ! 42: QLock rtclock; /* mutex on clock operations */ ! 43: ! 44: enum{ ! 45: Qrtc = 1, ! 46: Qnvram, ! 47: }; ! 48: ! 49: #define NRTC 2 ! 50: Dirtab rtcdir[]={ ! 51: "nvram", {Qnvram, 0}, Nvsize, 0664, ! 52: "rtc", {Qrtc, 0}, 0, 0664, ! 53: }; ! 54: ! 55: ulong rtc2sec(Rtc*); ! 56: void sec2rtc(ulong, Rtc*); ! 57: int *yrsize(int); ! 58: ! 59: void ! 60: rtcreset(void) ! 61: { ! 62: } ! 63: ! 64: void ! 65: rtcinit(void) ! 66: { ! 67: } ! 68: ! 69: Chan* ! 70: rtcattach(char *spec) ! 71: { ! 72: return devattach('r', spec); ! 73: } ! 74: ! 75: Chan* ! 76: rtcclone(Chan *c, Chan *nc) ! 77: { ! 78: return devclone(c, nc); ! 79: } ! 80: ! 81: int ! 82: rtcwalk(Chan *c, char *name) ! 83: { ! 84: return devwalk(c, name, rtcdir, NRTC, devgen); ! 85: } ! 86: ! 87: void ! 88: rtcstat(Chan *c, char *dp) ! 89: { ! 90: devstat(c, dp, rtcdir, NRTC, devgen); ! 91: } ! 92: ! 93: Chan* ! 94: rtcopen(Chan *c, int omode) ! 95: { ! 96: omode = openmode(omode); ! 97: switch(c->qid.path){ ! 98: case Qrtc: ! 99: if(strcmp(u->p->user, eve)!=0 && omode!=OREAD) ! 100: error(Eperm); ! 101: break; ! 102: case Qnvram: ! 103: if(strcmp(u->p->user, eve)!=0) ! 104: error(Eperm); ! 105: } ! 106: return devopen(c, omode, rtcdir, NRTC, devgen); ! 107: } ! 108: ! 109: void ! 110: rtccreate(Chan *c, char *name, int omode, ulong perm) ! 111: { ! 112: USED(c, name, omode, perm); ! 113: error(Eperm); ! 114: } ! 115: ! 116: void ! 117: rtcclose(Chan *c) ! 118: { ! 119: USED(c); ! 120: } ! 121: ! 122: #define GETBCD(o) ((bcdclock[o]&0xf) + 10*(bcdclock[o]>>4)) ! 123: ! 124: long ! 125: rtctime(void) ! 126: { ! 127: uchar bcdclock[Nbcd]; ! 128: Rtc rtc; ! 129: int i; ! 130: ! 131: for(i = 0; i < 10000; i++){ ! 132: outb(Paddr, Status); ! 133: if((inb(Pdata) & 1) == 0) ! 134: break; ! 135: } ! 136: outb(Paddr, Seconds); bcdclock[0] = inb(Pdata); ! 137: outb(Paddr, Minutes); bcdclock[1] = inb(Pdata); ! 138: outb(Paddr, Hours); bcdclock[2] = inb(Pdata); ! 139: outb(Paddr, Mday); bcdclock[3] = inb(Pdata); ! 140: outb(Paddr, Month); bcdclock[4] = inb(Pdata); ! 141: outb(Paddr, Year); bcdclock[5] = inb(Pdata); ! 142: ! 143: /* ! 144: * convert from BCD ! 145: */ ! 146: rtc.sec = GETBCD(0); ! 147: rtc.min = GETBCD(1); ! 148: rtc.hour = GETBCD(2); ! 149: rtc.mday = GETBCD(3); ! 150: rtc.mon = GETBCD(4); ! 151: rtc.year = GETBCD(5); ! 152: ! 153: /* ! 154: * the world starts jan 1 1970 ! 155: */ ! 156: if(rtc.year < 70) ! 157: rtc.year += 2000; ! 158: else ! 159: rtc.year += 1900; ! 160: return rtc2sec(&rtc); ! 161: } ! 162: ! 163: long ! 164: rtcread(Chan *c, void *buf, long n, ulong offset) ! 165: { ! 166: ulong t, ot; ! 167: char *a; ! 168: ! 169: if(c->qid.path & CHDIR) ! 170: return devdirread(c, buf, n, rtcdir, NRTC, devgen); ! 171: ! 172: switch(c->qid.path){ ! 173: case Qrtc: ! 174: qlock(&rtclock); ! 175: t = rtctime(); ! 176: do{ ! 177: ot = t; ! 178: t = rtctime(); /* make sure there's no skew */ ! 179: }while(t != ot); ! 180: qunlock(&rtclock); ! 181: n = readnum(offset, buf, n, t, 12); ! 182: return n; ! 183: case Qnvram: ! 184: a = buf; ! 185: if(waserror()){ ! 186: qunlock(&rtclock); ! 187: nexterror(); ! 188: } ! 189: qlock(&rtclock); ! 190: for(t = offset; t < offset + n; t++){ ! 191: if(t >= Nvsize) ! 192: break; ! 193: outb(Paddr, Nvoff+t); ! 194: delay(1); ! 195: *a++ = inb(Pdata); ! 196: } ! 197: qunlock(&rtclock); ! 198: poperror(); ! 199: return t - offset; ! 200: } ! 201: error(Ebadarg); ! 202: return 0; ! 203: } ! 204: ! 205: #define PUTBCD(n,o) bcdclock[o] = (n % 10) | (((n / 10) % 10)<<4) ! 206: ! 207: long ! 208: rtcwrite(Chan *c, void *buf, long n, ulong offset) ! 209: { ! 210: int t; ! 211: char *a; ! 212: Rtc rtc; ! 213: ulong secs; ! 214: uchar bcdclock[Nbcd]; ! 215: char *cp, *ep; ! 216: ! 217: USED(c); ! 218: if(offset!=0) ! 219: error(Ebadarg); ! 220: ! 221: ! 222: switch(c->qid.path){ ! 223: case Qrtc: ! 224: /* ! 225: * read the time ! 226: */ ! 227: cp = ep = buf; ! 228: ep += n; ! 229: while(cp < ep){ ! 230: if(*cp>='0' && *cp<='9') ! 231: break; ! 232: cp++; ! 233: } ! 234: secs = strtoul(cp, 0, 0); ! 235: ! 236: /* ! 237: * convert to bcd ! 238: */ ! 239: sec2rtc(secs, &rtc); ! 240: PUTBCD(rtc.sec, 0); ! 241: PUTBCD(rtc.min, 1); ! 242: PUTBCD(rtc.hour, 2); ! 243: PUTBCD(rtc.mday, 3); ! 244: PUTBCD(rtc.mon, 4); ! 245: PUTBCD(rtc.year, 5); ! 246: ! 247: /* ! 248: * write the clock ! 249: */ ! 250: qlock(&rtclock); ! 251: outb(Paddr, Seconds); outb(Pdata, bcdclock[0]); ! 252: outb(Paddr, Minutes); outb(Pdata, bcdclock[1]); ! 253: outb(Paddr, Hours); outb(Pdata, bcdclock[2]); ! 254: outb(Paddr, Mday); outb(Pdata, bcdclock[3]); ! 255: outb(Paddr, Month); outb(Pdata, bcdclock[4]); ! 256: outb(Paddr, Year); outb(Pdata, bcdclock[5]); ! 257: qunlock(&rtclock); ! 258: return n; ! 259: case Qnvram: ! 260: a = buf; ! 261: if(waserror()){ ! 262: qunlock(&rtclock); ! 263: nexterror(); ! 264: } ! 265: qlock(&rtclock); ! 266: for(t = offset; t < offset + n; t++){ ! 267: if(t >= Nvsize) ! 268: break; ! 269: outb(Paddr, Nvoff+t); ! 270: outb(Pdata, *a++); ! 271: } ! 272: qunlock(&rtclock); ! 273: poperror(); ! 274: return t - offset; ! 275: } ! 276: error(Ebadarg); ! 277: return 0; ! 278: } ! 279: ! 280: void ! 281: rtcremove(Chan *c) ! 282: { ! 283: USED(c); ! 284: error(Eperm); ! 285: } ! 286: ! 287: void ! 288: rtcwstat(Chan *c, char *dp) ! 289: { ! 290: USED(c, dp); ! 291: error(Eperm); ! 292: } ! 293: ! 294: #define SEC2MIN 60L ! 295: #define SEC2HOUR (60L*SEC2MIN) ! 296: #define SEC2DAY (24L*SEC2HOUR) ! 297: ! 298: /* ! 299: * days per month plus days/year ! 300: */ ! 301: static int dmsize[] = ! 302: { ! 303: 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ! 304: }; ! 305: static int ldmsize[] = ! 306: { ! 307: 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 ! 308: }; ! 309: ! 310: /* ! 311: * return the days/month for the given year ! 312: */ ! 313: int * ! 314: yrsize(int yr) ! 315: { ! 316: if((yr % 4) == 0) ! 317: return ldmsize; ! 318: else ! 319: return dmsize; ! 320: } ! 321: ! 322: /* ! 323: * compute seconds since Jan 1 1970 ! 324: */ ! 325: ulong ! 326: rtc2sec(Rtc *rtc) ! 327: { ! 328: ulong secs; ! 329: int i; ! 330: int *d2m; ! 331: ! 332: secs = 0; ! 333: ! 334: /* ! 335: * seconds per year ! 336: */ ! 337: for(i = 1970; i < rtc->year; i++){ ! 338: d2m = yrsize(i); ! 339: secs += d2m[0] * SEC2DAY; ! 340: } ! 341: ! 342: /* ! 343: * seconds per month ! 344: */ ! 345: d2m = yrsize(rtc->year); ! 346: for(i = 1; i < rtc->mon; i++) ! 347: secs += d2m[i] * SEC2DAY; ! 348: ! 349: secs += (rtc->mday-1) * SEC2DAY; ! 350: secs += rtc->hour * SEC2HOUR; ! 351: secs += rtc->min * SEC2MIN; ! 352: secs += rtc->sec; ! 353: ! 354: return secs; ! 355: } ! 356: ! 357: /* ! 358: * compute rtc from seconds since Jan 1 1970 ! 359: */ ! 360: void ! 361: sec2rtc(ulong secs, Rtc *rtc) ! 362: { ! 363: int d; ! 364: long hms, day; ! 365: int *d2m; ! 366: ! 367: /* ! 368: * break initial number into days ! 369: */ ! 370: hms = secs % SEC2DAY; ! 371: day = secs / SEC2DAY; ! 372: if(hms < 0) { ! 373: hms += SEC2DAY; ! 374: day -= 1; ! 375: } ! 376: ! 377: /* ! 378: * generate hours:minutes:seconds ! 379: */ ! 380: rtc->sec = hms % 60; ! 381: d = hms / 60; ! 382: rtc->min = d % 60; ! 383: d /= 60; ! 384: rtc->hour = d; ! 385: ! 386: /* ! 387: * year number ! 388: */ ! 389: if(day >= 0) ! 390: for(d = 1970; day >= *yrsize(d); d++) ! 391: day -= *yrsize(d); ! 392: else ! 393: for (d = 1970; day < 0; d--) ! 394: day += *yrsize(d-1); ! 395: rtc->year = d; ! 396: ! 397: /* ! 398: * generate month ! 399: */ ! 400: d2m = yrsize(rtc->year); ! 401: for(d = 1; day >= d2m[d]; d++) ! 402: day -= d2m[d]; ! 403: rtc->mday = day + 1; ! 404: rtc->mon = d; ! 405: ! 406: return; ! 407: } ! 408: ! 409: uchar ! 410: nvramread(int offset) ! 411: { ! 412: outb(Paddr, offset); ! 413: delay(1); ! 414: return inb(Pdata); ! 415: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.