The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/mtx/devrtc.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  *      M48T59/559 Timekeeper
    3  */
    4 #include        "u.h"
    5 #include        "../port/lib.h"
    6 #include        "mem.h"
    7 #include        "dat.h"
    8 #include        "fns.h"
    9 #include        "../port/error.h"
   10 
   11 #include        "io.h"
   12 
   13 enum{
   14         STB0 = 0x74,
   15         STB1 = 0x75,
   16         Data = 0x77,
   17 
   18         NVOFF=  0,
   19         NVLEN=  0x1ff0,         /* length in bytes of NV RAM */
   20 
   21         /*
   22          *  register offsets into time of day clock
   23          */
   24         NVflags=                0x1ff0,
   25         NVwatchdog=     0x1ff7,
   26         NVctl=          0x1ff8,
   27         NVsec,
   28         NVmin,
   29         NVhour, 
   30         NVday,          /* (1 = Sun) */
   31         NVmday,         /* (1-31) */
   32         NVmon,          /* (1-12) */
   33         NVyear,         /* (0-99) */
   34 
   35         /* NVctl */
   36         RTwrite = (1<<7),
   37         RTread = (1<<6),
   38         RTsign = (1<<5),
   39         RTcal = 0x1f,
   40 
   41         /* NVwatchdog */
   42         WDsteer = (1<<7),               /* 0 -> intr, 1 -> reset */
   43         WDmult = (1<<2),                /* 5 bits of multiplier */
   44         WDres0 = (0<<0),                /* 1/16 sec resolution */
   45         WDres1 = (1<<0),                /* 1/4 sec resolution */
   46         WDres2 = (2<<0),                /* 1 sec resolution */
   47         WDres3 = (3<<0),                /* 4 sec resolution */
   48 
   49         Qdir = 0,
   50         Qrtc,
   51         Qnvram,
   52 };
   53 
   54 /*
   55  *  broken down time
   56  */
   57 typedef struct
   58 {
   59         int     sec;
   60         int     min;
   61         int     hour;
   62         int     mday;
   63         int     mon;
   64         int     year;
   65 } Rtc;
   66 
   67 QLock   rtclock;                /* mutex on nvram operations */
   68 
   69 static Dirtab rtcdir[]={
   70         ".",            {Qdir, 0, QTDIR},       0,      DMDIR|0555,
   71         "rtc",          {Qrtc, 0},      0,      0644,
   72         "nvram",        {Qnvram, 0},    0,      0600,
   73 };
   74 
   75 static ulong    rtc2sec(Rtc*);
   76 static void     sec2rtc(ulong, Rtc*);
   77 static void     setrtc(Rtc*);
   78 static void     nvcksum(void);
   79 static void     nvput(int, uchar);
   80 static uchar    nvget(int);
   81 
   82 static Chan*
   83 rtcattach(char *spec)
   84 {
   85         return devattach('r', spec);
   86 }
   87 
   88 static Walkqid*
   89 rtcwalk(Chan *c, Chan *nc, char **name, int nname)
   90 {
   91         return devwalk(c, nc, name, nname, rtcdir, nelem(rtcdir), devgen);
   92 }
   93 
   94 static int       
   95 rtcstat(Chan *c, uchar *dp, int n)
   96 {
   97         return devstat(c, dp, n, rtcdir, nelem(rtcdir), devgen);
   98 }
   99 
  100 static Chan*
  101 rtcopen(Chan *c, int omode)
  102 {
  103         omode = openmode(omode);
  104         switch((ulong)c->qid.path){
  105         case Qrtc:
  106                 if(strcmp(up->user, eve)!=0 && omode!=OREAD)
  107                         error(Eperm);
  108                 break;
  109         case Qnvram:
  110                 if(strcmp(up->user, eve)!=0 || !cpuserver)
  111                         error(Eperm);
  112         }
  113         return devopen(c, omode, rtcdir, nelem(rtcdir), devgen);
  114 }
  115 
  116 static void      
  117 rtcclose(Chan*)
  118 {
  119 }
  120 
  121 static long      
  122 rtcread(Chan *c, void *buf, long n, vlong off)
  123 {
  124         char *p;
  125         ulong t;
  126         int i;
  127         ulong offset = off;
  128 
  129         if(c->qid.type & QTDIR)
  130                 return devdirread(c, buf, n, rtcdir, nelem(rtcdir), devgen);
  131 
  132         switch((ulong)c->qid.path){
  133         case Qrtc:
  134                 qlock(&rtclock);
  135                 t = rtctime();
  136                 qunlock(&rtclock);
  137                 n = readnum(offset, buf, n, t, 12);
  138                 return n;
  139         case Qnvram:
  140                 offset += NVOFF;
  141                 if(offset > NVLEN)
  142                         return 0;
  143                 if(n > NVLEN - offset)
  144                         n = NVLEN - offset;
  145                 p = buf;
  146                 qlock(&rtclock);
  147                 for(i = 0; i < n; i++)
  148                         p[i] = nvget(i+offset);
  149                 qunlock(&rtclock);
  150                 return n;
  151         }
  152         error(Egreg);
  153         return -1;              /* never reached */
  154 }
  155 
  156 static long      
  157 rtcwrite(Chan *c, void *buf, long n, vlong off)
  158 {
  159         Rtc rtc;
  160         ulong secs;
  161         char *cp, *ep;
  162         int i;
  163         ulong offset = off;
  164 
  165         switch((ulong)c->qid.path){
  166         case Qrtc:
  167                 if(offset!=0)
  168                         error(Ebadarg);
  169                 /*
  170                  *  read the time
  171                  */
  172                 cp = ep = buf;
  173                 ep += n;
  174                 while(cp < ep){
  175                         if(*cp>='' && *cp<='9')
  176                                 break;
  177                         cp++;
  178                 }
  179                 secs = strtoul(cp, 0, 0);
  180                 /*
  181                  *  convert to bcd
  182                  */
  183                 sec2rtc(secs, &rtc);
  184                 /*
  185                  * write it
  186                  */
  187                 qlock(&rtclock);
  188                 setrtc(&rtc);
  189                 qunlock(&rtclock);
  190                 return n;
  191         case Qnvram:
  192                 offset += NVOFF;
  193                 if(offset > NVLEN)
  194                         return 0;
  195                 if(n > NVLEN - offset)
  196                         n = NVLEN - offset;
  197                 qlock(&rtclock);
  198                 for(i = 0; i < n; i++)
  199                         nvput(i+offset, ((uchar*)buf)[i]);
  200                 nvcksum();
  201                 qunlock(&rtclock);
  202                 return n;
  203         }
  204         error(Egreg);
  205         return -1;              /* never reached */
  206 }
  207 
  208 long
  209 rtcbwrite(Chan *c, Block *bp, ulong offset)
  210 {
  211         return devbwrite(c, bp, offset);
  212 }
  213 
  214 Dev rtcdevtab = {
  215         'r',
  216         "rtc",
  217 
  218         devreset,
  219         devinit,
  220         devshutdown,
  221         rtcattach,
  222         rtcwalk,
  223         rtcstat,
  224         rtcopen,
  225         devcreate,
  226         rtcclose,
  227         rtcread,
  228         devbread,
  229         rtcwrite,
  230         devbwrite,
  231         devremove,
  232         devwstat,
  233 };
  234 
  235 static void
  236 nvput(int offset, uchar val)
  237 {
  238         outb(STB0, offset);
  239         outb(STB1, offset>>8);
  240         outb(Data, val);
  241 }
  242 
  243 static uchar
  244 nvget(int offset)
  245 {
  246         outb(STB0, offset);
  247         outb(STB1, offset>>8);
  248         return inb(Data);
  249 }
  250 
  251 static void
  252 nvcksum(void)
  253 {
  254 }
  255 
  256 void
  257 watchreset(void)
  258 {
  259         splhi();
  260         nvput(NVwatchdog, WDsteer|(1*WDmult)|WDres0);
  261         for(;;);
  262 }
  263 
  264 static int
  265 getbcd(int bcd)
  266 {
  267         return (bcd&0x0f) + 10 * (bcd>>4);
  268 }
  269 
  270 static int
  271 putbcd(int val)
  272 {
  273         return (val % 10) | (((val/10) % 10) << 4);
  274 }
  275 
  276 long     
  277 rtctime(void)
  278 {
  279         int ctl;
  280         Rtc rtc;
  281 
  282         /*
  283          *  convert from BCD
  284          */
  285         ctl = nvget(NVctl);
  286         ctl &= RTsign|RTcal;
  287         nvput(NVctl, ctl|RTread);
  288 
  289         rtc.sec = getbcd(nvget(NVsec) & 0x7f);
  290         rtc.min = getbcd(nvget(NVmin));
  291         rtc.hour = getbcd(nvget(NVhour));
  292         rtc.mday = getbcd(nvget(NVmday));
  293         rtc.mon = getbcd(nvget(NVmon));
  294         rtc.year = getbcd(nvget(NVyear));
  295         if(rtc.year < 70)
  296                 rtc.year += 2000;
  297         else
  298                 rtc.year += 1900;
  299 
  300         nvput(NVctl, ctl);
  301 
  302         return rtc2sec(&rtc);
  303 }
  304 
  305 static void
  306 setrtc(Rtc *rtc)
  307 {
  308         int ctl;
  309 
  310         ctl = nvget(NVctl);
  311         ctl &= RTsign|RTcal;
  312         nvput(NVctl, ctl|RTwrite);
  313 
  314         nvput(NVsec, putbcd(rtc->sec));
  315         nvput(NVmin, putbcd(rtc->min));
  316         nvput(NVhour, putbcd(rtc->hour));
  317         nvput(NVmday, putbcd(rtc->mday));
  318         nvput(NVmon, putbcd(rtc->mon));
  319         nvput(NVyear, putbcd(rtc->year % 100));
  320 
  321         nvput(NVctl, ctl);
  322 }
  323 
  324 #define SEC2MIN 60L
  325 #define SEC2HOUR (60L*SEC2MIN)
  326 #define SEC2DAY (24L*SEC2HOUR)
  327 
  328 /*
  329  *  days per month plus days/year
  330  */
  331 static  int     dmsize[] =
  332 {
  333         365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  334 };
  335 static  int     ldmsize[] =
  336 {
  337         366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  338 };
  339 
  340 /*
  341  *  return the days/month for the given year
  342  */
  343 static int *
  344 yrsize(int y)
  345 {
  346 
  347         if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
  348                 return ldmsize;
  349         else
  350                 return dmsize;
  351 }
  352 
  353 /*
  354  *  compute seconds since Jan 1 1970
  355  */
  356 static ulong
  357 rtc2sec(Rtc *rtc)
  358 {
  359         ulong secs;
  360         int i;
  361         int *d2m;
  362 
  363         secs = 0;
  364 
  365         /*
  366          *  seconds per year
  367          */
  368         for(i = 1970; i < rtc->year; i++){
  369                 d2m = yrsize(i);
  370                 secs += d2m[0] * SEC2DAY;
  371         }
  372 
  373         /*
  374          *  seconds per month
  375          */
  376         d2m = yrsize(rtc->year);
  377         for(i = 1; i < rtc->mon; i++)
  378                 secs += d2m[i] * SEC2DAY;
  379 
  380         secs += (rtc->mday-1) * SEC2DAY;
  381         secs += rtc->hour * SEC2HOUR;
  382         secs += rtc->min * SEC2MIN;
  383         secs += rtc->sec;
  384 
  385         return secs;
  386 }
  387 
  388 /*
  389  *  compute rtc from seconds since Jan 1 1970
  390  */
  391 static void
  392 sec2rtc(ulong secs, Rtc *rtc)
  393 {
  394         int d;
  395         long hms, day;
  396         int *d2m;
  397 
  398         /*
  399          * break initial number into days
  400          */
  401         hms = secs % SEC2DAY;
  402         day = secs / SEC2DAY;
  403         if(hms < 0) {
  404                 hms += SEC2DAY;
  405                 day -= 1;
  406         }
  407 
  408         /*
  409          * generate hours:minutes:seconds
  410          */
  411         rtc->sec = hms % 60;
  412         d = hms / 60;
  413         rtc->min = d % 60;
  414         d /= 60;
  415         rtc->hour = d;
  416 
  417         /*
  418          * year number
  419          */
  420         if(day >= 0)
  421                 for(d = 1970; day >= *yrsize(d); d++)
  422                         day -= *yrsize(d);
  423         else
  424                 for (d = 1970; day < 0; d--)
  425                         day += *yrsize(d-1);
  426         rtc->year = d;
  427 
  428         /*
  429          * generate month
  430          */
  431         d2m = yrsize(rtc->year);
  432         for(d = 1; day >= d2m[d]; d++)
  433                 day -= d2m[d];
  434         rtc->mday = day + 1;
  435         rtc->mon = d;
  436 
  437         return;
  438 }

Cache object: 76872331e1db13f294d0f36423f5a7ab


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.