]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/scram.c
merge
[plan9front.git] / sys / src / cmd / scram.c
1 #include <u.h>
2 #include </386/include/ureg.h>
3 #include <libc.h>
4 #include <aml.h>
5
6 int fd, iofd;
7 struct Ureg u;
8 ulong PM1a_CNT_BLK, PM1b_CNT_BLK, SLP_TYPa, SLP_TYPb;
9 enum {
10         SLP_EN = 0x2000,
11         SLP_TM = 0x1c00,
12 };
13
14 typedef struct Tbl Tbl;
15 struct Tbl {
16         uchar   sig[4];
17         uchar   len[4];
18         uchar   rev;
19         uchar   csum;
20         uchar   oemid[6];
21         uchar   oemtid[8];
22         uchar   oemrev[4];
23         uchar   cid[4];
24         uchar   crev[4];
25         uchar   data[];
26 };
27
28 enum {
29         Tblsz   = 4+4+1+1+6+8+4+4+4,
30 };
31
32 void*
33 amlalloc(int n){
34         return mallocz(n, 1);
35 }
36
37 void
38 amlfree(void *p){
39         free(p);
40 }
41
42 static ulong
43 get32(uchar *p){
44         return p[3]<<24 | p[2]<<16 | p[1]<<8 | p[0];
45 }
46
47 void
48 apm(void)
49 {
50         seek(fd, 0, 0);
51         if(write(fd, &u, sizeof u) < 0)
52                 sysfatal("write: %r");
53         seek(fd, 0, 0);
54         if(read(fd, &u, sizeof u) < 0)
55                 sysfatal("read: %r");
56         if(u.flags & 1)
57                 sysfatal("apm: %lux", (u.ax>>8) & 0xFF);
58 }
59
60 int
61 loadacpi(void)
62 {
63         void *r, **rr;
64         ulong l;
65         Tbl *t;
66         int n;
67
68         amlinit();
69         for(;;){
70                 t = malloc(sizeof(*t));
71                 if((n = readn(fd, t, Tblsz)) <= 0)
72                         break;
73                 if(n != Tblsz)
74                         return -1;
75                 l = get32(t->len);
76                 if(l < Tblsz)
77                         return -1;
78                 l -= Tblsz;
79                 t = realloc(t, sizeof(*t) + l);
80                 if(readn(fd, t->data, l) != l)
81                         return -1;
82                 if(memcmp("DSDT", t->sig, 4) == 0)
83                         amlload(t->data, l);
84                 else if(memcmp("SSDT", t->sig, 4) == 0)
85                         amlload(t->data, l);
86                 else if(memcmp("FACP", t->sig, 4) == 0){
87                         PM1a_CNT_BLK = get32(((uchar*)t) + 64);
88                         PM1b_CNT_BLK = get32(((uchar*)t) + 68);
89                 }
90         }
91         if(amleval(amlwalk(amlroot, "_S5"), "", &r) < 0)
92                 return -1;
93         if(amltag(r) != 'p' || amllen(r) < 2)
94                 return -1;
95         rr = amlval(r);
96         SLP_TYPa = amlint(rr[0]);
97         SLP_TYPb = amlint(rr[1]);
98         return 0;
99 }
100
101 void
102 outw(long addr, ushort val)
103 {
104         uchar buf[2];
105
106         if(addr == 0)
107                 return;
108         buf[0] = val;
109         buf[1] = val >> 8;
110         pwrite(iofd, buf, 2, addr);
111 }
112
113 void
114 wirecpu0(void)
115 {
116         char buf[128];
117         int ctl;
118
119         snprint(buf, sizeof(buf), "/proc/%d/ctl", getpid());
120         if((ctl = open(buf, OWRITE)) < 0){
121                 snprint(buf, sizeof(buf), "#p/%d/ctl", getpid());
122                 if((ctl = open(buf, OWRITE)) < 0)
123                         return;
124         }
125         write(ctl, "wired 0", 7);
126         close(ctl);
127 }
128
129 void
130 main()
131 {
132         wirecpu0();
133
134         if((fd = open("/dev/apm", ORDWR)) < 0)
135                 if((fd = open("#P/apm", ORDWR)) < 0)
136                         goto tryacpi;
137
138         u.ax = 0x530E;
139         u.bx = 0x0000;
140         u.cx = 0x0102;
141         apm();
142         u.ax = 0x5307;
143         u.bx = 0x0001;
144         u.cx = 0x0003;
145         apm();
146         
147 tryacpi:
148         if((fd = open("/dev/acpitbls", OREAD)) < 0)
149                 if((fd = open("#P/acpitbls", OREAD)) < 0)
150                         goto fail;
151         if((iofd = open("/dev/iow", OWRITE)) < 0)
152                 if((iofd = open("#P/iow", OWRITE)) < 0)
153                         goto fail;
154         if(loadacpi() < 0)
155                 goto fail;
156
157         outw(PM1a_CNT_BLK, ((SLP_TYPa << 10) & SLP_TM) | SLP_EN);
158         outw(PM1b_CNT_BLK, ((SLP_TYPb << 10) & SLP_TM) | SLP_EN);
159         sleep(100);
160
161         /*
162          * The SetSystemSleeping() example from the ACPI spec 
163          * writes the same value in both registers. But Linux/BSD
164          * write distinct values from the _Sx package (like the
165          * code above). The _S5 package on a HP DC5700 is
166          * Package(0x2){0x0, 0x7} and writing SLP_TYPa of 0 to
167          * PM1a_CNT_BLK seems to have no effect but 0x7 seems
168          * to work fine. So trying the following as a last effort.
169          */
170         SLP_TYPa |= SLP_TYPb;
171         outw(PM1a_CNT_BLK, ((SLP_TYPa << 10) & SLP_TM) | SLP_EN);
172         outw(PM1b_CNT_BLK, ((SLP_TYPa << 10) & SLP_TM) | SLP_EN);
173         sleep(100);
174
175 fail:
176         exits("scram");
177 }