Commit 267002cd28318c6ca246205c9b8c42c3cca48960
1 parent
63066f4f
CUDA + ADB support
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@881 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
3 changed files
with
902 additions
and
1 deletions
hw/adb.c
0 → 100644
1 | +/* | ||
2 | + * QEMU ADB support | ||
3 | + * | ||
4 | + * Copyright (c) 2004 Fabrice Bellard | ||
5 | + * | ||
6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | + * of this software and associated documentation files (the "Software"), to deal | ||
8 | + * in the Software without restriction, including without limitation the rights | ||
9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | + * copies of the Software, and to permit persons to whom the Software is | ||
11 | + * furnished to do so, subject to the following conditions: | ||
12 | + * | ||
13 | + * The above copyright notice and this permission notice shall be included in | ||
14 | + * all copies or substantial portions of the Software. | ||
15 | + * | ||
16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | + * THE SOFTWARE. | ||
23 | + */ | ||
24 | +#include "vl.h" | ||
25 | + | ||
26 | +/* ADB commands */ | ||
27 | +#define ADB_BUSRESET 0x00 | ||
28 | +#define ADB_FLUSH 0x01 | ||
29 | +#define ADB_WRITEREG 0x08 | ||
30 | +#define ADB_READREG 0x0c | ||
31 | + | ||
32 | +/* ADB device commands */ | ||
33 | +#define ADB_CMD_SELF_TEST 0xff | ||
34 | +#define ADB_CMD_CHANGE_ID 0xfe | ||
35 | +#define ADB_CMD_CHANGE_ID_AND_ACT 0xfd | ||
36 | +#define ADB_CMD_CHANGE_ID_AND_ENABLE 0x00 | ||
37 | + | ||
38 | +/* ADB default device IDs (upper 4 bits of ADB command byte) */ | ||
39 | +#define ADB_DONGLE 1 | ||
40 | +#define ADB_KEYBOARD 2 | ||
41 | +#define ADB_MOUSE 3 | ||
42 | +#define ADB_TABLET 4 | ||
43 | +#define ADB_MODEM 5 | ||
44 | +#define ADB_MISC 7 | ||
45 | + | ||
46 | +#define ADB_RET_OK 0 | ||
47 | +#define ADB_RET_INUSE 1 | ||
48 | +#define ADB_RET_NOTPRESENT 2 | ||
49 | +#define ADB_RET_TIMEOUT 3 | ||
50 | +#define ADB_RET_UNEXPECTED_RESULT 4 | ||
51 | +#define ADB_RET_REQUEST_ERROR 5 | ||
52 | +#define ADB_RET_BUS_ERROR 6 | ||
53 | + | ||
54 | + | ||
55 | +static void adb_send_packet1(ADBBusState *s, uint8_t reply) | ||
56 | +{ | ||
57 | + adb_send_packet(s, &reply, 1); | ||
58 | +} | ||
59 | + | ||
60 | +void adb_receive_packet(ADBBusState *s, const uint8_t *buf, int len) | ||
61 | +{ | ||
62 | + ADBDevice *d; | ||
63 | + int devaddr, cmd, i; | ||
64 | + uint8_t obuf[4]; | ||
65 | + | ||
66 | + cmd = buf[1] & 0xf; | ||
67 | + devaddr = buf[1] >> 4; | ||
68 | + if (buf[1] == ADB_BUSRESET) { | ||
69 | + obuf[0] = 0x00; | ||
70 | + obuf[1] = 0x00; | ||
71 | + adb_send_packet(s, obuf, 2); | ||
72 | + return; | ||
73 | + } | ||
74 | + if (cmd == ADB_FLUSH) { | ||
75 | + obuf[0] = 0x00; | ||
76 | + obuf[1] = 0x00; | ||
77 | + adb_send_packet(s, obuf, 2); | ||
78 | + return; | ||
79 | + } | ||
80 | + | ||
81 | + for(i = 0; i < s->nb_devices; i++) { | ||
82 | + d = &s->devices[i]; | ||
83 | + if (d->devaddr == devaddr) { | ||
84 | + d->receive_packet(d, buf, len); | ||
85 | + return; | ||
86 | + } | ||
87 | + } | ||
88 | + adb_send_packet1(s, ADB_RET_NOTPRESENT); | ||
89 | +} | ||
90 | + | ||
91 | +ADBDevice *adb_register_device(ADBBusState *s, int devaddr, | ||
92 | + ADBDeviceReceivePacket *receive_packet, | ||
93 | + void *opaque) | ||
94 | +{ | ||
95 | + ADBDevice *d; | ||
96 | + if (s->nb_devices >= MAX_ADB_DEVICES) | ||
97 | + return NULL; | ||
98 | + d = &s->devices[s->nb_devices++]; | ||
99 | + d->bus = s; | ||
100 | + d->devaddr = devaddr; | ||
101 | + d->receive_packet = receive_packet; | ||
102 | + d->opaque = opaque; | ||
103 | + return d; | ||
104 | +} | ||
105 | + | ||
106 | +/***************************************************************/ | ||
107 | +/* Keyboard ADB device */ | ||
108 | + | ||
109 | +static const uint8_t pc_to_adb_keycode[256] = { | ||
110 | + 0, 53, 18, 19, 20, 21, 23, 22, 26, 28, 25, 29, 27, 24, 51, 48, | ||
111 | + 12, 13, 14, 15, 17, 16, 32, 34, 31, 35, 33, 30, 36, 54, 0, 1, | ||
112 | + 2, 3, 5, 4, 38, 40, 37, 41, 39, 50, 56, 42, 6, 7, 8, 9, | ||
113 | + 11, 45, 46, 43, 47, 44,123, 67, 58, 49, 57,122,120, 99,118, 96, | ||
114 | + 97, 98,100,101,109, 71,107, 89, 91, 92, 78, 86, 87, 88, 69, 83, | ||
115 | + 84, 85, 82, 65, 0, 0, 10,103,111, 0, 0, 0, 0, 0, 0, 0, | ||
116 | + 76,125, 75,105,124,110,115, 62,116, 59, 60,119, 61,121,114,117, | ||
117 | + 0, 0, 0, 0,127, 81, 0,113, 0, 0, 0, 0, 95, 55, 0, 0, | ||
118 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
119 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
120 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
121 | + 0, 0, 0, 0, 0, 94, 0, 93, 0, 0, 0, 0, 0, 0,104,102, | ||
122 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
123 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
124 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
125 | + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, | ||
126 | +}; | ||
127 | + | ||
128 | +static void adb_kbd_put_keycode(void *opaque, int keycode) | ||
129 | +{ | ||
130 | + static int ext_keycode; | ||
131 | + ADBDevice *d = opaque; | ||
132 | + uint8_t buf[4]; | ||
133 | + int adb_keycode; | ||
134 | + | ||
135 | + if (keycode == 0xe0) { | ||
136 | + ext_keycode = 1; | ||
137 | + } else { | ||
138 | + | ||
139 | + if (ext_keycode) | ||
140 | + adb_keycode = pc_to_adb_keycode[keycode | 0x80]; | ||
141 | + else | ||
142 | + adb_keycode = pc_to_adb_keycode[keycode & 0x7f]; | ||
143 | + | ||
144 | + buf[0] = 0x40; | ||
145 | + buf[1] = (d->devaddr << 4) | 0x0c; | ||
146 | + buf[2] = adb_keycode | (keycode & 0x80); | ||
147 | + buf[3] = 0xff; | ||
148 | + adb_send_packet(d->bus, buf, 4); | ||
149 | + ext_keycode = 0; | ||
150 | + } | ||
151 | +} | ||
152 | + | ||
153 | +static void adb_kbd_receive_packet(ADBDevice *d, const uint8_t *buf, int len) | ||
154 | +{ | ||
155 | + int cmd, reg; | ||
156 | + uint8_t obuf[4]; | ||
157 | + | ||
158 | + cmd = buf[0] & 0xc; | ||
159 | + reg = buf[0] & 0x3; | ||
160 | + switch(cmd) { | ||
161 | + case ADB_WRITEREG: | ||
162 | + switch(reg) { | ||
163 | + case 2: | ||
164 | + /* LED status */ | ||
165 | + adb_send_packet1(d->bus, ADB_RET_OK); | ||
166 | + break; | ||
167 | + case 3: | ||
168 | + switch(buf[2]) { | ||
169 | + case ADB_CMD_SELF_TEST: | ||
170 | + adb_send_packet1(d->bus, ADB_RET_OK); | ||
171 | + break; | ||
172 | + case ADB_CMD_CHANGE_ID: | ||
173 | + case ADB_CMD_CHANGE_ID_AND_ACT: | ||
174 | + case ADB_CMD_CHANGE_ID_AND_ENABLE: | ||
175 | + d->devaddr = buf[1] & 0xf; | ||
176 | + adb_send_packet1(d->bus, ADB_RET_OK); | ||
177 | + break; | ||
178 | + default: | ||
179 | + /* XXX: check this */ | ||
180 | + d->devaddr = buf[1] & 0xf; | ||
181 | + d->handler = buf[2]; | ||
182 | + adb_send_packet1(d->bus, ADB_RET_OK); | ||
183 | + break; | ||
184 | + } | ||
185 | + } | ||
186 | + break; | ||
187 | + case ADB_READREG: | ||
188 | + switch(reg) { | ||
189 | + case 1: | ||
190 | + adb_send_packet1(d->bus, ADB_RET_OK); | ||
191 | + break; | ||
192 | + case 2: | ||
193 | + obuf[0] = ADB_RET_OK; | ||
194 | + obuf[1] = 0x00; /* XXX: check this */ | ||
195 | + obuf[2] = 0x07; /* led status */ | ||
196 | + adb_send_packet(d->bus, obuf, 3); | ||
197 | + break; | ||
198 | + case 3: | ||
199 | + obuf[0] = ADB_RET_OK; | ||
200 | + obuf[1] = d->handler; | ||
201 | + obuf[2] = d->devaddr; | ||
202 | + adb_send_packet(d->bus, obuf, 3); | ||
203 | + break; | ||
204 | + } | ||
205 | + break; | ||
206 | + } | ||
207 | +} | ||
208 | + | ||
209 | +void adb_kbd_init(ADBBusState *bus) | ||
210 | +{ | ||
211 | + ADBDevice *d; | ||
212 | + | ||
213 | + d = adb_register_device(bus, ADB_KEYBOARD, adb_kbd_receive_packet, NULL); | ||
214 | + qemu_add_kbd_event_handler(adb_kbd_put_keycode, d); | ||
215 | +} | ||
216 | + | ||
217 | +/***************************************************************/ | ||
218 | +/* Mouse ADB device */ | ||
219 | + | ||
220 | +static void adb_mouse_event(void *opaque, | ||
221 | + int dx1, int dy1, int dz1, int buttons_state) | ||
222 | +{ | ||
223 | + ADBDevice *d = opaque; | ||
224 | + uint8_t buf[4]; | ||
225 | + int dx, dy; | ||
226 | + | ||
227 | + dx = dx1; | ||
228 | + if (dx < -63) | ||
229 | + dx = -63; | ||
230 | + else if (dx > 63) | ||
231 | + dx = 63; | ||
232 | + | ||
233 | + dy = dy1; | ||
234 | + if (dy < -63) | ||
235 | + dy = -63; | ||
236 | + else if (dy > 63) | ||
237 | + dy = 63; | ||
238 | + | ||
239 | + dx &= 0x7f; | ||
240 | + dy &= 0x7f; | ||
241 | + | ||
242 | + if (buttons_state & MOUSE_EVENT_LBUTTON) | ||
243 | + dy |= 0x80; | ||
244 | + if (buttons_state & MOUSE_EVENT_RBUTTON) | ||
245 | + dx |= 0x80; | ||
246 | + | ||
247 | + buf[0] = 0x40; | ||
248 | + buf[1] = (d->devaddr << 4) | 0x0c; | ||
249 | + buf[2] = dy; | ||
250 | + buf[3] = dx; | ||
251 | + adb_send_packet(d->bus, buf, 4); | ||
252 | +} | ||
253 | + | ||
254 | +static void adb_mouse_receive_packet(ADBDevice *d, const uint8_t *buf, int len) | ||
255 | +{ | ||
256 | + int cmd, reg; | ||
257 | + uint8_t obuf[4]; | ||
258 | + | ||
259 | + cmd = buf[0] & 0xc; | ||
260 | + reg = buf[0] & 0x3; | ||
261 | + switch(cmd) { | ||
262 | + case ADB_WRITEREG: | ||
263 | + switch(reg) { | ||
264 | + case 2: | ||
265 | + adb_send_packet1(d->bus, ADB_RET_OK); | ||
266 | + break; | ||
267 | + case 3: | ||
268 | + switch(buf[2]) { | ||
269 | + case ADB_CMD_SELF_TEST: | ||
270 | + adb_send_packet1(d->bus, ADB_RET_OK); | ||
271 | + break; | ||
272 | + case ADB_CMD_CHANGE_ID: | ||
273 | + case ADB_CMD_CHANGE_ID_AND_ACT: | ||
274 | + case ADB_CMD_CHANGE_ID_AND_ENABLE: | ||
275 | + d->devaddr = buf[1] & 0xf; | ||
276 | + adb_send_packet1(d->bus, ADB_RET_OK); | ||
277 | + break; | ||
278 | + default: | ||
279 | + /* XXX: check this */ | ||
280 | + d->devaddr = buf[1] & 0xf; | ||
281 | + adb_send_packet1(d->bus, ADB_RET_OK); | ||
282 | + break; | ||
283 | + } | ||
284 | + } | ||
285 | + break; | ||
286 | + case ADB_READREG: | ||
287 | + switch(reg) { | ||
288 | + case 1: | ||
289 | + adb_send_packet1(d->bus, ADB_RET_OK); | ||
290 | + break; | ||
291 | + case 3: | ||
292 | + obuf[0] = ADB_RET_OK; | ||
293 | + obuf[1] = d->handler; | ||
294 | + obuf[2] = d->devaddr; | ||
295 | + adb_send_packet(d->bus, obuf, 3); | ||
296 | + break; | ||
297 | + } | ||
298 | + break; | ||
299 | + } | ||
300 | +} | ||
301 | + | ||
302 | +void adb_mouse_init(ADBBusState *bus) | ||
303 | +{ | ||
304 | + ADBDevice *d; | ||
305 | + | ||
306 | + d = adb_register_device(bus, ADB_MOUSE, adb_mouse_receive_packet, NULL); | ||
307 | + qemu_add_mouse_event_handler(adb_mouse_event, d); | ||
308 | +} |
hw/cuda.c
0 → 100644
1 | +/* | ||
2 | + * QEMU CUDA support | ||
3 | + * | ||
4 | + * Copyright (c) 2004 Fabrice Bellard | ||
5 | + * | ||
6 | + * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
7 | + * of this software and associated documentation files (the "Software"), to deal | ||
8 | + * in the Software without restriction, including without limitation the rights | ||
9 | + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
10 | + * copies of the Software, and to permit persons to whom the Software is | ||
11 | + * furnished to do so, subject to the following conditions: | ||
12 | + * | ||
13 | + * The above copyright notice and this permission notice shall be included in | ||
14 | + * all copies or substantial portions of the Software. | ||
15 | + * | ||
16 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
17 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
18 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | ||
19 | + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
20 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
21 | + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | ||
22 | + * THE SOFTWARE. | ||
23 | + */ | ||
24 | +#include "vl.h" | ||
25 | + | ||
26 | +/* Bits in B data register: all active low */ | ||
27 | +#define TREQ 0x08 /* Transfer request (input) */ | ||
28 | +#define TACK 0x10 /* Transfer acknowledge (output) */ | ||
29 | +#define TIP 0x20 /* Transfer in progress (output) */ | ||
30 | + | ||
31 | +/* Bits in ACR */ | ||
32 | +#define SR_CTRL 0x1c /* Shift register control bits */ | ||
33 | +#define SR_EXT 0x0c /* Shift on external clock */ | ||
34 | +#define SR_OUT 0x10 /* Shift out if 1 */ | ||
35 | + | ||
36 | +/* Bits in IFR and IER */ | ||
37 | +#define IER_SET 0x80 /* set bits in IER */ | ||
38 | +#define IER_CLR 0 /* clear bits in IER */ | ||
39 | +#define SR_INT 0x04 /* Shift register full/empty */ | ||
40 | +#define T1_INT 0x40 /* Timer 1 interrupt */ | ||
41 | + | ||
42 | +/* Bits in ACR */ | ||
43 | +#define T1MODE 0xc0 /* Timer 1 mode */ | ||
44 | +#define T1MODE_CONT 0x40 /* continuous interrupts */ | ||
45 | + | ||
46 | +/* commands (1st byte) */ | ||
47 | +#define ADB_PACKET 0 | ||
48 | +#define CUDA_PACKET 1 | ||
49 | +#define ERROR_PACKET 2 | ||
50 | +#define TIMER_PACKET 3 | ||
51 | +#define POWER_PACKET 4 | ||
52 | +#define MACIIC_PACKET 5 | ||
53 | +#define PMU_PACKET 6 | ||
54 | + | ||
55 | + | ||
56 | +/* CUDA commands (2nd byte) */ | ||
57 | +#define CUDA_WARM_START 0x0 | ||
58 | +#define CUDA_AUTOPOLL 0x1 | ||
59 | +#define CUDA_GET_6805_ADDR 0x2 | ||
60 | +#define CUDA_GET_TIME 0x3 | ||
61 | +#define CUDA_GET_PRAM 0x7 | ||
62 | +#define CUDA_SET_6805_ADDR 0x8 | ||
63 | +#define CUDA_SET_TIME 0x9 | ||
64 | +#define CUDA_POWERDOWN 0xa | ||
65 | +#define CUDA_POWERUP_TIME 0xb | ||
66 | +#define CUDA_SET_PRAM 0xc | ||
67 | +#define CUDA_MS_RESET 0xd | ||
68 | +#define CUDA_SEND_DFAC 0xe | ||
69 | +#define CUDA_BATTERY_SWAP_SENSE 0x10 | ||
70 | +#define CUDA_RESET_SYSTEM 0x11 | ||
71 | +#define CUDA_SET_IPL 0x12 | ||
72 | +#define CUDA_FILE_SERVER_FLAG 0x13 | ||
73 | +#define CUDA_SET_AUTO_RATE 0x14 | ||
74 | +#define CUDA_GET_AUTO_RATE 0x16 | ||
75 | +#define CUDA_SET_DEVICE_LIST 0x19 | ||
76 | +#define CUDA_GET_DEVICE_LIST 0x1a | ||
77 | +#define CUDA_SET_ONE_SECOND_MODE 0x1b | ||
78 | +#define CUDA_SET_POWER_MESSAGES 0x21 | ||
79 | +#define CUDA_GET_SET_IIC 0x22 | ||
80 | +#define CUDA_WAKEUP 0x23 | ||
81 | +#define CUDA_TIMER_TICKLE 0x24 | ||
82 | +#define CUDA_COMBINED_FORMAT_IIC 0x25 | ||
83 | + | ||
84 | +#define CUDA_TIMER_FREQ (4700000 / 6) | ||
85 | + | ||
86 | +typedef struct CUDATimer { | ||
87 | + unsigned int latch; | ||
88 | + uint16_t counter_value; /* counter value at load time */ | ||
89 | + int64_t load_time; | ||
90 | + int64_t next_irq_time; | ||
91 | + QEMUTimer *timer; | ||
92 | +} CUDATimer; | ||
93 | + | ||
94 | +typedef struct CUDAState { | ||
95 | + /* cuda registers */ | ||
96 | + uint8_t b; /* B-side data */ | ||
97 | + uint8_t a; /* A-side data */ | ||
98 | + uint8_t dirb; /* B-side direction (1=output) */ | ||
99 | + uint8_t dira; /* A-side direction (1=output) */ | ||
100 | + uint8_t sr; /* Shift register */ | ||
101 | + uint8_t acr; /* Auxiliary control register */ | ||
102 | + uint8_t pcr; /* Peripheral control register */ | ||
103 | + uint8_t ifr; /* Interrupt flag register */ | ||
104 | + uint8_t ier; /* Interrupt enable register */ | ||
105 | + uint8_t anh; /* A-side data, no handshake */ | ||
106 | + | ||
107 | + CUDATimer timers[2]; | ||
108 | + | ||
109 | + uint8_t last_b; /* last value of B register */ | ||
110 | + uint8_t last_acr; /* last value of B register */ | ||
111 | + | ||
112 | + int data_in_size; | ||
113 | + int data_in_index; | ||
114 | + int data_out_index; | ||
115 | + | ||
116 | + int irq; | ||
117 | + uint8_t autopoll; | ||
118 | + uint8_t data_in[128]; | ||
119 | + uint8_t data_out[16]; | ||
120 | +} CUDAState; | ||
121 | + | ||
122 | +static CUDAState cuda_state; | ||
123 | +ADBBusState adb_bus; | ||
124 | + | ||
125 | +static void cuda_update(CUDAState *s); | ||
126 | +static void cuda_receive_packet_from_host(CUDAState *s, | ||
127 | + const uint8_t *data, int len); | ||
128 | + | ||
129 | +static void cuda_update_irq(CUDAState *s) | ||
130 | +{ | ||
131 | + if (s->ifr & s->ier & SR_INT) { | ||
132 | + pic_set_irq(s->irq, 1); | ||
133 | + } else { | ||
134 | + pic_set_irq(s->irq, 0); | ||
135 | + } | ||
136 | +} | ||
137 | + | ||
138 | +static unsigned int get_counter(CUDATimer *s) | ||
139 | +{ | ||
140 | + int64_t d; | ||
141 | + unsigned int counter; | ||
142 | + | ||
143 | + d = muldiv64(qemu_get_clock(vm_clock) - s->load_time, | ||
144 | + CUDA_TIMER_FREQ, ticks_per_sec); | ||
145 | + if (d <= s->counter_value) { | ||
146 | + counter = d; | ||
147 | + } else { | ||
148 | + counter = s->latch - 1 - ((d - s->counter_value) % s->latch); | ||
149 | + } | ||
150 | + return counter; | ||
151 | +} | ||
152 | + | ||
153 | +static void set_counter(CUDATimer *s, unsigned int val) | ||
154 | +{ | ||
155 | + s->load_time = qemu_get_clock(vm_clock); | ||
156 | + s->counter_value = val; | ||
157 | +} | ||
158 | + | ||
159 | +static int64_t get_next_irq_time(CUDATimer *s, int64_t current_time) | ||
160 | +{ | ||
161 | + int64_t d, next_time, base; | ||
162 | + /* current counter value */ | ||
163 | + d = muldiv64(current_time - s->load_time, | ||
164 | + CUDA_TIMER_FREQ, ticks_per_sec); | ||
165 | + if (d <= s->counter_value) { | ||
166 | + next_time = s->counter_value + 1; | ||
167 | + } else { | ||
168 | + base = ((d - s->counter_value) % s->latch); | ||
169 | + base = (base * s->latch) + s->counter_value; | ||
170 | + next_time = base + s->latch; | ||
171 | + } | ||
172 | + next_time = muldiv64(next_time, ticks_per_sec, CUDA_TIMER_FREQ) + | ||
173 | + s->load_time; | ||
174 | + if (next_time <= current_time) | ||
175 | + next_time = current_time + 1; | ||
176 | + return next_time; | ||
177 | +} | ||
178 | + | ||
179 | +static void cuda_timer1(void *opaque) | ||
180 | +{ | ||
181 | + CUDAState *s = opaque; | ||
182 | + CUDATimer *ti = &s->timers[0]; | ||
183 | + | ||
184 | + ti->next_irq_time = get_next_irq_time(ti, ti->next_irq_time); | ||
185 | + qemu_mod_timer(ti->timer, ti->next_irq_time); | ||
186 | + s->ifr |= T1_INT; | ||
187 | + cuda_update_irq(s); | ||
188 | +} | ||
189 | + | ||
190 | +static uint32_t cuda_readb(void *opaque, target_phys_addr_t addr) | ||
191 | +{ | ||
192 | + CUDAState *s = opaque; | ||
193 | + uint32_t val; | ||
194 | + | ||
195 | + addr = (addr >> 9) & 0xf; | ||
196 | + switch(addr) { | ||
197 | + case 0: | ||
198 | + val = s->b; | ||
199 | + break; | ||
200 | + case 1: | ||
201 | + val = s->a; | ||
202 | + break; | ||
203 | + case 2: | ||
204 | + val = s->dirb; | ||
205 | + break; | ||
206 | + case 3: | ||
207 | + val = s->dira; | ||
208 | + break; | ||
209 | + case 4: | ||
210 | + val = get_counter(&s->timers[0]) & 0xff; | ||
211 | + s->ifr &= ~T1_INT; | ||
212 | + cuda_update_irq(s); | ||
213 | + break; | ||
214 | + case 5: | ||
215 | + val = get_counter(&s->timers[0]) >> 8; | ||
216 | + s->ifr &= ~T1_INT; | ||
217 | + cuda_update_irq(s); | ||
218 | + break; | ||
219 | + case 6: | ||
220 | + val = s->timers[0].latch & 0xff; | ||
221 | + break; | ||
222 | + case 7: | ||
223 | + val = (s->timers[0].latch >> 8) & 0xff; | ||
224 | + break; | ||
225 | + case 8: | ||
226 | + val = get_counter(&s->timers[1]) & 0xff; | ||
227 | + break; | ||
228 | + case 9: | ||
229 | + val = get_counter(&s->timers[1]) >> 8; | ||
230 | + break; | ||
231 | + case 10: | ||
232 | + if (s->data_in_index < s->data_in_size) { | ||
233 | + val = s->data_in[s->data_in_index]; | ||
234 | + } else { | ||
235 | + val = 0; | ||
236 | + } | ||
237 | + break; | ||
238 | + case 11: | ||
239 | + val = s->acr; | ||
240 | + break; | ||
241 | + case 12: | ||
242 | + val = s->pcr; | ||
243 | + break; | ||
244 | + case 13: | ||
245 | + val = s->ifr; | ||
246 | + break; | ||
247 | + case 14: | ||
248 | + val = s->ier; | ||
249 | + break; | ||
250 | + default: | ||
251 | + case 15: | ||
252 | + val = s->anh; | ||
253 | + break; | ||
254 | + } | ||
255 | +#ifdef DEBUG_CUDA | ||
256 | + printf("cuda: read: reg=0x%x val=%02x\n", addr, val); | ||
257 | +#endif | ||
258 | + return val; | ||
259 | +} | ||
260 | + | ||
261 | +static void cuda_writeb(void *opaque, target_phys_addr_t addr, uint32_t val) | ||
262 | +{ | ||
263 | + CUDAState *s = opaque; | ||
264 | + | ||
265 | + addr = (addr >> 9) & 0xf; | ||
266 | +#ifdef DEBUG_CUDA | ||
267 | + printf("cuda: write: reg=0x%x val=%02x\n", addr, val); | ||
268 | +#endif | ||
269 | + | ||
270 | + switch(addr) { | ||
271 | + case 0: | ||
272 | + s->b = val; | ||
273 | + cuda_update(s); | ||
274 | + break; | ||
275 | + case 1: | ||
276 | + s->a = val; | ||
277 | + break; | ||
278 | + case 2: | ||
279 | + s->dirb = val; | ||
280 | + break; | ||
281 | + case 3: | ||
282 | + s->dira = val; | ||
283 | + break; | ||
284 | + case 4: | ||
285 | + val = val | (get_counter(&s->timers[0]) & 0xff00); | ||
286 | + set_counter(&s->timers[0], val); | ||
287 | + break; | ||
288 | + case 5: | ||
289 | + val = (val << 8) | (get_counter(&s->timers[0]) & 0xff); | ||
290 | + set_counter(&s->timers[0], val); | ||
291 | + break; | ||
292 | + case 6: | ||
293 | + s->timers[0].latch = (s->timers[0].latch & 0xff00) | val; | ||
294 | + break; | ||
295 | + case 7: | ||
296 | + s->timers[0].latch = (s->timers[0].latch & 0xff) | (val << 8); | ||
297 | + break; | ||
298 | + case 8: | ||
299 | + val = val | (get_counter(&s->timers[1]) & 0xff00); | ||
300 | + set_counter(&s->timers[1], val); | ||
301 | + break; | ||
302 | + case 9: | ||
303 | + val = (val << 8) | (get_counter(&s->timers[1]) & 0xff); | ||
304 | + set_counter(&s->timers[1], val); | ||
305 | + break; | ||
306 | + case 10: | ||
307 | + s->sr = val; | ||
308 | + break; | ||
309 | + case 11: | ||
310 | + s->acr = val; | ||
311 | + if ((s->acr & T1MODE) == T1MODE_CONT) { | ||
312 | + if ((s->last_acr & T1MODE) != T1MODE_CONT) { | ||
313 | + CUDATimer *ti = &s->timers[0]; | ||
314 | + /* activate timer interrupt */ | ||
315 | + ti->next_irq_time = get_next_irq_time(ti, qemu_get_clock(vm_clock)); | ||
316 | + qemu_mod_timer(ti->timer, ti->next_irq_time); | ||
317 | + } | ||
318 | + } else { | ||
319 | + if ((s->last_acr & T1MODE) == T1MODE_CONT) { | ||
320 | + CUDATimer *ti = &s->timers[0]; | ||
321 | + qemu_del_timer(ti->timer); | ||
322 | + } | ||
323 | + } | ||
324 | + cuda_update(s); | ||
325 | + break; | ||
326 | + case 12: | ||
327 | + s->pcr = val; | ||
328 | + break; | ||
329 | + case 13: | ||
330 | + /* reset bits */ | ||
331 | + s->ifr &= ~val; | ||
332 | + cuda_update_irq(s); | ||
333 | + break; | ||
334 | + case 14: | ||
335 | + if (val & IER_SET) { | ||
336 | + /* set bits */ | ||
337 | + s->ier |= val & 0x7f; | ||
338 | + } else { | ||
339 | + /* reset bits */ | ||
340 | + s->ier &= ~val; | ||
341 | + } | ||
342 | + cuda_update_irq(s); | ||
343 | + break; | ||
344 | + default: | ||
345 | + case 15: | ||
346 | + s->anh = val; | ||
347 | + break; | ||
348 | + } | ||
349 | +} | ||
350 | + | ||
351 | +/* NOTE: TIP and TREQ are negated */ | ||
352 | +static void cuda_update(CUDAState *s) | ||
353 | +{ | ||
354 | + if (s->data_in_index < s->data_in_size) { | ||
355 | + /* data input */ | ||
356 | + if (!(s->b & TIP) && | ||
357 | + (s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) { | ||
358 | + s->sr = s->data_in[s->data_in_index++]; | ||
359 | + s->ifr |= SR_INT; | ||
360 | + cuda_update_irq(s); | ||
361 | + } | ||
362 | + } | ||
363 | + if (s->data_in_index < s->data_in_size) { | ||
364 | + /* there is some data to read */ | ||
365 | + s->b = (s->b & ~TREQ); | ||
366 | + } else { | ||
367 | + s->b = (s->b | TREQ); | ||
368 | + } | ||
369 | + | ||
370 | + if (s->acr & SR_OUT) { | ||
371 | + /* data output */ | ||
372 | + if (!(s->b & TIP) && | ||
373 | + (s->b & (TACK | TIP)) != (s->last_b & (TACK | TIP))) { | ||
374 | + if (s->data_out_index < sizeof(s->data_out)) { | ||
375 | + s->data_out[s->data_out_index++] = s->sr; | ||
376 | + } | ||
377 | + s->ifr |= SR_INT; | ||
378 | + cuda_update_irq(s); | ||
379 | + } | ||
380 | + } | ||
381 | + | ||
382 | + /* check end of data output */ | ||
383 | + if (!(s->acr & SR_OUT) && (s->last_acr & SR_OUT)) { | ||
384 | + if (s->data_out_index > 0) | ||
385 | + cuda_receive_packet_from_host(s, s->data_out, s->data_out_index); | ||
386 | + s->data_out_index = 0; | ||
387 | + } | ||
388 | + s->last_acr = s->acr; | ||
389 | + s->last_b = s->b; | ||
390 | +} | ||
391 | + | ||
392 | +static void cuda_send_packet_to_host(CUDAState *s, | ||
393 | + const uint8_t *data, int len) | ||
394 | +{ | ||
395 | + memcpy(s->data_in, data, len); | ||
396 | + s->data_in_size = len; | ||
397 | + s->data_in_index = 0; | ||
398 | + cuda_update(s); | ||
399 | + s->ifr |= SR_INT; | ||
400 | + cuda_update_irq(s); | ||
401 | +} | ||
402 | + | ||
403 | +void adb_send_packet(ADBBusState *bus, const uint8_t *buf, int len) | ||
404 | +{ | ||
405 | + CUDAState *s = &cuda_state; | ||
406 | + uint8_t data[16]; | ||
407 | + | ||
408 | + memcpy(data + 1, buf, len); | ||
409 | + data[0] = ADB_PACKET; | ||
410 | + cuda_send_packet_to_host(s, data, len + 1); | ||
411 | +} | ||
412 | + | ||
413 | +static void cuda_receive_packet(CUDAState *s, | ||
414 | + const uint8_t *data, int len) | ||
415 | +{ | ||
416 | + uint8_t obuf[16]; | ||
417 | + int ti; | ||
418 | + | ||
419 | + switch(data[0]) { | ||
420 | + case CUDA_AUTOPOLL: | ||
421 | + s->autopoll = data[1]; | ||
422 | + obuf[0] = CUDA_PACKET; | ||
423 | + obuf[1] = data[1]; | ||
424 | + cuda_send_packet_to_host(s, obuf, 2); | ||
425 | + break; | ||
426 | + case CUDA_GET_TIME: | ||
427 | + /* XXX: add time support ? */ | ||
428 | + ti = 0; | ||
429 | + obuf[0] = CUDA_PACKET; | ||
430 | + obuf[1] = 0; | ||
431 | + obuf[2] = 0; | ||
432 | + obuf[3] = ti >> 24; | ||
433 | + obuf[4] = ti >> 16; | ||
434 | + obuf[5] = ti >> 8; | ||
435 | + obuf[6] = ti; | ||
436 | + cuda_send_packet_to_host(s, obuf, 7); | ||
437 | + break; | ||
438 | + case CUDA_SET_TIME: | ||
439 | + case CUDA_FILE_SERVER_FLAG: | ||
440 | + case CUDA_SET_DEVICE_LIST: | ||
441 | + case CUDA_SET_AUTO_RATE: | ||
442 | + case CUDA_SET_POWER_MESSAGES: | ||
443 | + obuf[0] = CUDA_PACKET; | ||
444 | + obuf[1] = 0; | ||
445 | + cuda_send_packet_to_host(s, obuf, 2); | ||
446 | + break; | ||
447 | + default: | ||
448 | + break; | ||
449 | + } | ||
450 | +} | ||
451 | + | ||
452 | +static void cuda_receive_packet_from_host(CUDAState *s, | ||
453 | + const uint8_t *data, int len) | ||
454 | +{ | ||
455 | + switch(data[0]) { | ||
456 | + case ADB_PACKET: | ||
457 | + adb_receive_packet(&adb_bus, data + 1, len - 1); | ||
458 | + break; | ||
459 | + case CUDA_PACKET: | ||
460 | + cuda_receive_packet(s, data + 1, len - 1); | ||
461 | + break; | ||
462 | + } | ||
463 | +} | ||
464 | + | ||
465 | +static void cuda_writew (void *opaque, target_phys_addr_t addr, uint32_t value) | ||
466 | +{ | ||
467 | +} | ||
468 | + | ||
469 | +static void cuda_writel (void *opaque, target_phys_addr_t addr, uint32_t value) | ||
470 | +{ | ||
471 | +} | ||
472 | + | ||
473 | +static uint32_t cuda_readw (void *opaque, target_phys_addr_t addr) | ||
474 | +{ | ||
475 | + return 0; | ||
476 | +} | ||
477 | + | ||
478 | +static uint32_t cuda_readl (void *opaque, target_phys_addr_t addr) | ||
479 | +{ | ||
480 | + return 0; | ||
481 | +} | ||
482 | + | ||
483 | +static CPUWriteMemoryFunc *cuda_write[] = { | ||
484 | + &cuda_writeb, | ||
485 | + &cuda_writew, | ||
486 | + &cuda_writel, | ||
487 | +}; | ||
488 | + | ||
489 | +static CPUReadMemoryFunc *cuda_read[] = { | ||
490 | + &cuda_readb, | ||
491 | + &cuda_readw, | ||
492 | + &cuda_readl, | ||
493 | +}; | ||
494 | + | ||
495 | +int cuda_init(void) | ||
496 | +{ | ||
497 | + CUDAState *s = &cuda_state; | ||
498 | + int cuda_mem_index; | ||
499 | + | ||
500 | + s->timers[0].latch = 0x10000; | ||
501 | + set_counter(&s->timers[0], 0xffff); | ||
502 | + s->timers[0].timer = qemu_new_timer(vm_clock, cuda_timer1, s); | ||
503 | + s->timers[1].latch = 0x10000; | ||
504 | + set_counter(&s->timers[1], 0xffff); | ||
505 | + cuda_mem_index = cpu_register_io_memory(0, cuda_read, cuda_write, s); | ||
506 | + return cuda_mem_index; | ||
507 | +} |
hw/ppc_chrp.c
@@ -26,6 +26,86 @@ | @@ -26,6 +26,86 @@ | ||
26 | #define BIOS_FILENAME "ppc_rom.bin" | 26 | #define BIOS_FILENAME "ppc_rom.bin" |
27 | #define NVRAM_SIZE 0x2000 | 27 | #define NVRAM_SIZE 0x2000 |
28 | 28 | ||
29 | +/* MacIO devices (mapped inside the MacIO address space): CUDA, DBDMA, | ||
30 | + NVRAM (not implemented). */ | ||
31 | + | ||
32 | +static int dbdma_mem_index; | ||
33 | +static int cuda_mem_index; | ||
34 | + | ||
35 | +/* DBDMA: currently no op - should suffice right now */ | ||
36 | + | ||
37 | +static void dbdma_writeb (void *opaque, target_phys_addr_t addr, uint32_t value) | ||
38 | +{ | ||
39 | +} | ||
40 | + | ||
41 | +static void dbdma_writew (void *opaque, target_phys_addr_t addr, uint32_t value) | ||
42 | +{ | ||
43 | +} | ||
44 | + | ||
45 | +static void dbdma_writel (void *opaque, target_phys_addr_t addr, uint32_t value) | ||
46 | +{ | ||
47 | +} | ||
48 | + | ||
49 | +static uint32_t dbdma_readb (void *opaque, target_phys_addr_t addr) | ||
50 | +{ | ||
51 | + return 0; | ||
52 | +} | ||
53 | + | ||
54 | +static uint32_t dbdma_readw (void *opaque, target_phys_addr_t addr) | ||
55 | +{ | ||
56 | + return 0; | ||
57 | +} | ||
58 | + | ||
59 | +static uint32_t dbdma_readl (void *opaque, target_phys_addr_t addr) | ||
60 | +{ | ||
61 | + return 0; | ||
62 | +} | ||
63 | + | ||
64 | +static CPUWriteMemoryFunc *dbdma_write[] = { | ||
65 | + &dbdma_writeb, | ||
66 | + &dbdma_writew, | ||
67 | + &dbdma_writel, | ||
68 | +}; | ||
69 | + | ||
70 | +static CPUReadMemoryFunc *dbdma_read[] = { | ||
71 | + &dbdma_readb, | ||
72 | + &dbdma_readw, | ||
73 | + &dbdma_readl, | ||
74 | +}; | ||
75 | + | ||
76 | +static void macio_map(PCIDevice *pci_dev, int region_num, | ||
77 | + uint32_t addr, uint32_t size, int type) | ||
78 | +{ | ||
79 | + cpu_register_physical_memory(addr + 0x08000, 0x1000, dbdma_mem_index); | ||
80 | + cpu_register_physical_memory(addr + 0x16000, 0x2000, cuda_mem_index); | ||
81 | +} | ||
82 | + | ||
83 | +static void macio_init(void) | ||
84 | +{ | ||
85 | + PCIDevice *d; | ||
86 | + | ||
87 | + d = pci_register_device("macio", sizeof(PCIDevice), | ||
88 | + 0, -1, | ||
89 | + NULL, NULL); | ||
90 | + /* Note: this code is strongly inspirated from the corresponding code | ||
91 | + in PearPC */ | ||
92 | + d->config[0x00] = 0x6b; // vendor_id | ||
93 | + d->config[0x01] = 0x10; | ||
94 | + d->config[0x02] = 0x17; | ||
95 | + d->config[0x03] = 0x00; | ||
96 | + | ||
97 | + d->config[0x0a] = 0x00; // class_sub = pci2pci | ||
98 | + d->config[0x0b] = 0xff; // class_base = bridge | ||
99 | + d->config[0x0e] = 0x00; // header_type | ||
100 | + | ||
101 | + d->config[0x3d] = 0x01; // interrupt on pin 1 | ||
102 | + | ||
103 | + dbdma_mem_index = cpu_register_io_memory(0, dbdma_read, dbdma_write, NULL); | ||
104 | + | ||
105 | + pci_register_io_region(d, 0, 0x80000, | ||
106 | + PCI_ADDRESS_SPACE_MEM, macio_map); | ||
107 | +} | ||
108 | + | ||
29 | /* PowerPC PREP hardware initialisation */ | 109 | /* PowerPC PREP hardware initialisation */ |
30 | void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, | 110 | void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, |
31 | DisplayState *ds, const char **fd_filename, int snapshot, | 111 | DisplayState *ds, const char **fd_filename, int snapshot, |
@@ -86,7 +166,13 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, | @@ -86,7 +166,13 @@ void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, | ||
86 | 166 | ||
87 | pci_ide_init(bs_table); | 167 | pci_ide_init(bs_table); |
88 | 168 | ||
89 | - kbd_init(); | 169 | + /* cuda also initialize ADB */ |
170 | + cuda_mem_index = cuda_init(); | ||
171 | + | ||
172 | + adb_kbd_init(&adb_bus); | ||
173 | + adb_mouse_init(&adb_bus); | ||
174 | + | ||
175 | + macio_init(); | ||
90 | 176 | ||
91 | nvram = m48t59_init(8, 0x0074, NVRAM_SIZE); | 177 | nvram = m48t59_init(8, 0x0074, NVRAM_SIZE); |
92 | 178 |