Annotation of lucent/sys/src/9/pc/devrtc.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.