]> git.proxmox.com Git - qemu.git/blame - hw/slavio_serial.c
more correct display functions
[qemu.git] / hw / slavio_serial.c
CommitLineData
e80cfcfc
FB
1/*
2 * QEMU Sparc SLAVIO serial port emulation
3 *
8be1f5c8 4 * Copyright (c) 2003-2005 Fabrice Bellard
e80cfcfc
FB
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"
8be1f5c8 25/* debug serial */
e80cfcfc
FB
26//#define DEBUG_SERIAL
27
28/* debug keyboard */
29//#define DEBUG_KBD
30
8be1f5c8 31/* debug mouse */
e80cfcfc
FB
32//#define DEBUG_MOUSE
33
34/*
35 * This is the serial port, mouse and keyboard part of chip STP2001
36 * (Slave I/O), also produced as NCR89C105. See
37 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
38 *
39 * The serial ports implement full AMD AM8530 or Zilog Z8530 chips,
40 * mouse and keyboard ports don't implement all functions and they are
41 * only asynchronous. There is no DMA.
42 *
43 */
44
8be1f5c8
FB
45#ifdef DEBUG_SERIAL
46#define SER_DPRINTF(fmt, args...) \
47do { printf("SER: " fmt , ##args); } while (0)
ba3c64fb
FB
48#define pic_set_irq(irq, level) \
49do { printf("SER: set_irq(%d): %d\n", (irq), (level)); pic_set_irq((irq),(level));} while (0)
8be1f5c8
FB
50#else
51#define SER_DPRINTF(fmt, args...)
52#endif
53#ifdef DEBUG_KBD
54#define KBD_DPRINTF(fmt, args...) \
55do { printf("KBD: " fmt , ##args); } while (0)
56#else
57#define KBD_DPRINTF(fmt, args...)
58#endif
59#ifdef DEBUG_MOUSE
60#define MS_DPRINTF(fmt, args...) \
61do { printf("SER: " fmt , ##args); } while (0)
62#else
63#define MS_DPRINTF(fmt, args...)
64#endif
65
66typedef enum {
67 chn_a, chn_b,
68} chn_id_t;
69
70typedef enum {
71 ser, kbd, mouse,
72} chn_type_t;
73
74#define KBD_QUEUE_SIZE 256
75
76typedef struct {
77 uint8_t data[KBD_QUEUE_SIZE];
78 int rptr, wptr, count;
79} KBDQueue;
80
e80cfcfc
FB
81typedef struct ChannelState {
82 int irq;
83 int reg;
84 int rxint, txint;
8be1f5c8
FB
85 chn_id_t chn; // this channel, A (base+4) or B (base+0)
86 chn_type_t type;
87 struct ChannelState *otherchn;
e80cfcfc 88 uint8_t rx, tx, wregs[16], rregs[16];
8be1f5c8 89 KBDQueue queue;
e80cfcfc
FB
90 CharDriverState *chr;
91} ChannelState;
92
93struct SerialState {
94 struct ChannelState chn[2];
95};
96
97#define SERIAL_MAXADDR 7
98
8be1f5c8
FB
99static void handle_kbd_command(ChannelState *s, int val);
100static int serial_can_receive(void *opaque);
101static void serial_receive_byte(ChannelState *s, int ch);
102
103static void put_queue(void *opaque, int b)
104{
105 ChannelState *s = opaque;
106 KBDQueue *q = &s->queue;
107
108 KBD_DPRINTF("put: 0x%02x\n", b);
109 if (q->count >= KBD_QUEUE_SIZE)
110 return;
111 q->data[q->wptr] = b;
112 if (++q->wptr == KBD_QUEUE_SIZE)
113 q->wptr = 0;
114 q->count++;
115 serial_receive_byte(s, 0);
116}
117
118static uint32_t get_queue(void *opaque)
119{
120 ChannelState *s = opaque;
121 KBDQueue *q = &s->queue;
122 int val;
123
124 if (q->count == 0) {
125 return 0;
126 } else {
127 val = q->data[q->rptr];
128 if (++q->rptr == KBD_QUEUE_SIZE)
129 q->rptr = 0;
130 q->count--;
131 }
132 KBD_DPRINTF("get 0x%02x\n", val);
133 if (q->count > 0)
134 serial_receive_byte(s, 0);
135 return val;
136}
137
e80cfcfc
FB
138static void slavio_serial_update_irq(ChannelState *s)
139{
140 if ((s->wregs[1] & 1) && // interrupts enabled
141 (((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending
142 ((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) &&
143 s->rxint == 1) || // rx ints enabled, pending
144 ((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p
145 pic_set_irq(s->irq, 1);
146 } else {
147 pic_set_irq(s->irq, 0);
148 }
149}
150
151static void slavio_serial_reset_chn(ChannelState *s)
152{
153 int i;
154
155 s->reg = 0;
156 for (i = 0; i < SERIAL_MAXADDR; i++) {
157 s->rregs[i] = 0;
158 s->wregs[i] = 0;
159 }
160 s->wregs[4] = 4;
161 s->wregs[9] = 0xc0;
162 s->wregs[11] = 8;
163 s->wregs[14] = 0x30;
164 s->wregs[15] = 0xf8;
165 s->rregs[0] = 0x44;
166 s->rregs[1] = 6;
167
168 s->rx = s->tx = 0;
169 s->rxint = s->txint = 0;
170}
171
172static void slavio_serial_reset(void *opaque)
173{
174 SerialState *s = opaque;
175 slavio_serial_reset_chn(&s->chn[0]);
176 slavio_serial_reset_chn(&s->chn[1]);
177}
178
ba3c64fb
FB
179static inline void clr_rxint(ChannelState *s)
180{
181 s->rxint = 0;
182 if (s->chn == 0)
183 s->rregs[3] &= ~0x20;
184 else {
185 s->otherchn->rregs[3] &= ~4;
186 }
187 slavio_serial_update_irq(s);
188}
189
190static inline void set_rxint(ChannelState *s)
191{
192 s->rxint = 1;
193 if (s->chn == 0)
194 s->rregs[3] |= 0x20;
195 else {
196 s->otherchn->rregs[3] |= 4;
197 }
198 slavio_serial_update_irq(s);
199}
200
201static inline void clr_txint(ChannelState *s)
202{
203 s->txint = 0;
204 if (s->chn == 0)
205 s->rregs[3] &= ~0x10;
206 else {
207 s->otherchn->rregs[3] &= ~2;
208 }
209 slavio_serial_update_irq(s);
210}
211
212static inline void set_txint(ChannelState *s)
213{
214 s->txint = 1;
215 if (s->chn == 0)
216 s->rregs[3] |= 0x10;
217 else {
218 s->otherchn->rregs[3] |= 2;
219 }
220 slavio_serial_update_irq(s);
221}
222
3a5c3138 223static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
e80cfcfc
FB
224{
225 SerialState *ser = opaque;
226 ChannelState *s;
227 uint32_t saddr;
228 int newreg, channel;
229
230 val &= 0xff;
231 saddr = (addr & 3) >> 1;
232 channel = (addr & SERIAL_MAXADDR) >> 2;
233 s = &ser->chn[channel];
234 switch (saddr) {
235 case 0:
8be1f5c8 236 SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, val & 0xff);
e80cfcfc
FB
237 newreg = 0;
238 switch (s->reg) {
239 case 0:
240 newreg = val & 7;
241 val &= 0x38;
242 switch (val) {
243 case 8:
f69a8695 244 newreg |= 0x8;
e80cfcfc
FB
245 break;
246 case 0x20:
ba3c64fb 247 clr_rxint(s);
e80cfcfc
FB
248 break;
249 case 0x28:
ba3c64fb
FB
250 clr_txint(s);
251 break;
252 case 0x38:
253 clr_rxint(s);
254 clr_txint(s);
e80cfcfc
FB
255 break;
256 default:
257 break;
258 }
259 break;
260 case 1 ... 8:
261 case 10 ... 15:
262 s->wregs[s->reg] = val;
263 break;
264 case 9:
265 switch (val & 0xc0) {
266 case 0:
267 default:
268 break;
269 case 0x40:
270 slavio_serial_reset_chn(&ser->chn[1]);
271 return;
272 case 0x80:
273 slavio_serial_reset_chn(&ser->chn[0]);
274 return;
275 case 0xc0:
276 slavio_serial_reset(ser);
277 return;
278 }
279 break;
280 default:
281 break;
282 }
283 if (s->reg == 0)
284 s->reg = newreg;
285 else
286 s->reg = 0;
287 break;
288 case 1:
8be1f5c8 289 SER_DPRINTF("Write channel %c, ch %d\n", channel? 'b' : 'a', val);
e80cfcfc
FB
290 if (s->wregs[5] & 8) { // tx enabled
291 s->tx = val;
292 if (s->chr)
293 qemu_chr_write(s->chr, &s->tx, 1);
8be1f5c8
FB
294 else if (s->type == kbd) {
295 handle_kbd_command(s, val);
296 }
e80cfcfc 297 s->txint = 1;
f69a8695
FB
298 s->rregs[0] |= 4; // Tx buffer empty
299 s->rregs[1] |= 1; // All sent
ba3c64fb 300 set_txint(s);
8be1f5c8 301 slavio_serial_update_irq(s);
e80cfcfc
FB
302 }
303 break;
304 default:
305 break;
306 }
307}
308
3a5c3138 309static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr)
e80cfcfc
FB
310{
311 SerialState *ser = opaque;
312 ChannelState *s;
313 uint32_t saddr;
314 uint32_t ret;
315 int channel;
316
317 saddr = (addr & 3) >> 1;
318 channel = (addr & SERIAL_MAXADDR) >> 2;
319 s = &ser->chn[channel];
320 switch (saddr) {
321 case 0:
8be1f5c8 322 SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, s->rregs[s->reg]);
e80cfcfc
FB
323 ret = s->rregs[s->reg];
324 s->reg = 0;
325 return ret;
326 case 1:
327 s->rregs[0] &= ~1;
ba3c64fb 328 clr_rxint(s);
8be1f5c8
FB
329 if (s->type == kbd)
330 ret = get_queue(s);
331 else
332 ret = s->rx;
f69a8695 333 SER_DPRINTF("Read channel %c, ch %d\n", channel? 'b' : 'a', ret);
8be1f5c8 334 return ret;
e80cfcfc
FB
335 default:
336 break;
337 }
338 return 0;
339}
340
341static int serial_can_receive(void *opaque)
342{
343 ChannelState *s = opaque;
344 if (((s->wregs[3] & 1) == 0) // Rx not enabled
345 || ((s->rregs[0] & 1) == 1)) // char already available
346 return 0;
347 else
348 return 1;
349}
350
351static void serial_receive_byte(ChannelState *s, int ch)
352{
ba3c64fb 353 SER_DPRINTF("put ch %d\n", ch);
e80cfcfc
FB
354 s->rregs[0] |= 1;
355 s->rx = ch;
ba3c64fb 356 set_rxint(s);
e80cfcfc
FB
357}
358
359static void serial_receive_break(ChannelState *s)
360{
361 s->rregs[0] |= 0x80;
362 slavio_serial_update_irq(s);
363}
364
365static void serial_receive1(void *opaque, const uint8_t *buf, int size)
366{
367 ChannelState *s = opaque;
368 serial_receive_byte(s, buf[0]);
369}
370
371static void serial_event(void *opaque, int event)
372{
373 ChannelState *s = opaque;
374 if (event == CHR_EVENT_BREAK)
375 serial_receive_break(s);
376}
377
378static CPUReadMemoryFunc *slavio_serial_mem_read[3] = {
379 slavio_serial_mem_readb,
380 slavio_serial_mem_readb,
381 slavio_serial_mem_readb,
382};
383
384static CPUWriteMemoryFunc *slavio_serial_mem_write[3] = {
385 slavio_serial_mem_writeb,
386 slavio_serial_mem_writeb,
387 slavio_serial_mem_writeb,
388};
389
390static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s)
391{
392 qemu_put_be32s(f, &s->irq);
393 qemu_put_be32s(f, &s->reg);
394 qemu_put_be32s(f, &s->rxint);
395 qemu_put_be32s(f, &s->txint);
396 qemu_put_8s(f, &s->rx);
397 qemu_put_8s(f, &s->tx);
398 qemu_put_buffer(f, s->wregs, 16);
399 qemu_put_buffer(f, s->rregs, 16);
400}
401
402static void slavio_serial_save(QEMUFile *f, void *opaque)
403{
404 SerialState *s = opaque;
405
406 slavio_serial_save_chn(f, &s->chn[0]);
407 slavio_serial_save_chn(f, &s->chn[1]);
408}
409
410static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id)
411{
412 if (version_id != 1)
413 return -EINVAL;
414
415 qemu_get_be32s(f, &s->irq);
416 qemu_get_be32s(f, &s->reg);
417 qemu_get_be32s(f, &s->rxint);
418 qemu_get_be32s(f, &s->txint);
419 qemu_get_8s(f, &s->rx);
420 qemu_get_8s(f, &s->tx);
421 qemu_get_buffer(f, s->wregs, 16);
422 qemu_get_buffer(f, s->rregs, 16);
423 return 0;
424}
425
426static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id)
427{
428 SerialState *s = opaque;
429 int ret;
430
431 ret = slavio_serial_load_chn(f, &s->chn[0], version_id);
432 if (ret != 0)
433 return ret;
434 ret = slavio_serial_load_chn(f, &s->chn[1], version_id);
435 return ret;
436
437}
438
439SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2)
440{
8be1f5c8 441 int slavio_serial_io_memory, i;
e80cfcfc
FB
442 SerialState *s;
443
444 s = qemu_mallocz(sizeof(SerialState));
445 if (!s)
446 return NULL;
e80cfcfc
FB
447
448 slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s);
449 cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory);
450
8be1f5c8
FB
451 s->chn[0].chr = chr1;
452 s->chn[1].chr = chr2;
453
454 for (i = 0; i < 2; i++) {
455 s->chn[i].irq = irq;
456 s->chn[i].chn = 1 - i;
457 s->chn[i].type = ser;
458 if (s->chn[i].chr) {
459 qemu_chr_add_read_handler(s->chn[i].chr, serial_can_receive, serial_receive1, &s->chn[i]);
460 qemu_chr_add_event_handler(s->chn[i].chr, serial_event);
461 }
e80cfcfc 462 }
8be1f5c8
FB
463 s->chn[0].otherchn = &s->chn[1];
464 s->chn[1].otherchn = &s->chn[0];
e80cfcfc
FB
465 register_savevm("slavio_serial", base, 1, slavio_serial_save, slavio_serial_load, s);
466 qemu_register_reset(slavio_serial_reset, s);
467 slavio_serial_reset(s);
468 return s;
469}
470
8be1f5c8
FB
471static const uint8_t keycodes[128] = {
472 127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53,
473 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78,
474 79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103,
475 104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12,
476 14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112,
477 113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0,
478 90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66,
479 0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67,
480};
481
e80cfcfc
FB
482static void sunkbd_event(void *opaque, int ch)
483{
484 ChannelState *s = opaque;
8be1f5c8
FB
485 int release = ch & 0x80;
486
487 ch = keycodes[ch & 0x7f];
488 KBD_DPRINTF("Keycode %d (%s)\n", ch, release? "release" : "press");
489 put_queue(s, ch | release);
490}
491
492static void handle_kbd_command(ChannelState *s, int val)
493{
494 KBD_DPRINTF("Command %d\n", val);
495 switch (val) {
496 case 1: // Reset, return type code
8be1f5c8
FB
497 put_queue(s, 0xff);
498 put_queue(s, 5); // Type 5
499 break;
500 case 7: // Query layout
501 put_queue(s, 0xfe);
502 put_queue(s, 0x20); // XXX, layout?
503 break;
504 default:
505 break;
506 }
e80cfcfc
FB
507}
508
509static void sunmouse_event(void *opaque,
510 int dx, int dy, int dz, int buttons_state)
511{
512 ChannelState *s = opaque;
513 int ch;
514
515 // XXX
516 ch = 0x42;
517 serial_receive_byte(s, ch);
518}
519
520void slavio_serial_ms_kbd_init(int base, int irq)
521{
8be1f5c8 522 int slavio_serial_io_memory, i;
e80cfcfc
FB
523 SerialState *s;
524
525 s = qemu_mallocz(sizeof(SerialState));
526 if (!s)
527 return;
8be1f5c8
FB
528 for (i = 0; i < 2; i++) {
529 s->chn[i].irq = irq;
530 s->chn[i].chn = 1 - i;
531 s->chn[i].chr = NULL;
532 }
533 s->chn[0].otherchn = &s->chn[1];
534 s->chn[1].otherchn = &s->chn[0];
535 s->chn[0].type = mouse;
536 s->chn[1].type = kbd;
e80cfcfc
FB
537
538 slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s);
539 cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory);
540
ffcdb539 541 qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0);
8be1f5c8 542 qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
e80cfcfc
FB
543 qemu_register_reset(slavio_serial_reset, s);
544 slavio_serial_reset(s);
545}