1*74a4d8c2SCharles.Forsyth #include "u.h"
2*74a4d8c2SCharles.Forsyth #include "../port/lib.h"
3*74a4d8c2SCharles.Forsyth #include "mem.h"
4*74a4d8c2SCharles.Forsyth #include "dat.h"
5*74a4d8c2SCharles.Forsyth #include "fns.h"
6*74a4d8c2SCharles.Forsyth #include "../port/error.h"
7*74a4d8c2SCharles.Forsyth
8*74a4d8c2SCharles.Forsyth /*
9*74a4d8c2SCharles.Forsyth * real time clock and non-volatile ram
10*74a4d8c2SCharles.Forsyth */
11*74a4d8c2SCharles.Forsyth
12*74a4d8c2SCharles.Forsyth enum {
13*74a4d8c2SCharles.Forsyth Paddr= 0x70, /* address port */
14*74a4d8c2SCharles.Forsyth Pdata= 0x71, /* data port */
15*74a4d8c2SCharles.Forsyth
16*74a4d8c2SCharles.Forsyth Seconds= 0x00,
17*74a4d8c2SCharles.Forsyth Minutes= 0x02,
18*74a4d8c2SCharles.Forsyth Hours= 0x04,
19*74a4d8c2SCharles.Forsyth Mday= 0x07,
20*74a4d8c2SCharles.Forsyth Month= 0x08,
21*74a4d8c2SCharles.Forsyth Year= 0x09,
22*74a4d8c2SCharles.Forsyth Status= 0x0A,
23*74a4d8c2SCharles.Forsyth
24*74a4d8c2SCharles.Forsyth Nvoff= 128, /* where usable nvram lives */
25*74a4d8c2SCharles.Forsyth Nvsize= 256,
26*74a4d8c2SCharles.Forsyth
27*74a4d8c2SCharles.Forsyth Nbcd= 6,
28*74a4d8c2SCharles.Forsyth };
29*74a4d8c2SCharles.Forsyth
30*74a4d8c2SCharles.Forsyth typedef struct Rtc Rtc;
31*74a4d8c2SCharles.Forsyth struct Rtc
32*74a4d8c2SCharles.Forsyth {
33*74a4d8c2SCharles.Forsyth int sec;
34*74a4d8c2SCharles.Forsyth int min;
35*74a4d8c2SCharles.Forsyth int hour;
36*74a4d8c2SCharles.Forsyth int mday;
37*74a4d8c2SCharles.Forsyth int mon;
38*74a4d8c2SCharles.Forsyth int year;
39*74a4d8c2SCharles.Forsyth };
40*74a4d8c2SCharles.Forsyth
41*74a4d8c2SCharles.Forsyth
42*74a4d8c2SCharles.Forsyth enum{
43*74a4d8c2SCharles.Forsyth Qdir = 0,
44*74a4d8c2SCharles.Forsyth Qrtc,
45*74a4d8c2SCharles.Forsyth Qnvram,
46*74a4d8c2SCharles.Forsyth };
47*74a4d8c2SCharles.Forsyth
48*74a4d8c2SCharles.Forsyth Dirtab rtcdir[]={
49*74a4d8c2SCharles.Forsyth ".", {Qdir, 0, QTDIR}, 0, 0555,
50*74a4d8c2SCharles.Forsyth "nvram", {Qnvram, 0}, Nvsize, 0664,
51*74a4d8c2SCharles.Forsyth "rtc", {Qrtc, 0}, 0, 0664,
52*74a4d8c2SCharles.Forsyth };
53*74a4d8c2SCharles.Forsyth
54*74a4d8c2SCharles.Forsyth static ulong rtc2sec(Rtc*);
55*74a4d8c2SCharles.Forsyth static void sec2rtc(ulong, Rtc*);
56*74a4d8c2SCharles.Forsyth
57*74a4d8c2SCharles.Forsyth void
rtcinit(void)58*74a4d8c2SCharles.Forsyth rtcinit(void)
59*74a4d8c2SCharles.Forsyth {
60*74a4d8c2SCharles.Forsyth if(ioalloc(Paddr, 2, 0, "rtc/nvr") < 0)
61*74a4d8c2SCharles.Forsyth panic("rtcinit: ioalloc failed");
62*74a4d8c2SCharles.Forsyth }
63*74a4d8c2SCharles.Forsyth
64*74a4d8c2SCharles.Forsyth static Chan*
rtcattach(char * spec)65*74a4d8c2SCharles.Forsyth rtcattach(char* spec)
66*74a4d8c2SCharles.Forsyth {
67*74a4d8c2SCharles.Forsyth return devattach('r', spec);
68*74a4d8c2SCharles.Forsyth }
69*74a4d8c2SCharles.Forsyth
70*74a4d8c2SCharles.Forsyth static Walkqid*
rtcwalk(Chan * c,Chan * nc,char ** name,int nname)71*74a4d8c2SCharles.Forsyth rtcwalk(Chan* c, Chan *nc, char** name, int nname)
72*74a4d8c2SCharles.Forsyth {
73*74a4d8c2SCharles.Forsyth return devwalk(c, nc, name, nname, rtcdir, nelem(rtcdir), devgen);
74*74a4d8c2SCharles.Forsyth }
75*74a4d8c2SCharles.Forsyth
76*74a4d8c2SCharles.Forsyth static int
rtcstat(Chan * c,uchar * dp,int n)77*74a4d8c2SCharles.Forsyth rtcstat(Chan* c, uchar* dp, int n)
78*74a4d8c2SCharles.Forsyth {
79*74a4d8c2SCharles.Forsyth return devstat(c, dp, n, rtcdir, nelem(rtcdir), devgen);
80*74a4d8c2SCharles.Forsyth }
81*74a4d8c2SCharles.Forsyth
82*74a4d8c2SCharles.Forsyth static Chan*
rtcopen(Chan * c,int omode)83*74a4d8c2SCharles.Forsyth rtcopen(Chan* c, int omode)
84*74a4d8c2SCharles.Forsyth {
85*74a4d8c2SCharles.Forsyth omode = openmode(omode);
86*74a4d8c2SCharles.Forsyth switch((ulong)c->qid.path){
87*74a4d8c2SCharles.Forsyth case Qrtc:
88*74a4d8c2SCharles.Forsyth if(strcmp(up->env->user, eve)!=0 && omode!=OREAD)
89*74a4d8c2SCharles.Forsyth error(Eperm);
90*74a4d8c2SCharles.Forsyth break;
91*74a4d8c2SCharles.Forsyth case Qnvram:
92*74a4d8c2SCharles.Forsyth if(strcmp(up->env->user, eve)!=0)
93*74a4d8c2SCharles.Forsyth error(Eperm);
94*74a4d8c2SCharles.Forsyth }
95*74a4d8c2SCharles.Forsyth return devopen(c, omode, rtcdir, nelem(rtcdir), devgen);
96*74a4d8c2SCharles.Forsyth }
97*74a4d8c2SCharles.Forsyth
98*74a4d8c2SCharles.Forsyth static void
rtcclose(Chan *)99*74a4d8c2SCharles.Forsyth rtcclose(Chan*)
100*74a4d8c2SCharles.Forsyth {
101*74a4d8c2SCharles.Forsyth }
102*74a4d8c2SCharles.Forsyth
103*74a4d8c2SCharles.Forsyth #define GETBCD(o) ((bcdclock[o]&0xf) + 10*(bcdclock[o]>>4))
104*74a4d8c2SCharles.Forsyth
105*74a4d8c2SCharles.Forsyth static long
_rtctime(void)106*74a4d8c2SCharles.Forsyth _rtctime(void)
107*74a4d8c2SCharles.Forsyth {
108*74a4d8c2SCharles.Forsyth uchar bcdclock[Nbcd];
109*74a4d8c2SCharles.Forsyth Rtc rtc;
110*74a4d8c2SCharles.Forsyth int i;
111*74a4d8c2SCharles.Forsyth
112*74a4d8c2SCharles.Forsyth /* don't do the read until the clock is no longer busy */
113*74a4d8c2SCharles.Forsyth for(i = 0; i < 10000; i++){
114*74a4d8c2SCharles.Forsyth outb(Paddr, Status);
115*74a4d8c2SCharles.Forsyth if(inb(Pdata) & 0x80)
116*74a4d8c2SCharles.Forsyth continue;
117*74a4d8c2SCharles.Forsyth
118*74a4d8c2SCharles.Forsyth /* read clock values */
119*74a4d8c2SCharles.Forsyth outb(Paddr, Seconds); bcdclock[0] = inb(Pdata);
120*74a4d8c2SCharles.Forsyth outb(Paddr, Minutes); bcdclock[1] = inb(Pdata);
121*74a4d8c2SCharles.Forsyth outb(Paddr, Hours); bcdclock[2] = inb(Pdata);
122*74a4d8c2SCharles.Forsyth outb(Paddr, Mday); bcdclock[3] = inb(Pdata);
123*74a4d8c2SCharles.Forsyth outb(Paddr, Month); bcdclock[4] = inb(Pdata);
124*74a4d8c2SCharles.Forsyth outb(Paddr, Year); bcdclock[5] = inb(Pdata);
125*74a4d8c2SCharles.Forsyth
126*74a4d8c2SCharles.Forsyth outb(Paddr, Status);
127*74a4d8c2SCharles.Forsyth if((inb(Pdata) & 0x80) == 0)
128*74a4d8c2SCharles.Forsyth break;
129*74a4d8c2SCharles.Forsyth }
130*74a4d8c2SCharles.Forsyth
131*74a4d8c2SCharles.Forsyth /*
132*74a4d8c2SCharles.Forsyth * convert from BCD
133*74a4d8c2SCharles.Forsyth */
134*74a4d8c2SCharles.Forsyth rtc.sec = GETBCD(0);
135*74a4d8c2SCharles.Forsyth rtc.min = GETBCD(1);
136*74a4d8c2SCharles.Forsyth rtc.hour = GETBCD(2);
137*74a4d8c2SCharles.Forsyth rtc.mday = GETBCD(3);
138*74a4d8c2SCharles.Forsyth rtc.mon = GETBCD(4);
139*74a4d8c2SCharles.Forsyth rtc.year = GETBCD(5);
140*74a4d8c2SCharles.Forsyth
141*74a4d8c2SCharles.Forsyth /*
142*74a4d8c2SCharles.Forsyth * the world starts jan 1 1970
143*74a4d8c2SCharles.Forsyth */
144*74a4d8c2SCharles.Forsyth if(rtc.year < 70)
145*74a4d8c2SCharles.Forsyth rtc.year += 2000;
146*74a4d8c2SCharles.Forsyth else
147*74a4d8c2SCharles.Forsyth rtc.year += 1900;
148*74a4d8c2SCharles.Forsyth return rtc2sec(&rtc);
149*74a4d8c2SCharles.Forsyth }
150*74a4d8c2SCharles.Forsyth
151*74a4d8c2SCharles.Forsyth static Lock nvrtlock;
152*74a4d8c2SCharles.Forsyth
153*74a4d8c2SCharles.Forsyth long
rtctime(void)154*74a4d8c2SCharles.Forsyth rtctime(void)
155*74a4d8c2SCharles.Forsyth {
156*74a4d8c2SCharles.Forsyth int i;
157*74a4d8c2SCharles.Forsyth long t, ot;
158*74a4d8c2SCharles.Forsyth
159*74a4d8c2SCharles.Forsyth ilock(&nvrtlock);
160*74a4d8c2SCharles.Forsyth
161*74a4d8c2SCharles.Forsyth /* loop till we get two reads in a row the same */
162*74a4d8c2SCharles.Forsyth t = _rtctime();
163*74a4d8c2SCharles.Forsyth for(i = 0; i < 100; i++){
164*74a4d8c2SCharles.Forsyth ot = t;
165*74a4d8c2SCharles.Forsyth t = _rtctime();
166*74a4d8c2SCharles.Forsyth if(ot == t)
167*74a4d8c2SCharles.Forsyth break;
168*74a4d8c2SCharles.Forsyth }
169*74a4d8c2SCharles.Forsyth if(i == 100) print("we are boofheads\n");
170*74a4d8c2SCharles.Forsyth
171*74a4d8c2SCharles.Forsyth iunlock(&nvrtlock);
172*74a4d8c2SCharles.Forsyth
173*74a4d8c2SCharles.Forsyth return t;
174*74a4d8c2SCharles.Forsyth }
175*74a4d8c2SCharles.Forsyth
176*74a4d8c2SCharles.Forsyth static long
rtcread(Chan * c,void * buf,long n,vlong off)177*74a4d8c2SCharles.Forsyth rtcread(Chan* c, void* buf, long n, vlong off)
178*74a4d8c2SCharles.Forsyth {
179*74a4d8c2SCharles.Forsyth ulong t;
180*74a4d8c2SCharles.Forsyth char *a, *start;
181*74a4d8c2SCharles.Forsyth ulong offset = off;
182*74a4d8c2SCharles.Forsyth
183*74a4d8c2SCharles.Forsyth if(c->qid.type & QTDIR)
184*74a4d8c2SCharles.Forsyth return devdirread(c, buf, n, rtcdir, nelem(rtcdir), devgen);
185*74a4d8c2SCharles.Forsyth
186*74a4d8c2SCharles.Forsyth switch((ulong)c->qid.path){
187*74a4d8c2SCharles.Forsyth case Qrtc:
188*74a4d8c2SCharles.Forsyth t = rtctime();
189*74a4d8c2SCharles.Forsyth n = readnum(offset, buf, n, t, 12);
190*74a4d8c2SCharles.Forsyth return n;
191*74a4d8c2SCharles.Forsyth case Qnvram:
192*74a4d8c2SCharles.Forsyth if(n == 0)
193*74a4d8c2SCharles.Forsyth return 0;
194*74a4d8c2SCharles.Forsyth if(n > Nvsize)
195*74a4d8c2SCharles.Forsyth n = Nvsize;
196*74a4d8c2SCharles.Forsyth a = start = smalloc(n);
197*74a4d8c2SCharles.Forsyth
198*74a4d8c2SCharles.Forsyth ilock(&nvrtlock);
199*74a4d8c2SCharles.Forsyth for(t = offset; t < offset + n; t++){
200*74a4d8c2SCharles.Forsyth if(t >= Nvsize)
201*74a4d8c2SCharles.Forsyth break;
202*74a4d8c2SCharles.Forsyth outb(Paddr, Nvoff+t);
203*74a4d8c2SCharles.Forsyth *a++ = inb(Pdata);
204*74a4d8c2SCharles.Forsyth }
205*74a4d8c2SCharles.Forsyth iunlock(&nvrtlock);
206*74a4d8c2SCharles.Forsyth
207*74a4d8c2SCharles.Forsyth if(waserror()){
208*74a4d8c2SCharles.Forsyth free(start);
209*74a4d8c2SCharles.Forsyth nexterror();
210*74a4d8c2SCharles.Forsyth }
211*74a4d8c2SCharles.Forsyth memmove(buf, start, t - offset);
212*74a4d8c2SCharles.Forsyth poperror();
213*74a4d8c2SCharles.Forsyth
214*74a4d8c2SCharles.Forsyth free(start);
215*74a4d8c2SCharles.Forsyth return t - offset;
216*74a4d8c2SCharles.Forsyth }
217*74a4d8c2SCharles.Forsyth error(Ebadarg);
218*74a4d8c2SCharles.Forsyth return 0;
219*74a4d8c2SCharles.Forsyth }
220*74a4d8c2SCharles.Forsyth
221*74a4d8c2SCharles.Forsyth #define PUTBCD(n,o) bcdclock[o] = (n % 10) | (((n / 10) % 10)<<4)
222*74a4d8c2SCharles.Forsyth
223*74a4d8c2SCharles.Forsyth static long
rtcwrite(Chan * c,void * buf,long n,vlong off)224*74a4d8c2SCharles.Forsyth rtcwrite(Chan* c, void* buf, long n, vlong off)
225*74a4d8c2SCharles.Forsyth {
226*74a4d8c2SCharles.Forsyth int t;
227*74a4d8c2SCharles.Forsyth char *a, *start;
228*74a4d8c2SCharles.Forsyth Rtc rtc;
229*74a4d8c2SCharles.Forsyth ulong secs;
230*74a4d8c2SCharles.Forsyth uchar bcdclock[Nbcd];
231*74a4d8c2SCharles.Forsyth char *cp, *ep;
232*74a4d8c2SCharles.Forsyth ulong offset = off;
233*74a4d8c2SCharles.Forsyth
234*74a4d8c2SCharles.Forsyth if(offset!=0)
235*74a4d8c2SCharles.Forsyth error(Ebadarg);
236*74a4d8c2SCharles.Forsyth
237*74a4d8c2SCharles.Forsyth
238*74a4d8c2SCharles.Forsyth switch((ulong)c->qid.path){
239*74a4d8c2SCharles.Forsyth case Qrtc:
240*74a4d8c2SCharles.Forsyth /*
241*74a4d8c2SCharles.Forsyth * read the time
242*74a4d8c2SCharles.Forsyth */
243*74a4d8c2SCharles.Forsyth cp = ep = buf;
244*74a4d8c2SCharles.Forsyth ep += n;
245*74a4d8c2SCharles.Forsyth while(cp < ep){
246*74a4d8c2SCharles.Forsyth if(*cp>='0' && *cp<='9')
247*74a4d8c2SCharles.Forsyth break;
248*74a4d8c2SCharles.Forsyth cp++;
249*74a4d8c2SCharles.Forsyth }
250*74a4d8c2SCharles.Forsyth secs = strtoul(cp, 0, 0);
251*74a4d8c2SCharles.Forsyth
252*74a4d8c2SCharles.Forsyth /*
253*74a4d8c2SCharles.Forsyth * convert to bcd
254*74a4d8c2SCharles.Forsyth */
255*74a4d8c2SCharles.Forsyth sec2rtc(secs, &rtc);
256*74a4d8c2SCharles.Forsyth PUTBCD(rtc.sec, 0);
257*74a4d8c2SCharles.Forsyth PUTBCD(rtc.min, 1);
258*74a4d8c2SCharles.Forsyth PUTBCD(rtc.hour, 2);
259*74a4d8c2SCharles.Forsyth PUTBCD(rtc.mday, 3);
260*74a4d8c2SCharles.Forsyth PUTBCD(rtc.mon, 4);
261*74a4d8c2SCharles.Forsyth PUTBCD(rtc.year, 5);
262*74a4d8c2SCharles.Forsyth
263*74a4d8c2SCharles.Forsyth /*
264*74a4d8c2SCharles.Forsyth * write the clock
265*74a4d8c2SCharles.Forsyth */
266*74a4d8c2SCharles.Forsyth ilock(&nvrtlock);
267*74a4d8c2SCharles.Forsyth outb(Paddr, Seconds); outb(Pdata, bcdclock[0]);
268*74a4d8c2SCharles.Forsyth outb(Paddr, Minutes); outb(Pdata, bcdclock[1]);
269*74a4d8c2SCharles.Forsyth outb(Paddr, Hours); outb(Pdata, bcdclock[2]);
270*74a4d8c2SCharles.Forsyth outb(Paddr, Mday); outb(Pdata, bcdclock[3]);
271*74a4d8c2SCharles.Forsyth outb(Paddr, Month); outb(Pdata, bcdclock[4]);
272*74a4d8c2SCharles.Forsyth outb(Paddr, Year); outb(Pdata, bcdclock[5]);
273*74a4d8c2SCharles.Forsyth iunlock(&nvrtlock);
274*74a4d8c2SCharles.Forsyth return n;
275*74a4d8c2SCharles.Forsyth case Qnvram:
276*74a4d8c2SCharles.Forsyth if(n == 0)
277*74a4d8c2SCharles.Forsyth return 0;
278*74a4d8c2SCharles.Forsyth if(n > Nvsize)
279*74a4d8c2SCharles.Forsyth n = Nvsize;
280*74a4d8c2SCharles.Forsyth
281*74a4d8c2SCharles.Forsyth start = a = smalloc(n);
282*74a4d8c2SCharles.Forsyth if(waserror()){
283*74a4d8c2SCharles.Forsyth free(start);
284*74a4d8c2SCharles.Forsyth nexterror();
285*74a4d8c2SCharles.Forsyth }
286*74a4d8c2SCharles.Forsyth memmove(a, buf, n);
287*74a4d8c2SCharles.Forsyth poperror();
288*74a4d8c2SCharles.Forsyth
289*74a4d8c2SCharles.Forsyth ilock(&nvrtlock);
290*74a4d8c2SCharles.Forsyth for(t = offset; t < offset + n; t++){
291*74a4d8c2SCharles.Forsyth if(t >= Nvsize)
292*74a4d8c2SCharles.Forsyth break;
293*74a4d8c2SCharles.Forsyth outb(Paddr, Nvoff+t);
294*74a4d8c2SCharles.Forsyth outb(Pdata, *a++);
295*74a4d8c2SCharles.Forsyth }
296*74a4d8c2SCharles.Forsyth iunlock(&nvrtlock);
297*74a4d8c2SCharles.Forsyth
298*74a4d8c2SCharles.Forsyth free(start);
299*74a4d8c2SCharles.Forsyth return t - offset;
300*74a4d8c2SCharles.Forsyth }
301*74a4d8c2SCharles.Forsyth error(Ebadarg);
302*74a4d8c2SCharles.Forsyth return 0;
303*74a4d8c2SCharles.Forsyth }
304*74a4d8c2SCharles.Forsyth
305*74a4d8c2SCharles.Forsyth Dev rtcdevtab = {
306*74a4d8c2SCharles.Forsyth 'r',
307*74a4d8c2SCharles.Forsyth "rtc",
308*74a4d8c2SCharles.Forsyth
309*74a4d8c2SCharles.Forsyth devreset,
310*74a4d8c2SCharles.Forsyth rtcinit,
311*74a4d8c2SCharles.Forsyth devshutdown,
312*74a4d8c2SCharles.Forsyth rtcattach,
313*74a4d8c2SCharles.Forsyth rtcwalk,
314*74a4d8c2SCharles.Forsyth rtcstat,
315*74a4d8c2SCharles.Forsyth rtcopen,
316*74a4d8c2SCharles.Forsyth devcreate,
317*74a4d8c2SCharles.Forsyth rtcclose,
318*74a4d8c2SCharles.Forsyth rtcread,
319*74a4d8c2SCharles.Forsyth devbread,
320*74a4d8c2SCharles.Forsyth rtcwrite,
321*74a4d8c2SCharles.Forsyth devbwrite,
322*74a4d8c2SCharles.Forsyth devremove,
323*74a4d8c2SCharles.Forsyth devwstat,
324*74a4d8c2SCharles.Forsyth };
325*74a4d8c2SCharles.Forsyth
326*74a4d8c2SCharles.Forsyth #define SEC2MIN 60L
327*74a4d8c2SCharles.Forsyth #define SEC2HOUR (60L*SEC2MIN)
328*74a4d8c2SCharles.Forsyth #define SEC2DAY (24L*SEC2HOUR)
329*74a4d8c2SCharles.Forsyth
330*74a4d8c2SCharles.Forsyth /*
331*74a4d8c2SCharles.Forsyth * days per month plus days/year
332*74a4d8c2SCharles.Forsyth */
333*74a4d8c2SCharles.Forsyth static int dmsize[] =
334*74a4d8c2SCharles.Forsyth {
335*74a4d8c2SCharles.Forsyth 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
336*74a4d8c2SCharles.Forsyth };
337*74a4d8c2SCharles.Forsyth static int ldmsize[] =
338*74a4d8c2SCharles.Forsyth {
339*74a4d8c2SCharles.Forsyth 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
340*74a4d8c2SCharles.Forsyth };
341*74a4d8c2SCharles.Forsyth
342*74a4d8c2SCharles.Forsyth /*
343*74a4d8c2SCharles.Forsyth * return the days/month for the given year
344*74a4d8c2SCharles.Forsyth */
345*74a4d8c2SCharles.Forsyth static int*
yrsize(int y)346*74a4d8c2SCharles.Forsyth yrsize(int y)
347*74a4d8c2SCharles.Forsyth {
348*74a4d8c2SCharles.Forsyth if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
349*74a4d8c2SCharles.Forsyth return ldmsize;
350*74a4d8c2SCharles.Forsyth else
351*74a4d8c2SCharles.Forsyth return dmsize;
352*74a4d8c2SCharles.Forsyth }
353*74a4d8c2SCharles.Forsyth
354*74a4d8c2SCharles.Forsyth /*
355*74a4d8c2SCharles.Forsyth * compute seconds since Jan 1 1970
356*74a4d8c2SCharles.Forsyth */
357*74a4d8c2SCharles.Forsyth static ulong
rtc2sec(Rtc * rtc)358*74a4d8c2SCharles.Forsyth rtc2sec(Rtc *rtc)
359*74a4d8c2SCharles.Forsyth {
360*74a4d8c2SCharles.Forsyth ulong secs;
361*74a4d8c2SCharles.Forsyth int i;
362*74a4d8c2SCharles.Forsyth int *d2m;
363*74a4d8c2SCharles.Forsyth
364*74a4d8c2SCharles.Forsyth secs = 0;
365*74a4d8c2SCharles.Forsyth
366*74a4d8c2SCharles.Forsyth /*
367*74a4d8c2SCharles.Forsyth * seconds per year
368*74a4d8c2SCharles.Forsyth */
369*74a4d8c2SCharles.Forsyth for(i = 1970; i < rtc->year; i++){
370*74a4d8c2SCharles.Forsyth d2m = yrsize(i);
371*74a4d8c2SCharles.Forsyth secs += d2m[0] * SEC2DAY;
372*74a4d8c2SCharles.Forsyth }
373*74a4d8c2SCharles.Forsyth
374*74a4d8c2SCharles.Forsyth /*
375*74a4d8c2SCharles.Forsyth * seconds per month
376*74a4d8c2SCharles.Forsyth */
377*74a4d8c2SCharles.Forsyth d2m = yrsize(rtc->year);
378*74a4d8c2SCharles.Forsyth for(i = 1; i < rtc->mon; i++)
379*74a4d8c2SCharles.Forsyth secs += d2m[i] * SEC2DAY;
380*74a4d8c2SCharles.Forsyth
381*74a4d8c2SCharles.Forsyth secs += (rtc->mday-1) * SEC2DAY;
382*74a4d8c2SCharles.Forsyth secs += rtc->hour * SEC2HOUR;
383*74a4d8c2SCharles.Forsyth secs += rtc->min * SEC2MIN;
384*74a4d8c2SCharles.Forsyth secs += rtc->sec;
385*74a4d8c2SCharles.Forsyth
386*74a4d8c2SCharles.Forsyth return secs;
387*74a4d8c2SCharles.Forsyth }
388*74a4d8c2SCharles.Forsyth
389*74a4d8c2SCharles.Forsyth /*
390*74a4d8c2SCharles.Forsyth * compute rtc from seconds since Jan 1 1970
391*74a4d8c2SCharles.Forsyth */
392*74a4d8c2SCharles.Forsyth static void
sec2rtc(ulong secs,Rtc * rtc)393*74a4d8c2SCharles.Forsyth sec2rtc(ulong secs, Rtc *rtc)
394*74a4d8c2SCharles.Forsyth {
395*74a4d8c2SCharles.Forsyth int d;
396*74a4d8c2SCharles.Forsyth long hms, day;
397*74a4d8c2SCharles.Forsyth int *d2m;
398*74a4d8c2SCharles.Forsyth
399*74a4d8c2SCharles.Forsyth /*
400*74a4d8c2SCharles.Forsyth * break initial number into days
401*74a4d8c2SCharles.Forsyth */
402*74a4d8c2SCharles.Forsyth hms = secs % SEC2DAY;
403*74a4d8c2SCharles.Forsyth day = secs / SEC2DAY;
404*74a4d8c2SCharles.Forsyth if(hms < 0) {
405*74a4d8c2SCharles.Forsyth hms += SEC2DAY;
406*74a4d8c2SCharles.Forsyth day -= 1;
407*74a4d8c2SCharles.Forsyth }
408*74a4d8c2SCharles.Forsyth
409*74a4d8c2SCharles.Forsyth /*
410*74a4d8c2SCharles.Forsyth * generate hours:minutes:seconds
411*74a4d8c2SCharles.Forsyth */
412*74a4d8c2SCharles.Forsyth rtc->sec = hms % 60;
413*74a4d8c2SCharles.Forsyth d = hms / 60;
414*74a4d8c2SCharles.Forsyth rtc->min = d % 60;
415*74a4d8c2SCharles.Forsyth d /= 60;
416*74a4d8c2SCharles.Forsyth rtc->hour = d;
417*74a4d8c2SCharles.Forsyth
418*74a4d8c2SCharles.Forsyth /*
419*74a4d8c2SCharles.Forsyth * year number
420*74a4d8c2SCharles.Forsyth */
421*74a4d8c2SCharles.Forsyth if(day >= 0)
422*74a4d8c2SCharles.Forsyth for(d = 1970; day >= *yrsize(d); d++)
423*74a4d8c2SCharles.Forsyth day -= *yrsize(d);
424*74a4d8c2SCharles.Forsyth else
425*74a4d8c2SCharles.Forsyth for (d = 1970; day < 0; d--)
426*74a4d8c2SCharles.Forsyth day += *yrsize(d-1);
427*74a4d8c2SCharles.Forsyth rtc->year = d;
428*74a4d8c2SCharles.Forsyth
429*74a4d8c2SCharles.Forsyth /*
430*74a4d8c2SCharles.Forsyth * generate month
431*74a4d8c2SCharles.Forsyth */
432*74a4d8c2SCharles.Forsyth d2m = yrsize(rtc->year);
433*74a4d8c2SCharles.Forsyth for(d = 1; day >= d2m[d]; d++)
434*74a4d8c2SCharles.Forsyth day -= d2m[d];
435*74a4d8c2SCharles.Forsyth rtc->mday = day + 1;
436*74a4d8c2SCharles.Forsyth rtc->mon = d;
437*74a4d8c2SCharles.Forsyth
438*74a4d8c2SCharles.Forsyth return;
439*74a4d8c2SCharles.Forsyth }
440*74a4d8c2SCharles.Forsyth
441*74a4d8c2SCharles.Forsyth uchar
nvramread(int addr)442*74a4d8c2SCharles.Forsyth nvramread(int addr)
443*74a4d8c2SCharles.Forsyth {
444*74a4d8c2SCharles.Forsyth uchar data;
445*74a4d8c2SCharles.Forsyth
446*74a4d8c2SCharles.Forsyth ilock(&nvrtlock);
447*74a4d8c2SCharles.Forsyth outb(Paddr, addr);
448*74a4d8c2SCharles.Forsyth data = inb(Pdata);
449*74a4d8c2SCharles.Forsyth iunlock(&nvrtlock);
450*74a4d8c2SCharles.Forsyth
451*74a4d8c2SCharles.Forsyth return data;
452*74a4d8c2SCharles.Forsyth }
453*74a4d8c2SCharles.Forsyth
454*74a4d8c2SCharles.Forsyth void
nvramwrite(int addr,uchar data)455*74a4d8c2SCharles.Forsyth nvramwrite(int addr, uchar data)
456*74a4d8c2SCharles.Forsyth {
457*74a4d8c2SCharles.Forsyth ilock(&nvrtlock);
458*74a4d8c2SCharles.Forsyth outb(Paddr, addr);
459*74a4d8c2SCharles.Forsyth outb(Pdata, data);
460*74a4d8c2SCharles.Forsyth iunlock(&nvrtlock);
461*74a4d8c2SCharles.Forsyth }
462