ref: 308ce1e4fbf0f948dbf0ce07168f18b8c3cbdcb1
parent: 526a3ce4ff371c0e20a2e6b36a6694a07af857a2
author: aiju <aiju@phicode.de>
date: Fri Jun 29 12:55:48 EDT 2012
acpi shutdown
--- a/rc/bin/fshalt
+++ b/rc/bin/fshalt
@@ -38,9 +38,12 @@
# 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 @@
echo rebooting...
echo reboot >'#c/reboot'
}
- if (~ $scram yes)
+ if (~ $scram yes){scram
+ echo 'It''s now safe to turn off your computer'
+ }
}
x
--- a/sys/src/cmd/scram.c
+++ b/sys/src/cmd/scram.c
@@ -1,11 +1,41 @@
#include <u.h>
#include </386/include/ureg.h>
#include <libc.h>
+#include <aml.h>
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)
{seek(fd, 0, 0);
@@ -18,12 +48,67 @@
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 @@
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:
+ ;
}
--
⑨