root / hw / misc / applesmc.c @ e3914e3a
History | View | Annotate | Download (7.9 kB)
1 | 1ddda5cd | Alexander Graf | /*
|
---|---|---|---|
2 | 1ddda5cd | Alexander Graf | * Apple SMC controller
|
3 | 1ddda5cd | Alexander Graf | *
|
4 | 1ddda5cd | Alexander Graf | * Copyright (c) 2007 Alexander Graf
|
5 | 1ddda5cd | Alexander Graf | *
|
6 | 1ddda5cd | Alexander Graf | * Authors: Alexander Graf <agraf@suse.de>
|
7 | 1ddda5cd | Alexander Graf | * Susanne Graf <suse@csgraf.de>
|
8 | 1ddda5cd | Alexander Graf | *
|
9 | 1ddda5cd | Alexander Graf | * This library is free software; you can redistribute it and/or
|
10 | 1ddda5cd | Alexander Graf | * modify it under the terms of the GNU Lesser General Public
|
11 | 1ddda5cd | Alexander Graf | * License as published by the Free Software Foundation; either
|
12 | 1ddda5cd | Alexander Graf | * version 2 of the License, or (at your option) any later version.
|
13 | 1ddda5cd | Alexander Graf | *
|
14 | 1ddda5cd | Alexander Graf | * This library is distributed in the hope that it will be useful,
|
15 | 1ddda5cd | Alexander Graf | * but WITHOUT ANY WARRANTY; without even the implied warranty of
|
16 | 1ddda5cd | Alexander Graf | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
17 | 1ddda5cd | Alexander Graf | * Lesser General Public License for more details.
|
18 | 1ddda5cd | Alexander Graf | *
|
19 | 1ddda5cd | Alexander Graf | * You should have received a copy of the GNU Lesser General Public
|
20 | 1ddda5cd | Alexander Graf | * License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
21 | 1ddda5cd | Alexander Graf | *
|
22 | 1ddda5cd | Alexander Graf | * *****************************************************************
|
23 | 1ddda5cd | Alexander Graf | *
|
24 | 1ddda5cd | Alexander Graf | * In all Intel-based Apple hardware there is an SMC chip to control the
|
25 | 1ddda5cd | Alexander Graf | * backlight, fans and several other generic device parameters. It also
|
26 | 1ddda5cd | Alexander Graf | * contains the magic keys used to dongle Mac OS X to the device.
|
27 | 1ddda5cd | Alexander Graf | *
|
28 | 1ddda5cd | Alexander Graf | * This driver was mostly created by looking at the Linux AppleSMC driver
|
29 | 1ddda5cd | Alexander Graf | * implementation and does not support IRQ.
|
30 | 1ddda5cd | Alexander Graf | *
|
31 | 1ddda5cd | Alexander Graf | */
|
32 | 1ddda5cd | Alexander Graf | |
33 | 83c9f4ca | Paolo Bonzini | #include "hw/hw.h" |
34 | 0d09e41a | Paolo Bonzini | #include "hw/isa/isa.h" |
35 | 28ecbaee | Paolo Bonzini | #include "ui/console.h" |
36 | 1de7afc9 | Paolo Bonzini | #include "qemu/timer.h" |
37 | 1ddda5cd | Alexander Graf | |
38 | 1ddda5cd | Alexander Graf | /* #define DEBUG_SMC */
|
39 | 1ddda5cd | Alexander Graf | |
40 | 1ddda5cd | Alexander Graf | #define APPLESMC_DEFAULT_IOBASE 0x300 |
41 | 1ddda5cd | Alexander Graf | /* data port used by Apple SMC */
|
42 | 1ddda5cd | Alexander Graf | #define APPLESMC_DATA_PORT 0x0 |
43 | 1ddda5cd | Alexander Graf | /* command/status port used by Apple SMC */
|
44 | 1ddda5cd | Alexander Graf | #define APPLESMC_CMD_PORT 0x4 |
45 | 1ddda5cd | Alexander Graf | #define APPLESMC_NR_PORTS 32 |
46 | 1ddda5cd | Alexander Graf | #define APPLESMC_MAX_DATA_LENGTH 32 |
47 | 1ddda5cd | Alexander Graf | |
48 | 1ddda5cd | Alexander Graf | #define APPLESMC_READ_CMD 0x10 |
49 | 1ddda5cd | Alexander Graf | #define APPLESMC_WRITE_CMD 0x11 |
50 | 1ddda5cd | Alexander Graf | #define APPLESMC_GET_KEY_BY_INDEX_CMD 0x12 |
51 | 1ddda5cd | Alexander Graf | #define APPLESMC_GET_KEY_TYPE_CMD 0x13 |
52 | 1ddda5cd | Alexander Graf | |
53 | 1ddda5cd | Alexander Graf | #ifdef DEBUG_SMC
|
54 | 1ddda5cd | Alexander Graf | #define smc_debug(...) fprintf(stderr, "AppleSMC: " __VA_ARGS__) |
55 | 1ddda5cd | Alexander Graf | #else
|
56 | 1ddda5cd | Alexander Graf | #define smc_debug(...) do { } while(0) |
57 | 1ddda5cd | Alexander Graf | #endif
|
58 | 1ddda5cd | Alexander Graf | |
59 | 1ddda5cd | Alexander Graf | static char default_osk[64] = "This is a dummy key. Enter the real key " |
60 | 1ddda5cd | Alexander Graf | "using the -osk parameter";
|
61 | 1ddda5cd | Alexander Graf | |
62 | 1ddda5cd | Alexander Graf | struct AppleSMCData {
|
63 | 1ddda5cd | Alexander Graf | uint8_t len; |
64 | 1ddda5cd | Alexander Graf | const char *key; |
65 | 1ddda5cd | Alexander Graf | const char *data; |
66 | 1ddda5cd | Alexander Graf | QLIST_ENTRY(AppleSMCData) node; |
67 | 1ddda5cd | Alexander Graf | }; |
68 | 1ddda5cd | Alexander Graf | |
69 | 82407b6c | Andreas Färber | #define TYPE_APPLE_SMC "isa-applesmc" |
70 | 82407b6c | Andreas Färber | #define APPLE_SMC(obj) OBJECT_CHECK(AppleSMCState, (obj), TYPE_APPLE_SMC)
|
71 | 82407b6c | Andreas Färber | |
72 | 82407b6c | Andreas Färber | typedef struct AppleSMCState AppleSMCState; |
73 | 82407b6c | Andreas Färber | struct AppleSMCState {
|
74 | 82407b6c | Andreas Färber | ISADevice parent_obj; |
75 | 82407b6c | Andreas Färber | |
76 | e3914e3a | Jan Kiszka | MemoryRegion io_data; |
77 | e3914e3a | Jan Kiszka | MemoryRegion io_cmd; |
78 | 1ddda5cd | Alexander Graf | uint32_t iobase; |
79 | 1ddda5cd | Alexander Graf | uint8_t cmd; |
80 | 1ddda5cd | Alexander Graf | uint8_t status; |
81 | 1ddda5cd | Alexander Graf | uint8_t key[4];
|
82 | 1ddda5cd | Alexander Graf | uint8_t read_pos; |
83 | 1ddda5cd | Alexander Graf | uint8_t data_len; |
84 | 1ddda5cd | Alexander Graf | uint8_t data_pos; |
85 | 1ddda5cd | Alexander Graf | uint8_t data[255];
|
86 | 1ddda5cd | Alexander Graf | uint8_t charactic[4];
|
87 | 1ddda5cd | Alexander Graf | char *osk;
|
88 | 1ddda5cd | Alexander Graf | QLIST_HEAD(, AppleSMCData) data_def; |
89 | 1ddda5cd | Alexander Graf | }; |
90 | 1ddda5cd | Alexander Graf | |
91 | e3914e3a | Jan Kiszka | static void applesmc_io_cmd_write(void *opaque, hwaddr addr, uint64_t val, |
92 | e3914e3a | Jan Kiszka | unsigned size)
|
93 | 1ddda5cd | Alexander Graf | { |
94 | 82407b6c | Andreas Färber | AppleSMCState *s = opaque; |
95 | 1ddda5cd | Alexander Graf | |
96 | 1ddda5cd | Alexander Graf | smc_debug("CMD Write B: %#x = %#x\n", addr, val);
|
97 | 1ddda5cd | Alexander Graf | switch(val) {
|
98 | 1ddda5cd | Alexander Graf | case APPLESMC_READ_CMD:
|
99 | 1ddda5cd | Alexander Graf | s->status = 0x0c;
|
100 | 1ddda5cd | Alexander Graf | break;
|
101 | 1ddda5cd | Alexander Graf | } |
102 | 1ddda5cd | Alexander Graf | s->cmd = val; |
103 | 1ddda5cd | Alexander Graf | s->read_pos = 0;
|
104 | 1ddda5cd | Alexander Graf | s->data_pos = 0;
|
105 | 1ddda5cd | Alexander Graf | } |
106 | 1ddda5cd | Alexander Graf | |
107 | 82407b6c | Andreas Färber | static void applesmc_fill_data(AppleSMCState *s) |
108 | 1ddda5cd | Alexander Graf | { |
109 | 1ddda5cd | Alexander Graf | struct AppleSMCData *d;
|
110 | 1ddda5cd | Alexander Graf | |
111 | 1ddda5cd | Alexander Graf | QLIST_FOREACH(d, &s->data_def, node) { |
112 | 1ddda5cd | Alexander Graf | if (!memcmp(d->key, s->key, 4)) { |
113 | 1ddda5cd | Alexander Graf | smc_debug("Key matched (%s Len=%d Data=%s)\n", d->key,
|
114 | 1ddda5cd | Alexander Graf | d->len, d->data); |
115 | 1ddda5cd | Alexander Graf | memcpy(s->data, d->data, d->len); |
116 | 1ddda5cd | Alexander Graf | return;
|
117 | 1ddda5cd | Alexander Graf | } |
118 | 1ddda5cd | Alexander Graf | } |
119 | 1ddda5cd | Alexander Graf | } |
120 | 1ddda5cd | Alexander Graf | |
121 | e3914e3a | Jan Kiszka | static void applesmc_io_data_write(void *opaque, hwaddr addr, uint64_t val, |
122 | e3914e3a | Jan Kiszka | unsigned size)
|
123 | 1ddda5cd | Alexander Graf | { |
124 | 82407b6c | Andreas Färber | AppleSMCState *s = opaque; |
125 | 1ddda5cd | Alexander Graf | |
126 | 1ddda5cd | Alexander Graf | smc_debug("DATA Write B: %#x = %#x\n", addr, val);
|
127 | 1ddda5cd | Alexander Graf | switch(s->cmd) {
|
128 | 1ddda5cd | Alexander Graf | case APPLESMC_READ_CMD:
|
129 | 1ddda5cd | Alexander Graf | if(s->read_pos < 4) { |
130 | 1ddda5cd | Alexander Graf | s->key[s->read_pos] = val; |
131 | 1ddda5cd | Alexander Graf | s->status = 0x04;
|
132 | 1ddda5cd | Alexander Graf | } else if(s->read_pos == 4) { |
133 | 1ddda5cd | Alexander Graf | s->data_len = val; |
134 | 1ddda5cd | Alexander Graf | s->status = 0x05;
|
135 | 1ddda5cd | Alexander Graf | s->data_pos = 0;
|
136 | 1ddda5cd | Alexander Graf | smc_debug("Key = %c%c%c%c Len = %d\n", s->key[0], |
137 | 1ddda5cd | Alexander Graf | s->key[1], s->key[2], s->key[3], val); |
138 | 1ddda5cd | Alexander Graf | applesmc_fill_data(s); |
139 | 1ddda5cd | Alexander Graf | } |
140 | 1ddda5cd | Alexander Graf | s->read_pos++; |
141 | 1ddda5cd | Alexander Graf | break;
|
142 | 1ddda5cd | Alexander Graf | } |
143 | 1ddda5cd | Alexander Graf | } |
144 | 1ddda5cd | Alexander Graf | |
145 | e3914e3a | Jan Kiszka | static uint64_t applesmc_io_data_read(void *opaque, hwaddr addr1, |
146 | e3914e3a | Jan Kiszka | unsigned size)
|
147 | 1ddda5cd | Alexander Graf | { |
148 | 82407b6c | Andreas Färber | AppleSMCState *s = opaque; |
149 | 1ddda5cd | Alexander Graf | uint8_t retval = 0;
|
150 | 1ddda5cd | Alexander Graf | |
151 | 1ddda5cd | Alexander Graf | switch(s->cmd) {
|
152 | 1ddda5cd | Alexander Graf | case APPLESMC_READ_CMD:
|
153 | 1ddda5cd | Alexander Graf | if(s->data_pos < s->data_len) {
|
154 | 1ddda5cd | Alexander Graf | retval = s->data[s->data_pos]; |
155 | 1ddda5cd | Alexander Graf | smc_debug("READ_DATA[%d] = %#hhx\n", s->data_pos,
|
156 | 1ddda5cd | Alexander Graf | retval); |
157 | 1ddda5cd | Alexander Graf | s->data_pos++; |
158 | 1ddda5cd | Alexander Graf | if(s->data_pos == s->data_len) {
|
159 | 1ddda5cd | Alexander Graf | s->status = 0x00;
|
160 | 1ddda5cd | Alexander Graf | smc_debug("EOF\n");
|
161 | 1ddda5cd | Alexander Graf | } else
|
162 | 1ddda5cd | Alexander Graf | s->status = 0x05;
|
163 | 1ddda5cd | Alexander Graf | } |
164 | 1ddda5cd | Alexander Graf | } |
165 | 1ddda5cd | Alexander Graf | smc_debug("DATA Read b: %#x = %#x\n", addr1, retval);
|
166 | 1ddda5cd | Alexander Graf | |
167 | 1ddda5cd | Alexander Graf | return retval;
|
168 | 1ddda5cd | Alexander Graf | } |
169 | 1ddda5cd | Alexander Graf | |
170 | e3914e3a | Jan Kiszka | static uint64_t applesmc_io_cmd_read(void *opaque, hwaddr addr1, unsigned size) |
171 | 1ddda5cd | Alexander Graf | { |
172 | 82407b6c | Andreas Färber | AppleSMCState *s = opaque; |
173 | 1ddda5cd | Alexander Graf | |
174 | 1ddda5cd | Alexander Graf | smc_debug("CMD Read B: %#x\n", addr1);
|
175 | 1ddda5cd | Alexander Graf | return s->status;
|
176 | 1ddda5cd | Alexander Graf | } |
177 | 1ddda5cd | Alexander Graf | |
178 | 82407b6c | Andreas Färber | static void applesmc_add_key(AppleSMCState *s, const char *key, |
179 | 1ddda5cd | Alexander Graf | int len, const char *data) |
180 | 1ddda5cd | Alexander Graf | { |
181 | 1ddda5cd | Alexander Graf | struct AppleSMCData *def;
|
182 | 1ddda5cd | Alexander Graf | |
183 | 7267c094 | Anthony Liguori | def = g_malloc0(sizeof(struct AppleSMCData)); |
184 | 1ddda5cd | Alexander Graf | def->key = key; |
185 | 1ddda5cd | Alexander Graf | def->len = len; |
186 | 1ddda5cd | Alexander Graf | def->data = data; |
187 | 1ddda5cd | Alexander Graf | |
188 | 1ddda5cd | Alexander Graf | QLIST_INSERT_HEAD(&s->data_def, def, node); |
189 | 1ddda5cd | Alexander Graf | } |
190 | 1ddda5cd | Alexander Graf | |
191 | 1ddda5cd | Alexander Graf | static void qdev_applesmc_isa_reset(DeviceState *dev) |
192 | 1ddda5cd | Alexander Graf | { |
193 | 82407b6c | Andreas Färber | AppleSMCState *s = APPLE_SMC(dev); |
194 | 1ddda5cd | Alexander Graf | struct AppleSMCData *d, *next;
|
195 | 1ddda5cd | Alexander Graf | |
196 | 1ddda5cd | Alexander Graf | /* Remove existing entries */
|
197 | 1ddda5cd | Alexander Graf | QLIST_FOREACH_SAFE(d, &s->data_def, node, next) { |
198 | 1ddda5cd | Alexander Graf | QLIST_REMOVE(d, node); |
199 | 1ddda5cd | Alexander Graf | } |
200 | 1ddda5cd | Alexander Graf | |
201 | 7f90fa77 | René Rebe | applesmc_add_key(s, "REV ", 6, "\x01\x13\x0f\x00\x00\x03"); |
202 | 1ddda5cd | Alexander Graf | applesmc_add_key(s, "OSK0", 32, s->osk); |
203 | 1ddda5cd | Alexander Graf | applesmc_add_key(s, "OSK1", 32, s->osk + 32); |
204 | 1ddda5cd | Alexander Graf | applesmc_add_key(s, "NATJ", 1, "\0"); |
205 | 1ddda5cd | Alexander Graf | applesmc_add_key(s, "MSSP", 1, "\0"); |
206 | 1ddda5cd | Alexander Graf | applesmc_add_key(s, "MSSD", 1, "\0x3"); |
207 | 1ddda5cd | Alexander Graf | } |
208 | 1ddda5cd | Alexander Graf | |
209 | e3914e3a | Jan Kiszka | static const MemoryRegionOps applesmc_data_io_ops = { |
210 | e3914e3a | Jan Kiszka | .write = applesmc_io_data_write, |
211 | e3914e3a | Jan Kiszka | .read = applesmc_io_data_read, |
212 | e3914e3a | Jan Kiszka | .endianness = DEVICE_NATIVE_ENDIAN, |
213 | e3914e3a | Jan Kiszka | .impl = { |
214 | e3914e3a | Jan Kiszka | .min_access_size = 1,
|
215 | e3914e3a | Jan Kiszka | .max_access_size = 1,
|
216 | e3914e3a | Jan Kiszka | }, |
217 | e3914e3a | Jan Kiszka | }; |
218 | e3914e3a | Jan Kiszka | |
219 | e3914e3a | Jan Kiszka | static const MemoryRegionOps applesmc_cmd_io_ops = { |
220 | e3914e3a | Jan Kiszka | .write = applesmc_io_cmd_write, |
221 | e3914e3a | Jan Kiszka | .read = applesmc_io_cmd_read, |
222 | e3914e3a | Jan Kiszka | .endianness = DEVICE_NATIVE_ENDIAN, |
223 | e3914e3a | Jan Kiszka | .impl = { |
224 | e3914e3a | Jan Kiszka | .min_access_size = 1,
|
225 | e3914e3a | Jan Kiszka | .max_access_size = 1,
|
226 | e3914e3a | Jan Kiszka | }, |
227 | e3914e3a | Jan Kiszka | }; |
228 | e3914e3a | Jan Kiszka | |
229 | db895a1e | Andreas Färber | static void applesmc_isa_realize(DeviceState *dev, Error **errp) |
230 | 1ddda5cd | Alexander Graf | { |
231 | 82407b6c | Andreas Färber | AppleSMCState *s = APPLE_SMC(dev); |
232 | 1ddda5cd | Alexander Graf | |
233 | e3914e3a | Jan Kiszka | memory_region_init_io(&s->io_data, &applesmc_data_io_ops, s, |
234 | e3914e3a | Jan Kiszka | "applesmc-data", 4); |
235 | e3914e3a | Jan Kiszka | isa_register_ioport(&s->parent_obj, &s->io_data, |
236 | e3914e3a | Jan Kiszka | s->iobase + APPLESMC_DATA_PORT); |
237 | e3914e3a | Jan Kiszka | |
238 | e3914e3a | Jan Kiszka | memory_region_init_io(&s->io_cmd, &applesmc_cmd_io_ops, s, |
239 | e3914e3a | Jan Kiszka | "applesmc-cmd", 4); |
240 | e3914e3a | Jan Kiszka | isa_register_ioport(&s->parent_obj, &s->io_cmd, |
241 | e3914e3a | Jan Kiszka | s->iobase + APPLESMC_CMD_PORT); |
242 | 1ddda5cd | Alexander Graf | |
243 | 1ddda5cd | Alexander Graf | if (!s->osk || (strlen(s->osk) != 64)) { |
244 | 1ddda5cd | Alexander Graf | fprintf(stderr, "WARNING: Using AppleSMC with invalid key\n");
|
245 | 1ddda5cd | Alexander Graf | s->osk = default_osk; |
246 | 1ddda5cd | Alexander Graf | } |
247 | 1ddda5cd | Alexander Graf | |
248 | 1ddda5cd | Alexander Graf | QLIST_INIT(&s->data_def); |
249 | db895a1e | Andreas Färber | qdev_applesmc_isa_reset(dev); |
250 | 1ddda5cd | Alexander Graf | } |
251 | 1ddda5cd | Alexander Graf | |
252 | 39bffca2 | Anthony Liguori | static Property applesmc_isa_properties[] = {
|
253 | 82407b6c | Andreas Färber | DEFINE_PROP_HEX32("iobase", AppleSMCState, iobase,
|
254 | 39bffca2 | Anthony Liguori | APPLESMC_DEFAULT_IOBASE), |
255 | 82407b6c | Andreas Färber | DEFINE_PROP_STRING("osk", AppleSMCState, osk),
|
256 | 39bffca2 | Anthony Liguori | DEFINE_PROP_END_OF_LIST(), |
257 | 39bffca2 | Anthony Liguori | }; |
258 | 39bffca2 | Anthony Liguori | |
259 | 8f04ee08 | Anthony Liguori | static void qdev_applesmc_class_init(ObjectClass *klass, void *data) |
260 | 8f04ee08 | Anthony Liguori | { |
261 | 39bffca2 | Anthony Liguori | DeviceClass *dc = DEVICE_CLASS(klass); |
262 | db895a1e | Andreas Färber | |
263 | db895a1e | Andreas Färber | dc->realize = applesmc_isa_realize; |
264 | 39bffca2 | Anthony Liguori | dc->reset = qdev_applesmc_isa_reset; |
265 | 39bffca2 | Anthony Liguori | dc->props = applesmc_isa_properties; |
266 | 8f04ee08 | Anthony Liguori | } |
267 | 8f04ee08 | Anthony Liguori | |
268 | 8c43a6f0 | Andreas Färber | static const TypeInfo applesmc_isa_info = { |
269 | 82407b6c | Andreas Färber | .name = TYPE_APPLE_SMC, |
270 | 39bffca2 | Anthony Liguori | .parent = TYPE_ISA_DEVICE, |
271 | 82407b6c | Andreas Färber | .instance_size = sizeof(AppleSMCState),
|
272 | 39bffca2 | Anthony Liguori | .class_init = qdev_applesmc_class_init, |
273 | 1ddda5cd | Alexander Graf | }; |
274 | 1ddda5cd | Alexander Graf | |
275 | 83f7d43a | Andreas Färber | static void applesmc_register_types(void) |
276 | 1ddda5cd | Alexander Graf | { |
277 | 39bffca2 | Anthony Liguori | type_register_static(&applesmc_isa_info); |
278 | 1ddda5cd | Alexander Graf | } |
279 | 1ddda5cd | Alexander Graf | |
280 | 83f7d43a | Andreas Färber | type_init(applesmc_register_types) |