13e12c5d1SDavid du Colombier #include "u.h"
23e12c5d1SDavid du Colombier #include "../port/lib.h"
33e12c5d1SDavid du Colombier #include "mem.h"
43e12c5d1SDavid du Colombier #include "dat.h"
53e12c5d1SDavid du Colombier #include "fns.h"
63e12c5d1SDavid du Colombier #include "../port/error.h"
73e12c5d1SDavid du Colombier
83e12c5d1SDavid du Colombier /*
93e12c5d1SDavid du Colombier * real time clock and non-volatile ram
103e12c5d1SDavid du Colombier */
113e12c5d1SDavid du Colombier
123e12c5d1SDavid du Colombier enum {
133e12c5d1SDavid du Colombier Paddr= 0x70, /* address port */
143e12c5d1SDavid du Colombier Pdata= 0x71, /* data port */
153e12c5d1SDavid du Colombier
163e12c5d1SDavid du Colombier Seconds= 0x00,
173e12c5d1SDavid du Colombier Minutes= 0x02,
183e12c5d1SDavid du Colombier Hours= 0x04,
193e12c5d1SDavid du Colombier Mday= 0x07,
203e12c5d1SDavid du Colombier Month= 0x08,
213e12c5d1SDavid du Colombier Year= 0x09,
223e12c5d1SDavid du Colombier Status= 0x0A,
233e12c5d1SDavid du Colombier
24219b2ee8SDavid du Colombier Nvoff= 128, /* where usable nvram lives */
25219b2ee8SDavid du Colombier Nvsize= 256,
26219b2ee8SDavid du Colombier
273e12c5d1SDavid du Colombier Nbcd= 6,
283e12c5d1SDavid du Colombier };
293e12c5d1SDavid du Colombier
303e12c5d1SDavid du Colombier typedef struct Rtc Rtc;
313e12c5d1SDavid du Colombier struct Rtc
323e12c5d1SDavid du Colombier {
333e12c5d1SDavid du Colombier int sec;
343e12c5d1SDavid du Colombier int min;
353e12c5d1SDavid du Colombier int hour;
363e12c5d1SDavid du Colombier int mday;
373e12c5d1SDavid du Colombier int mon;
383e12c5d1SDavid du Colombier int year;
393e12c5d1SDavid du Colombier };
403e12c5d1SDavid du Colombier
413e12c5d1SDavid du Colombier
423e12c5d1SDavid du Colombier enum{
43*9a747e4fSDavid du Colombier Qdir = 0,
44*9a747e4fSDavid du Colombier Qrtc,
453e12c5d1SDavid du Colombier Qnvram,
463e12c5d1SDavid du Colombier };
473e12c5d1SDavid du Colombier
483e12c5d1SDavid du Colombier Dirtab rtcdir[]={
49*9a747e4fSDavid du Colombier ".", {Qdir, 0, QTDIR}, 0, 0555,
50219b2ee8SDavid du Colombier "nvram", {Qnvram, 0}, Nvsize, 0664,
51219b2ee8SDavid du Colombier "rtc", {Qrtc, 0}, 0, 0664,
523e12c5d1SDavid du Colombier };
533e12c5d1SDavid du Colombier
547dd7cddfSDavid du Colombier static ulong rtc2sec(Rtc*);
557dd7cddfSDavid du Colombier static void sec2rtc(ulong, Rtc*);
563e12c5d1SDavid du Colombier
573e12c5d1SDavid du Colombier void
rtcinit(void)583e12c5d1SDavid du Colombier rtcinit(void)
593e12c5d1SDavid du Colombier {
607dd7cddfSDavid du Colombier if(ioalloc(Paddr, 2, 0, "rtc/nvr") < 0)
617dd7cddfSDavid du Colombier panic("rtcinit: ioalloc failed");
623e12c5d1SDavid du Colombier }
633e12c5d1SDavid du Colombier
647dd7cddfSDavid du Colombier static Chan*
rtcattach(char * spec)653e12c5d1SDavid du Colombier rtcattach(char* spec)
663e12c5d1SDavid du Colombier {
673e12c5d1SDavid du Colombier return devattach('r', spec);
683e12c5d1SDavid du Colombier }
693e12c5d1SDavid du Colombier
70*9a747e4fSDavid du Colombier static Walkqid*
rtcwalk(Chan * c,Chan * nc,char ** name,int nname)71*9a747e4fSDavid du Colombier rtcwalk(Chan* c, Chan *nc, char** name, int nname)
723e12c5d1SDavid du Colombier {
73*9a747e4fSDavid du Colombier return devwalk(c, nc, name, nname, rtcdir, nelem(rtcdir), devgen);
743e12c5d1SDavid du Colombier }
753e12c5d1SDavid du Colombier
76*9a747e4fSDavid du Colombier static int
rtcstat(Chan * c,uchar * dp,int n)77*9a747e4fSDavid du Colombier rtcstat(Chan* c, uchar* dp, int n)
783e12c5d1SDavid du Colombier {
79*9a747e4fSDavid du Colombier return devstat(c, dp, n, rtcdir, nelem(rtcdir), devgen);
803e12c5d1SDavid du Colombier }
813e12c5d1SDavid du Colombier
827dd7cddfSDavid du Colombier static Chan*
rtcopen(Chan * c,int omode)833e12c5d1SDavid du Colombier rtcopen(Chan* c, int omode)
843e12c5d1SDavid du Colombier {
853e12c5d1SDavid du Colombier omode = openmode(omode);
86*9a747e4fSDavid du Colombier switch((ulong)c->qid.path){
873e12c5d1SDavid du Colombier case Qrtc:
887dd7cddfSDavid du Colombier if(strcmp(up->user, eve)!=0 && omode!=OREAD)
893e12c5d1SDavid du Colombier error(Eperm);
903e12c5d1SDavid du Colombier break;
913e12c5d1SDavid du Colombier case Qnvram:
927dd7cddfSDavid du Colombier if(strcmp(up->user, eve)!=0)
933e12c5d1SDavid du Colombier error(Eperm);
943e12c5d1SDavid du Colombier }
957dd7cddfSDavid du Colombier return devopen(c, omode, rtcdir, nelem(rtcdir), devgen);
963e12c5d1SDavid du Colombier }
973e12c5d1SDavid du Colombier
987dd7cddfSDavid du Colombier static void
rtcclose(Chan *)997dd7cddfSDavid du Colombier rtcclose(Chan*)
1003e12c5d1SDavid du Colombier {
1013e12c5d1SDavid du Colombier }
1023e12c5d1SDavid du Colombier
1033e12c5d1SDavid du Colombier #define GETBCD(o) ((bcdclock[o]&0xf) + 10*(bcdclock[o]>>4))
1043e12c5d1SDavid du Colombier
1057dd7cddfSDavid du Colombier static long
_rtctime(void)1067dd7cddfSDavid du Colombier _rtctime(void)
1073e12c5d1SDavid du Colombier {
1083e12c5d1SDavid du Colombier uchar bcdclock[Nbcd];
1093e12c5d1SDavid du Colombier Rtc rtc;
110bd389b36SDavid du Colombier int i;
1113e12c5d1SDavid du Colombier
1127dd7cddfSDavid du Colombier /* don't do the read until the clock is no longer busy */
113bd389b36SDavid du Colombier for(i = 0; i < 10000; i++){
1143e12c5d1SDavid du Colombier outb(Paddr, Status);
1157dd7cddfSDavid du Colombier if(inb(Pdata) & 0x80)
1167dd7cddfSDavid du Colombier continue;
1177dd7cddfSDavid du Colombier
1187dd7cddfSDavid du Colombier /* read clock values */
1193e12c5d1SDavid du Colombier outb(Paddr, Seconds); bcdclock[0] = inb(Pdata);
1203e12c5d1SDavid du Colombier outb(Paddr, Minutes); bcdclock[1] = inb(Pdata);
1213e12c5d1SDavid du Colombier outb(Paddr, Hours); bcdclock[2] = inb(Pdata);
1223e12c5d1SDavid du Colombier outb(Paddr, Mday); bcdclock[3] = inb(Pdata);
1233e12c5d1SDavid du Colombier outb(Paddr, Month); bcdclock[4] = inb(Pdata);
1243e12c5d1SDavid du Colombier outb(Paddr, Year); bcdclock[5] = inb(Pdata);
1253e12c5d1SDavid du Colombier
1267dd7cddfSDavid du Colombier outb(Paddr, Status);
1277dd7cddfSDavid du Colombier if((inb(Pdata) & 0x80) == 0)
1287dd7cddfSDavid du Colombier break;
1297dd7cddfSDavid du Colombier }
1307dd7cddfSDavid du Colombier
1313e12c5d1SDavid du Colombier /*
1323e12c5d1SDavid du Colombier * convert from BCD
1333e12c5d1SDavid du Colombier */
1343e12c5d1SDavid du Colombier rtc.sec = GETBCD(0);
1353e12c5d1SDavid du Colombier rtc.min = GETBCD(1);
1363e12c5d1SDavid du Colombier rtc.hour = GETBCD(2);
1373e12c5d1SDavid du Colombier rtc.mday = GETBCD(3);
1383e12c5d1SDavid du Colombier rtc.mon = GETBCD(4);
1393e12c5d1SDavid du Colombier rtc.year = GETBCD(5);
1403e12c5d1SDavid du Colombier
1413e12c5d1SDavid du Colombier /*
1423e12c5d1SDavid du Colombier * the world starts jan 1 1970
1433e12c5d1SDavid du Colombier */
1443e12c5d1SDavid du Colombier if(rtc.year < 70)
1453e12c5d1SDavid du Colombier rtc.year += 2000;
1463e12c5d1SDavid du Colombier else
1473e12c5d1SDavid du Colombier rtc.year += 1900;
1483e12c5d1SDavid du Colombier return rtc2sec(&rtc);
1493e12c5d1SDavid du Colombier }
1503e12c5d1SDavid du Colombier
1517dd7cddfSDavid du Colombier static Lock nvrtlock;
1527dd7cddfSDavid du Colombier
1533e12c5d1SDavid du Colombier long
rtctime(void)1547dd7cddfSDavid du Colombier rtctime(void)
1553e12c5d1SDavid du Colombier {
1567dd7cddfSDavid du Colombier int i;
1577dd7cddfSDavid du Colombier long t, ot;
1587dd7cddfSDavid du Colombier
1597dd7cddfSDavid du Colombier ilock(&nvrtlock);
1607dd7cddfSDavid du Colombier
1617dd7cddfSDavid du Colombier /* loop till we get two reads in a row the same */
1627dd7cddfSDavid du Colombier t = _rtctime();
1637dd7cddfSDavid du Colombier for(i = 0; i < 100; i++){
1647dd7cddfSDavid du Colombier ot = t;
1657dd7cddfSDavid du Colombier t = _rtctime();
1667dd7cddfSDavid du Colombier if(ot == t)
1677dd7cddfSDavid du Colombier break;
1687dd7cddfSDavid du Colombier }
1697dd7cddfSDavid du Colombier if(i == 100) print("we are boofheads\n");
1707dd7cddfSDavid du Colombier
1717dd7cddfSDavid du Colombier iunlock(&nvrtlock);
1727dd7cddfSDavid du Colombier
1737dd7cddfSDavid du Colombier return t;
1747dd7cddfSDavid du Colombier }
1757dd7cddfSDavid du Colombier
1767dd7cddfSDavid du Colombier static long
rtcread(Chan * c,void * buf,long n,vlong off)1777dd7cddfSDavid du Colombier rtcread(Chan* c, void* buf, long n, vlong off)
1787dd7cddfSDavid du Colombier {
1797dd7cddfSDavid du Colombier ulong t;
1807dd7cddfSDavid du Colombier char *a, *start;
1817dd7cddfSDavid du Colombier ulong offset = off;
1823e12c5d1SDavid du Colombier
183*9a747e4fSDavid du Colombier if(c->qid.type & QTDIR)
1847dd7cddfSDavid du Colombier return devdirread(c, buf, n, rtcdir, nelem(rtcdir), devgen);
1853e12c5d1SDavid du Colombier
186*9a747e4fSDavid du Colombier switch((ulong)c->qid.path){
187219b2ee8SDavid du Colombier case Qrtc:
1883e12c5d1SDavid du Colombier t = rtctime();
1893e12c5d1SDavid du Colombier n = readnum(offset, buf, n, t, 12);
1903e12c5d1SDavid du Colombier return n;
191219b2ee8SDavid du Colombier case Qnvram:
1927dd7cddfSDavid du Colombier if(n == 0)
1937dd7cddfSDavid du Colombier return 0;
1947dd7cddfSDavid du Colombier if(n > Nvsize)
1957dd7cddfSDavid du Colombier n = Nvsize;
1967dd7cddfSDavid du Colombier a = start = smalloc(n);
1977dd7cddfSDavid du Colombier
1987dd7cddfSDavid du Colombier ilock(&nvrtlock);
199219b2ee8SDavid du Colombier for(t = offset; t < offset + n; t++){
200219b2ee8SDavid du Colombier if(t >= Nvsize)
201219b2ee8SDavid du Colombier break;
202219b2ee8SDavid du Colombier outb(Paddr, Nvoff+t);
203219b2ee8SDavid du Colombier *a++ = inb(Pdata);
204219b2ee8SDavid du Colombier }
2057dd7cddfSDavid du Colombier iunlock(&nvrtlock);
2067dd7cddfSDavid du Colombier
2077dd7cddfSDavid du Colombier if(waserror()){
2087dd7cddfSDavid du Colombier free(start);
2097dd7cddfSDavid du Colombier nexterror();
2107dd7cddfSDavid du Colombier }
2117dd7cddfSDavid du Colombier memmove(buf, start, t - offset);
212219b2ee8SDavid du Colombier poperror();
2137dd7cddfSDavid du Colombier
2147dd7cddfSDavid du Colombier free(start);
215219b2ee8SDavid du Colombier return t - offset;
216219b2ee8SDavid du Colombier }
217219b2ee8SDavid du Colombier error(Ebadarg);
218219b2ee8SDavid du Colombier return 0;
2193e12c5d1SDavid du Colombier }
2203e12c5d1SDavid du Colombier
2213e12c5d1SDavid du Colombier #define PUTBCD(n,o) bcdclock[o] = (n % 10) | (((n / 10) % 10)<<4)
2223e12c5d1SDavid du Colombier
2237dd7cddfSDavid du Colombier static long
rtcwrite(Chan * c,void * buf,long n,vlong off)2247dd7cddfSDavid du Colombier rtcwrite(Chan* c, void* buf, long n, vlong off)
2253e12c5d1SDavid du Colombier {
226219b2ee8SDavid du Colombier int t;
2277dd7cddfSDavid du Colombier char *a, *start;
2283e12c5d1SDavid du Colombier Rtc rtc;
2293e12c5d1SDavid du Colombier ulong secs;
2303e12c5d1SDavid du Colombier uchar bcdclock[Nbcd];
2313e12c5d1SDavid du Colombier char *cp, *ep;
2327dd7cddfSDavid du Colombier ulong offset = off;
2333e12c5d1SDavid du Colombier
2343e12c5d1SDavid du Colombier if(offset!=0)
2353e12c5d1SDavid du Colombier error(Ebadarg);
2363e12c5d1SDavid du Colombier
237219b2ee8SDavid du Colombier
238*9a747e4fSDavid du Colombier switch((ulong)c->qid.path){
239219b2ee8SDavid du Colombier case Qrtc:
2403e12c5d1SDavid du Colombier /*
2413e12c5d1SDavid du Colombier * read the time
2423e12c5d1SDavid du Colombier */
2433e12c5d1SDavid du Colombier cp = ep = buf;
2443e12c5d1SDavid du Colombier ep += n;
2453e12c5d1SDavid du Colombier while(cp < ep){
2463e12c5d1SDavid du Colombier if(*cp>='0' && *cp<='9')
2473e12c5d1SDavid du Colombier break;
2483e12c5d1SDavid du Colombier cp++;
2493e12c5d1SDavid du Colombier }
2503e12c5d1SDavid du Colombier secs = strtoul(cp, 0, 0);
2513e12c5d1SDavid du Colombier
2523e12c5d1SDavid du Colombier /*
2533e12c5d1SDavid du Colombier * convert to bcd
2543e12c5d1SDavid du Colombier */
2553e12c5d1SDavid du Colombier sec2rtc(secs, &rtc);
2563e12c5d1SDavid du Colombier PUTBCD(rtc.sec, 0);
2573e12c5d1SDavid du Colombier PUTBCD(rtc.min, 1);
2583e12c5d1SDavid du Colombier PUTBCD(rtc.hour, 2);
2593e12c5d1SDavid du Colombier PUTBCD(rtc.mday, 3);
2603e12c5d1SDavid du Colombier PUTBCD(rtc.mon, 4);
2613e12c5d1SDavid du Colombier PUTBCD(rtc.year, 5);
2623e12c5d1SDavid du Colombier
2633e12c5d1SDavid du Colombier /*
2643e12c5d1SDavid du Colombier * write the clock
2653e12c5d1SDavid du Colombier */
2667dd7cddfSDavid du Colombier ilock(&nvrtlock);
2673e12c5d1SDavid du Colombier outb(Paddr, Seconds); outb(Pdata, bcdclock[0]);
2683e12c5d1SDavid du Colombier outb(Paddr, Minutes); outb(Pdata, bcdclock[1]);
2693e12c5d1SDavid du Colombier outb(Paddr, Hours); outb(Pdata, bcdclock[2]);
2703e12c5d1SDavid du Colombier outb(Paddr, Mday); outb(Pdata, bcdclock[3]);
2713e12c5d1SDavid du Colombier outb(Paddr, Month); outb(Pdata, bcdclock[4]);
2723e12c5d1SDavid du Colombier outb(Paddr, Year); outb(Pdata, bcdclock[5]);
2737dd7cddfSDavid du Colombier iunlock(&nvrtlock);
2743e12c5d1SDavid du Colombier return n;
275219b2ee8SDavid du Colombier case Qnvram:
2767dd7cddfSDavid du Colombier if(n == 0)
2777dd7cddfSDavid du Colombier return 0;
2787dd7cddfSDavid du Colombier if(n > Nvsize)
2797dd7cddfSDavid du Colombier n = Nvsize;
2807dd7cddfSDavid du Colombier
2817dd7cddfSDavid du Colombier start = a = smalloc(n);
282219b2ee8SDavid du Colombier if(waserror()){
2837dd7cddfSDavid du Colombier free(start);
284219b2ee8SDavid du Colombier nexterror();
285219b2ee8SDavid du Colombier }
2867dd7cddfSDavid du Colombier memmove(a, buf, n);
2877dd7cddfSDavid du Colombier poperror();
2887dd7cddfSDavid du Colombier
2897dd7cddfSDavid du Colombier ilock(&nvrtlock);
290219b2ee8SDavid du Colombier for(t = offset; t < offset + n; t++){
291219b2ee8SDavid du Colombier if(t >= Nvsize)
292219b2ee8SDavid du Colombier break;
293219b2ee8SDavid du Colombier outb(Paddr, Nvoff+t);
294219b2ee8SDavid du Colombier outb(Pdata, *a++);
295219b2ee8SDavid du Colombier }
2967dd7cddfSDavid du Colombier iunlock(&nvrtlock);
2977dd7cddfSDavid du Colombier
2987dd7cddfSDavid du Colombier free(start);
299219b2ee8SDavid du Colombier return t - offset;
300219b2ee8SDavid du Colombier }
301219b2ee8SDavid du Colombier error(Ebadarg);
302219b2ee8SDavid du Colombier return 0;
3033e12c5d1SDavid du Colombier }
3043e12c5d1SDavid du Colombier
3057dd7cddfSDavid du Colombier Dev rtcdevtab = {
3067dd7cddfSDavid du Colombier 'r',
3077dd7cddfSDavid du Colombier "rtc",
3083e12c5d1SDavid du Colombier
3097dd7cddfSDavid du Colombier devreset,
3107dd7cddfSDavid du Colombier rtcinit,
311*9a747e4fSDavid du Colombier devshutdown,
3127dd7cddfSDavid du Colombier rtcattach,
3137dd7cddfSDavid du Colombier rtcwalk,
3147dd7cddfSDavid du Colombier rtcstat,
3157dd7cddfSDavid du Colombier rtcopen,
3167dd7cddfSDavid du Colombier devcreate,
3177dd7cddfSDavid du Colombier rtcclose,
3187dd7cddfSDavid du Colombier rtcread,
3197dd7cddfSDavid du Colombier devbread,
3207dd7cddfSDavid du Colombier rtcwrite,
3217dd7cddfSDavid du Colombier devbwrite,
3227dd7cddfSDavid du Colombier devremove,
3237dd7cddfSDavid du Colombier devwstat,
3247dd7cddfSDavid du Colombier };
3253e12c5d1SDavid du Colombier
3263e12c5d1SDavid du Colombier #define SEC2MIN 60L
3273e12c5d1SDavid du Colombier #define SEC2HOUR (60L*SEC2MIN)
3283e12c5d1SDavid du Colombier #define SEC2DAY (24L*SEC2HOUR)
3293e12c5d1SDavid du Colombier
3303e12c5d1SDavid du Colombier /*
3313e12c5d1SDavid du Colombier * days per month plus days/year
3323e12c5d1SDavid du Colombier */
3333e12c5d1SDavid du Colombier static int dmsize[] =
3343e12c5d1SDavid du Colombier {
3353e12c5d1SDavid du Colombier 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
3363e12c5d1SDavid du Colombier };
3373e12c5d1SDavid du Colombier static int ldmsize[] =
3383e12c5d1SDavid du Colombier {
3393e12c5d1SDavid du Colombier 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
3403e12c5d1SDavid du Colombier };
3413e12c5d1SDavid du Colombier
3423e12c5d1SDavid du Colombier /*
3433e12c5d1SDavid du Colombier * return the days/month for the given year
3443e12c5d1SDavid du Colombier */
3457dd7cddfSDavid du Colombier static int*
yrsize(int y)3467dd7cddfSDavid du Colombier yrsize(int y)
3473e12c5d1SDavid du Colombier {
3487dd7cddfSDavid du Colombier if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
3493e12c5d1SDavid du Colombier return ldmsize;
3503e12c5d1SDavid du Colombier else
3513e12c5d1SDavid du Colombier return dmsize;
3523e12c5d1SDavid du Colombier }
3533e12c5d1SDavid du Colombier
3543e12c5d1SDavid du Colombier /*
3553e12c5d1SDavid du Colombier * compute seconds since Jan 1 1970
3563e12c5d1SDavid du Colombier */
3577dd7cddfSDavid du Colombier static ulong
rtc2sec(Rtc * rtc)3583e12c5d1SDavid du Colombier rtc2sec(Rtc *rtc)
3593e12c5d1SDavid du Colombier {
3603e12c5d1SDavid du Colombier ulong secs;
3613e12c5d1SDavid du Colombier int i;
3623e12c5d1SDavid du Colombier int *d2m;
3633e12c5d1SDavid du Colombier
3643e12c5d1SDavid du Colombier secs = 0;
3653e12c5d1SDavid du Colombier
3663e12c5d1SDavid du Colombier /*
3673e12c5d1SDavid du Colombier * seconds per year
3683e12c5d1SDavid du Colombier */
3693e12c5d1SDavid du Colombier for(i = 1970; i < rtc->year; i++){
3703e12c5d1SDavid du Colombier d2m = yrsize(i);
3713e12c5d1SDavid du Colombier secs += d2m[0] * SEC2DAY;
3723e12c5d1SDavid du Colombier }
3733e12c5d1SDavid du Colombier
3743e12c5d1SDavid du Colombier /*
3753e12c5d1SDavid du Colombier * seconds per month
3763e12c5d1SDavid du Colombier */
3773e12c5d1SDavid du Colombier d2m = yrsize(rtc->year);
3783e12c5d1SDavid du Colombier for(i = 1; i < rtc->mon; i++)
3793e12c5d1SDavid du Colombier secs += d2m[i] * SEC2DAY;
3803e12c5d1SDavid du Colombier
3813e12c5d1SDavid du Colombier secs += (rtc->mday-1) * SEC2DAY;
3823e12c5d1SDavid du Colombier secs += rtc->hour * SEC2HOUR;
3833e12c5d1SDavid du Colombier secs += rtc->min * SEC2MIN;
3843e12c5d1SDavid du Colombier secs += rtc->sec;
3853e12c5d1SDavid du Colombier
3863e12c5d1SDavid du Colombier return secs;
3873e12c5d1SDavid du Colombier }
3883e12c5d1SDavid du Colombier
3893e12c5d1SDavid du Colombier /*
3903e12c5d1SDavid du Colombier * compute rtc from seconds since Jan 1 1970
3913e12c5d1SDavid du Colombier */
3927dd7cddfSDavid du Colombier static void
sec2rtc(ulong secs,Rtc * rtc)3933e12c5d1SDavid du Colombier sec2rtc(ulong secs, Rtc *rtc)
3943e12c5d1SDavid du Colombier {
3953e12c5d1SDavid du Colombier int d;
3963e12c5d1SDavid du Colombier long hms, day;
3973e12c5d1SDavid du Colombier int *d2m;
3983e12c5d1SDavid du Colombier
3993e12c5d1SDavid du Colombier /*
4003e12c5d1SDavid du Colombier * break initial number into days
4013e12c5d1SDavid du Colombier */
4023e12c5d1SDavid du Colombier hms = secs % SEC2DAY;
4033e12c5d1SDavid du Colombier day = secs / SEC2DAY;
4043e12c5d1SDavid du Colombier if(hms < 0) {
4053e12c5d1SDavid du Colombier hms += SEC2DAY;
4063e12c5d1SDavid du Colombier day -= 1;
4073e12c5d1SDavid du Colombier }
4083e12c5d1SDavid du Colombier
4093e12c5d1SDavid du Colombier /*
4103e12c5d1SDavid du Colombier * generate hours:minutes:seconds
4113e12c5d1SDavid du Colombier */
4123e12c5d1SDavid du Colombier rtc->sec = hms % 60;
4133e12c5d1SDavid du Colombier d = hms / 60;
4143e12c5d1SDavid du Colombier rtc->min = d % 60;
4153e12c5d1SDavid du Colombier d /= 60;
4163e12c5d1SDavid du Colombier rtc->hour = d;
4173e12c5d1SDavid du Colombier
4183e12c5d1SDavid du Colombier /*
4193e12c5d1SDavid du Colombier * year number
4203e12c5d1SDavid du Colombier */
4213e12c5d1SDavid du Colombier if(day >= 0)
4223e12c5d1SDavid du Colombier for(d = 1970; day >= *yrsize(d); d++)
4233e12c5d1SDavid du Colombier day -= *yrsize(d);
4243e12c5d1SDavid du Colombier else
4253e12c5d1SDavid du Colombier for (d = 1970; day < 0; d--)
4263e12c5d1SDavid du Colombier day += *yrsize(d-1);
4273e12c5d1SDavid du Colombier rtc->year = d;
4283e12c5d1SDavid du Colombier
4293e12c5d1SDavid du Colombier /*
4303e12c5d1SDavid du Colombier * generate month
4313e12c5d1SDavid du Colombier */
4323e12c5d1SDavid du Colombier d2m = yrsize(rtc->year);
4333e12c5d1SDavid du Colombier for(d = 1; day >= d2m[d]; d++)
4343e12c5d1SDavid du Colombier day -= d2m[d];
4353e12c5d1SDavid du Colombier rtc->mday = day + 1;
4363e12c5d1SDavid du Colombier rtc->mon = d;
4373e12c5d1SDavid du Colombier
4383e12c5d1SDavid du Colombier return;
4393e12c5d1SDavid du Colombier }
440bd389b36SDavid du Colombier
441bd389b36SDavid du Colombier uchar
nvramread(int addr)4427dd7cddfSDavid du Colombier nvramread(int addr)
443bd389b36SDavid du Colombier {
4447dd7cddfSDavid du Colombier uchar data;
4457dd7cddfSDavid du Colombier
4467dd7cddfSDavid du Colombier ilock(&nvrtlock);
4477dd7cddfSDavid du Colombier outb(Paddr, addr);
4487dd7cddfSDavid du Colombier data = inb(Pdata);
4497dd7cddfSDavid du Colombier iunlock(&nvrtlock);
4507dd7cddfSDavid du Colombier
4517dd7cddfSDavid du Colombier return data;
4527dd7cddfSDavid du Colombier }
4537dd7cddfSDavid du Colombier
4547dd7cddfSDavid du Colombier void
nvramwrite(int addr,uchar data)4557dd7cddfSDavid du Colombier nvramwrite(int addr, uchar data)
4567dd7cddfSDavid du Colombier {
4577dd7cddfSDavid du Colombier ilock(&nvrtlock);
4587dd7cddfSDavid du Colombier outb(Paddr, addr);
4597dd7cddfSDavid du Colombier outb(Pdata, data);
4607dd7cddfSDavid du Colombier iunlock(&nvrtlock);
461bd389b36SDavid du Colombier }
462