X-Git-Url: https://git.lizzy.rs/?a=blobdiff_plain;f=sys%2Fsrc%2Fcmd%2Fscram.c;h=32d4bc389f764996bb97b734e03d924c4c5779f7;hb=cea9e2267a70d17173c2b0fcdc421ee11b66ee79;hp=f61a0884159221d9c58a5437f57769d69d33859b;hpb=27dc8032ab5f4d2e8dabb2070827385f2832ac3c;p=plan9front.git diff --git a/sys/src/cmd/scram.c b/sys/src/cmd/scram.c index f61a08841..32d4bc389 100644 --- a/sys/src/cmd/scram.c +++ b/sys/src/cmd/scram.c @@ -1,20 +1,186 @@ #include #include -typedef struct Ureg Ureg; #include +#include + +int fd, iofd; +struct Ureg u; +ulong PM1a_CNT_BLK, PM1b_CNT_BLK, SLP_TYPa, SLP_TYPb; +ulong GPE0_BLK, GPE1_BLK, GPE0_BLK_LEN, GPE1_BLK_LEN; +enum { + SLP_EN = 0x2000, + SLP_TM = 0x1c00, +}; + +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[]; +}; + +enum { + Tblsz = 4+4+1+1+6+8+4+4+4, +}; + +static ulong +get32(uchar *p){ + return p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0]; +} + +void +apm(void) +{ + seek(fd, 0, 0); + if(write(fd, &u, sizeof u) < 0) + sysfatal("write: %r"); + seek(fd, 0, 0); + if(read(fd, &u, sizeof u) < 0) + sysfatal("read: %r"); + if(u.flags & 1) + sysfatal("apm: %lux", (u.ax>>8) & 0xFF); +} + +int +loadacpi(void) +{ + void *r, **rr; + ulong l; + Tbl *t; + int n; + + amlinit(); + for(;;){ + t = malloc(sizeof(*t)); + if((n = readn(fd, t, Tblsz)) <= 0) + break; + if(n != Tblsz) + return -1; + l = get32(t->len); + if(l < Tblsz) + return -1; + l -= Tblsz; + t = realloc(t, sizeof(*t) + l); + if(readn(fd, t->data, l) != l) + return -1; + if(memcmp("DSDT", t->sig, 4) == 0){ + amlintmask = (~0ULL) >> (t->rev <= 1)*32; + 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); + GPE0_BLK = get32(((uchar*)t) + 80); + GPE1_BLK = get32(((uchar*)t) + 84); + GPE0_BLK_LEN = *(((uchar*)t) + 92); + GPE1_BLK_LEN = *(((uchar*)t) + 93); + } + } + if(amleval(amlwalk(amlroot, "_S5"), "", &r) < 0) + return -1; + if(amltag(r) != 'p' || amllen(r) < 2) + return -1; + rr = amlval(r); + SLP_TYPa = amlint(rr[0]); + SLP_TYPb = amlint(rr[1]); + return 0; +} + +void +outw(long addr, ushort val) +{ + uchar buf[2]; + + if(addr == 0) + return; + buf[0] = val; + buf[1] = val >> 8; + pwrite(iofd, buf, 2, addr); +} + +void +wirecpu0(void) +{ + char buf[128]; + int ctl; + + snprint(buf, sizeof(buf), "/proc/%d/ctl", getpid()); + if((ctl = open(buf, OWRITE)) < 0){ + snprint(buf, sizeof(buf), "#p/%d/ctl", getpid()); + if((ctl = open(buf, OWRITE)) < 0) + return; + } + write(ctl, "wired 0", 7); + close(ctl); +} void main() { - Ureg ureg; - int fd; + int n; + + wirecpu0(); + + if((fd = open("/dev/apm", ORDWR)) < 0) + if((fd = open("#P/apm", ORDWR)) < 0) + goto tryacpi; + + u.ax = 0x530E; + u.bx = 0x0000; + u.cx = 0x0102; + apm(); + u.ax = 0x5307; + u.bx = 0x0001; + u.cx = 0x0003; + apm(); - fd = open("/dev/apm", OWRITE); - if(fd < 0) sysfatal("%r"); - memset(&ureg, 0, sizeof ureg); - ureg.ax = 0x5307; - ureg.bx = 0x0001; - ureg.cx = 0x0003; - ureg.trap = 0x15; - write(fd, &ureg, sizeof ureg); +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; + + /* disable GPEs */ + for(n = 0; GPE0_BLK > 0 && n < GPE0_BLK_LEN/2; n += 2){ + outw(GPE0_BLK + GPE0_BLK_LEN/2 + n, 0); /* EN */ + outw(GPE0_BLK + n, 0xffff); /* STS */ + } + for(n = 0; GPE1_BLK > 0 && n < GPE1_BLK_LEN/2; n += 2){ + outw(GPE1_BLK + GPE1_BLK_LEN/2 + n, 0); /* EN */ + outw(GPE1_BLK + n, 0xffff); /* STS */ + } + + outw(PM1a_CNT_BLK, ((SLP_TYPa << 10) & SLP_TM) | SLP_EN); + outw(PM1b_CNT_BLK, ((SLP_TYPb << 10) & SLP_TM) | SLP_EN); + sleep(100); + + /* + * The SetSystemSleeping() example from the ACPI spec + * writes the same value in both registers. But Linux/BSD + * write distinct values from the _Sx package (like the + * code above). The _S5 package on a HP DC5700 is + * Package(0x2){0x0, 0x7} and writing SLP_TYPa of 0 to + * PM1a_CNT_BLK seems to have no effect but 0x7 seems + * to work fine. So trying the following as a last effort. + */ + SLP_TYPa |= SLP_TYPb; + outw(PM1a_CNT_BLK, ((SLP_TYPa << 10) & SLP_TM) | SLP_EN); + outw(PM1b_CNT_BLK, ((SLP_TYPa << 10) & SLP_TM) | SLP_EN); + sleep(100); + +fail: + exits("scram"); }