|
|
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.