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 * MPC8xx real time clock 12 * optional board option switch 13 * optional nvram 14 * interrupt statistics 15 */ 16 17 enum{ 18 Qdir, 19 Qrtc, 20 Qswitch, 21 Qnvram, 22 Qintstat, 23 24 Qporta, 25 Qportb, 26 Qportc, 27 28 /* sccr */ 29 RTDIV= 1<<24, 30 RTSEL= 1<<23, 31 32 /* rtcsc */ 33 RTE= 1<<0, 34 R38K= 1<<4, 35 }; 36 37 static QLock rtclock; /* mutex on clock operations */ 38 39 static Dirtab rtcdir[]={ 40 ".", {Qdir,0,QTDIR}, 0, 0555, 41 "rtc", {Qrtc, 0}, 12, 0664, 42 "switch", {Qswitch, 0}, 0, 0444, 43 "intstat", {Qintstat, 0}, 0, 0444, 44 "porta", {Qporta, 0}, 0, 0444, 45 "portb", {Qportb, 0}, 0, 0444, 46 "portc", {Qportc, 0}, 0, 0444, 47 "nvram", {Qnvram, 0}, 0, 0660, 48 }; 49 static long nrtc = nelem(rtcdir)-1; /* excludes nvram */ 50 51 static long readport(int, ulong, char*, long); 52 53 static void 54 rtcreset(void) 55 { 56 IMM *io; 57 int n; 58 59 io = m->iomem; 60 io->rtcsck = KEEP_ALIVE_KEY; 61 n = (RTClevel<<8)|RTE; 62 if(m->clockgen == 5*MHz) 63 n |= R38K; 64 io->rtcsc = n; 65 io->rtcsck = ~KEEP_ALIVE_KEY; 66 if(conf.nvramsize != 0){ 67 rtcdir[nrtc].length = conf.nvramsize; 68 nrtc++; 69 } 70 } 71 72 static Chan* 73 rtcattach(char *spec) 74 { 75 return devattach('r', spec); 76 } 77 78 static Walkqid* 79 rtcwalk(Chan *c, Chan *nc, char **name, int nname) 80 { 81 return devwalk(c, nc, name, nname, rtcdir, nrtc, devgen); 82 } 83 84 static int 85 rtcstat(Chan *c, uchar *dp, int n) 86 { 87 return devstat(c, dp, n, rtcdir, nrtc, devgen); 88 } 89 90 static Chan* 91 rtcopen(Chan *c, int omode) 92 { 93 return devopen(c, omode, rtcdir, nrtc, devgen); 94 } 95 96 static void 97 rtcclose(Chan*) 98 { 99 } 100 101 static long 102 rtcread(Chan *c, void *buf, long n, vlong off) 103 { 104 ulong offset = off; 105 ulong t; 106 char *b; 107 108 if(c->qid.type & QTDIR) 109 return devdirread(c, buf, n, rtcdir, nrtc, devgen); 110 111 switch((ulong)c->qid.path){ 112 case Qrtc: 113 t = m->iomem->rtc; 114 n = readnum(offset, buf, n, t, 12); 115 return n; 116 case Qswitch: 117 return readnum(offset, buf, n, archoptionsw(), 12); 118 case Qintstat: 119 b = malloc(2048); 120 if(waserror()){ 121 free(b); 122 nexterror(); 123 } 124 intrstats(b, 2048); 125 t = readstr(offset, buf, n, b); 126 poperror(); 127 free(b); 128 return t; 129 case Qporta: 130 case Qportb: 131 case Qportc: 132 return readport(c->qid.path, offset, buf, n); 133 case Qnvram: 134 if(offset < 0 || offset >= conf.nvramsize) 135 return 0; 136 if(offset + n > conf.nvramsize) 137 n = conf.nvramsize - offset; 138 memmove(buf, (char*)conf.nvrambase+offset, n); 139 return n; 140 } 141 error(Egreg); 142 return 0; /* not reached */ 143 } 144 145 static long 146 rtcwrite(Chan *c, void *buf, long n, vlong off) 147 { 148 ulong offset = off; 149 ulong secs; 150 char *cp, sbuf[32]; 151 IMM *io; 152 153 switch((ulong)c->qid.path){ 154 case Qrtc: 155 /* 156 * read the time 157 */ 158 if(offset != 0 || n >= sizeof(sbuf)-1) 159 error(Ebadarg); 160 memmove(sbuf, buf, n); 161 sbuf[n] = '\0'; 162 cp = sbuf; 163 while(*cp){ 164 if(*cp>='0' && *cp<='9') 165 break; 166 cp++; 167 } 168 secs = strtoul(cp, 0, 0); 169 /* 170 * set it 171 */ 172 io = ioplock(); 173 io->rtck = KEEP_ALIVE_KEY; 174 io->rtc = secs; 175 io->rtck = ~KEEP_ALIVE_KEY; 176 iopunlock(); 177 return n; 178 case Qnvram: 179 if(offset < 0 || offset >= conf.nvramsize) 180 return 0; 181 if(offset + n > conf.nvramsize) 182 n = conf.nvramsize - offset; 183 memmove((char*)conf.nvrambase+offset, buf, n); 184 return n; 185 } 186 error(Egreg); 187 return 0; /* not reached */ 188 } 189 190 static long 191 readport(int p, ulong offset, char *buf, long n) 192 { 193 long t; 194 char *b; 195 int v[4], i; 196 IMM *io; 197 198 io = m->iomem; 199 for(i=0;i<nelem(v); i++) 200 v[i] = 0; 201 switch(p){ 202 case Qporta: 203 v[0] = io->padat; 204 v[1] = io->padir; 205 v[2] = io->papar; 206 break; 207 case Qportb: 208 v[0] = io->pbdat; 209 v[1] = io->pbdir; 210 v[2] = io->pbpar; 211 break; 212 case Qportc: 213 v[0] = io->pcdat; 214 v[1] = io->pcdir; 215 v[2] = io->pcpar; 216 v[3] = io->pcso; 217 break; 218 } 219 b = malloc(READSTR); 220 if(waserror()){ 221 free(b); 222 nexterror(); 223 } 224 t = 0; 225 for(i=0; i<nelem(v); i++) 226 t += snprint(b+t, READSTR-t, " %8.8ux", v[i]); 227 t = readstr(offset, buf, n, b); 228 poperror(); 229 free(b); 230 return t; 231 } 232 233 long 234 rtctime(void) 235 { 236 return m->iomem->rtc; 237 } 238 239 Dev rtcdevtab = { 240 'r', 241 "rtc", 242 243 rtcreset, 244 devinit, 245 devshutdown, 246 rtcattach, 247 rtcwalk, 248 rtcstat, 249 rtcopen, 250 devcreate, 251 rtcclose, 252 rtcread, 253 devbread, 254 rtcwrite, 255 devbwrite, 256 devremove, 257 devwstat, 258 }; 259