root / hw / acpi.c @ 1f56e32a
History | View | Annotate | Download (10 kB)
1 | 6515b203 | bellard | /*
|
---|---|---|---|
2 | 6515b203 | bellard | * ACPI implementation
|
3 | 5fafdf24 | ths | *
|
4 | 6515b203 | bellard | * Copyright (c) 2006 Fabrice Bellard
|
5 | 5fafdf24 | ths | *
|
6 | 6515b203 | bellard | * This library is free software; you can redistribute it and/or
|
7 | 6515b203 | bellard | * modify it under the terms of the GNU Lesser General Public
|
8 | 6515b203 | bellard | * License version 2 as published by the Free Software Foundation.
|
9 | 6515b203 | bellard | *
|
10 | 6515b203 | bellard | * This library is distributed in the hope that it will be useful,
|
11 | 6515b203 | bellard | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
12 | 6515b203 | bellard | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
13 | 6515b203 | bellard | * Lesser General Public License for more details.
|
14 | 6515b203 | bellard | *
|
15 | 6515b203 | bellard | * You should have received a copy of the GNU Lesser General Public
|
16 | 8167ee88 | Blue Swirl | * License along with this library; if not, see <http://www.gnu.org/licenses/>
|
17 | 6515b203 | bellard | */
|
18 | 04dc308f | Isaku Yamahata | #include "sysemu.h" |
19 | 87ecb68b | pbrook | #include "hw.h" |
20 | 87ecb68b | pbrook | #include "pc.h" |
21 | 990b150e | Isaku Yamahata | #include "acpi.h" |
22 | 6515b203 | bellard | |
23 | 8a92ea2f | aliguori | struct acpi_table_header
|
24 | 8a92ea2f | aliguori | { |
25 | 8a92ea2f | aliguori | char signature [4]; /* ACPI signature (4 ASCII characters) */ |
26 | 8a92ea2f | aliguori | uint32_t length; /* Length of table, in bytes, including header */
|
27 | 8a92ea2f | aliguori | uint8_t revision; /* ACPI Specification minor version # */
|
28 | 8a92ea2f | aliguori | uint8_t checksum; /* To make sum of entire table == 0 */
|
29 | 8a92ea2f | aliguori | char oem_id [6]; /* OEM identification */ |
30 | 8a92ea2f | aliguori | char oem_table_id [8]; /* OEM table identification */ |
31 | 8a92ea2f | aliguori | uint32_t oem_revision; /* OEM revision number */
|
32 | 8a92ea2f | aliguori | char asl_compiler_id [4]; /* ASL compiler vendor ID */ |
33 | 8a92ea2f | aliguori | uint32_t asl_compiler_revision; /* ASL compiler revision number */
|
34 | 8a92ea2f | aliguori | } __attribute__((packed)); |
35 | 8a92ea2f | aliguori | |
36 | 8a92ea2f | aliguori | char *acpi_tables;
|
37 | 8a92ea2f | aliguori | size_t acpi_tables_len; |
38 | 8a92ea2f | aliguori | |
39 | 8a92ea2f | aliguori | static int acpi_checksum(const uint8_t *data, int len) |
40 | 8a92ea2f | aliguori | { |
41 | 8a92ea2f | aliguori | int sum, i;
|
42 | 8a92ea2f | aliguori | sum = 0;
|
43 | 8a92ea2f | aliguori | for(i = 0; i < len; i++) |
44 | 8a92ea2f | aliguori | sum += data[i]; |
45 | 8a92ea2f | aliguori | return (-sum) & 0xff; |
46 | 8a92ea2f | aliguori | } |
47 | 8a92ea2f | aliguori | |
48 | 8a92ea2f | aliguori | int acpi_table_add(const char *t) |
49 | 8a92ea2f | aliguori | { |
50 | 8a92ea2f | aliguori | static const char *dfl_id = "QEMUQEMU"; |
51 | 8a92ea2f | aliguori | char buf[1024], *p, *f; |
52 | 8a92ea2f | aliguori | struct acpi_table_header acpi_hdr;
|
53 | 8a92ea2f | aliguori | unsigned long val; |
54 | d729bb9a | Isaku Yamahata | uint32_t length; |
55 | d729bb9a | Isaku Yamahata | struct acpi_table_header *acpi_hdr_p;
|
56 | 8a92ea2f | aliguori | size_t off; |
57 | 8a92ea2f | aliguori | |
58 | 8a92ea2f | aliguori | memset(&acpi_hdr, 0, sizeof(acpi_hdr)); |
59 | 8a92ea2f | aliguori | |
60 | 8a92ea2f | aliguori | if (get_param_value(buf, sizeof(buf), "sig", t)) { |
61 | 8a92ea2f | aliguori | strncpy(acpi_hdr.signature, buf, 4);
|
62 | 8a92ea2f | aliguori | } else {
|
63 | 8a92ea2f | aliguori | strncpy(acpi_hdr.signature, dfl_id, 4);
|
64 | 8a92ea2f | aliguori | } |
65 | 8a92ea2f | aliguori | if (get_param_value(buf, sizeof(buf), "rev", t)) { |
66 | 8a92ea2f | aliguori | val = strtoul(buf, &p, 10);
|
67 | 8a92ea2f | aliguori | if (val > 255 || *p != '\0') |
68 | 8a92ea2f | aliguori | goto out;
|
69 | 8a92ea2f | aliguori | } else {
|
70 | 8a92ea2f | aliguori | val = 1;
|
71 | 8a92ea2f | aliguori | } |
72 | 8a92ea2f | aliguori | acpi_hdr.revision = (int8_t)val; |
73 | 8a92ea2f | aliguori | |
74 | 8a92ea2f | aliguori | if (get_param_value(buf, sizeof(buf), "oem_id", t)) { |
75 | 8a92ea2f | aliguori | strncpy(acpi_hdr.oem_id, buf, 6);
|
76 | 8a92ea2f | aliguori | } else {
|
77 | 8a92ea2f | aliguori | strncpy(acpi_hdr.oem_id, dfl_id, 6);
|
78 | 8a92ea2f | aliguori | } |
79 | 8a92ea2f | aliguori | |
80 | 8a92ea2f | aliguori | if (get_param_value(buf, sizeof(buf), "oem_table_id", t)) { |
81 | 8a92ea2f | aliguori | strncpy(acpi_hdr.oem_table_id, buf, 8);
|
82 | 8a92ea2f | aliguori | } else {
|
83 | 8a92ea2f | aliguori | strncpy(acpi_hdr.oem_table_id, dfl_id, 8);
|
84 | 8a92ea2f | aliguori | } |
85 | 8a92ea2f | aliguori | |
86 | 8a92ea2f | aliguori | if (get_param_value(buf, sizeof(buf), "oem_rev", t)) { |
87 | 8a92ea2f | aliguori | val = strtol(buf, &p, 10);
|
88 | 8a92ea2f | aliguori | if(*p != '\0') |
89 | 8a92ea2f | aliguori | goto out;
|
90 | 8a92ea2f | aliguori | } else {
|
91 | 8a92ea2f | aliguori | val = 1;
|
92 | 8a92ea2f | aliguori | } |
93 | 8a92ea2f | aliguori | acpi_hdr.oem_revision = cpu_to_le32(val); |
94 | 8a92ea2f | aliguori | |
95 | 8a92ea2f | aliguori | if (get_param_value(buf, sizeof(buf), "asl_compiler_id", t)) { |
96 | 8a92ea2f | aliguori | strncpy(acpi_hdr.asl_compiler_id, buf, 4);
|
97 | 8a92ea2f | aliguori | } else {
|
98 | 8a92ea2f | aliguori | strncpy(acpi_hdr.asl_compiler_id, dfl_id, 4);
|
99 | 8a92ea2f | aliguori | } |
100 | 8a92ea2f | aliguori | |
101 | 8a92ea2f | aliguori | if (get_param_value(buf, sizeof(buf), "asl_compiler_rev", t)) { |
102 | 8a92ea2f | aliguori | val = strtol(buf, &p, 10);
|
103 | 8a92ea2f | aliguori | if(*p != '\0') |
104 | 8a92ea2f | aliguori | goto out;
|
105 | 8a92ea2f | aliguori | } else {
|
106 | 8a92ea2f | aliguori | val = 1;
|
107 | 8a92ea2f | aliguori | } |
108 | 8a92ea2f | aliguori | acpi_hdr.asl_compiler_revision = cpu_to_le32(val); |
109 | 8a92ea2f | aliguori | |
110 | 8a92ea2f | aliguori | if (!get_param_value(buf, sizeof(buf), "data", t)) { |
111 | 8a92ea2f | aliguori | buf[0] = '\0'; |
112 | 8a92ea2f | aliguori | } |
113 | 8a92ea2f | aliguori | |
114 | d729bb9a | Isaku Yamahata | length = sizeof(acpi_hdr);
|
115 | 8a92ea2f | aliguori | |
116 | 8a92ea2f | aliguori | f = buf; |
117 | 8a92ea2f | aliguori | while (buf[0]) { |
118 | 8a92ea2f | aliguori | struct stat s;
|
119 | 54042bcf | aliguori | char *n = strchr(f, ':'); |
120 | 8a92ea2f | aliguori | if (n)
|
121 | 8a92ea2f | aliguori | *n = '\0';
|
122 | 8a92ea2f | aliguori | if(stat(f, &s) < 0) { |
123 | 8a92ea2f | aliguori | fprintf(stderr, "Can't stat file '%s': %s\n", f, strerror(errno));
|
124 | 8a92ea2f | aliguori | goto out;
|
125 | 8a92ea2f | aliguori | } |
126 | d729bb9a | Isaku Yamahata | length += s.st_size; |
127 | 8a92ea2f | aliguori | if (!n)
|
128 | 8a92ea2f | aliguori | break;
|
129 | 8a92ea2f | aliguori | *n = ':';
|
130 | 8a92ea2f | aliguori | f = n + 1;
|
131 | 8a92ea2f | aliguori | } |
132 | 8a92ea2f | aliguori | |
133 | 8a92ea2f | aliguori | if (!acpi_tables) {
|
134 | 8a92ea2f | aliguori | acpi_tables_len = sizeof(uint16_t);
|
135 | 8a92ea2f | aliguori | acpi_tables = qemu_mallocz(acpi_tables_len); |
136 | 8a92ea2f | aliguori | } |
137 | d729bb9a | Isaku Yamahata | acpi_tables = qemu_realloc(acpi_tables, |
138 | d729bb9a | Isaku Yamahata | acpi_tables_len + sizeof(uint16_t) + length);
|
139 | 8a92ea2f | aliguori | p = acpi_tables + acpi_tables_len; |
140 | d729bb9a | Isaku Yamahata | acpi_tables_len += sizeof(uint16_t) + length;
|
141 | 8a92ea2f | aliguori | |
142 | d729bb9a | Isaku Yamahata | *(uint16_t*)p = cpu_to_le32(length); |
143 | 8a92ea2f | aliguori | p += sizeof(uint16_t);
|
144 | 8a92ea2f | aliguori | memcpy(p, &acpi_hdr, sizeof(acpi_hdr));
|
145 | 8a92ea2f | aliguori | off = sizeof(acpi_hdr);
|
146 | 8a92ea2f | aliguori | |
147 | 8a92ea2f | aliguori | f = buf; |
148 | 8a92ea2f | aliguori | while (buf[0]) { |
149 | 8a92ea2f | aliguori | struct stat s;
|
150 | 8a92ea2f | aliguori | int fd;
|
151 | 54042bcf | aliguori | char *n = strchr(f, ':'); |
152 | 8a92ea2f | aliguori | if (n)
|
153 | 8a92ea2f | aliguori | *n = '\0';
|
154 | 8a92ea2f | aliguori | fd = open(f, O_RDONLY); |
155 | 8a92ea2f | aliguori | |
156 | 8a92ea2f | aliguori | if(fd < 0) |
157 | 8a92ea2f | aliguori | goto out;
|
158 | 8a92ea2f | aliguori | if(fstat(fd, &s) < 0) { |
159 | 8a92ea2f | aliguori | close(fd); |
160 | 8a92ea2f | aliguori | goto out;
|
161 | 8a92ea2f | aliguori | } |
162 | 8a92ea2f | aliguori | |
163 | d729bb9a | Isaku Yamahata | /* off < length is necessary because file size can be changed
|
164 | d729bb9a | Isaku Yamahata | under our foot */
|
165 | b755a428 | Vincent Minet | while(s.st_size && off < length) {
|
166 | 8a92ea2f | aliguori | int r;
|
167 | 8a92ea2f | aliguori | r = read(fd, p + off, s.st_size); |
168 | 8a92ea2f | aliguori | if (r > 0) { |
169 | 8a92ea2f | aliguori | off += r; |
170 | 8a92ea2f | aliguori | s.st_size -= r; |
171 | 8a92ea2f | aliguori | } else if ((r < 0 && errno != EINTR) || r == 0) { |
172 | 8a92ea2f | aliguori | close(fd); |
173 | 8a92ea2f | aliguori | goto out;
|
174 | 8a92ea2f | aliguori | } |
175 | d729bb9a | Isaku Yamahata | } |
176 | 8a92ea2f | aliguori | |
177 | 8a92ea2f | aliguori | close(fd); |
178 | 8a92ea2f | aliguori | if (!n)
|
179 | 8a92ea2f | aliguori | break;
|
180 | 8a92ea2f | aliguori | f = n + 1;
|
181 | 8a92ea2f | aliguori | } |
182 | d729bb9a | Isaku Yamahata | if (off < length) {
|
183 | d729bb9a | Isaku Yamahata | /* don't pass random value in process to guest */
|
184 | d729bb9a | Isaku Yamahata | memset(p + off, 0, length - off);
|
185 | d729bb9a | Isaku Yamahata | } |
186 | 8a92ea2f | aliguori | |
187 | d729bb9a | Isaku Yamahata | acpi_hdr_p = (struct acpi_table_header*)p;
|
188 | d729bb9a | Isaku Yamahata | acpi_hdr_p->length = cpu_to_le32(length); |
189 | d729bb9a | Isaku Yamahata | acpi_hdr_p->checksum = acpi_checksum((uint8_t*)p, length); |
190 | 8a92ea2f | aliguori | /* increase number of tables */
|
191 | 8a92ea2f | aliguori | (*(uint16_t*)acpi_tables) = |
192 | 8a92ea2f | aliguori | cpu_to_le32(le32_to_cpu(*(uint16_t*)acpi_tables) + 1);
|
193 | 8a92ea2f | aliguori | return 0; |
194 | 8a92ea2f | aliguori | out:
|
195 | 8a92ea2f | aliguori | if (acpi_tables) {
|
196 | b2538b4b | Jean-Christophe DUBOIS | qemu_free(acpi_tables); |
197 | 8a92ea2f | aliguori | acpi_tables = NULL;
|
198 | 8a92ea2f | aliguori | } |
199 | 8a92ea2f | aliguori | return -1; |
200 | 8a92ea2f | aliguori | } |
201 | a54d41a8 | Isaku Yamahata | |
202 | 04dc308f | Isaku Yamahata | /* ACPI PM1a EVT */
|
203 | 04dc308f | Isaku Yamahata | uint16_t acpi_pm1_evt_get_sts(ACPIPM1EVT *pm1, int64_t overflow_time) |
204 | 04dc308f | Isaku Yamahata | { |
205 | 04dc308f | Isaku Yamahata | int64_t d = acpi_pm_tmr_get_clock(); |
206 | 04dc308f | Isaku Yamahata | if (d >= overflow_time) {
|
207 | 04dc308f | Isaku Yamahata | pm1->sts |= ACPI_BITMASK_TIMER_STATUS; |
208 | 04dc308f | Isaku Yamahata | } |
209 | 04dc308f | Isaku Yamahata | return pm1->sts;
|
210 | 04dc308f | Isaku Yamahata | } |
211 | 04dc308f | Isaku Yamahata | |
212 | 04dc308f | Isaku Yamahata | void acpi_pm1_evt_write_sts(ACPIPM1EVT *pm1, ACPIPMTimer *tmr, uint16_t val)
|
213 | 04dc308f | Isaku Yamahata | { |
214 | 04dc308f | Isaku Yamahata | uint16_t pm1_sts = acpi_pm1_evt_get_sts(pm1, tmr->overflow_time); |
215 | 04dc308f | Isaku Yamahata | if (pm1_sts & val & ACPI_BITMASK_TIMER_STATUS) {
|
216 | 04dc308f | Isaku Yamahata | /* if TMRSTS is reset, then compute the new overflow time */
|
217 | 04dc308f | Isaku Yamahata | acpi_pm_tmr_calc_overflow_time(tmr); |
218 | 04dc308f | Isaku Yamahata | } |
219 | 04dc308f | Isaku Yamahata | pm1->sts &= ~val; |
220 | 04dc308f | Isaku Yamahata | } |
221 | 04dc308f | Isaku Yamahata | |
222 | 04dc308f | Isaku Yamahata | void acpi_pm1_evt_power_down(ACPIPM1EVT *pm1, ACPIPMTimer *tmr)
|
223 | 04dc308f | Isaku Yamahata | { |
224 | 04dc308f | Isaku Yamahata | if (!pm1) {
|
225 | 04dc308f | Isaku Yamahata | qemu_system_shutdown_request(); |
226 | 04dc308f | Isaku Yamahata | } else if (pm1->en & ACPI_BITMASK_POWER_BUTTON_ENABLE) { |
227 | 04dc308f | Isaku Yamahata | pm1->sts |= ACPI_BITMASK_POWER_BUTTON_STATUS; |
228 | 04dc308f | Isaku Yamahata | tmr->update_sci(tmr); |
229 | 04dc308f | Isaku Yamahata | } |
230 | 04dc308f | Isaku Yamahata | } |
231 | 04dc308f | Isaku Yamahata | |
232 | 04dc308f | Isaku Yamahata | void acpi_pm1_evt_reset(ACPIPM1EVT *pm1)
|
233 | 04dc308f | Isaku Yamahata | { |
234 | 04dc308f | Isaku Yamahata | pm1->sts = 0;
|
235 | 04dc308f | Isaku Yamahata | pm1->en = 0;
|
236 | 04dc308f | Isaku Yamahata | } |
237 | 04dc308f | Isaku Yamahata | |
238 | a54d41a8 | Isaku Yamahata | /* ACPI PM_TMR */
|
239 | a54d41a8 | Isaku Yamahata | void acpi_pm_tmr_update(ACPIPMTimer *tmr, bool enable) |
240 | a54d41a8 | Isaku Yamahata | { |
241 | a54d41a8 | Isaku Yamahata | int64_t expire_time; |
242 | a54d41a8 | Isaku Yamahata | |
243 | a54d41a8 | Isaku Yamahata | /* schedule a timer interruption if needed */
|
244 | a54d41a8 | Isaku Yamahata | if (enable) {
|
245 | a54d41a8 | Isaku Yamahata | expire_time = muldiv64(tmr->overflow_time, get_ticks_per_sec(), |
246 | a54d41a8 | Isaku Yamahata | PM_TIMER_FREQUENCY); |
247 | a54d41a8 | Isaku Yamahata | qemu_mod_timer(tmr->timer, expire_time); |
248 | a54d41a8 | Isaku Yamahata | } else {
|
249 | a54d41a8 | Isaku Yamahata | qemu_del_timer(tmr->timer); |
250 | a54d41a8 | Isaku Yamahata | } |
251 | a54d41a8 | Isaku Yamahata | } |
252 | a54d41a8 | Isaku Yamahata | |
253 | a54d41a8 | Isaku Yamahata | void acpi_pm_tmr_calc_overflow_time(ACPIPMTimer *tmr)
|
254 | a54d41a8 | Isaku Yamahata | { |
255 | a54d41a8 | Isaku Yamahata | int64_t d = acpi_pm_tmr_get_clock(); |
256 | a54d41a8 | Isaku Yamahata | tmr->overflow_time = (d + 0x800000LL) & ~0x7fffffLL; |
257 | a54d41a8 | Isaku Yamahata | } |
258 | a54d41a8 | Isaku Yamahata | |
259 | a54d41a8 | Isaku Yamahata | uint32_t acpi_pm_tmr_get(ACPIPMTimer *tmr) |
260 | a54d41a8 | Isaku Yamahata | { |
261 | a54d41a8 | Isaku Yamahata | uint32_t d = acpi_pm_tmr_get_clock();; |
262 | a54d41a8 | Isaku Yamahata | return d & 0xffffff; |
263 | a54d41a8 | Isaku Yamahata | } |
264 | a54d41a8 | Isaku Yamahata | |
265 | a54d41a8 | Isaku Yamahata | static void acpi_pm_tmr_timer(void *opaque) |
266 | a54d41a8 | Isaku Yamahata | { |
267 | a54d41a8 | Isaku Yamahata | ACPIPMTimer *tmr = opaque; |
268 | a54d41a8 | Isaku Yamahata | tmr->update_sci(tmr); |
269 | a54d41a8 | Isaku Yamahata | } |
270 | a54d41a8 | Isaku Yamahata | |
271 | a54d41a8 | Isaku Yamahata | void acpi_pm_tmr_init(ACPIPMTimer *tmr, acpi_update_sci_fn update_sci)
|
272 | a54d41a8 | Isaku Yamahata | { |
273 | a54d41a8 | Isaku Yamahata | tmr->update_sci = update_sci; |
274 | a54d41a8 | Isaku Yamahata | tmr->timer = qemu_new_timer_ns(vm_clock, acpi_pm_tmr_timer, tmr); |
275 | a54d41a8 | Isaku Yamahata | } |
276 | a54d41a8 | Isaku Yamahata | |
277 | a54d41a8 | Isaku Yamahata | void acpi_pm_tmr_reset(ACPIPMTimer *tmr)
|
278 | a54d41a8 | Isaku Yamahata | { |
279 | a54d41a8 | Isaku Yamahata | tmr->overflow_time = 0;
|
280 | a54d41a8 | Isaku Yamahata | qemu_del_timer(tmr->timer); |
281 | a54d41a8 | Isaku Yamahata | } |
282 | eaba51c5 | Isaku Yamahata | |
283 | eaba51c5 | Isaku Yamahata | /* ACPI PM1aCNT */
|
284 | eaba51c5 | Isaku Yamahata | void acpi_pm1_cnt_init(ACPIPM1CNT *pm1_cnt, qemu_irq cmos_s3)
|
285 | eaba51c5 | Isaku Yamahata | { |
286 | eaba51c5 | Isaku Yamahata | pm1_cnt->cmos_s3 = cmos_s3; |
287 | eaba51c5 | Isaku Yamahata | } |
288 | eaba51c5 | Isaku Yamahata | |
289 | eaba51c5 | Isaku Yamahata | void acpi_pm1_cnt_write(ACPIPM1EVT *pm1a, ACPIPM1CNT *pm1_cnt, uint16_t val)
|
290 | eaba51c5 | Isaku Yamahata | { |
291 | eaba51c5 | Isaku Yamahata | pm1_cnt->cnt = val & ~(ACPI_BITMASK_SLEEP_ENABLE); |
292 | eaba51c5 | Isaku Yamahata | |
293 | eaba51c5 | Isaku Yamahata | if (val & ACPI_BITMASK_SLEEP_ENABLE) {
|
294 | eaba51c5 | Isaku Yamahata | /* change suspend type */
|
295 | eaba51c5 | Isaku Yamahata | uint16_t sus_typ = (val >> 10) & 7; |
296 | eaba51c5 | Isaku Yamahata | switch(sus_typ) {
|
297 | eaba51c5 | Isaku Yamahata | case 0: /* soft power off */ |
298 | eaba51c5 | Isaku Yamahata | qemu_system_shutdown_request(); |
299 | eaba51c5 | Isaku Yamahata | break;
|
300 | eaba51c5 | Isaku Yamahata | case 1: |
301 | eaba51c5 | Isaku Yamahata | /* ACPI_BITMASK_WAKE_STATUS should be set on resume.
|
302 | eaba51c5 | Isaku Yamahata | Pretend that resume was caused by power button */
|
303 | eaba51c5 | Isaku Yamahata | pm1a->sts |= |
304 | eaba51c5 | Isaku Yamahata | (ACPI_BITMASK_WAKE_STATUS | ACPI_BITMASK_POWER_BUTTON_STATUS); |
305 | eaba51c5 | Isaku Yamahata | qemu_system_reset_request(); |
306 | eaba51c5 | Isaku Yamahata | qemu_irq_raise(pm1_cnt->cmos_s3); |
307 | eaba51c5 | Isaku Yamahata | default:
|
308 | eaba51c5 | Isaku Yamahata | break;
|
309 | eaba51c5 | Isaku Yamahata | } |
310 | eaba51c5 | Isaku Yamahata | } |
311 | eaba51c5 | Isaku Yamahata | } |
312 | eaba51c5 | Isaku Yamahata | |
313 | eaba51c5 | Isaku Yamahata | void acpi_pm1_cnt_update(ACPIPM1CNT *pm1_cnt,
|
314 | eaba51c5 | Isaku Yamahata | bool sci_enable, bool sci_disable) |
315 | eaba51c5 | Isaku Yamahata | { |
316 | eaba51c5 | Isaku Yamahata | /* ACPI specs 3.0, 4.7.2.5 */
|
317 | eaba51c5 | Isaku Yamahata | if (sci_enable) {
|
318 | eaba51c5 | Isaku Yamahata | pm1_cnt->cnt |= ACPI_BITMASK_SCI_ENABLE; |
319 | eaba51c5 | Isaku Yamahata | } else if (sci_disable) { |
320 | eaba51c5 | Isaku Yamahata | pm1_cnt->cnt &= ~ACPI_BITMASK_SCI_ENABLE; |
321 | eaba51c5 | Isaku Yamahata | } |
322 | eaba51c5 | Isaku Yamahata | } |
323 | eaba51c5 | Isaku Yamahata | |
324 | eaba51c5 | Isaku Yamahata | void acpi_pm1_cnt_reset(ACPIPM1CNT *pm1_cnt)
|
325 | eaba51c5 | Isaku Yamahata | { |
326 | eaba51c5 | Isaku Yamahata | pm1_cnt->cnt = 0;
|
327 | eaba51c5 | Isaku Yamahata | if (pm1_cnt->cmos_s3) {
|
328 | eaba51c5 | Isaku Yamahata | qemu_irq_lower(pm1_cnt->cmos_s3); |
329 | eaba51c5 | Isaku Yamahata | } |
330 | eaba51c5 | Isaku Yamahata | } |
331 | 23910d3f | Isaku Yamahata | |
332 | 23910d3f | Isaku Yamahata | /* ACPI GPE */
|
333 | 23910d3f | Isaku Yamahata | void acpi_gpe_init(ACPIGPE *gpe, uint8_t len)
|
334 | 23910d3f | Isaku Yamahata | { |
335 | 23910d3f | Isaku Yamahata | gpe->len = len; |
336 | 23910d3f | Isaku Yamahata | gpe->sts = qemu_mallocz(len / 2);
|
337 | 23910d3f | Isaku Yamahata | gpe->en = qemu_mallocz(len / 2);
|
338 | 23910d3f | Isaku Yamahata | } |
339 | 23910d3f | Isaku Yamahata | |
340 | 23910d3f | Isaku Yamahata | void acpi_gpe_blk(ACPIGPE *gpe, uint32_t blk)
|
341 | 23910d3f | Isaku Yamahata | { |
342 | 23910d3f | Isaku Yamahata | gpe->blk = blk; |
343 | 23910d3f | Isaku Yamahata | } |
344 | 23910d3f | Isaku Yamahata | |
345 | 23910d3f | Isaku Yamahata | void acpi_gpe_reset(ACPIGPE *gpe)
|
346 | 23910d3f | Isaku Yamahata | { |
347 | 23910d3f | Isaku Yamahata | memset(gpe->sts, 0, gpe->len / 2); |
348 | 23910d3f | Isaku Yamahata | memset(gpe->en, 0, gpe->len / 2); |
349 | 23910d3f | Isaku Yamahata | } |
350 | 23910d3f | Isaku Yamahata | |
351 | 23910d3f | Isaku Yamahata | static uint8_t *acpi_gpe_ioport_get_ptr(ACPIGPE *gpe, uint32_t addr)
|
352 | 23910d3f | Isaku Yamahata | { |
353 | 23910d3f | Isaku Yamahata | uint8_t *cur = NULL;
|
354 | 23910d3f | Isaku Yamahata | |
355 | 23910d3f | Isaku Yamahata | if (addr < gpe->len / 2) { |
356 | 23910d3f | Isaku Yamahata | cur = gpe->sts + addr; |
357 | 23910d3f | Isaku Yamahata | } else if (addr < gpe->len) { |
358 | 54f8e61d | Wen Congyang | cur = gpe->en + addr - gpe->len / 2;
|
359 | 23910d3f | Isaku Yamahata | } else {
|
360 | 23910d3f | Isaku Yamahata | abort(); |
361 | 23910d3f | Isaku Yamahata | } |
362 | 23910d3f | Isaku Yamahata | |
363 | 23910d3f | Isaku Yamahata | return cur;
|
364 | 23910d3f | Isaku Yamahata | } |
365 | 23910d3f | Isaku Yamahata | |
366 | 23910d3f | Isaku Yamahata | void acpi_gpe_ioport_writeb(ACPIGPE *gpe, uint32_t addr, uint32_t val)
|
367 | 23910d3f | Isaku Yamahata | { |
368 | 23910d3f | Isaku Yamahata | uint8_t *cur; |
369 | 23910d3f | Isaku Yamahata | |
370 | 23910d3f | Isaku Yamahata | addr -= gpe->blk; |
371 | 23910d3f | Isaku Yamahata | cur = acpi_gpe_ioport_get_ptr(gpe, addr); |
372 | 23910d3f | Isaku Yamahata | if (addr < gpe->len / 2) { |
373 | 23910d3f | Isaku Yamahata | /* GPE_STS */
|
374 | 23910d3f | Isaku Yamahata | *cur = (*cur) & ~val; |
375 | 23910d3f | Isaku Yamahata | } else if (addr < gpe->len) { |
376 | 23910d3f | Isaku Yamahata | /* GPE_EN */
|
377 | 23910d3f | Isaku Yamahata | *cur = val; |
378 | 23910d3f | Isaku Yamahata | } else {
|
379 | 23910d3f | Isaku Yamahata | abort(); |
380 | 23910d3f | Isaku Yamahata | } |
381 | 23910d3f | Isaku Yamahata | } |
382 | 23910d3f | Isaku Yamahata | |
383 | 23910d3f | Isaku Yamahata | uint32_t acpi_gpe_ioport_readb(ACPIGPE *gpe, uint32_t addr) |
384 | 23910d3f | Isaku Yamahata | { |
385 | 23910d3f | Isaku Yamahata | uint8_t *cur; |
386 | 23910d3f | Isaku Yamahata | uint32_t val; |
387 | 23910d3f | Isaku Yamahata | |
388 | 23910d3f | Isaku Yamahata | addr -= gpe->blk; |
389 | 23910d3f | Isaku Yamahata | cur = acpi_gpe_ioport_get_ptr(gpe, addr); |
390 | 23910d3f | Isaku Yamahata | val = 0;
|
391 | 23910d3f | Isaku Yamahata | if (cur != NULL) { |
392 | 23910d3f | Isaku Yamahata | val = *cur; |
393 | 23910d3f | Isaku Yamahata | } |
394 | 23910d3f | Isaku Yamahata | |
395 | 23910d3f | Isaku Yamahata | return val;
|
396 | 23910d3f | Isaku Yamahata | } |