Commit 8be1f5c889fa39571f9dad766497b7bdd56e9d6d

Authored by bellard
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 }
... ...