From ff300baa9aedbc011223c32418fe9c2dc0e1bd20 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Tue, 4 Dec 1990 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1990-12-04 --- power/devrtc.c | 352 +++++++++++++++++++++++++++++++++++++++++++++++++ power/io.h | 3 + 2 files changed, 355 insertions(+) create mode 100644 power/devrtc.c diff --git a/power/devrtc.c b/power/devrtc.c new file mode 100644 index 0000000000000000000000000000000000000000..0e51a0c8c3087aeee55e23550a4bb1fbe7101ca7 --- /dev/null +++ b/power/devrtc.c @@ -0,0 +1,352 @@ +#include "u.h" +#include "lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "errno.h" +#include "devtab.h" + +#include "io.h" + +typedef struct Rtc Rtc; +struct Rtc +{ + QLock; + int sec; + int min; + int hour; + int mday; + int mon; + int year; +}; +Rtc rtc; + +Dirtab rtcdir[]={ + "rtc", {1}, 0, 0600, +}; + +static uchar pattern[] = +{ + 0xc5, 0x3a, 0xa3, 0x5c, 0xc5, 0x3a, 0xa3, 0x5c +}; + +/* + * issue pattern recognition bits to nv ram to address the + * real time clock + */ +rtcpattern(void) +{ + uchar *nv; + uchar ch; + int i, j; + + nv = RTC; + + /* + * read the pattern sequence pointer to reset it + */ + ch = *nv; + + /* + * stuff the pattern recognition codes one bit at + * a time into *nv. + */ + for(i = 0; i < sizeof(pattern); i++){ + ch = pattern[i]; + for (j = 0; j < 8; j++){ + *nv = ch & 0x1; + ch >>= 1; + } + } +} + +void +rtcreset(void) +{ +} + +void +rtcinit(void) +{ +} + +Chan* +rtcattach(char *spec) +{ + return devattach('r', spec); +} + +Chan* +rtcclone(Chan *c, Chan *nc) +{ + return devclone(c, nc); +} + +int +rtcwalk(Chan *c, char *name) +{ + if(c->qid.path != CHDIR) + return 0; + if(strcmp(name, "rtc") == 0){ + c->qid.path = 1; + return 1; + } + return 0; +} + +void +rtcstat(Chan *c, char *dp) +{ + devstat(c, dp, rtcdir, 1, devgen); +} + +Chan* +rtcopen(Chan *c, int omode) +{ + c->mode = openmode(omode); + c->flag |= COPEN; + c->offset = 0; + return c; +} + +void +rtccreate(Chan *c, char *name, int omode, ulong perm) +{ + error(Eperm); +} + +void +rtcclose(Chan *c) +{ +} + +#define GETBCD(o) ((clock[o]&0xf) + 10*(clock[o]>>4)) + +long +rtcread(Chan *c, void *buf, long n) +{ + int i,j; + uchar ch; + uchar *nv; + uchar clock[8]; + char atime[64]; + + if(c->offset!=0) + error(Ebadarg); + nv = RTC; + + /* + * set up the pattern for the clock + */ + qlock(&rtc); + rtcpattern(); + + /* + * read out the clock one bit at a time + */ + for (i = 0; i < 8; i++){ + ch = 0; + for (j = 0; j < 8; j++) + ch |= ((*nv & 0x1) << j); + clock[i] = ch; + } + qunlock(&rtc); + rtc.sec = GETBCD(1); + rtc.min = GETBCD(2); + rtc.hour = GETBCD(3); + rtc.mday = GETBCD(5); + rtc.mon = GETBCD(6); + rtc.year = GETBCD(7); + + /* + * the world starts jan 1 1970 + */ + if(rtc.year < 70) + rtc.year += 2000; + else + rtc.year += 1900; + + sprint(atime, "%.2d:%.2d:%.2d %d/%d/%d", rtc.hour, rtc.min, rtc.sec, + rtc.mon, rtc.mday, rtc.year); + i = strlen(atime); + + if(c->offset >= i) + return 0; + if(c->offset + n > i) + n = i - c->offset; + strncpy(buf, &atime[c->offset], n); + + return n; +} + +static int perm[] = +{ + 3, 2, 1, 6, 5, 7 +}; + +long +rtcwrite(Chan *c, void *buf, long n) +{ + int i,j; + uchar ch; + uchar clock[8]; + uchar *nv; + char *cp; + + if(c->offset!=0) + error(Ebadarg); + + /* + * parse (most any separator will do) + */ + ch = 0; + j = 0; + clock[0] = clock[4] = 0; + cp = buf; + for(i = 0; i < n; i++){ + switch(*cp){ + case ':': case ' ': case '\t': case '/': case '-': + clock[perm[j++]] = ch; + ch = 0; + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + ch = (ch<<4) | (*cp - '0'); + break; + default: + error(Ebadarg); + } + cp++; + } + clock[perm[j++]] = ch; + if(j != 6) + error(Ebadarg); + + /* + * set up the pattern for the clock + */ + qlock(&rtc); + rtcpattern(); + + /* + * write the clock one bit at a time + */ + nv = RTC; + for (i = 0; i < 8; i++){ + ch = clock[i]; + for (j = 0; j < 8; j++){ + *nv = ch & 1; + ch >>= 1; + } + } + qunlock(&rtc); + return n; +} + +void +rtcremove(Chan *c) +{ + error(Eperm); +} + +void +rtcwstat(Chan *c, char *dp) +{ + error(Eperm); +} + +#define SEC2MIN 60 +#define SEC2HOUR (60*SEC2MIN) +#define SEC2DAY (24*SEC2HOUR) +#define SEC2YR (365*SEC2DAY) + +static char dmsize[12] = +{ + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +/* + * compute seconds since Jan 1 1970 + */ +ulong +rtc2sec(void) +{ + ulong secs; + int i; + + for(i = 1970; i < rtc.year; i++) + secs += dysize(i); + for(i = 0; i < rtc.mon-1; i++) + secs += dmsize[i] * SEC2DAY; + if(dysize(rtc.year)==366 && rtc.mon>2) + secs += SEC2DAY; + secs += (rtc.mday-1) * SEC2DAY; + secs += rtc.hour * SEC2HOUR; + secs += rtc.min * SEC2MIN; + secs += rtc.sec; + return secs; +} + +/* + * compute rtc from seconds since Jan 1 1970 + */ +sec2rtc(ulong secs) +{ + int d0, d1; + long hms, day; + + /* + * break initial number into days + */ + hms = secs % SEC2DAY; + day = secs / SEC2DAY; + if(hms < 0) { + hms += SEC2DAY; + day -= 1; + } + + /* + * generate hours:minutes:seconds + */ + rtc.sec = hms % SEC2MIN; + d1 = hms / SEC2MIN; + rtc.min = d1 % SEC2MIN; + d1 /= SEC2MIN; + rtc.hour = d1; + + /* + * year number + */ + if(day >= 0) + for(d1 = 70; day >= dysize(d1); d1++) + day -= dysize(d1); + else + for (d1 = 70; day < 0; d1--) + day += dysize(d1-1); + rtc.year = d1; + + /* + * generate month + */ + if(dysize(d1) == 366) + dmsize[1] = 29; + for(d1 = 0; d0 >= dmsize[d1]; d1++) + d0 -= dmsize[d1]; + dmsize[1] = 28; + rtc.mday = d0 + 1; + rtc.mon = d1; + return; +} + +/* + * days to year + */ +static +dysize(int y) +{ + + if((y%4) == 0) + return 366; + return 365; +} + diff --git a/power/io.h b/power/io.h index a9fad458e1d967305a3f7427e98f129409e10473..fd9fe339a895b3c2648c630b75cb8bd911f20960 100644 --- a/power/io.h +++ b/power/io.h @@ -81,10 +81,13 @@ struct INTVEC { }; #define INTVECREG IO2(INTVEC, 0xF60000) +#define NVRAM IO2(uchar, 0xF10000) #define INTPENDREG IO2(uchar, 0xF20000) /* same as LED */ #define IO2CLRMASK IO2(uchar, 0xFE0000) #define IO2SETMASK IO2(uchar, 0xFE8000) #define IO2MASK IO2(ushort, 0xFE8000) #define MPBERR0 IO2(ulong, 0xF48000) #define MPBERR1 IO2(ulong, 0xF4C000) +#define RTC (NVRAM+0x3ff8) + #define SBEADDR ((ulong *)(UNCACHED|0x1F080000))