devrtc.c 2.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169
  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 "io.h"
  8. /*
  9. * SA11x0 real time clock
  10. * TO DO: alarms, wakeup, allow trim setting(?)
  11. */
  12. enum{
  13. Qdir,
  14. Qrtc,
  15. Qrtctrim,
  16. };
  17. static Dirtab rtcdir[]={
  18. ".", {Qdir,0,QTDIR}, 0, 0555,
  19. "rtc", {Qrtc}, NUMSIZE, 0664,
  20. "rtctrim", {Qrtctrim}, 0, 0664,
  21. };
  22. #define NRTC (sizeof(rtcdir)/sizeof(rtcdir[0]))
  23. extern ulong boottime;
  24. enum {
  25. RTSR_al= 1<<0, /* RTC alarm detected */
  26. RTSR_hz= 1<<1, /* 1-Hz rising-edge detected */
  27. RTSR_ale= 1<<2, /* RTC alarm interrupt enabled */
  28. RTSR_hze= 1<<3, /* 1-Hz interrupt enable */
  29. };
  30. static void
  31. rtcreset(void)
  32. {
  33. RTCreg *r;
  34. r = RTCREG;
  35. if((r->rttr & 0xFFFF) == 0){ /* reset state */
  36. r->rttr = 32768-1;
  37. r->rcnr = boottime; /* typically zero */
  38. }
  39. r->rtar = ~0;
  40. r->rtsr = RTSR_al | RTSR_hz;
  41. }
  42. static Chan*
  43. rtcattach(char *spec)
  44. {
  45. return devattach('r', spec);
  46. }
  47. static Walkqid*
  48. rtcwalk(Chan *c, Chan *nc, char **name, int nname)
  49. {
  50. return devwalk(c, nc, name, nname, rtcdir, NRTC, devgen);
  51. }
  52. static int
  53. rtcstat(Chan *c, uchar *dp, int n)
  54. {
  55. return devstat(c, dp, n, rtcdir, NRTC, devgen);
  56. }
  57. static Chan*
  58. rtcopen(Chan *c, int omode)
  59. {
  60. return devopen(c, omode, rtcdir, NRTC, devgen);
  61. }
  62. static void
  63. rtcclose(Chan*)
  64. {
  65. }
  66. static long
  67. rtcread(Chan *c, void *buf, long n, vlong off)
  68. {
  69. if(c->qid.type & QTDIR)
  70. return devdirread(c, buf, n, rtcdir, NRTC, devgen);
  71. switch((ulong)c->qid.path){
  72. case Qrtc:
  73. return readnum(off, buf, n, RTCREG->rcnr, NUMSIZE);
  74. case Qrtctrim:
  75. return readnum(off, buf, n, RTCREG->rttr, NUMSIZE);
  76. }
  77. error(Egreg);
  78. return 0; /* not reached */
  79. }
  80. static long
  81. rtcwrite(Chan *c, void *buf, long n, vlong off)
  82. {
  83. ulong offset = off;
  84. ulong secs;
  85. char *cp, sbuf[32];
  86. switch((ulong)c->qid.path){
  87. case Qrtc:
  88. /*
  89. * write the time
  90. */
  91. if(offset != 0 || n >= sizeof(sbuf)-1)
  92. error(Ebadarg);
  93. memmove(sbuf, buf, n);
  94. sbuf[n] = '\0';
  95. cp = sbuf;
  96. while(*cp){
  97. if(*cp>='0' && *cp<='9')
  98. break;
  99. cp++;
  100. }
  101. secs = strtoul(cp, 0, 0);
  102. RTCREG->rcnr = secs;
  103. return n;
  104. case Qrtctrim:
  105. if(offset != 0 || n >= sizeof(sbuf)-1)
  106. error(Ebadarg);
  107. memmove(sbuf, buf, n);
  108. sbuf[n] = '\0';
  109. RTCREG->rttr = strtoul(sbuf, 0, 0);
  110. return n;
  111. }
  112. error(Egreg);
  113. return 0; /* not reached */
  114. }
  115. static void
  116. rtcpower(int on)
  117. {
  118. if(on)
  119. boottime = RTCREG->rcnr - TK2SEC(MACHP(0)->ticks);
  120. else
  121. RTCREG->rcnr = seconds();
  122. }
  123. long
  124. rtctime(void)
  125. {
  126. return RTCREG->rcnr;
  127. }
  128. Dev rtcdevtab = {
  129. 'r',
  130. "rtc",
  131. rtcreset,
  132. devinit,
  133. devshutdown,
  134. rtcattach,
  135. rtcwalk,
  136. rtcstat,
  137. rtcopen,
  138. devcreate,
  139. rtcclose,
  140. rtcread,
  141. devbread,
  142. rtcwrite,
  143. devbwrite,
  144. devremove,
  145. devwstat,
  146. rtcpower,
  147. };