]> git.proxmox.com Git - qemu.git/blame - hw/slavio_serial.c
Intel Mainstone II (ARM) machine by Armin Kuster.
[qemu.git] / hw / slavio_serial.c
CommitLineData
e80cfcfc
FB
1/*
2 * QEMU Sparc SLAVIO serial port emulation
5fafdf24 3 *
8be1f5c8 4 * Copyright (c) 2003-2005 Fabrice Bellard
5fafdf24 5 *
e80cfcfc
FB
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 */
87ecb68b
PB
24#include "hw.h"
25#include "sun4m.h"
26#include "qemu-char.h"
27#include "console.h"
28
8be1f5c8 29/* debug serial */
e80cfcfc
FB
30//#define DEBUG_SERIAL
31
32/* debug keyboard */
33//#define DEBUG_KBD
34
8be1f5c8 35/* debug mouse */
e80cfcfc
FB
36//#define DEBUG_MOUSE
37
38/*
39 * This is the serial port, mouse and keyboard part of chip STP2001
40 * (Slave I/O), also produced as NCR89C105. See
41 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
5fafdf24 42 *
e80cfcfc
FB
43 * The serial ports implement full AMD AM8530 or Zilog Z8530 chips,
44 * mouse and keyboard ports don't implement all functions and they are
45 * only asynchronous. There is no DMA.
46 *
47 */
48
715748fa
FB
49/*
50 * Modifications:
51 * 2006-Aug-10 Igor Kovalenko : Renamed KBDQueue to SERIOQueue, implemented
52 * serial mouse queue.
53 * Implemented serial mouse protocol.
54 */
55
8be1f5c8
FB
56#ifdef DEBUG_SERIAL
57#define SER_DPRINTF(fmt, args...) \
58do { printf("SER: " fmt , ##args); } while (0)
59#else
60#define SER_DPRINTF(fmt, args...)
61#endif
62#ifdef DEBUG_KBD
63#define KBD_DPRINTF(fmt, args...) \
64do { printf("KBD: " fmt , ##args); } while (0)
65#else
66#define KBD_DPRINTF(fmt, args...)
67#endif
68#ifdef DEBUG_MOUSE
69#define MS_DPRINTF(fmt, args...) \
715748fa 70do { printf("MSC: " fmt , ##args); } while (0)
8be1f5c8
FB
71#else
72#define MS_DPRINTF(fmt, args...)
73#endif
74
75typedef enum {
76 chn_a, chn_b,
77} chn_id_t;
78
35db099d
FB
79#define CHN_C(s) ((s)->chn == chn_b? 'b' : 'a')
80
8be1f5c8
FB
81typedef enum {
82 ser, kbd, mouse,
83} chn_type_t;
84
715748fa 85#define SERIO_QUEUE_SIZE 256
8be1f5c8
FB
86
87typedef struct {
715748fa 88 uint8_t data[SERIO_QUEUE_SIZE];
8be1f5c8 89 int rptr, wptr, count;
715748fa 90} SERIOQueue;
8be1f5c8 91
e80cfcfc 92typedef struct ChannelState {
d537cf6c 93 qemu_irq irq;
e80cfcfc 94 int reg;
e4a89056 95 int rxint, txint, rxint_under_svc, txint_under_svc;
8be1f5c8
FB
96 chn_id_t chn; // this channel, A (base+4) or B (base+0)
97 chn_type_t type;
98 struct ChannelState *otherchn;
e80cfcfc 99 uint8_t rx, tx, wregs[16], rregs[16];
715748fa 100 SERIOQueue queue;
e80cfcfc 101 CharDriverState *chr;
bbbb2f0a 102 int e0_mode, led_mode, caps_lock_mode, num_lock_mode;
e80cfcfc
FB
103} ChannelState;
104
105struct SerialState {
106 struct ChannelState chn[2];
107};
108
109#define SERIAL_MAXADDR 7
5aca8c3b 110#define SERIAL_SIZE (SERIAL_MAXADDR + 1)
e80cfcfc 111
8be1f5c8
FB
112static void handle_kbd_command(ChannelState *s, int val);
113static int serial_can_receive(void *opaque);
114static void serial_receive_byte(ChannelState *s, int ch);
e4a89056 115static inline void set_txint(ChannelState *s);
8be1f5c8 116
67deb562
BS
117static void clear_queue(void *opaque)
118{
119 ChannelState *s = opaque;
120 SERIOQueue *q = &s->queue;
121 q->rptr = q->wptr = q->count = 0;
122}
123
8be1f5c8
FB
124static void put_queue(void *opaque, int b)
125{
126 ChannelState *s = opaque;
715748fa 127 SERIOQueue *q = &s->queue;
8be1f5c8 128
35db099d 129 SER_DPRINTF("channel %c put: 0x%02x\n", CHN_C(s), b);
715748fa 130 if (q->count >= SERIO_QUEUE_SIZE)
8be1f5c8
FB
131 return;
132 q->data[q->wptr] = b;
715748fa 133 if (++q->wptr == SERIO_QUEUE_SIZE)
8be1f5c8
FB
134 q->wptr = 0;
135 q->count++;
136 serial_receive_byte(s, 0);
137}
138
139static uint32_t get_queue(void *opaque)
140{
141 ChannelState *s = opaque;
715748fa 142 SERIOQueue *q = &s->queue;
8be1f5c8 143 int val;
3b46e624 144
8be1f5c8 145 if (q->count == 0) {
f930d07e 146 return 0;
8be1f5c8
FB
147 } else {
148 val = q->data[q->rptr];
715748fa 149 if (++q->rptr == SERIO_QUEUE_SIZE)
8be1f5c8
FB
150 q->rptr = 0;
151 q->count--;
152 }
67deb562 153 SER_DPRINTF("channel %c get 0x%02x\n", CHN_C(s), val);
8be1f5c8 154 if (q->count > 0)
f930d07e 155 serial_receive_byte(s, 0);
8be1f5c8
FB
156 return val;
157}
158
e4a89056 159static int slavio_serial_update_irq_chn(ChannelState *s)
e80cfcfc
FB
160{
161 if ((s->wregs[1] & 1) && // interrupts enabled
f930d07e
BS
162 (((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending
163 ((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) &&
164 s->rxint == 1) || // rx ints enabled, pending
165 ((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p
e4a89056 166 return 1;
e80cfcfc 167 }
e4a89056
FB
168 return 0;
169}
170
171static void slavio_serial_update_irq(ChannelState *s)
172{
173 int irq;
174
175 irq = slavio_serial_update_irq_chn(s);
176 irq |= slavio_serial_update_irq_chn(s->otherchn);
177
d537cf6c
PB
178 SER_DPRINTF("IRQ = %d\n", irq);
179 qemu_set_irq(s->irq, irq);
e80cfcfc
FB
180}
181
182static void slavio_serial_reset_chn(ChannelState *s)
183{
184 int i;
185
186 s->reg = 0;
5aca8c3b 187 for (i = 0; i < SERIAL_SIZE; i++) {
f930d07e
BS
188 s->rregs[i] = 0;
189 s->wregs[i] = 0;
e80cfcfc
FB
190 }
191 s->wregs[4] = 4;
192 s->wregs[9] = 0xc0;
193 s->wregs[11] = 8;
194 s->wregs[14] = 0x30;
195 s->wregs[15] = 0xf8;
196 s->rregs[0] = 0x44;
197 s->rregs[1] = 6;
198
199 s->rx = s->tx = 0;
200 s->rxint = s->txint = 0;
e4a89056 201 s->rxint_under_svc = s->txint_under_svc = 0;
bbbb2f0a 202 s->e0_mode = s->led_mode = s->caps_lock_mode = s->num_lock_mode = 0;
67deb562 203 clear_queue(s);
e80cfcfc
FB
204}
205
206static void slavio_serial_reset(void *opaque)
207{
208 SerialState *s = opaque;
209 slavio_serial_reset_chn(&s->chn[0]);
210 slavio_serial_reset_chn(&s->chn[1]);
211}
212
ba3c64fb
FB
213static inline void clr_rxint(ChannelState *s)
214{
215 s->rxint = 0;
e4a89056 216 s->rxint_under_svc = 0;
67deb562
BS
217 if (s->chn == chn_a) {
218 if (s->wregs[9] & 0x10)
219 s->otherchn->rregs[2] = 0x60;
220 else
221 s->otherchn->rregs[2] = 0x06;
ba3c64fb 222 s->rregs[3] &= ~0x20;
67deb562
BS
223 } else {
224 if (s->wregs[9] & 0x10)
225 s->rregs[2] = 0x60;
226 else
227 s->rregs[2] = 0x06;
ba3c64fb 228 s->otherchn->rregs[3] &= ~4;
67deb562 229 }
e4a89056
FB
230 if (s->txint)
231 set_txint(s);
ba3c64fb
FB
232 slavio_serial_update_irq(s);
233}
234
235static inline void set_rxint(ChannelState *s)
236{
237 s->rxint = 1;
e4a89056
FB
238 if (!s->txint_under_svc) {
239 s->rxint_under_svc = 1;
67deb562
BS
240 if (s->chn == chn_a) {
241 if (s->wregs[9] & 0x10)
242 s->otherchn->rregs[2] = 0x30;
243 else
244 s->otherchn->rregs[2] = 0x0c;
67deb562
BS
245 } else {
246 if (s->wregs[9] & 0x10)
247 s->rregs[2] = 0x20;
248 else
249 s->rregs[2] = 0x04;
67deb562 250 }
ba3c64fb 251 }
b9652ca3
BS
252 if (s->chn == chn_a)
253 s->rregs[3] |= 0x20;
254 else
255 s->otherchn->rregs[3] |= 4;
256 slavio_serial_update_irq(s);
ba3c64fb
FB
257}
258
259static inline void clr_txint(ChannelState *s)
260{
261 s->txint = 0;
e4a89056 262 s->txint_under_svc = 0;
b9652ca3
BS
263 if (s->chn == chn_a) {
264 if (s->wregs[9] & 0x10)
265 s->otherchn->rregs[2] = 0x60;
266 else
267 s->otherchn->rregs[2] = 0x06;
ba3c64fb 268 s->rregs[3] &= ~0x10;
b9652ca3
BS
269 } else {
270 if (s->wregs[9] & 0x10)
271 s->rregs[2] = 0x60;
272 else
273 s->rregs[2] = 0x06;
ba3c64fb 274 s->otherchn->rregs[3] &= ~2;
b9652ca3 275 }
e4a89056
FB
276 if (s->rxint)
277 set_rxint(s);
ba3c64fb
FB
278 slavio_serial_update_irq(s);
279}
280
281static inline void set_txint(ChannelState *s)
282{
283 s->txint = 1;
e4a89056
FB
284 if (!s->rxint_under_svc) {
285 s->txint_under_svc = 1;
b9652ca3
BS
286 if (s->chn == chn_a) {
287 if (s->wregs[9] & 0x10)
288 s->otherchn->rregs[2] = 0x10;
289 else
290 s->otherchn->rregs[2] = 0x08;
291 } else {
292 s->rregs[2] = 0;
293 }
ba3c64fb 294 }
b9652ca3
BS
295 if (s->chn == chn_a)
296 s->rregs[3] |= 0x10;
297 else
298 s->otherchn->rregs[3] |= 2;
299 slavio_serial_update_irq(s);
ba3c64fb
FB
300}
301
35db099d
FB
302static void slavio_serial_update_parameters(ChannelState *s)
303{
304 int speed, parity, data_bits, stop_bits;
305 QEMUSerialSetParams ssp;
306
307 if (!s->chr || s->type != ser)
308 return;
309
310 if (s->wregs[4] & 1) {
311 if (s->wregs[4] & 2)
312 parity = 'E';
313 else
314 parity = 'O';
315 } else {
316 parity = 'N';
317 }
318 if ((s->wregs[4] & 0x0c) == 0x0c)
319 stop_bits = 2;
320 else
321 stop_bits = 1;
322 switch (s->wregs[5] & 0x60) {
323 case 0x00:
324 data_bits = 5;
325 break;
326 case 0x20:
327 data_bits = 7;
328 break;
329 case 0x40:
330 data_bits = 6;
331 break;
332 default:
333 case 0x60:
334 data_bits = 8;
335 break;
336 }
337 speed = 2457600 / ((s->wregs[12] | (s->wregs[13] << 8)) + 2);
338 switch (s->wregs[4] & 0xc0) {
339 case 0x00:
340 break;
341 case 0x40:
342 speed /= 16;
343 break;
344 case 0x80:
345 speed /= 32;
346 break;
347 default:
348 case 0xc0:
349 speed /= 64;
350 break;
351 }
352 ssp.speed = speed;
353 ssp.parity = parity;
354 ssp.data_bits = data_bits;
355 ssp.stop_bits = stop_bits;
356 SER_DPRINTF("channel %c: speed=%d parity=%c data=%d stop=%d\n", CHN_C(s),
357 speed, parity, data_bits, stop_bits);
358 qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
359}
360
3a5c3138 361static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
e80cfcfc 362{
b3ceef24 363 SerialState *serial = opaque;
e80cfcfc
FB
364 ChannelState *s;
365 uint32_t saddr;
366 int newreg, channel;
367
368 val &= 0xff;
369 saddr = (addr & 3) >> 1;
370 channel = (addr & SERIAL_MAXADDR) >> 2;
b3ceef24 371 s = &serial->chn[channel];
e80cfcfc
FB
372 switch (saddr) {
373 case 0:
f930d07e
BS
374 SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, val & 0xff);
375 newreg = 0;
376 switch (s->reg) {
377 case 0:
378 newreg = val & 7;
379 val &= 0x38;
380 switch (val) {
381 case 8:
382 newreg |= 0x8;
383 break;
384 case 0x28:
ba3c64fb 385 clr_txint(s);
f930d07e
BS
386 break;
387 case 0x38:
e4a89056
FB
388 if (s->rxint_under_svc)
389 clr_rxint(s);
390 else if (s->txint_under_svc)
391 clr_txint(s);
f930d07e
BS
392 break;
393 default:
394 break;
395 }
396 break;
35db099d
FB
397 case 1 ... 3:
398 case 6 ... 8:
399 case 10 ... 11:
400 case 14 ... 15:
f930d07e
BS
401 s->wregs[s->reg] = val;
402 break;
35db099d
FB
403 case 4:
404 case 5:
405 case 12:
406 case 13:
f930d07e 407 s->wregs[s->reg] = val;
35db099d 408 slavio_serial_update_parameters(s);
f930d07e
BS
409 break;
410 case 9:
411 switch (val & 0xc0) {
412 case 0:
413 default:
414 break;
415 case 0x40:
416 slavio_serial_reset_chn(&serial->chn[1]);
417 return;
418 case 0x80:
419 slavio_serial_reset_chn(&serial->chn[0]);
420 return;
421 case 0xc0:
422 slavio_serial_reset(serial);
423 return;
424 }
425 break;
426 default:
427 break;
428 }
429 if (s->reg == 0)
430 s->reg = newreg;
431 else
432 s->reg = 0;
433 break;
e80cfcfc 434 case 1:
f930d07e 435 SER_DPRINTF("Write channel %c, ch %d\n", CHN_C(s), val);
96c4f569 436 s->tx = val;
f930d07e
BS
437 if (s->wregs[5] & 8) { // tx enabled
438 if (s->chr)
439 qemu_chr_write(s->chr, &s->tx, 1);
440 else if (s->type == kbd) {
441 handle_kbd_command(s, val);
442 }
443 }
96c4f569
BS
444 s->rregs[0] |= 4; // Tx buffer empty
445 s->rregs[1] |= 1; // All sent
446 set_txint(s);
f930d07e 447 break;
e80cfcfc 448 default:
f930d07e 449 break;
e80cfcfc
FB
450 }
451}
452
3a5c3138 453static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr)
e80cfcfc 454{
b3ceef24 455 SerialState *serial = opaque;
e80cfcfc
FB
456 ChannelState *s;
457 uint32_t saddr;
458 uint32_t ret;
459 int channel;
460
461 saddr = (addr & 3) >> 1;
462 channel = (addr & SERIAL_MAXADDR) >> 2;
b3ceef24 463 s = &serial->chn[channel];
e80cfcfc
FB
464 switch (saddr) {
465 case 0:
f930d07e
BS
466 SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg, s->rregs[s->reg]);
467 ret = s->rregs[s->reg];
468 s->reg = 0;
469 return ret;
e80cfcfc 470 case 1:
f930d07e 471 s->rregs[0] &= ~1;
ba3c64fb 472 clr_rxint(s);
f930d07e
BS
473 if (s->type == kbd || s->type == mouse)
474 ret = get_queue(s);
475 else
476 ret = s->rx;
477 SER_DPRINTF("Read channel %c, ch %d\n", CHN_C(s), ret);
bd9bdce6 478 qemu_chr_accept_input(s->chr);
f930d07e 479 return ret;
e80cfcfc 480 default:
f930d07e 481 break;
e80cfcfc
FB
482 }
483 return 0;
484}
485
486static int serial_can_receive(void *opaque)
487{
488 ChannelState *s = opaque;
e4a89056
FB
489 int ret;
490
e80cfcfc 491 if (((s->wregs[3] & 1) == 0) // Rx not enabled
f930d07e
BS
492 || ((s->rregs[0] & 1) == 1)) // char already available
493 ret = 0;
e80cfcfc 494 else
f930d07e 495 ret = 1;
35db099d 496 //SER_DPRINTF("channel %c can receive %d\n", CHN_C(s), ret);
e4a89056 497 return ret;
e80cfcfc
FB
498}
499
500static void serial_receive_byte(ChannelState *s, int ch)
501{
35db099d 502 SER_DPRINTF("channel %c put ch %d\n", CHN_C(s), ch);
e80cfcfc
FB
503 s->rregs[0] |= 1;
504 s->rx = ch;
ba3c64fb 505 set_rxint(s);
e80cfcfc
FB
506}
507
508static void serial_receive_break(ChannelState *s)
509{
510 s->rregs[0] |= 0x80;
511 slavio_serial_update_irq(s);
512}
513
514static void serial_receive1(void *opaque, const uint8_t *buf, int size)
515{
516 ChannelState *s = opaque;
517 serial_receive_byte(s, buf[0]);
518}
519
520static void serial_event(void *opaque, int event)
521{
522 ChannelState *s = opaque;
523 if (event == CHR_EVENT_BREAK)
524 serial_receive_break(s);
525}
526
527static CPUReadMemoryFunc *slavio_serial_mem_read[3] = {
528 slavio_serial_mem_readb,
529 slavio_serial_mem_readb,
530 slavio_serial_mem_readb,
531};
532
533static CPUWriteMemoryFunc *slavio_serial_mem_write[3] = {
534 slavio_serial_mem_writeb,
535 slavio_serial_mem_writeb,
536 slavio_serial_mem_writeb,
537};
538
539static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s)
540{
d537cf6c
PB
541 int tmp;
542 tmp = 0;
543 qemu_put_be32s(f, &tmp); /* unused, was IRQ. */
e80cfcfc
FB
544 qemu_put_be32s(f, &s->reg);
545 qemu_put_be32s(f, &s->rxint);
546 qemu_put_be32s(f, &s->txint);
e4a89056
FB
547 qemu_put_be32s(f, &s->rxint_under_svc);
548 qemu_put_be32s(f, &s->txint_under_svc);
e80cfcfc
FB
549 qemu_put_8s(f, &s->rx);
550 qemu_put_8s(f, &s->tx);
551 qemu_put_buffer(f, s->wregs, 16);
552 qemu_put_buffer(f, s->rregs, 16);
553}
554
555static void slavio_serial_save(QEMUFile *f, void *opaque)
556{
557 SerialState *s = opaque;
558
559 slavio_serial_save_chn(f, &s->chn[0]);
560 slavio_serial_save_chn(f, &s->chn[1]);
561}
562
563static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id)
564{
d537cf6c
PB
565 int tmp;
566
e4a89056 567 if (version_id > 2)
e80cfcfc
FB
568 return -EINVAL;
569
d537cf6c 570 qemu_get_be32s(f, &tmp); /* unused */
e80cfcfc
FB
571 qemu_get_be32s(f, &s->reg);
572 qemu_get_be32s(f, &s->rxint);
573 qemu_get_be32s(f, &s->txint);
e4a89056
FB
574 if (version_id >= 2) {
575 qemu_get_be32s(f, &s->rxint_under_svc);
576 qemu_get_be32s(f, &s->txint_under_svc);
577 }
e80cfcfc
FB
578 qemu_get_8s(f, &s->rx);
579 qemu_get_8s(f, &s->tx);
580 qemu_get_buffer(f, s->wregs, 16);
581 qemu_get_buffer(f, s->rregs, 16);
582 return 0;
583}
584
585static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id)
586{
587 SerialState *s = opaque;
588 int ret;
589
590 ret = slavio_serial_load_chn(f, &s->chn[0], version_id);
591 if (ret != 0)
f930d07e 592 return ret;
e80cfcfc
FB
593 ret = slavio_serial_load_chn(f, &s->chn[1], version_id);
594 return ret;
595
596}
597
5dcb6b91
BS
598SerialState *slavio_serial_init(target_phys_addr_t base, qemu_irq irq,
599 CharDriverState *chr1, CharDriverState *chr2)
e80cfcfc 600{
8be1f5c8 601 int slavio_serial_io_memory, i;
e80cfcfc
FB
602 SerialState *s;
603
604 s = qemu_mallocz(sizeof(SerialState));
605 if (!s)
606 return NULL;
e80cfcfc
FB
607
608 slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s);
5aca8c3b 609 cpu_register_physical_memory(base, SERIAL_SIZE, slavio_serial_io_memory);
e80cfcfc 610
8be1f5c8
FB
611 s->chn[0].chr = chr1;
612 s->chn[1].chr = chr2;
613
614 for (i = 0; i < 2; i++) {
f930d07e
BS
615 s->chn[i].irq = irq;
616 s->chn[i].chn = 1 - i;
617 s->chn[i].type = ser;
618 if (s->chn[i].chr) {
619 qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive,
e5b0bc44 620 serial_receive1, serial_event, &s->chn[i]);
f930d07e 621 }
e80cfcfc 622 }
8be1f5c8
FB
623 s->chn[0].otherchn = &s->chn[1];
624 s->chn[1].otherchn = &s->chn[0];
e4a89056 625 register_savevm("slavio_serial", base, 2, slavio_serial_save, slavio_serial_load, s);
e80cfcfc
FB
626 qemu_register_reset(slavio_serial_reset, s);
627 slavio_serial_reset(s);
628 return s;
629}
630
8be1f5c8
FB
631static const uint8_t keycodes[128] = {
632 127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53,
633 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78,
634 79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103,
635 104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12,
636 14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112,
637 113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0,
638 90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66,
639 0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67,
640};
641
43febf49
BS
642static const uint8_t e0_keycodes[128] = {
643 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
644 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 76, 0, 0,
645 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
646 0, 0, 0, 0, 0, 109, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0,
647 0, 0, 0, 0, 0, 0, 0, 68, 69, 70, 0, 91, 0, 93, 0, 112,
648 113, 114, 94, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
649 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
650 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
651};
652
e80cfcfc
FB
653static void sunkbd_event(void *opaque, int ch)
654{
655 ChannelState *s = opaque;
8be1f5c8
FB
656 int release = ch & 0x80;
657
43febf49 658 KBD_DPRINTF("Untranslated keycode %2.2x (%s)\n", ch, release? "release" : "press");
bbbb2f0a
BS
659 switch (ch) {
660 case 58: // Caps lock press
661 s->caps_lock_mode ^= 1;
662 if (s->caps_lock_mode == 2)
663 return; // Drop second press
664 break;
665 case 69: // Num lock press
666 s->num_lock_mode ^= 1;
667 if (s->num_lock_mode == 2)
668 return; // Drop second press
669 break;
670 case 186: // Caps lock release
671 s->caps_lock_mode ^= 2;
672 if (s->caps_lock_mode == 3)
673 return; // Drop first release
674 break;
675 case 197: // Num lock release
676 s->num_lock_mode ^= 2;
677 if (s->num_lock_mode == 3)
678 return; // Drop first release
679 break;
680 case 0xe0:
43febf49
BS
681 s->e0_mode = 1;
682 return;
bbbb2f0a
BS
683 default:
684 break;
43febf49
BS
685 }
686 if (s->e0_mode) {
687 s->e0_mode = 0;
688 ch = e0_keycodes[ch & 0x7f];
689 } else {
690 ch = keycodes[ch & 0x7f];
691 }
692 KBD_DPRINTF("Translated keycode %2.2x\n", ch);
8be1f5c8
FB
693 put_queue(s, ch | release);
694}
695
696static void handle_kbd_command(ChannelState *s, int val)
697{
698 KBD_DPRINTF("Command %d\n", val);
43febf49
BS
699 if (s->led_mode) { // Ignore led byte
700 s->led_mode = 0;
701 return;
702 }
8be1f5c8
FB
703 switch (val) {
704 case 1: // Reset, return type code
67deb562 705 clear_queue(s);
f930d07e
BS
706 put_queue(s, 0xff);
707 put_queue(s, 4); // Type 4
708 put_queue(s, 0x7f);
709 break;
43febf49
BS
710 case 0xe: // Set leds
711 s->led_mode = 1;
712 break;
8be1f5c8 713 case 7: // Query layout
67deb562
BS
714 case 0xf:
715 clear_queue(s);
f930d07e
BS
716 put_queue(s, 0xfe);
717 put_queue(s, 0); // XXX, layout?
718 break;
8be1f5c8 719 default:
f930d07e 720 break;
8be1f5c8 721 }
e80cfcfc
FB
722}
723
5fafdf24 724static void sunmouse_event(void *opaque,
e80cfcfc
FB
725 int dx, int dy, int dz, int buttons_state)
726{
727 ChannelState *s = opaque;
728 int ch;
729
715748fa
FB
730 MS_DPRINTF("dx=%d dy=%d buttons=%01x\n", dx, dy, buttons_state);
731
732 ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
733
734 if (buttons_state & MOUSE_EVENT_LBUTTON)
735 ch ^= 0x4;
736 if (buttons_state & MOUSE_EVENT_MBUTTON)
737 ch ^= 0x2;
738 if (buttons_state & MOUSE_EVENT_RBUTTON)
739 ch ^= 0x1;
740
741 put_queue(s, ch);
742
743 ch = dx;
744
745 if (ch > 127)
746 ch=127;
747 else if (ch < -127)
748 ch=-127;
749
750 put_queue(s, ch & 0xff);
751
752 ch = -dy;
753
754 if (ch > 127)
755 ch=127;
756 else if (ch < -127)
757 ch=-127;
758
759 put_queue(s, ch & 0xff);
760
761 // MSC protocol specify two extra motion bytes
762
763 put_queue(s, 0);
764 put_queue(s, 0);
e80cfcfc
FB
765}
766
5dcb6b91 767void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq)
e80cfcfc 768{
8be1f5c8 769 int slavio_serial_io_memory, i;
e80cfcfc
FB
770 SerialState *s;
771
772 s = qemu_mallocz(sizeof(SerialState));
773 if (!s)
774 return;
8be1f5c8 775 for (i = 0; i < 2; i++) {
f930d07e
BS
776 s->chn[i].irq = irq;
777 s->chn[i].chn = 1 - i;
778 s->chn[i].chr = NULL;
8be1f5c8
FB
779 }
780 s->chn[0].otherchn = &s->chn[1];
781 s->chn[1].otherchn = &s->chn[0];
782 s->chn[0].type = mouse;
783 s->chn[1].type = kbd;
e80cfcfc
FB
784
785 slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s);
5aca8c3b 786 cpu_register_physical_memory(base, SERIAL_SIZE, slavio_serial_io_memory);
e80cfcfc 787
455204eb 788 qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0, "QEMU Sun Mouse");
8be1f5c8 789 qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
5425a216 790 register_savevm("slavio_serial_mouse", base, 2, slavio_serial_save, slavio_serial_load, s);
e80cfcfc
FB
791 qemu_register_reset(slavio_serial_reset, s);
792 slavio_serial_reset(s);
793}