devµc.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  1. #include "u.h"
  2. #include "../port/lib.h"
  3. #include "mem.h"
  4. #include "dat.h"
  5. #include "fns.h"
  6. #include "io.h"
  7. #include "../port/error.h"
  8. enum{
  9. Qdir,
  10. Qbacklight,
  11. Qbattery,
  12. Qbuttons,
  13. Qcruft,
  14. Qkbdin,
  15. Qled,
  16. Qversion,
  17. Qpower,
  18. /* command types */
  19. BLversion= 0,
  20. BLbuttons= 2, /* button events */
  21. BLtouch= 3, /* read touch screen events */
  22. BLled= 8, /* turn LED on/off */
  23. BLbattery= 9, /* read battery status */
  24. BLbacklight= 0xd, /* backlight control */
  25. SOF= 0x2, /* start of frame */
  26. };
  27. /* from /sys/include/keyboard.h */
  28. enum {
  29. KF= 0xF000, /* Rune: beginning of private Unicode space */
  30. /* KF|1, KF|2, ..., KF|0xC is F1, F2, ..., F12 */
  31. Khome= KF|0x0D,
  32. Kup= KF|0x0E,
  33. Kpgup= KF|0x0F,
  34. Kprint= KF|0x10,
  35. Kleft= KF|0x11,
  36. Kright= KF|0x12,
  37. Kdown= 0x80,
  38. Kview= 0x80,
  39. Kpgdown= KF|0x13,
  40. Kins= KF|0x14,
  41. Kend= '\r', /* [sic] */
  42. Kalt= KF|0x15,
  43. Kshift= KF|0x16,
  44. Kctl= KF|0x17,
  45. };
  46. Dirtab µcdir[]={
  47. ".", { Qdir, 0, QTDIR }, 0, DMDIR|0755,
  48. "backlight", { Qbacklight, 0 }, 0, 0664,
  49. "battery", { Qbattery, 0 }, 0, 0664,
  50. "buttons", { Qbuttons, 0 }, 0, 0664,
  51. "cruft", { Qcruft, 0 }, 0, 0664,
  52. "kbdin", { Qkbdin, 0 }, 0, 0664,
  53. "led", { Qled, 0 }, 0, 0664,
  54. "version", { Qversion, 0 }, 0, 0664,
  55. "power", { Qpower, 0 }, 0, 0600,
  56. };
  57. static struct µcontroller
  58. {
  59. /* message being rcvd */
  60. int state;
  61. uchar buf[16+4];
  62. uchar n;
  63. /* for messages that require acks */
  64. QLock;
  65. Rendez r;
  66. /* battery */
  67. uchar acstatus;
  68. uchar voltage;
  69. ushort batstatus;
  70. uchar batchem;
  71. /* version string */
  72. char version[16+2];
  73. } ctlr;
  74. /* button map */
  75. Rune bmap[2][4] =
  76. {
  77. {Kup, Kright, Kleft, Kdown}, /* portrait mode */
  78. {Kright, Kdown, Kup, Kleft}, /* landscape mode */
  79. };
  80. extern int landscape;
  81. int
  82. µcputc(Queue*, int ch)
  83. {
  84. int i, len, b, up;
  85. uchar cksum;
  86. uchar *p;
  87. static int samseq;
  88. static int touching; /* guard against something we call going spllo() */
  89. static int buttoning; /* guard against something we call going spllo() */
  90. if(ctlr.n > sizeof(ctlr.buf))
  91. panic("µcputc");
  92. ctlr.buf[ctlr.n++] = (uchar)ch;
  93. for(;;){
  94. /* message hasn't started yet? */
  95. if(ctlr.buf[0] != SOF){
  96. p = memchr(ctlr.buf, SOF, ctlr.n);
  97. if(p == nil){
  98. ctlr.n = 0;
  99. break;
  100. } else {
  101. ctlr.n -= p-ctlr.buf;
  102. memmove(ctlr.buf, p, ctlr.n);
  103. }
  104. }
  105. /* whole msg? */
  106. len = ctlr.buf[1] & 0xf;
  107. if(ctlr.n < 3 || ctlr.n < len+3)
  108. break;
  109. /* check the sum */
  110. ctlr.buf[0] = ~SOF; /* make sure we process this msg exactly once */
  111. cksum = 0;
  112. for(i = 1; i < len+2; i++)
  113. cksum += ctlr.buf[i];
  114. if(ctlr.buf[len+2] != cksum)
  115. continue;
  116. /* parse resulting message */
  117. p = ctlr.buf+2;
  118. switch(ctlr.buf[1] >> 4){
  119. case BLversion:
  120. strncpy(ctlr.version, (char*)p, len);
  121. ctlr.version[len] = '0';
  122. strcat(ctlr.version, "\n");
  123. wakeup(&ctlr.r);
  124. break;
  125. case BLbuttons:
  126. if(len < 1 || buttoning)
  127. break;
  128. buttoning = 1;
  129. b = p[0] & 0x7f;
  130. up = p[0] & 0x80;
  131. if(b > 5) {
  132. /* rocker panel acts like arrow keys */
  133. if(b < 10 && !up)
  134. kbdputc(kbdq, bmap[landscape][b-6]);
  135. } else {
  136. /* the rest like mouse buttons */
  137. if(--b == 0)
  138. b = 5;
  139. penbutton(up, 1<<b);
  140. }
  141. buttoning = 0;
  142. break;
  143. case BLtouch:
  144. if(touching)
  145. break;
  146. touching = 1;
  147. if(len == 4) {
  148. if (samseq++ > 10){
  149. if (landscape)
  150. pentrackxy((p[0]<<8)|p[1], (p[2]<<8)|p[3]);
  151. else
  152. pentrackxy((p[2]<<8)|p[3], (p[0]<<8)|p[1]);
  153. }
  154. } else {
  155. samseq = 0;
  156. pentrackxy(-1, -1);
  157. }
  158. touching = 0;
  159. break;
  160. case BLled:
  161. wakeup(&ctlr.r);
  162. break;
  163. case BLbattery:
  164. if(len >= 5){
  165. ctlr.acstatus = p[0];
  166. ctlr.voltage = (p[3]<<8)|p[2];
  167. ctlr.batstatus = p[4];
  168. ctlr.batchem = p[1];
  169. }
  170. wakeup(&ctlr.r);
  171. break;
  172. case BLbacklight:
  173. wakeup(&ctlr.r);
  174. break;
  175. default:
  176. print("unknown µc message: %ux", ctlr.buf[1] >> 4);
  177. for(i = 0; i < len; i++)
  178. print(" %ux", p[i]);
  179. print("\n");
  180. break;
  181. }
  182. /* remove the message */
  183. ctlr.n -= len+3;
  184. memmove(ctlr.buf, &ctlr.buf[len+3], ctlr.n);
  185. }
  186. return 0;
  187. }
  188. static void
  189. _sendmsg(uchar id, uchar *data, int len)
  190. {
  191. uchar buf[20];
  192. uchar cksum;
  193. uchar c;
  194. uchar *p = buf;
  195. int i;
  196. /* create the message */
  197. if(sizeof(buf) < len+4)
  198. return;
  199. cksum = (id<<4) | len;
  200. *p++ = SOF;
  201. *p++ = cksum;
  202. for(i = 0; i < len; i++){
  203. c = data[i];
  204. cksum += c;
  205. *p++ = c;
  206. }
  207. *p++ = cksum;
  208. /* send the message - there should be a more generic way to do this */
  209. serialµcputs(buf, p-buf);
  210. }
  211. /* the tsleep takes care of lost acks */
  212. static void
  213. sendmsgwithack(uchar id, uchar *data, int len)
  214. {
  215. if(waserror()){
  216. qunlock(&ctlr);
  217. nexterror();
  218. }
  219. qlock(&ctlr);
  220. _sendmsg(id, data, len);
  221. tsleep(&ctlr.r, return0, 0, 100);
  222. qunlock(&ctlr);
  223. poperror();
  224. }
  225. static void
  226. sendmsg(uchar id, uchar *data, int len)
  227. {
  228. if(waserror()){
  229. qunlock(&ctlr);
  230. nexterror();
  231. }
  232. qlock(&ctlr);
  233. _sendmsg(id, data, len);
  234. qunlock(&ctlr);
  235. poperror();
  236. }
  237. void
  238. µcinit(void)
  239. {
  240. }
  241. static Chan*
  242. µcattach(char* spec)
  243. {
  244. return devattach('r', spec);
  245. }
  246. static Walkqid*
  247. µcwalk(Chan *c, Chan *nc, char **name, int nname)
  248. {
  249. return devwalk(c, nc, name, nname, µcdir, nelem(µcdir), devgen);
  250. }
  251. static int
  252. µcstat(Chan *c, uchar *dp, int n)
  253. {
  254. return devstat(c, dp, n, µcdir, nelem(µcdir), devgen);
  255. }
  256. static Chan*
  257. µcopen(Chan* c, int omode)
  258. {
  259. omode = openmode(omode);
  260. if(!iseve())
  261. error(Eperm);
  262. return devopen(c, omode, µcdir, nelem(µcdir), devgen);
  263. }
  264. static void
  265. µcclose(Chan*)
  266. {
  267. }
  268. char*
  269. acstatus(int x)
  270. {
  271. if(x)
  272. return "attached";
  273. else
  274. return "detached";
  275. }
  276. char*
  277. batstatus(int x)
  278. {
  279. switch(x){
  280. case 1: return "high";
  281. case 2: return "low";
  282. case 4: return "critical";
  283. case 8: return "charging";
  284. case 0x80: return "none";
  285. }
  286. return "ok";
  287. }
  288. static long
  289. µcread(Chan* c, void* a, long n, vlong off)
  290. {
  291. char buf[64];
  292. if(c->qid.path == Qdir)
  293. return devdirread(c, a, n, µcdir, nelem(µcdir), devgen);
  294. switch((ulong)c->qid.path){
  295. case Qbattery:
  296. sendmsgwithack(BLbattery, nil, 0); /* send a battery request */
  297. sprint(buf, "voltage: %d\nac: %s\nstatus: %s\n", ctlr.voltage,
  298. acstatus(ctlr.acstatus),
  299. batstatus(ctlr.batstatus));
  300. return readstr(off, a, n, buf);
  301. case Qversion:
  302. sendmsgwithack(BLversion, nil, 0); /* send a battery request */
  303. return readstr(off, a, n, ctlr.version);
  304. }
  305. error(Ebadarg);
  306. return 0;
  307. }
  308. #define PUTBCD(n,o) bcdclock[o] = (n % 10) | (((n / 10) % 10)<<4)
  309. static uchar lightdata[16];
  310. static long
  311. µcwrite(Chan* c, void* a, long n, vlong)
  312. {
  313. Cmdbuf *cmd;
  314. uchar data[16];
  315. char str[64];
  316. int i, j;
  317. ulong l;
  318. Rune r;
  319. extern ulong resumeaddr[];
  320. extern void power_resume(void);
  321. if(c->qid.path == Qkbdin){
  322. if(n >= sizeof(str))
  323. n = sizeof(str)-1;
  324. memmove(str, a, n);
  325. str[n] = 0;
  326. for(i = 0; i < n; i += j){
  327. j = chartorune(&r, &str[i]);
  328. kbdcr2nl(nil, r);
  329. }
  330. return n;
  331. }
  332. if(c->qid.path == Qpower){
  333. if(!iseve())
  334. error(Eperm);
  335. if(strncmp(a, "suspend", 7) == 0)
  336. *resumeaddr = (ulong)power_resume;
  337. else if(strncmp(a, "halt", 4) == 0)
  338. *resumeaddr = 0;
  339. else if(strncmp(a, "wakeup", 6) == 0){
  340. cmd = parsecmd(a, n);
  341. if (cmd->nf != 2)
  342. error(Ebadarg);
  343. l = strtoul(cmd->f[1], 0, 0);
  344. rtcalarm(l);
  345. return n;
  346. } else
  347. error(Ebadarg);
  348. deepsleep();
  349. return n;
  350. }
  351. cmd = parsecmd(a, n);
  352. if(cmd->nf > 15)
  353. error(Ebadarg);
  354. for(i = 0; i < cmd->nf; i++)
  355. data[i] = atoi(cmd->f[i]);
  356. switch((ulong)c->qid.path){
  357. case Qled:
  358. sendmsgwithack(BLled, data, cmd->nf);
  359. break;
  360. case Qbacklight:
  361. memmove(lightdata, data, 16);
  362. sendmsgwithack(BLbacklight, data, cmd->nf);
  363. break;
  364. case Qcruft:
  365. // lcdtweak(cmd);
  366. break;
  367. default:
  368. error(Ebadarg);
  369. }
  370. return n;
  371. }
  372. void
  373. µcpower(int on)
  374. {
  375. uchar data[16];
  376. if (on == 0)
  377. return;
  378. /* maybe dangerous, not holding the lock */
  379. if (lightdata[0] == 0){
  380. data[0]= 2;
  381. data[1]= 1;
  382. data[2]= 0;
  383. } else
  384. memmove(data, lightdata, 16);
  385. _sendmsg(0xd, data, 3);
  386. wakeup(&ctlr.r);
  387. }
  388. Dev µcdevtab = {
  389. 'r',
  390. "µc",
  391. devreset,
  392. µcinit,
  393. devshutdown,
  394. µcattach,
  395. µcwalk,
  396. µcstat,
  397. µcopen,
  398. devcreate,
  399. µcclose,
  400. µcread,
  401. devbread,
  402. µcwrite,
  403. devbwrite,
  404. devremove,
  405. devwstat,
  406. };