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