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 8 #include "io.h" 9 10 /* 11 * SA11x0 real time clock 12 * TO DO: alarms, wakeup, allow trim setting(?) 13 */ 14 15 enum{ 16 Qdir, 17 Qrtc, 18 Qrtctrim, 19 }; 20 21 static Dirtab rtcdir[]={ 22 ".", {Qdir,0,QTDIR}, 0, 0555, 23 "rtc", {Qrtc}, NUMSIZE, 0664, 24 "rtctrim", {Qrtctrim}, 0, 0664, 25 }; 26 #define NRTC (sizeof(rtcdir)/sizeof(rtcdir[0])) 27 28 extern ulong boottime; 29 30 enum { 31 RTSR_al= 1<<0, /* RTC alarm detected */ 32 RTSR_hz= 1<<1, /* 1-Hz rising-edge detected */ 33 RTSR_ale= 1<<2, /* RTC alarm interrupt enabled */ 34 RTSR_hze= 1<<3, /* 1-Hz interrupt enable */ 35 }; 36 37 static void 38 rtcreset(void) 39 { 40 RTCreg *r; 41 42 r = RTCREG; 43 if((r->rttr & 0xFFFF) == 0){ /* reset state */ 44 r->rttr = 32768-1; 45 r->rcnr = boottime; /* typically zero */ 46 } 47 r->rtar = ~0; 48 r->rtsr = RTSR_al | RTSR_hz; 49 } 50 51 static Chan* 52 rtcattach(char *spec) 53 { 54 return devattach('r', spec); 55 } 56 57 static Walkqid* 58 rtcwalk(Chan *c, Chan *nc, char **name, int nname) 59 { 60 return devwalk(c, nc, name, nname, rtcdir, NRTC, devgen); 61 } 62 63 static int 64 rtcstat(Chan *c, uchar *dp, int n) 65 { 66 return devstat(c, dp, n, rtcdir, NRTC, devgen); 67 } 68 69 static Chan* 70 rtcopen(Chan *c, int omode) 71 { 72 return devopen(c, omode, rtcdir, NRTC, devgen); 73 } 74 75 static void 76 rtcclose(Chan*) 77 { 78 } 79 80 static long 81 rtcread(Chan *c, void *buf, long n, vlong off) 82 { 83 if(c->qid.type & QTDIR) 84 return devdirread(c, buf, n, rtcdir, NRTC, devgen); 85 86 switch((ulong)c->qid.path){ 87 case Qrtc: 88 return readnum(off, buf, n, RTCREG->rcnr, NUMSIZE); 89 case Qrtctrim: 90 return readnum(off, buf, n, RTCREG->rttr, NUMSIZE); 91 } 92 error(Egreg); 93 return 0; /* not reached */ 94 } 95 96 static long 97 rtcwrite(Chan *c, void *buf, long n, vlong off) 98 { 99 ulong offset = off; 100 ulong secs; 101 char *cp, sbuf[32]; 102 103 switch((ulong)c->qid.path){ 104 case Qrtc: 105 /* 106 * write the time 107 */ 108 if(offset != 0 || n >= sizeof(sbuf)-1) 109 error(Ebadarg); 110 memmove(sbuf, buf, n); 111 sbuf[n] = '\0'; 112 cp = sbuf; 113 while(*cp){ 114 if(*cp>='0' && *cp<='9') 115 break; 116 cp++; 117 } 118 secs = strtoul(cp, 0, 0); 119 RTCREG->rcnr = secs; 120 return n; 121 122 case Qrtctrim: 123 if(offset != 0 || n >= sizeof(sbuf)-1) 124 error(Ebadarg); 125 memmove(sbuf, buf, n); 126 sbuf[n] = '\0'; 127 RTCREG->rttr = strtoul(sbuf, 0, 0); 128 return n; 129 } 130 error(Egreg); 131 return 0; /* not reached */ 132 } 133 134 static void 135 rtcpower(int on) 136 { 137 if(on) 138 boottime = RTCREG->rcnr - TK2SEC(MACHP(0)->ticks); 139 else 140 RTCREG->rcnr = seconds(); 141 } 142 143 long 144 rtctime(void) 145 { 146 return RTCREG->rcnr; 147 } 148 149 Dev rtcdevtab = { 150 'r', 151 "rtc", 152 153 rtcreset, 154 devinit, 155 devshutdown, 156 rtcattach, 157 rtcwalk, 158 rtcstat, 159 rtcopen, 160 devcreate, 161 rtcclose, 162 rtcread, 163 devbread, 164 rtcwrite, 165 devbwrite, 166 devremove, 167 devwstat, 168 rtcpower, 169 }; 170