root / hw / applesmc.c @ 5b96d8f9
History | View | Annotate | Download (7 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 | 1ddda5cd | Alexander Graf | #include "hw.h" |
34 | 1ddda5cd | Alexander Graf | #include "isa.h" |
35 | 1ddda5cd | Alexander Graf | #include "console.h" |
36 | 1ddda5cd | Alexander Graf | #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 | 1ddda5cd | Alexander Graf | struct AppleSMCStatus {
|
70 | 1ddda5cd | Alexander Graf | ISADevice dev; |
71 | 1ddda5cd | Alexander Graf | uint32_t iobase; |
72 | 1ddda5cd | Alexander Graf | uint8_t cmd; |
73 | 1ddda5cd | Alexander Graf | uint8_t status; |
74 | 1ddda5cd | Alexander Graf | uint8_t key[4];
|
75 | 1ddda5cd | Alexander Graf | uint8_t read_pos; |
76 | 1ddda5cd | Alexander Graf | uint8_t data_len; |
77 | 1ddda5cd | Alexander Graf | uint8_t data_pos; |
78 | 1ddda5cd | Alexander Graf | uint8_t data[255];
|
79 | 1ddda5cd | Alexander Graf | uint8_t charactic[4];
|
80 | 1ddda5cd | Alexander Graf | char *osk;
|
81 | 1ddda5cd | Alexander Graf | QLIST_HEAD(, AppleSMCData) data_def; |
82 | 1ddda5cd | Alexander Graf | }; |
83 | 1ddda5cd | Alexander Graf | |
84 | 1ddda5cd | Alexander Graf | static void applesmc_io_cmd_writeb(void *opaque, uint32_t addr, uint32_t val) |
85 | 1ddda5cd | Alexander Graf | { |
86 | 1ddda5cd | Alexander Graf | struct AppleSMCStatus *s = opaque;
|
87 | 1ddda5cd | Alexander Graf | |
88 | 1ddda5cd | Alexander Graf | smc_debug("CMD Write B: %#x = %#x\n", addr, val);
|
89 | 1ddda5cd | Alexander Graf | switch(val) {
|
90 | 1ddda5cd | Alexander Graf | case APPLESMC_READ_CMD:
|
91 | 1ddda5cd | Alexander Graf | s->status = 0x0c;
|
92 | 1ddda5cd | Alexander Graf | break;
|
93 | 1ddda5cd | Alexander Graf | } |
94 | 1ddda5cd | Alexander Graf | s->cmd = val; |
95 | 1ddda5cd | Alexander Graf | s->read_pos = 0;
|
96 | 1ddda5cd | Alexander Graf | s->data_pos = 0;
|
97 | 1ddda5cd | Alexander Graf | } |
98 | 1ddda5cd | Alexander Graf | |
99 | 1ddda5cd | Alexander Graf | static void applesmc_fill_data(struct AppleSMCStatus *s) |
100 | 1ddda5cd | Alexander Graf | { |
101 | 1ddda5cd | Alexander Graf | struct AppleSMCData *d;
|
102 | 1ddda5cd | Alexander Graf | |
103 | 1ddda5cd | Alexander Graf | QLIST_FOREACH(d, &s->data_def, node) { |
104 | 1ddda5cd | Alexander Graf | if (!memcmp(d->key, s->key, 4)) { |
105 | 1ddda5cd | Alexander Graf | smc_debug("Key matched (%s Len=%d Data=%s)\n", d->key,
|
106 | 1ddda5cd | Alexander Graf | d->len, d->data); |
107 | 1ddda5cd | Alexander Graf | memcpy(s->data, d->data, d->len); |
108 | 1ddda5cd | Alexander Graf | return;
|
109 | 1ddda5cd | Alexander Graf | } |
110 | 1ddda5cd | Alexander Graf | } |
111 | 1ddda5cd | Alexander Graf | } |
112 | 1ddda5cd | Alexander Graf | |
113 | 1ddda5cd | Alexander Graf | static void applesmc_io_data_writeb(void *opaque, uint32_t addr, uint32_t val) |
114 | 1ddda5cd | Alexander Graf | { |
115 | 1ddda5cd | Alexander Graf | struct AppleSMCStatus *s = opaque;
|
116 | 1ddda5cd | Alexander Graf | |
117 | 1ddda5cd | Alexander Graf | smc_debug("DATA Write B: %#x = %#x\n", addr, val);
|
118 | 1ddda5cd | Alexander Graf | switch(s->cmd) {
|
119 | 1ddda5cd | Alexander Graf | case APPLESMC_READ_CMD:
|
120 | 1ddda5cd | Alexander Graf | if(s->read_pos < 4) { |
121 | 1ddda5cd | Alexander Graf | s->key[s->read_pos] = val; |
122 | 1ddda5cd | Alexander Graf | s->status = 0x04;
|
123 | 1ddda5cd | Alexander Graf | } else if(s->read_pos == 4) { |
124 | 1ddda5cd | Alexander Graf | s->data_len = val; |
125 | 1ddda5cd | Alexander Graf | s->status = 0x05;
|
126 | 1ddda5cd | Alexander Graf | s->data_pos = 0;
|
127 | 1ddda5cd | Alexander Graf | smc_debug("Key = %c%c%c%c Len = %d\n", s->key[0], |
128 | 1ddda5cd | Alexander Graf | s->key[1], s->key[2], s->key[3], val); |
129 | 1ddda5cd | Alexander Graf | applesmc_fill_data(s); |
130 | 1ddda5cd | Alexander Graf | } |
131 | 1ddda5cd | Alexander Graf | s->read_pos++; |
132 | 1ddda5cd | Alexander Graf | break;
|
133 | 1ddda5cd | Alexander Graf | } |
134 | 1ddda5cd | Alexander Graf | } |
135 | 1ddda5cd | Alexander Graf | |
136 | 1ddda5cd | Alexander Graf | static uint32_t applesmc_io_data_readb(void *opaque, uint32_t addr1) |
137 | 1ddda5cd | Alexander Graf | { |
138 | 1ddda5cd | Alexander Graf | struct AppleSMCStatus *s = opaque;
|
139 | 1ddda5cd | Alexander Graf | uint8_t retval = 0;
|
140 | 1ddda5cd | Alexander Graf | |
141 | 1ddda5cd | Alexander Graf | switch(s->cmd) {
|
142 | 1ddda5cd | Alexander Graf | case APPLESMC_READ_CMD:
|
143 | 1ddda5cd | Alexander Graf | if(s->data_pos < s->data_len) {
|
144 | 1ddda5cd | Alexander Graf | retval = s->data[s->data_pos]; |
145 | 1ddda5cd | Alexander Graf | smc_debug("READ_DATA[%d] = %#hhx\n", s->data_pos,
|
146 | 1ddda5cd | Alexander Graf | retval); |
147 | 1ddda5cd | Alexander Graf | s->data_pos++; |
148 | 1ddda5cd | Alexander Graf | if(s->data_pos == s->data_len) {
|
149 | 1ddda5cd | Alexander Graf | s->status = 0x00;
|
150 | 1ddda5cd | Alexander Graf | smc_debug("EOF\n");
|
151 | 1ddda5cd | Alexander Graf | } else
|
152 | 1ddda5cd | Alexander Graf | s->status = 0x05;
|
153 | 1ddda5cd | Alexander Graf | } |
154 | 1ddda5cd | Alexander Graf | } |
155 | 1ddda5cd | Alexander Graf | smc_debug("DATA Read b: %#x = %#x\n", addr1, retval);
|
156 | 1ddda5cd | Alexander Graf | |
157 | 1ddda5cd | Alexander Graf | return retval;
|
158 | 1ddda5cd | Alexander Graf | } |
159 | 1ddda5cd | Alexander Graf | |
160 | 1ddda5cd | Alexander Graf | static uint32_t applesmc_io_cmd_readb(void *opaque, uint32_t addr1) |
161 | 1ddda5cd | Alexander Graf | { |
162 | 1ddda5cd | Alexander Graf | struct AppleSMCStatus *s = opaque;
|
163 | 1ddda5cd | Alexander Graf | |
164 | 1ddda5cd | Alexander Graf | smc_debug("CMD Read B: %#x\n", addr1);
|
165 | 1ddda5cd | Alexander Graf | return s->status;
|
166 | 1ddda5cd | Alexander Graf | } |
167 | 1ddda5cd | Alexander Graf | |
168 | 1ddda5cd | Alexander Graf | static void applesmc_add_key(struct AppleSMCStatus *s, const char *key, |
169 | 1ddda5cd | Alexander Graf | int len, const char *data) |
170 | 1ddda5cd | Alexander Graf | { |
171 | 1ddda5cd | Alexander Graf | struct AppleSMCData *def;
|
172 | 1ddda5cd | Alexander Graf | |
173 | 1ddda5cd | Alexander Graf | def = qemu_mallocz(sizeof(struct AppleSMCData)); |
174 | 1ddda5cd | Alexander Graf | def->key = key; |
175 | 1ddda5cd | Alexander Graf | def->len = len; |
176 | 1ddda5cd | Alexander Graf | def->data = data; |
177 | 1ddda5cd | Alexander Graf | |
178 | 1ddda5cd | Alexander Graf | QLIST_INSERT_HEAD(&s->data_def, def, node); |
179 | 1ddda5cd | Alexander Graf | } |
180 | 1ddda5cd | Alexander Graf | |
181 | 1ddda5cd | Alexander Graf | static void qdev_applesmc_isa_reset(DeviceState *dev) |
182 | 1ddda5cd | Alexander Graf | { |
183 | 1ddda5cd | Alexander Graf | struct AppleSMCStatus *s = DO_UPCAST(struct AppleSMCStatus, dev.qdev, dev); |
184 | 1ddda5cd | Alexander Graf | struct AppleSMCData *d, *next;
|
185 | 1ddda5cd | Alexander Graf | |
186 | 1ddda5cd | Alexander Graf | /* Remove existing entries */
|
187 | 1ddda5cd | Alexander Graf | QLIST_FOREACH_SAFE(d, &s->data_def, node, next) { |
188 | 1ddda5cd | Alexander Graf | QLIST_REMOVE(d, node); |
189 | 1ddda5cd | Alexander Graf | } |
190 | 1ddda5cd | Alexander Graf | |
191 | 7f90fa77 | René Rebe | applesmc_add_key(s, "REV ", 6, "\x01\x13\x0f\x00\x00\x03"); |
192 | 1ddda5cd | Alexander Graf | applesmc_add_key(s, "OSK0", 32, s->osk); |
193 | 1ddda5cd | Alexander Graf | applesmc_add_key(s, "OSK1", 32, s->osk + 32); |
194 | 1ddda5cd | Alexander Graf | applesmc_add_key(s, "NATJ", 1, "\0"); |
195 | 1ddda5cd | Alexander Graf | applesmc_add_key(s, "MSSP", 1, "\0"); |
196 | 1ddda5cd | Alexander Graf | applesmc_add_key(s, "MSSD", 1, "\0x3"); |
197 | 1ddda5cd | Alexander Graf | } |
198 | 1ddda5cd | Alexander Graf | |
199 | 1ddda5cd | Alexander Graf | static int applesmc_isa_init(ISADevice *dev) |
200 | 1ddda5cd | Alexander Graf | { |
201 | 1ddda5cd | Alexander Graf | struct AppleSMCStatus *s = DO_UPCAST(struct AppleSMCStatus, dev, dev); |
202 | 1ddda5cd | Alexander Graf | |
203 | 1ddda5cd | Alexander Graf | register_ioport_read(s->iobase + APPLESMC_DATA_PORT, 4, 1, |
204 | 1ddda5cd | Alexander Graf | applesmc_io_data_readb, s); |
205 | 1ddda5cd | Alexander Graf | register_ioport_read(s->iobase + APPLESMC_CMD_PORT, 4, 1, |
206 | 1ddda5cd | Alexander Graf | applesmc_io_cmd_readb, s); |
207 | 1ddda5cd | Alexander Graf | register_ioport_write(s->iobase + APPLESMC_DATA_PORT, 4, 1, |
208 | 1ddda5cd | Alexander Graf | applesmc_io_data_writeb, s); |
209 | 1ddda5cd | Alexander Graf | register_ioport_write(s->iobase + APPLESMC_CMD_PORT, 4, 1, |
210 | 1ddda5cd | Alexander Graf | applesmc_io_cmd_writeb, s); |
211 | 1ddda5cd | Alexander Graf | |
212 | 1ddda5cd | Alexander Graf | if (!s->osk || (strlen(s->osk) != 64)) { |
213 | 1ddda5cd | Alexander Graf | fprintf(stderr, "WARNING: Using AppleSMC with invalid key\n");
|
214 | 1ddda5cd | Alexander Graf | s->osk = default_osk; |
215 | 1ddda5cd | Alexander Graf | } |
216 | 1ddda5cd | Alexander Graf | |
217 | 1ddda5cd | Alexander Graf | QLIST_INIT(&s->data_def); |
218 | 1ddda5cd | Alexander Graf | qdev_applesmc_isa_reset(&dev->qdev); |
219 | 1ddda5cd | Alexander Graf | |
220 | 1ddda5cd | Alexander Graf | return 0; |
221 | 1ddda5cd | Alexander Graf | } |
222 | 1ddda5cd | Alexander Graf | |
223 | 1ddda5cd | Alexander Graf | static ISADeviceInfo applesmc_isa_info = {
|
224 | 1ddda5cd | Alexander Graf | .qdev.name = "isa-applesmc",
|
225 | 1ddda5cd | Alexander Graf | .qdev.size = sizeof(struct AppleSMCStatus), |
226 | 1ddda5cd | Alexander Graf | .qdev.reset = qdev_applesmc_isa_reset, |
227 | 1ddda5cd | Alexander Graf | .init = applesmc_isa_init, |
228 | 1ddda5cd | Alexander Graf | .qdev.props = (Property[]) { |
229 | 1ddda5cd | Alexander Graf | DEFINE_PROP_HEX32("iobase", struct AppleSMCStatus, iobase, |
230 | 1ddda5cd | Alexander Graf | APPLESMC_DEFAULT_IOBASE), |
231 | 1ddda5cd | Alexander Graf | DEFINE_PROP_STRING("osk", struct AppleSMCStatus, osk), |
232 | 1ddda5cd | Alexander Graf | DEFINE_PROP_END_OF_LIST(), |
233 | 1ddda5cd | Alexander Graf | }, |
234 | 1ddda5cd | Alexander Graf | }; |
235 | 1ddda5cd | Alexander Graf | |
236 | 1ddda5cd | Alexander Graf | static void applesmc_register_devices(void) |
237 | 1ddda5cd | Alexander Graf | { |
238 | 1ddda5cd | Alexander Graf | isa_qdev_register(&applesmc_isa_info); |
239 | 1ddda5cd | Alexander Graf | } |
240 | 1ddda5cd | Alexander Graf | |
241 | 1ddda5cd | Alexander Graf | device_init(applesmc_register_devices) |