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 | ... | ... |