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