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