ref: 1eff3709b4b9e257e536f6a2c8926bc5c519a532
parent: 3500a4fafe60bdc617769cbbea90aaac97d3f28d
author: aiju <[email protected]>
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:
+ ;
}