From 1eff3709b4b9e257e536f6a2c8926bc5c519a532 Mon Sep 17 00:00:00 2001 From: aiju Date: Fri, 29 Jun 2012 16:55:48 +0200 Subject: [PATCH] acpi shutdown --- rc/bin/fshalt | 11 +++-- sys/src/cmd/scram.c | 104 +++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 110 insertions(+), 5 deletions(-) diff --git a/rc/bin/fshalt b/rc/bin/fshalt index c6bf8c854..2847e6a6c 100755 --- a/rc/bin/fshalt +++ b/rc/bin/fshalt @@ -38,9 +38,12 @@ for (i in $k){ # for scram, don't scram other systems bind -b '#P' /dev -if (test -e '#P'/apm) - if (! ~ $reboot yes) +if(! ~ $reboot yes){ + if (test -e '#P'/apm) scram=yes + if (test -e '#P'/acpitbls -a -e '#P'/iow) + scram=yes +} # halting (binaries we run can't be on the fs we're halting) ramfs @@ -85,8 +88,10 @@ fn x { echo rebooting... echo reboot >'#c/reboot' } - if (~ $scram yes) + if (~ $scram yes){ scram + echo 'It''s now safe to turn off your computer' + } } x diff --git a/sys/src/cmd/scram.c b/sys/src/cmd/scram.c index 7bd2299fe..83fc6c26c 100644 --- a/sys/src/cmd/scram.c +++ b/sys/src/cmd/scram.c @@ -1,9 +1,39 @@ #include #include #include +#include struct Ureg u; -int fd; +int fd, iofd, PM1A_CNT_BLK, PM1B_CNT_BLK, SLP_TYPa, SLP_TYPb; + +typedef struct Tbl Tbl; +struct Tbl { + uchar sig[4]; + uchar len[4]; + uchar rev; + uchar csum; + uchar oemid[6]; + uchar oemtid[8]; + uchar oemrev[4]; + uchar cid[4]; + uchar crev[4]; + uchar data[]; +}; + +void* +amlalloc(int n){ + return mallocz(n, 1); +} + +void +amlfree(void *p){ + free(p); +} + +static uint +get32(uchar *p){ + return p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0]; +} void apm(void) @@ -18,12 +48,67 @@ apm(void) sysfatal("apm: %lux", (u.ax>>8) & 0xFF); } +int +loadacpi(void) +{ + void *r, **rr; + Tbl *t; + int n; + ulong l; + + amlinit(); + for(;;){ + t = malloc(sizeof(*t)); + if((n = readn(fd, t, sizeof(*t))) <= 0) + break; + if(n != sizeof(*t)) + return -1; + l = *(ulong*)(t->len); + if(l < sizeof(*t)) + return -1; + t = realloc(t, l); + l -= sizeof(*t); + if(readn(fd, t->data, l) != l) + return -1; + if(memcmp("DSDT", t->sig, 4) == 0) + amlload(t->data, l); + else if(memcmp("SSDT", t->sig, 4) == 0) + amlload(t->data, l); + else if(memcmp("FACP", t->sig, 4) == 0){ + PM1A_CNT_BLK = get32(((uchar*)t) + 64); + PM1B_CNT_BLK = get32(((uchar*)t) + 68); + } + } + if(PM1A_CNT_BLK == 0) + return -1; + if(amleval(amlwalk(amlroot, "_S5"), "", &r) < 0) + return -1; + if(amltag(r) != 'p' || amllen(r) < 2) + return -1; + rr = amlval(r); + if(amltag(rr[1]) != 'i') + return -1; + SLP_TYPa = (amlint(rr[1]) & 0xFF) << 10; + SLP_TYPb = ((amlint(rr[1]) >> 8) & 0xFF) << 10; + return 0; +} + +void +outw(long addr, short val) +{ + char buf[2]; + + buf[0] = val; + buf[1] = val >> 8; + pwrite(iofd, buf, 2, addr); +} + void main() { if((fd = open("/dev/apm", ORDWR)) < 0) if((fd = open("#P/apm", ORDWR)) < 0) - sysfatal("open: %r"); + goto tryacpi; u.ax = 0x530E; u.bx = 0x0000; @@ -33,4 +118,19 @@ main() u.bx = 0x0001; u.cx = 0x0003; apm(); + +tryacpi: + if((fd = open("/dev/acpitbls", OREAD)) < 0) + if((fd = open("#P/acpitbls", OREAD)) < 0) + goto fail; + if((iofd = open("/dev/iow", OWRITE)) < 0) + if((iofd = open("#P/iow", OWRITE)) < 0) + goto fail; + if(loadacpi() < 0) + goto fail; + outw(PM1A_CNT_BLK, SLP_TYPa | 0x2000); + if(PM1B_CNT_BLK != 0) + outw(PM1B_CNT_BLK, SLP_TYPb | 0x2000); +fail: + ; }