Commit 8be1f5c889fa39571f9dad766497b7bdd56e9d6d
1 parent
d827220b
keyboard support (Blue Swirl)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1346 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
166 additions
and
25 deletions
hw/slavio_serial.c
| 1 | 1 | /* |
| 2 | 2 | * QEMU Sparc SLAVIO serial port emulation |
| 3 | 3 | * |
| 4 | - * Copyright (c) 2003-2004 Fabrice Bellard | |
| 4 | + * Copyright (c) 2003-2005 Fabrice Bellard | |
| 5 | 5 | * |
| 6 | 6 | * Permission is hereby granted, free of charge, to any person obtaining a copy |
| 7 | 7 | * of this software and associated documentation files (the "Software"), to deal |
| ... | ... | @@ -22,13 +22,13 @@ |
| 22 | 22 | * THE SOFTWARE. |
| 23 | 23 | */ |
| 24 | 24 | #include "vl.h" |
| 25 | - | |
| 25 | +/* debug serial */ | |
| 26 | 26 | //#define DEBUG_SERIAL |
| 27 | 27 | |
| 28 | 28 | /* debug keyboard */ |
| 29 | 29 | //#define DEBUG_KBD |
| 30 | 30 | |
| 31 | -/* debug keyboard : only mouse */ | |
| 31 | +/* debug mouse */ | |
| 32 | 32 | //#define DEBUG_MOUSE |
| 33 | 33 | |
| 34 | 34 | /* |
| ... | ... | @@ -42,11 +42,49 @@ |
| 42 | 42 | * |
| 43 | 43 | */ |
| 44 | 44 | |
| 45 | +#ifdef DEBUG_SERIAL | |
| 46 | +#define SER_DPRINTF(fmt, args...) \ | |
| 47 | +do { printf("SER: " fmt , ##args); } while (0) | |
| 48 | +#else | |
| 49 | +#define SER_DPRINTF(fmt, args...) | |
| 50 | +#endif | |
| 51 | +#ifdef DEBUG_KBD | |
| 52 | +#define KBD_DPRINTF(fmt, args...) \ | |
| 53 | +do { printf("KBD: " fmt , ##args); } while (0) | |
| 54 | +#else | |
| 55 | +#define KBD_DPRINTF(fmt, args...) | |
| 56 | +#endif | |
| 57 | +#ifdef DEBUG_MOUSE | |
| 58 | +#define MS_DPRINTF(fmt, args...) \ | |
| 59 | +do { printf("SER: " fmt , ##args); } while (0) | |
| 60 | +#else | |
| 61 | +#define MS_DPRINTF(fmt, args...) | |
| 62 | +#endif | |
| 63 | + | |
| 64 | +typedef enum { | |
| 65 | + chn_a, chn_b, | |
| 66 | +} chn_id_t; | |
| 67 | + | |
| 68 | +typedef enum { | |
| 69 | + ser, kbd, mouse, | |
| 70 | +} chn_type_t; | |
| 71 | + | |
| 72 | +#define KBD_QUEUE_SIZE 256 | |
| 73 | + | |
| 74 | +typedef struct { | |
| 75 | + uint8_t data[KBD_QUEUE_SIZE]; | |
| 76 | + int rptr, wptr, count; | |
| 77 | +} KBDQueue; | |
| 78 | + | |
| 45 | 79 | typedef struct ChannelState { |
| 46 | 80 | int irq; |
| 47 | 81 | int reg; |
| 48 | 82 | int rxint, txint; |
| 83 | + chn_id_t chn; // this channel, A (base+4) or B (base+0) | |
| 84 | + chn_type_t type; | |
| 85 | + struct ChannelState *otherchn; | |
| 49 | 86 | uint8_t rx, tx, wregs[16], rregs[16]; |
| 87 | + KBDQueue queue; | |
| 50 | 88 | CharDriverState *chr; |
| 51 | 89 | } ChannelState; |
| 52 | 90 | |
| ... | ... | @@ -56,6 +94,45 @@ struct SerialState { |
| 56 | 94 | |
| 57 | 95 | #define SERIAL_MAXADDR 7 |
| 58 | 96 | |
| 97 | +static void handle_kbd_command(ChannelState *s, int val); | |
| 98 | +static int serial_can_receive(void *opaque); | |
| 99 | +static void serial_receive_byte(ChannelState *s, int ch); | |
| 100 | + | |
| 101 | +static void put_queue(void *opaque, int b) | |
| 102 | +{ | |
| 103 | + ChannelState *s = opaque; | |
| 104 | + KBDQueue *q = &s->queue; | |
| 105 | + | |
| 106 | + KBD_DPRINTF("put: 0x%02x\n", b); | |
| 107 | + if (q->count >= KBD_QUEUE_SIZE) | |
| 108 | + return; | |
| 109 | + q->data[q->wptr] = b; | |
| 110 | + if (++q->wptr == KBD_QUEUE_SIZE) | |
| 111 | + q->wptr = 0; | |
| 112 | + q->count++; | |
| 113 | + serial_receive_byte(s, 0); | |
| 114 | +} | |
| 115 | + | |
| 116 | +static uint32_t get_queue(void *opaque) | |
| 117 | +{ | |
| 118 | + ChannelState *s = opaque; | |
| 119 | + KBDQueue *q = &s->queue; | |
| 120 | + int val; | |
| 121 | + | |
| 122 | + if (q->count == 0) { | |
| 123 | + return 0; | |
| 124 | + } else { | |
| 125 | + val = q->data[q->rptr]; | |
| 126 | + if (++q->rptr == KBD_QUEUE_SIZE) | |
| 127 | + q->rptr = 0; | |
| 128 | + q->count--; | |
| 129 | + } | |
| 130 | + KBD_DPRINTF("get 0x%02x\n", val); | |
| 131 | + if (q->count > 0) | |
| 132 | + serial_receive_byte(s, 0); | |
| 133 | + return val; | |
| 134 | +} | |
| 135 | + | |
| 59 | 136 | static void slavio_serial_update_irq(ChannelState *s) |
| 60 | 137 | { |
| 61 | 138 | if ((s->wregs[1] & 1) && // interrupts enabled |
| ... | ... | @@ -110,6 +187,7 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint |
| 110 | 187 | s = &ser->chn[channel]; |
| 111 | 188 | switch (saddr) { |
| 112 | 189 | case 0: |
| 190 | + SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, val & 0xff); | |
| 113 | 191 | newreg = 0; |
| 114 | 192 | switch (s->reg) { |
| 115 | 193 | case 0: |
| ... | ... | @@ -158,11 +236,23 @@ static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint |
| 158 | 236 | s->reg = 0; |
| 159 | 237 | break; |
| 160 | 238 | case 1: |
| 239 | + SER_DPRINTF("Write channel %c, ch %d\n", channel? 'b' : 'a', val); | |
| 161 | 240 | if (s->wregs[5] & 8) { // tx enabled |
| 162 | 241 | s->tx = val; |
| 163 | 242 | if (s->chr) |
| 164 | 243 | qemu_chr_write(s->chr, &s->tx, 1); |
| 244 | + else if (s->type == kbd) { | |
| 245 | + handle_kbd_command(s, val); | |
| 246 | + } | |
| 165 | 247 | s->txint = 1; |
| 248 | + s->rregs[0] |= 4; | |
| 249 | + // Interrupts reported only on channel A | |
| 250 | + if (s->chn == 0) | |
| 251 | + s->rregs[3] |= 0x10; | |
| 252 | + else { | |
| 253 | + s->otherchn->rregs[3] |= 2; | |
| 254 | + } | |
| 255 | + slavio_serial_update_irq(s); | |
| 166 | 256 | } |
| 167 | 257 | break; |
| 168 | 258 | default: |
| ... | ... | @@ -183,12 +273,18 @@ static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr) |
| 183 | 273 | s = &ser->chn[channel]; |
| 184 | 274 | switch (saddr) { |
| 185 | 275 | case 0: |
| 276 | + SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, s->rregs[s->reg]); | |
| 186 | 277 | ret = s->rregs[s->reg]; |
| 187 | 278 | s->reg = 0; |
| 188 | 279 | return ret; |
| 189 | 280 | case 1: |
| 281 | + SER_DPRINTF("Read channel %c, ch %d\n", channel? 'b' : 'a', s->rx); | |
| 190 | 282 | s->rregs[0] &= ~1; |
| 191 | - return s->rx; | |
| 283 | + if (s->type == kbd) | |
| 284 | + ret = get_queue(s); | |
| 285 | + else | |
| 286 | + ret = s->rx; | |
| 287 | + return ret; | |
| 192 | 288 | default: |
| 193 | 289 | break; |
| 194 | 290 | } |
| ... | ... | @@ -208,6 +304,12 @@ static int serial_can_receive(void *opaque) |
| 208 | 304 | static void serial_receive_byte(ChannelState *s, int ch) |
| 209 | 305 | { |
| 210 | 306 | s->rregs[0] |= 1; |
| 307 | + // Interrupts reported only on channel A | |
| 308 | + if (s->chn == 0) | |
| 309 | + s->rregs[3] |= 0x20; | |
| 310 | + else { | |
| 311 | + s->otherchn->rregs[3] |= 4; | |
| 312 | + } | |
| 211 | 313 | s->rx = ch; |
| 212 | 314 | s->rxint = 1; |
| 213 | 315 | slavio_serial_update_irq(s); |
| ... | ... | @@ -295,39 +397,73 @@ static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id) |
| 295 | 397 | |
| 296 | 398 | SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2) |
| 297 | 399 | { |
| 298 | - int slavio_serial_io_memory; | |
| 400 | + int slavio_serial_io_memory, i; | |
| 299 | 401 | SerialState *s; |
| 300 | 402 | |
| 301 | 403 | s = qemu_mallocz(sizeof(SerialState)); |
| 302 | 404 | if (!s) |
| 303 | 405 | return NULL; |
| 304 | - s->chn[0].irq = irq; | |
| 305 | - s->chn[1].irq = irq; | |
| 306 | - s->chn[0].chr = chr1; | |
| 307 | - s->chn[1].chr = chr2; | |
| 308 | 406 | |
| 309 | 407 | slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s); |
| 310 | 408 | cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory); |
| 311 | 409 | |
| 312 | - if (chr1) { | |
| 313 | - qemu_chr_add_read_handler(chr1, serial_can_receive, serial_receive1, &s->chn[0]); | |
| 314 | - qemu_chr_add_event_handler(chr1, serial_event); | |
| 315 | - } | |
| 316 | - if (chr2) { | |
| 317 | - qemu_chr_add_read_handler(chr2, serial_can_receive, serial_receive1, &s->chn[1]); | |
| 318 | - qemu_chr_add_event_handler(chr2, serial_event); | |
| 410 | + s->chn[0].chr = chr1; | |
| 411 | + s->chn[1].chr = chr2; | |
| 412 | + | |
| 413 | + for (i = 0; i < 2; i++) { | |
| 414 | + s->chn[i].irq = irq; | |
| 415 | + s->chn[i].chn = 1 - i; | |
| 416 | + s->chn[i].type = ser; | |
| 417 | + if (s->chn[i].chr) { | |
| 418 | + qemu_chr_add_read_handler(s->chn[i].chr, serial_can_receive, serial_receive1, &s->chn[i]); | |
| 419 | + qemu_chr_add_event_handler(s->chn[i].chr, serial_event); | |
| 420 | + } | |
| 319 | 421 | } |
| 422 | + s->chn[0].otherchn = &s->chn[1]; | |
| 423 | + s->chn[1].otherchn = &s->chn[0]; | |
| 320 | 424 | register_savevm("slavio_serial", base, 1, slavio_serial_save, slavio_serial_load, s); |
| 321 | 425 | qemu_register_reset(slavio_serial_reset, s); |
| 322 | 426 | slavio_serial_reset(s); |
| 323 | 427 | return s; |
| 324 | 428 | } |
| 325 | 429 | |
| 430 | +static const uint8_t keycodes[128] = { | |
| 431 | + 127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53, | |
| 432 | + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78, | |
| 433 | + 79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103, | |
| 434 | + 104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12, | |
| 435 | + 14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112, | |
| 436 | + 113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0, | |
| 437 | + 90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66, | |
| 438 | + 0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67, | |
| 439 | +}; | |
| 440 | + | |
| 326 | 441 | static void sunkbd_event(void *opaque, int ch) |
| 327 | 442 | { |
| 328 | 443 | ChannelState *s = opaque; |
| 329 | - // XXX: PC -> Sun Type 5 translation? | |
| 330 | - serial_receive_byte(s, ch); | |
| 444 | + int release = ch & 0x80; | |
| 445 | + | |
| 446 | + ch = keycodes[ch & 0x7f]; | |
| 447 | + KBD_DPRINTF("Keycode %d (%s)\n", ch, release? "release" : "press"); | |
| 448 | + put_queue(s, ch | release); | |
| 449 | +} | |
| 450 | + | |
| 451 | +static void handle_kbd_command(ChannelState *s, int val) | |
| 452 | +{ | |
| 453 | + KBD_DPRINTF("Command %d\n", val); | |
| 454 | + switch (val) { | |
| 455 | + case 1: // Reset, return type code | |
| 456 | + put_queue(s, 0xff); | |
| 457 | + put_queue(s, 0xff); | |
| 458 | + put_queue(s, 5); // Type 5 | |
| 459 | + break; | |
| 460 | + case 7: // Query layout | |
| 461 | + put_queue(s, 0xfe); | |
| 462 | + put_queue(s, 0x20); // XXX, layout? | |
| 463 | + break; | |
| 464 | + default: | |
| 465 | + break; | |
| 466 | + } | |
| 331 | 467 | } |
| 332 | 468 | |
| 333 | 469 | static void sunmouse_event(void *opaque, |
| ... | ... | @@ -343,22 +479,27 @@ static void sunmouse_event(void *opaque, |
| 343 | 479 | |
| 344 | 480 | void slavio_serial_ms_kbd_init(int base, int irq) |
| 345 | 481 | { |
| 346 | - int slavio_serial_io_memory; | |
| 482 | + int slavio_serial_io_memory, i; | |
| 347 | 483 | SerialState *s; |
| 348 | 484 | |
| 349 | 485 | s = qemu_mallocz(sizeof(SerialState)); |
| 350 | 486 | if (!s) |
| 351 | 487 | return; |
| 352 | - s->chn[0].irq = irq; | |
| 353 | - s->chn[1].irq = irq; | |
| 354 | - s->chn[0].chr = NULL; | |
| 355 | - s->chn[1].chr = NULL; | |
| 488 | + for (i = 0; i < 2; i++) { | |
| 489 | + s->chn[i].irq = irq; | |
| 490 | + s->chn[i].chn = 1 - i; | |
| 491 | + s->chn[i].chr = NULL; | |
| 492 | + } | |
| 493 | + s->chn[0].otherchn = &s->chn[1]; | |
| 494 | + s->chn[1].otherchn = &s->chn[0]; | |
| 495 | + s->chn[0].type = mouse; | |
| 496 | + s->chn[1].type = kbd; | |
| 356 | 497 | |
| 357 | 498 | slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s); |
| 358 | 499 | cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory); |
| 359 | 500 | |
| 360 | - qemu_add_kbd_event_handler(sunkbd_event, &s->chn[0]); | |
| 361 | - qemu_add_mouse_event_handler(sunmouse_event, &s->chn[1]); | |
| 501 | + qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0]); | |
| 502 | + qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]); | |
| 362 | 503 | qemu_register_reset(slavio_serial_reset, s); |
| 363 | 504 | slavio_serial_reset(s); |
| 364 | 505 | } | ... | ... |