devrtc.c 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359
  1. /*
  2. * devrtc - real-time clock, for kirkwood
  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. #include "io.h"
  11. typedef struct RtcReg RtcReg;
  12. typedef struct Rtc Rtc;
  13. struct RtcReg
  14. {
  15. ulong time;
  16. ulong date;
  17. ulong alarmtm;
  18. ulong alarmdt;
  19. ulong intrmask;
  20. ulong intrcause;
  21. };
  22. struct Rtc
  23. {
  24. int sec;
  25. int min;
  26. int hour;
  27. int wday;
  28. int mday;
  29. int mon;
  30. int year;
  31. };
  32. enum {
  33. Qdir,
  34. Qrtc,
  35. };
  36. static Dirtab rtcdir[] = {
  37. ".", {Qdir, 0, QTDIR}, 0, 0555,
  38. "rtc", {Qrtc}, NUMSIZE, 0664,
  39. };
  40. static RtcReg *rtcreg; /* filled in by attach */
  41. static Lock rtclock;
  42. #define SEC2MIN 60
  43. #define SEC2HOUR (60*SEC2MIN)
  44. #define SEC2DAY (24L*SEC2HOUR)
  45. /*
  46. * days per month plus days/year
  47. */
  48. static int dmsize[] =
  49. {
  50. 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  51. };
  52. static int ldmsize[] =
  53. {
  54. 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
  55. };
  56. /*
  57. * return the days/month for the given year
  58. */
  59. static int *
  60. yrsize(int yr)
  61. {
  62. if((yr % 4) == 0)
  63. return ldmsize;
  64. else
  65. return dmsize;
  66. }
  67. /*
  68. * compute seconds since Jan 1 1970
  69. */
  70. static ulong
  71. rtc2sec(Rtc *rtc)
  72. {
  73. ulong secs;
  74. int i;
  75. int *d2m;
  76. /*
  77. * seconds per year
  78. */
  79. secs = 0;
  80. for(i = 1970; i < rtc->year; i++){
  81. d2m = yrsize(i);
  82. secs += d2m[0] * SEC2DAY;
  83. }
  84. /*
  85. * seconds per month
  86. */
  87. d2m = yrsize(rtc->year);
  88. for(i = 1; i < rtc->mon; i++)
  89. secs += d2m[i] * SEC2DAY;
  90. secs += (rtc->mday-1) * SEC2DAY;
  91. secs += rtc->hour * SEC2HOUR;
  92. secs += rtc->min * SEC2MIN;
  93. secs += rtc->sec;
  94. return secs;
  95. }
  96. /*
  97. * compute rtc from seconds since Jan 1 1970
  98. */
  99. static void
  100. sec2rtc(ulong secs, Rtc *rtc)
  101. {
  102. int d;
  103. long hms, day;
  104. int *d2m;
  105. /*
  106. * break initial number into days
  107. */
  108. hms = secs % SEC2DAY;
  109. day = secs / SEC2DAY;
  110. if(hms < 0) {
  111. hms += SEC2DAY;
  112. day -= 1;
  113. }
  114. /*
  115. * 19700101 was thursday
  116. */
  117. rtc->wday = (day + 7340036L) % 7;
  118. /*
  119. * generate hours:minutes:seconds
  120. */
  121. rtc->sec = hms % 60;
  122. d = hms / 60;
  123. rtc->min = d % 60;
  124. d /= 60;
  125. rtc->hour = d;
  126. /*
  127. * year number
  128. */
  129. if(day >= 0)
  130. for(d = 1970; day >= *yrsize(d); d++)
  131. day -= *yrsize(d);
  132. else
  133. for (d = 1970; day < 0; d--)
  134. day += *yrsize(d-1);
  135. rtc->year = d;
  136. /*
  137. * generate month
  138. */
  139. d2m = yrsize(rtc->year);
  140. for(d = 1; day >= d2m[d]; d++)
  141. day -= d2m[d];
  142. rtc->mday = day + 1;
  143. rtc->mon = d;
  144. }
  145. enum {
  146. Rtcsec = 0x00007f,
  147. Rtcmin = 0x007f00,
  148. Rtcms = 8,
  149. Rtchr12 = 0x1f0000,
  150. Rtchr24 = 0x3f0000,
  151. Rtchrs = 16,
  152. Rdmday = 0x00003f,
  153. Rdmon = 0x001f00,
  154. Rdms = 8,
  155. Rdyear = 0x7f0000,
  156. Rdys = 16,
  157. Rtcpm = 1<<21, /* pm bit */
  158. Rtc12 = 1<<22, /* 12 hr clock */
  159. };
  160. static ulong
  161. bcd2dec(ulong bcd)
  162. {
  163. ulong d, m, i;
  164. d = 0;
  165. m = 1;
  166. for(i = 0; i < 2 * sizeof d; i++){
  167. d += ((bcd >> (4*i)) & 0xf) * m;
  168. m *= 10;
  169. }
  170. return d;
  171. }
  172. static ulong
  173. dec2bcd(ulong d)
  174. {
  175. ulong bcd, i;
  176. bcd = 0;
  177. for(i = 0; d != 0; i++){
  178. bcd |= (d%10) << (4*i);
  179. d /= 10;
  180. }
  181. return bcd;
  182. }
  183. static long
  184. _rtctime(void)
  185. {
  186. ulong t, d;
  187. Rtc rtc;
  188. t = rtcreg->time;
  189. d = rtcreg->date;
  190. rtc.sec = bcd2dec(t & Rtcsec);
  191. rtc.min = bcd2dec((t & Rtcmin) >> Rtcms);
  192. if(t & Rtc12){
  193. rtc.hour = bcd2dec((t & Rtchr12) >> Rtchrs) - 1; /* 1—12 */
  194. if(t & Rtcpm)
  195. rtc.hour += 12;
  196. }else
  197. rtc.hour = bcd2dec((t & Rtchr24) >> Rtchrs); /* 0—23 */
  198. rtc.mday = bcd2dec(d & Rdmday); /* 1—31 */
  199. rtc.mon = bcd2dec((d & Rdmon) >> Rdms); /* 1—12 */
  200. rtc.year = bcd2dec((d & Rdyear) >> Rdys) + 2000; /* year%100 */
  201. // print("%0.2d:%0.2d:%.02d %0.2d/%0.2d/%0.2d\n", /* HH:MM:SS YY/MM/DD */
  202. // rtc.hour, rtc.min, rtc.sec, rtc.year, rtc.mon, rtc.mday);
  203. return rtc2sec(&rtc);
  204. }
  205. long
  206. rtctime(void)
  207. {
  208. int i;
  209. long t, ot;
  210. ilock(&rtclock);
  211. /* loop until we get two reads in a row the same */
  212. t = _rtctime();
  213. ot = ~t;
  214. for(i = 0; i < 100 && ot != t; i++){
  215. ot = t;
  216. t = _rtctime();
  217. }
  218. if(ot != t)
  219. print("rtctime: we are boofheads\n");
  220. iunlock(&rtclock);
  221. return t;
  222. }
  223. static void
  224. setrtc(Rtc *rtc)
  225. {
  226. ilock(&rtclock);
  227. rtcreg->time = dec2bcd(rtc->wday) << 24 | dec2bcd(rtc->hour) << 16 |
  228. dec2bcd(rtc->min) << 8 | dec2bcd(rtc->sec);
  229. rtcreg->date = dec2bcd(rtc->year - 2000) << 16 |
  230. dec2bcd(rtc->mon) << 8 | dec2bcd(rtc->mday);
  231. iunlock(&rtclock);
  232. }
  233. static Chan*
  234. rtcattach(char *spec)
  235. {
  236. rtcreg = (RtcReg*)soc.rtc;
  237. return devattach(L'r', spec);
  238. }
  239. static Walkqid*
  240. rtcwalk(Chan *c, Chan *nc, char **name, int nname)
  241. {
  242. return devwalk(c, nc, name, nname, rtcdir, nelem(rtcdir), devgen);
  243. }
  244. static int
  245. rtcstat(Chan *c, uchar *dp, int n)
  246. {
  247. return devstat(c, dp, n, rtcdir, nelem(rtcdir), devgen);
  248. }
  249. static Chan*
  250. rtcopen(Chan *c, int omode)
  251. {
  252. return devopen(c, omode, rtcdir, nelem(rtcdir), devgen);
  253. }
  254. static void
  255. rtcclose(Chan*)
  256. {
  257. }
  258. static long
  259. rtcread(Chan *c, void *buf, long n, vlong off)
  260. {
  261. if(c->qid.type & QTDIR)
  262. return devdirread(c, buf, n, rtcdir, nelem(rtcdir), devgen);
  263. switch((ulong)c->qid.path){
  264. default:
  265. error(Egreg);
  266. case Qrtc:
  267. return readnum(off, buf, n, rtctime(), NUMSIZE);
  268. }
  269. }
  270. static long
  271. rtcwrite(Chan *c, void *buf, long n, vlong off)
  272. {
  273. ulong offset = off;
  274. char *cp, sbuf[32];
  275. Rtc rtc;
  276. switch((ulong)c->qid.path){
  277. default:
  278. error(Egreg);
  279. case Qrtc:
  280. if(offset != 0 || n >= sizeof(sbuf)-1)
  281. error(Ebadarg);
  282. memmove(sbuf, buf, n);
  283. sbuf[n] = '\0';
  284. for(cp = sbuf; *cp != '\0'; cp++)
  285. if(*cp >= '0' && *cp <= '9')
  286. break;
  287. sec2rtc(strtoul(cp, 0, 0), &rtc);
  288. setrtc(&rtc);
  289. return n;
  290. }
  291. }
  292. Dev rtcdevtab = {
  293. L'r',
  294. "rtc",
  295. devreset,
  296. devinit,
  297. devshutdown,
  298. rtcattach,
  299. rtcwalk,
  300. rtcstat,
  301. rtcopen,
  302. devcreate,
  303. rtcclose,
  304. rtcread,
  305. devbread,
  306. rtcwrite,
  307. devbwrite,
  308. devremove,
  309. devwstat,
  310. devpower,
  311. };