]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/aux/acpi.c
kbdfs: handle mouse control (Kmouse, Kshift button swap) in parallel, bring back...
[plan9front.git] / sys / src / cmd / aux / acpi.c
1 #include <u.h>
2 #include <libc.h>
3 #include <fcall.h>
4 #include <thread.h>
5 #include <9p.h>
6 #include <aml.h>
7
8 typedef struct Batstat Batstat;
9 typedef struct Battery Battery;
10 typedef struct Dfile Dfile;
11 typedef struct Tbl Tbl;
12 typedef struct Thermal Thermal;
13
14 struct Batstat {
15         int rate;
16         int capacity;
17         int state;
18         int voltage;
19 };
20
21 struct Battery {
22         char *unit;
23         void *bst;
24         int fullcharge;
25         int capacity;
26         int capacitywarn;
27         int capacitylow;
28         int voltage;
29 };
30
31 struct Dfile {
32         Qid qid;
33         char *name;
34         ulong mode;
35         void (*read)(Req*);
36         void (*write)(Req*);
37 };
38
39 struct Tbl {
40         uchar sig[4];
41         uchar len[4];
42         uchar rev;
43         uchar csum;
44         uchar oemid[6];
45         uchar oemtid[8];
46         uchar oemrev[4];
47         uchar cid[4];
48         uchar crev[4];
49         uchar data[];
50 };
51
52 struct Thermal {
53         uint cpus;
54         void *tmp;
55 };
56
57 enum {
58         Stacksz = 16384,
59         Tblsz = 4+4+1+1+6+8+4+4+4,
60
61         Qroot = 0,
62         Qbattery,
63         Qcputemp,
64         Qctl,
65 };
66
67 static void rootread(Req*);
68 static void ctlread(Req*);
69 static void ctlwrite(Req*);
70 static void batteryread(Req*);
71 static void tmpread(Req*);
72
73 int ec, mem, iofd[5], nbats, ntherms, rp, wp;
74 char *units[] = {"mW", "mA"};
75 Battery bats[4];
76 Thermal therms[4];
77 Channel *creq, *cevent;
78 Req *rlist, **tailp;
79
80 Dfile dfile[] = {
81         {{Qroot,0,QTDIR},       "/",            DMDIR|0555,     rootread,               nil},
82         {{Qbattery},            "battery",      0444,           batteryread,    nil},
83         {{Qcputemp},            "cputemp",      0444,           tmpread,                nil},
84         {{Qctl},                        "ctl",          0666,           ctlread,                ctlwrite},
85 };
86
87 static int
88 enumbat(void *dot, void *)
89 {
90         void *p, *r, **rr;
91         Battery *b;
92         int n;
93
94         if(nbats >= nelem(bats))
95                 return 1;
96
97         if((p = amlwalk(dot, "^_STA")) == nil)
98                 return 1;
99         if(amleval(p, "", &r) < 0 || (amlint(r)&3) != 3)
100                 return 1;
101         if(amleval(dot, "", &r) < 0) /* _BIF */
102                 return 1;
103         if(r == nil || amltag(r) != 'p' || amllen(r) < 7)
104                 return 1;
105
106         rr = amlval(r);
107         b = &bats[nbats];
108         if((n = amlint(rr[0])) >= nelem(units) || n < 0)
109                 b->unit = "??";
110         else
111                 b->unit = units[n];
112         b->capacity = amlint(rr[1]);
113         if((int)b->capacity < 0) /* even though _STA tells it's there */
114                 return 1;
115         b->fullcharge = amlint(rr[2]);
116         b->voltage = amlint(rr[4]);
117         b->capacitywarn = amlint(rr[5]);
118         b->capacitylow = amlint(rr[6]);
119         b->bst = amlwalk(dot, "^_BST");
120         if(b->bst != nil){
121                 amltake(b->bst);
122                 nbats++;
123         }
124
125         return 1;
126 }
127
128 static int
129 enumtmp(void *dot, void *)
130 {
131         void *r, **rr;
132         char s[64];
133         int i, n;
134         uint cpus;
135
136         cpus = 0;
137         if(ntherms < nelem(therms) && amleval(dot, "", &r) >= 0 && amllen(r) > 0 && (rr = amlval(r)) != nil){
138                 for(i = 0; i < amllen(r); i++){
139                         snprint(s, sizeof(s), "%N", amlval(rr[i]));
140                         if((n = strlen(s)) > 0){
141                                 for(n--; n > 3; n--){
142                                         if(s[n-2] == 'C' && s[n-1] == 'P' && s[n] == 'U' && s[n+1] >= '0' && s[n+1] <= '9'){
143                                                 cpus |= 1<<atoi(&s[n+1]);
144                                                 break;
145                                         }
146                                 }
147                         }
148                 }
149         }
150
151         if(cpus != 0 && (dot = amlwalk(dot, "^_TMP")) != nil){
152                 therms[ntherms].cpus = cpus;
153                 therms[ntherms].tmp = dot;
154                 ntherms++;
155         }
156
157         return 1;
158 }
159
160 static int
161 batstat(Battery *b, Batstat *s)
162 {
163         void *r, **rr;
164
165         if(amleval(b->bst, "", &r) < 0)
166                 return -1;
167         if(r == nil || amltag(r) != 'p' || amllen(r) < 4)
168                 return -1;
169         rr = amlval(r);
170         s->state = amlint(rr[0]);
171         s->rate = amlint(rr[1]);
172         s->capacity = amlint(rr[2]);
173         s->voltage = amlint(rr[3]);
174         return 0;
175 }
176
177 static void
178 batteryread(Req *r)
179 {
180         char buf[nelem(bats)*120], *ep, *p, *state;
181         Battery *b;
182         Batstat st;
183         int n, x, h, m, s;
184
185         p = buf;
186         *p = 0;
187         ep = buf + sizeof(buf);
188         for(n = 0; n < nbats; n++){
189                 b = &bats[n];
190
191                 st.rate = -1;
192                 st.capacity = -1;
193                 st.state = 0;
194                 st.voltage = -1;
195                 batstat(b, &st);
196
197                 h = m = s = 0;
198                 if(st.state & 4)
199                         state = "critical";
200                 else if(st.state & 1)
201                         state = "discharging";
202                 else if(st.state & 2)
203                         state = "charging";
204                 else
205                         state = "unknown";
206                 if(st.rate > 0){
207                         s = ((st.state & 2) ? bats[n].fullcharge - st.capacity : st.capacity) * 3600 / st.rate;
208                         h = s/3600;
209                         s -= 3600*(s/3600);
210                         m = s/60;
211                         s -= 60*(s/60);
212                 }
213                 x = bats[n].fullcharge > 0 ? st.capacity * 100 / bats[n].fullcharge : -1;
214                 p += snprint(p, ep-p, "%d %s %d %d %d %d %d %s %d %d %02d:%02d:%02d %s\n",
215                         x,
216                         bats[n].unit, st.capacity, b->fullcharge, b->capacity, b->capacitywarn, b->capacitylow,
217                         "mV", st.voltage, b->voltage,
218                         h, m, s,
219                         state
220                 );
221         }
222         
223         readstr(r, buf);
224         respond(r, nil);
225 }
226
227 static void
228 tmpread(Req *r)
229 {
230         char buf[32], *ep, *p;
231         void *er;
232         int n, t;
233
234         p = buf;
235         ep = buf + sizeof(buf);
236
237         for(n = 0; n < ntherms; n++){
238                 t = 0;
239                 if(amleval(therms[n].tmp, "", &er) >= 0)
240                         t = amlint(er);
241                         p += snprint(p, ep-p, "%d\n", (t - 2732)/10);
242         }
243
244         readstr(r, buf);
245         respond(r, nil);
246 }
247
248 static void
249 ctlread(Req *r)
250 {
251         respond(r, "no.");
252 }
253
254 static void
255 ctlwrite(Req *r)
256 {
257         respond(r, "no.");
258 }
259
260 void*
261 emalloc(ulong n)
262 {
263         void *v;
264
265         v = malloc(n);
266         if(v == nil)
267                 sysfatal("out of memory allocating %lud", n);
268         memset(v, 0, n);
269         setmalloctag(v, getcallerpc(&n));
270         return v;
271 }
272
273 char*
274 estrdup(char *s)
275 {
276         int l;
277         char *t;
278
279         if (s == nil)
280                 return nil;
281         l = strlen(s)+1;
282         t = emalloc(l);
283         memcpy(t, s, l);
284         setmalloctag(t, getcallerpc(&s));
285         return t;
286 }
287
288 static int
289 fillstat(uvlong path, Dir *d, int doalloc)
290 {
291         int i;
292
293         for(i=0; i<nelem(dfile); i++)
294                 if(path == dfile[i].qid.path)
295                         break;
296         if(i == nelem(dfile))
297                 return -1;
298
299         memset(d, 0, sizeof *d);
300         d->uid = doalloc ? estrdup("acpi") : "acpi";
301         d->gid = doalloc ? estrdup("acpi") : "acpi";
302         d->length = 0;
303         d->name = doalloc ? estrdup(dfile[i].name) : dfile[i].name;
304         d->mode = dfile[i].mode;
305         d->atime = d->mtime = time(0);
306         d->qid = dfile[i].qid;
307         return 0;
308 }
309
310 static char*
311 fswalk1(Fid *fid, char *name, Qid *qid)
312 {
313         int i;
314
315         if(strcmp(name, "..") == 0){
316                 *qid = dfile[0].qid;
317                 fid->qid = *qid;
318                 return nil;
319         }
320
321         for(i = 1; i < nelem(dfile); i++){      /* i=1: 0 is root dir */
322                 if(strcmp(dfile[i].name, name) == 0){
323                         *qid = dfile[i].qid;
324                         fid->qid = *qid;
325                         return nil;
326                 }
327         }
328         return "file does not exist";
329 }
330
331 static void
332 fsopen(Req *r)
333 {
334         switch((ulong)r->fid->qid.path){
335         case Qroot:
336                 r->fid->aux = (void*)0;
337                 respond(r, nil);
338                 return;
339
340         case Qbattery:
341         case Qcputemp:
342                 if(r->ifcall.mode == OREAD){
343                         respond(r, nil);
344                         return;
345                 }
346                 break;
347
348         case Qctl:
349                 if((r->ifcall.mode & ~(OTRUNC|OREAD|OWRITE|ORDWR)) == 0){
350                         respond(r, nil);
351                         return;
352                 }
353                 break;
354         }
355         respond(r, "permission denied");
356         return;
357 }
358
359 static void
360 fsstat(Req *r)
361 {
362         fillstat(r->fid->qid.path, &r->d, 1);
363         respond(r, nil);
364 }
365
366 static void
367 fsread(Req *r)
368 {
369         dfile[r->fid->qid.path].read(r);
370 }
371
372 static void
373 fswrite(Req *r)
374 {
375         dfile[r->fid->qid.path].write(r);
376 }
377
378 static void
379 rootread(Req *r)
380 {
381         int n;
382         uvlong offset;
383         char *p, *ep;
384         Dir d;
385
386         offset = r->ifcall.offset == 0 ? 0 : (uvlong)r->fid->aux;
387         p = r->ofcall.data;
388         ep = r->ofcall.data + r->ifcall.count;
389
390         if(offset == 0) /* skip root */
391                 offset = 1;
392         for(; p+2 < ep; p += n){
393                 if(fillstat(offset, &d, 0) < 0)
394                         break;
395                 n = convD2M(&d, (uchar*)p, ep-p);
396                 if(n <= BIT16SZ)
397                         break;
398                 offset++;
399         }
400         r->fid->aux = (void*)offset;
401         r->ofcall.count = p - r->ofcall.data;
402         respond(r, nil);
403 }
404
405 static void
406 fsattach(Req *r)
407 {
408         if(r->ifcall.aname && r->ifcall.aname[0]){
409                 respond(r, "invalid attach specifier");
410                 return;
411         }
412         r->fid->qid = dfile[0].qid;
413         r->ofcall.qid = dfile[0].qid;
414         respond(r, nil);
415 }
416
417 static void
418 usage(void)
419 {
420         fprint(2, "usage: aux/acpi [-Di] [-d /dev] [-m /mnt/acpi] [-s service]\n");
421         exits("usage");
422 }
423
424 static ulong
425 get32(uchar *p){
426         return p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0];
427 }
428
429 Srv fs = {
430         .attach = fsattach,
431         .walk1 = fswalk1,
432         .open = fsopen,
433         .read = fsread,
434         .write = fswrite,
435         .stat = fsstat,
436 };
437
438 void
439 threadmain(int argc, char **argv)
440 {
441         char *mtpt, *srv;
442         Tbl *t;
443         int fd, n, l;
444
445         mtpt = "/mnt/acpi";
446         srv = nil;
447         ARGBEGIN{
448         case 'D':
449                 chatty9p = 1;
450                 break;
451         case 'i':
452                 fs.nopipe++;
453                 fs.infd = 0;
454                 fs.outfd = 1;
455                 mtpt = nil;
456                 break;
457         case 'm':
458                 mtpt = EARGF(usage());
459                 break;
460         case 's':
461                 srv = EARGF(usage());
462                 break;
463         }ARGEND
464
465         if((ec = open("/dev/ec", ORDWR)) < 0)
466                 if((ec = open("#P/ec", ORDWR)) < 0)
467                         goto fail;
468         if((mem = open("/dev/acpimem", ORDWR)) < 0)
469                 mem = open("#P/acpimem", ORDWR);
470         if((iofd[1] = open("/dev/iob", ORDWR)) < 0)
471                 if((iofd[1] = open("#P/iob", ORDWR)) < 0)
472                         goto fail;
473         if((iofd[2] = open("/dev/iow", ORDWR)) < 0)
474                 if((iofd[2] = open("#P/iow", ORDWR)) < 0)
475                         goto fail;
476         if((iofd[4] = open("/dev/iol", ORDWR)) < 0)
477                 if((iofd[4] = open("#P/iol", ORDWR)) < 0)
478                         goto fail;
479         if((fd = open("/dev/acpitbls", OREAD)) < 0)
480                 if((fd = open("#P/acpitbls", OREAD)) < 0)
481                         goto fail;
482
483         amlinit();
484         for(;;){
485                 t = malloc(sizeof(*t));
486                 if((n = readn(fd, t, Tblsz)) <= 0)
487                         break;
488                 if(n != Tblsz)
489                         goto fail;
490                 l = get32(t->len);
491                 if(l < Tblsz)
492                         goto fail;
493                 l -= Tblsz;
494                 t = realloc(t, sizeof(*t) + l);
495                 if(readn(fd, t->data, l) != l)
496                         goto fail;
497                 if(memcmp("DSDT", t->sig, 4) == 0){
498                         amlintmask = (~0ULL) >> (t->rev <= 1)*32;
499                         amlload(t->data, l);
500                 }else if(memcmp("SSDT", t->sig, 4) == 0)
501                         amlload(t->data, l);
502         }
503         close(fd);
504
505         amlenum(amlroot, "_BIF", enumbat, nil);
506         amlenum(amlroot, "_PSL", enumtmp, nil);
507
508         rfork(RFNOTEG);
509         threadpostmountsrv(&fs, srv, mtpt, MREPL);
510         return;
511
512 fail:
513         fprint(2, "%r\n");
514         amlexit();
515         threadexitsall("acpi");
516 }
517
518 static int
519 readec(Amlio *, void *data, int len, int off)
520 {
521         return pread(ec, data, len, off);
522 }
523
524 static int
525 writeec(Amlio *, void *data, int len, int off)
526 {
527         return pwrite(ec, data, len, off);
528 }
529
530 static int
531 readio(Amlio *io, void *data, int len, int port)
532 {
533         assert(len == 1 || len == 2 || len == 4);
534         return pread(iofd[len], data, len, io->off+port);
535 }
536
537 static int
538 writeio(Amlio *io, void *data, int len, int port)
539 {
540         assert(len == 1 || len == 2 || len == 4);
541         return pwrite(iofd[len], data, len, io->off+port);
542 }
543
544 static int
545 memread(Amlio *io, void *data, int len, int addr)
546 {
547         return pread(mem, data, len, io->off+addr);
548 }
549
550 static int
551 memwrite(Amlio *io, void *data, int len, int addr)
552 {
553         return pwrite(mem, data, len, io->off+addr);
554 }
555
556 static int
557 dummy(Amlio *, void *, int len, int)
558 {
559         return len;
560 }
561
562 int
563 amlmapio(Amlio *io)
564 {
565         switch(io->space){
566         case EbctlSpace:
567                 io->read = readec;
568                 io->write = writeec;
569                 break;
570         case IoSpace:
571                 io->read = readio;
572                 io->write = writeio;
573                 break;
574         case MemSpace:
575                 io->read = mem >= 0 ? memread : dummy;
576                 io->write = mem >= 0 ? memwrite : dummy;
577                 break;
578         default:
579                 io->read = dummy;
580                 io->write = dummy;
581                 break;
582         }
583         return 0;
584 }
585
586 void
587 amlunmapio(Amlio *)
588 {
589 }