123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359 |
- /*
- * devrtc - real-time clock, for kirkwood
- */
- #include "u.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "../port/error.h"
- #include "io.h"
- typedef struct RtcReg RtcReg;
- typedef struct Rtc Rtc;
- struct RtcReg
- {
- ulong time;
- ulong date;
- ulong alarmtm;
- ulong alarmdt;
- ulong intrmask;
- ulong intrcause;
- };
- struct Rtc
- {
- int sec;
- int min;
- int hour;
- int wday;
- int mday;
- int mon;
- int year;
- };
- enum {
- Qdir,
- Qrtc,
- };
- static Dirtab rtcdir[] = {
- ".", {Qdir, 0, QTDIR}, 0, 0555,
- "rtc", {Qrtc}, NUMSIZE, 0664,
- };
- static RtcReg *rtcreg; /* filled in by attach */
- static Lock rtclock;
- #define SEC2MIN 60
- #define SEC2HOUR (60*SEC2MIN)
- #define SEC2DAY (24L*SEC2HOUR)
- /*
- * days per month plus days/year
- */
- static int dmsize[] =
- {
- 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
- };
- static int ldmsize[] =
- {
- 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
- };
- /*
- * return the days/month for the given year
- */
- static int *
- yrsize(int yr)
- {
- if((yr % 4) == 0)
- return ldmsize;
- else
- return dmsize;
- }
- /*
- * compute seconds since Jan 1 1970
- */
- static ulong
- rtc2sec(Rtc *rtc)
- {
- ulong secs;
- int i;
- int *d2m;
- /*
- * seconds per year
- */
- secs = 0;
- for(i = 1970; i < rtc->year; i++){
- d2m = yrsize(i);
- secs += d2m[0] * SEC2DAY;
- }
- /*
- * seconds per month
- */
- d2m = yrsize(rtc->year);
- for(i = 1; i < rtc->mon; i++)
- secs += d2m[i] * 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
- */
- static void
- sec2rtc(ulong secs, Rtc *rtc)
- {
- int d;
- long hms, day;
- int *d2m;
- /*
- * break initial number into days
- */
- hms = secs % SEC2DAY;
- day = secs / SEC2DAY;
- if(hms < 0) {
- hms += SEC2DAY;
- day -= 1;
- }
- /*
- * 19700101 was thursday
- */
- rtc->wday = (day + 7340036L) % 7;
- /*
- * generate hours:minutes:seconds
- */
- rtc->sec = hms % 60;
- d = hms / 60;
- rtc->min = d % 60;
- d /= 60;
- rtc->hour = d;
- /*
- * year number
- */
- if(day >= 0)
- for(d = 1970; day >= *yrsize(d); d++)
- day -= *yrsize(d);
- else
- for (d = 1970; day < 0; d--)
- day += *yrsize(d-1);
- rtc->year = d;
- /*
- * generate month
- */
- d2m = yrsize(rtc->year);
- for(d = 1; day >= d2m[d]; d++)
- day -= d2m[d];
- rtc->mday = day + 1;
- rtc->mon = d;
- }
- enum {
- Rtcsec = 0x00007f,
- Rtcmin = 0x007f00,
- Rtcms = 8,
- Rtchr12 = 0x1f0000,
- Rtchr24 = 0x3f0000,
- Rtchrs = 16,
- Rdmday = 0x00003f,
- Rdmon = 0x001f00,
- Rdms = 8,
- Rdyear = 0x7f0000,
- Rdys = 16,
- Rtcpm = 1<<21, /* pm bit */
- Rtc12 = 1<<22, /* 12 hr clock */
- };
- static ulong
- bcd2dec(ulong bcd)
- {
- ulong d, m, i;
- d = 0;
- m = 1;
- for(i = 0; i < 2 * sizeof d; i++){
- d += ((bcd >> (4*i)) & 0xf) * m;
- m *= 10;
- }
- return d;
- }
- static ulong
- dec2bcd(ulong d)
- {
- ulong bcd, i;
- bcd = 0;
- for(i = 0; d != 0; i++){
- bcd |= (d%10) << (4*i);
- d /= 10;
- }
- return bcd;
- }
- static long
- _rtctime(void)
- {
- ulong t, d;
- Rtc rtc;
- t = rtcreg->time;
- d = rtcreg->date;
- rtc.sec = bcd2dec(t & Rtcsec);
- rtc.min = bcd2dec((t & Rtcmin) >> Rtcms);
- if(t & Rtc12){
- rtc.hour = bcd2dec((t & Rtchr12) >> Rtchrs) - 1; /* 1—12 */
- if(t & Rtcpm)
- rtc.hour += 12;
- }else
- rtc.hour = bcd2dec((t & Rtchr24) >> Rtchrs); /* 0—23 */
- rtc.mday = bcd2dec(d & Rdmday); /* 1—31 */
- rtc.mon = bcd2dec((d & Rdmon) >> Rdms); /* 1—12 */
- rtc.year = bcd2dec((d & Rdyear) >> Rdys) + 2000; /* year%100 */
- // print("%0.2d:%0.2d:%.02d %0.2d/%0.2d/%0.2d\n", /* HH:MM:SS YY/MM/DD */
- // rtc.hour, rtc.min, rtc.sec, rtc.year, rtc.mon, rtc.mday);
- return rtc2sec(&rtc);
- }
- long
- rtctime(void)
- {
- int i;
- long t, ot;
- ilock(&rtclock);
- /* loop until we get two reads in a row the same */
- t = _rtctime();
- ot = ~t;
- for(i = 0; i < 100 && ot != t; i++){
- ot = t;
- t = _rtctime();
- }
- if(ot != t)
- print("rtctime: we are boofheads\n");
- iunlock(&rtclock);
- return t;
- }
- static void
- setrtc(Rtc *rtc)
- {
- ilock(&rtclock);
- rtcreg->time = dec2bcd(rtc->wday) << 24 | dec2bcd(rtc->hour) << 16 |
- dec2bcd(rtc->min) << 8 | dec2bcd(rtc->sec);
- rtcreg->date = dec2bcd(rtc->year - 2000) << 16 |
- dec2bcd(rtc->mon) << 8 | dec2bcd(rtc->mday);
- iunlock(&rtclock);
- }
- static Chan*
- rtcattach(char *spec)
- {
- rtcreg = (RtcReg*)soc.rtc;
- return devattach(L'r', spec);
- }
- static Walkqid*
- rtcwalk(Chan *c, Chan *nc, char **name, int nname)
- {
- return devwalk(c, nc, name, nname, rtcdir, nelem(rtcdir), devgen);
- }
- static int
- rtcstat(Chan *c, uchar *dp, int n)
- {
- return devstat(c, dp, n, rtcdir, nelem(rtcdir), devgen);
- }
- static Chan*
- rtcopen(Chan *c, int omode)
- {
- return devopen(c, omode, rtcdir, nelem(rtcdir), devgen);
- }
- static void
- rtcclose(Chan*)
- {
- }
- static long
- rtcread(Chan *c, void *buf, long n, vlong off)
- {
- if(c->qid.type & QTDIR)
- return devdirread(c, buf, n, rtcdir, nelem(rtcdir), devgen);
- switch((ulong)c->qid.path){
- default:
- error(Egreg);
- case Qrtc:
- return readnum(off, buf, n, rtctime(), NUMSIZE);
- }
- }
- static long
- rtcwrite(Chan *c, void *buf, long n, vlong off)
- {
- ulong offset = off;
- char *cp, sbuf[32];
- Rtc rtc;
- switch((ulong)c->qid.path){
- default:
- error(Egreg);
- case Qrtc:
- if(offset != 0 || n >= sizeof(sbuf)-1)
- error(Ebadarg);
- memmove(sbuf, buf, n);
- sbuf[n] = '\0';
- for(cp = sbuf; *cp != '\0'; cp++)
- if(*cp >= '0' && *cp <= '9')
- break;
- sec2rtc(strtoul(cp, 0, 0), &rtc);
- setrtc(&rtc);
- return n;
- }
- }
- Dev rtcdevtab = {
- L'r',
- "rtc",
- devreset,
- devinit,
- devshutdown,
- rtcattach,
- rtcwalk,
- rtcstat,
- rtcopen,
- devcreate,
- rtcclose,
- rtcread,
- devbread,
- rtcwrite,
- devbwrite,
- devremove,
- devwstat,
- devpower,
- };
|