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 | 26 | #define BIOS_FILENAME "ppc_rom.bin" |
27 | 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 | 109 | /* PowerPC PREP hardware initialisation */ |
30 | 110 | void ppc_chrp_init(int ram_size, int vga_ram_size, int boot_device, |
31 | 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 | 166 | |
87 | 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 | 177 | nvram = m48t59_init(8, 0x0074, NVRAM_SIZE); |
92 | 178 | ... | ... |