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