guest agent: remove uneeded dependencies
[qemu/mdroth.git] / hw / escc.c
blob76d94f30fe63038cbb62b19e4435b60757b1768d
1 /*
2 * QEMU ESCC (Z8030/Z8530/Z85C30/SCC/ESCC) serial port emulation
4 * Copyright (c) 2003-2005 Fabrice Bellard
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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.
25 #include "hw.h"
26 #include "sysbus.h"
27 #include "escc.h"
28 #include "qemu-char.h"
29 #include "console.h"
30 #include "trace.h"
33 * Chipset docs:
34 * "Z80C30/Z85C30/Z80230/Z85230/Z85233 SCC/ESCC User Manual",
35 * http://www.zilog.com/docs/serial/scc_escc_um.pdf
37 * On Sparc32 this is the serial port, mouse and keyboard part of chip STP2001
38 * (Slave I/O), also produced as NCR89C105. See
39 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
41 * The serial ports implement full AMD AM8530 or Zilog Z8530 chips,
42 * mouse and keyboard ports don't implement all functions and they are
43 * only asynchronous. There is no DMA.
45 * Z85C30 is also used on PowerMacs. There are some small differences
46 * between Sparc version (sunzilog) and PowerMac (pmac):
47 * Offset between control and data registers
48 * There is some kind of lockup bug, but we can ignore it
49 * CTS is inverted
50 * DMA on pmac using DBDMA chip
51 * pmac can do IRDA and faster rates, sunzilog can only do 38400
52 * pmac baud rate generator clock is 3.6864 MHz, sunzilog 4.9152 MHz
56 * Modifications:
57 * 2006-Aug-10 Igor Kovalenko : Renamed KBDQueue to SERIOQueue, implemented
58 * serial mouse queue.
59 * Implemented serial mouse protocol.
61 * 2010-May-23 Artyom Tarasenko: Reworked IUS logic
64 typedef enum {
65 chn_a, chn_b,
66 } ChnID;
68 #define CHN_C(s) ((s)->chn == chn_b? 'b' : 'a')
70 typedef enum {
71 ser, kbd, mouse,
72 } ChnType;
74 #define SERIO_QUEUE_SIZE 256
76 typedef struct {
77 uint8_t data[SERIO_QUEUE_SIZE];
78 int rptr, wptr, count;
79 } SERIOQueue;
81 #define SERIAL_REGS 16
82 typedef struct ChannelState {
83 qemu_irq irq;
84 uint32_t rxint, txint, rxint_under_svc, txint_under_svc;
85 struct ChannelState *otherchn;
86 uint32_t reg;
87 uint8_t wregs[SERIAL_REGS], rregs[SERIAL_REGS];
88 SERIOQueue queue;
89 CharDriverState *chr;
90 int e0_mode, led_mode, caps_lock_mode, num_lock_mode;
91 int disabled;
92 int clock;
93 uint32_t vmstate_dummy;
94 ChnID chn; // this channel, A (base+4) or B (base+0)
95 ChnType type;
96 uint8_t rx, tx;
97 } ChannelState;
99 struct SerialState {
100 SysBusDevice busdev;
101 struct ChannelState chn[2];
102 uint32_t it_shift;
103 MemoryRegion mmio;
104 uint32_t disabled;
105 uint32_t frequency;
108 #define SERIAL_CTRL 0
109 #define SERIAL_DATA 1
111 #define W_CMD 0
112 #define CMD_PTR_MASK 0x07
113 #define CMD_CMD_MASK 0x38
114 #define CMD_HI 0x08
115 #define CMD_CLR_TXINT 0x28
116 #define CMD_CLR_IUS 0x38
117 #define W_INTR 1
118 #define INTR_INTALL 0x01
119 #define INTR_TXINT 0x02
120 #define INTR_RXMODEMSK 0x18
121 #define INTR_RXINT1ST 0x08
122 #define INTR_RXINTALL 0x10
123 #define W_IVEC 2
124 #define W_RXCTRL 3
125 #define RXCTRL_RXEN 0x01
126 #define W_TXCTRL1 4
127 #define TXCTRL1_PAREN 0x01
128 #define TXCTRL1_PAREV 0x02
129 #define TXCTRL1_1STOP 0x04
130 #define TXCTRL1_1HSTOP 0x08
131 #define TXCTRL1_2STOP 0x0c
132 #define TXCTRL1_STPMSK 0x0c
133 #define TXCTRL1_CLK1X 0x00
134 #define TXCTRL1_CLK16X 0x40
135 #define TXCTRL1_CLK32X 0x80
136 #define TXCTRL1_CLK64X 0xc0
137 #define TXCTRL1_CLKMSK 0xc0
138 #define W_TXCTRL2 5
139 #define TXCTRL2_TXEN 0x08
140 #define TXCTRL2_BITMSK 0x60
141 #define TXCTRL2_5BITS 0x00
142 #define TXCTRL2_7BITS 0x20
143 #define TXCTRL2_6BITS 0x40
144 #define TXCTRL2_8BITS 0x60
145 #define W_SYNC1 6
146 #define W_SYNC2 7
147 #define W_TXBUF 8
148 #define W_MINTR 9
149 #define MINTR_STATUSHI 0x10
150 #define MINTR_RST_MASK 0xc0
151 #define MINTR_RST_B 0x40
152 #define MINTR_RST_A 0x80
153 #define MINTR_RST_ALL 0xc0
154 #define W_MISC1 10
155 #define W_CLOCK 11
156 #define CLOCK_TRXC 0x08
157 #define W_BRGLO 12
158 #define W_BRGHI 13
159 #define W_MISC2 14
160 #define MISC2_PLLDIS 0x30
161 #define W_EXTINT 15
162 #define EXTINT_DCD 0x08
163 #define EXTINT_SYNCINT 0x10
164 #define EXTINT_CTSINT 0x20
165 #define EXTINT_TXUNDRN 0x40
166 #define EXTINT_BRKINT 0x80
168 #define R_STATUS 0
169 #define STATUS_RXAV 0x01
170 #define STATUS_ZERO 0x02
171 #define STATUS_TXEMPTY 0x04
172 #define STATUS_DCD 0x08
173 #define STATUS_SYNC 0x10
174 #define STATUS_CTS 0x20
175 #define STATUS_TXUNDRN 0x40
176 #define STATUS_BRK 0x80
177 #define R_SPEC 1
178 #define SPEC_ALLSENT 0x01
179 #define SPEC_BITS8 0x06
180 #define R_IVEC 2
181 #define IVEC_TXINTB 0x00
182 #define IVEC_LONOINT 0x06
183 #define IVEC_LORXINTA 0x0c
184 #define IVEC_LORXINTB 0x04
185 #define IVEC_LOTXINTA 0x08
186 #define IVEC_HINOINT 0x60
187 #define IVEC_HIRXINTA 0x30
188 #define IVEC_HIRXINTB 0x20
189 #define IVEC_HITXINTA 0x10
190 #define R_INTR 3
191 #define INTR_EXTINTB 0x01
192 #define INTR_TXINTB 0x02
193 #define INTR_RXINTB 0x04
194 #define INTR_EXTINTA 0x08
195 #define INTR_TXINTA 0x10
196 #define INTR_RXINTA 0x20
197 #define R_IPEN 4
198 #define R_TXCTRL1 5
199 #define R_TXCTRL2 6
200 #define R_BC 7
201 #define R_RXBUF 8
202 #define R_RXCTRL 9
203 #define R_MISC 10
204 #define R_MISC1 11
205 #define R_BRGLO 12
206 #define R_BRGHI 13
207 #define R_MISC1I 14
208 #define R_EXTINT 15
210 static void handle_kbd_command(ChannelState *s, int val);
211 static int serial_can_receive(void *opaque);
212 static void serial_receive_byte(ChannelState *s, int ch);
214 static void clear_queue(void *opaque)
216 ChannelState *s = opaque;
217 SERIOQueue *q = &s->queue;
218 q->rptr = q->wptr = q->count = 0;
221 static void put_queue(void *opaque, int b)
223 ChannelState *s = opaque;
224 SERIOQueue *q = &s->queue;
226 trace_escc_put_queue(CHN_C(s), b);
227 if (q->count >= SERIO_QUEUE_SIZE)
228 return;
229 q->data[q->wptr] = b;
230 if (++q->wptr == SERIO_QUEUE_SIZE)
231 q->wptr = 0;
232 q->count++;
233 serial_receive_byte(s, 0);
236 static uint32_t get_queue(void *opaque)
238 ChannelState *s = opaque;
239 SERIOQueue *q = &s->queue;
240 int val;
242 if (q->count == 0) {
243 return 0;
244 } else {
245 val = q->data[q->rptr];
246 if (++q->rptr == SERIO_QUEUE_SIZE)
247 q->rptr = 0;
248 q->count--;
250 trace_escc_get_queue(CHN_C(s), val);
251 if (q->count > 0)
252 serial_receive_byte(s, 0);
253 return val;
256 static int escc_update_irq_chn(ChannelState *s)
258 if ((((s->wregs[W_INTR] & INTR_TXINT) && (s->txint == 1)) ||
259 // tx ints enabled, pending
260 ((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) ||
261 ((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) &&
262 s->rxint == 1) || // rx ints enabled, pending
263 ((s->wregs[W_EXTINT] & EXTINT_BRKINT) &&
264 (s->rregs[R_STATUS] & STATUS_BRK)))) { // break int e&p
265 return 1;
267 return 0;
270 static void escc_update_irq(ChannelState *s)
272 int irq;
274 irq = escc_update_irq_chn(s);
275 irq |= escc_update_irq_chn(s->otherchn);
277 trace_escc_update_irq(irq);
278 qemu_set_irq(s->irq, irq);
281 static void escc_reset_chn(ChannelState *s)
283 int i;
285 s->reg = 0;
286 for (i = 0; i < SERIAL_REGS; i++) {
287 s->rregs[i] = 0;
288 s->wregs[i] = 0;
290 s->wregs[W_TXCTRL1] = TXCTRL1_1STOP; // 1X divisor, 1 stop bit, no parity
291 s->wregs[W_MINTR] = MINTR_RST_ALL;
292 s->wregs[W_CLOCK] = CLOCK_TRXC; // Synch mode tx clock = TRxC
293 s->wregs[W_MISC2] = MISC2_PLLDIS; // PLL disabled
294 s->wregs[W_EXTINT] = EXTINT_DCD | EXTINT_SYNCINT | EXTINT_CTSINT |
295 EXTINT_TXUNDRN | EXTINT_BRKINT; // Enable most interrupts
296 if (s->disabled)
297 s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_DCD | STATUS_SYNC |
298 STATUS_CTS | STATUS_TXUNDRN;
299 else
300 s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_TXUNDRN;
301 s->rregs[R_SPEC] = SPEC_BITS8 | SPEC_ALLSENT;
303 s->rx = s->tx = 0;
304 s->rxint = s->txint = 0;
305 s->rxint_under_svc = s->txint_under_svc = 0;
306 s->e0_mode = s->led_mode = s->caps_lock_mode = s->num_lock_mode = 0;
307 clear_queue(s);
310 static void escc_reset(DeviceState *d)
312 SerialState *s = container_of(d, SerialState, busdev.qdev);
314 escc_reset_chn(&s->chn[0]);
315 escc_reset_chn(&s->chn[1]);
318 static inline void set_rxint(ChannelState *s)
320 s->rxint = 1;
321 /* XXX: missing daisy chainnig: chn_b rx should have a lower priority
322 than chn_a rx/tx/special_condition service*/
323 s->rxint_under_svc = 1;
324 if (s->chn == chn_a) {
325 s->rregs[R_INTR] |= INTR_RXINTA;
326 if (s->wregs[W_MINTR] & MINTR_STATUSHI)
327 s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
328 else
329 s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
330 } else {
331 s->otherchn->rregs[R_INTR] |= INTR_RXINTB;
332 if (s->wregs[W_MINTR] & MINTR_STATUSHI)
333 s->rregs[R_IVEC] = IVEC_HIRXINTB;
334 else
335 s->rregs[R_IVEC] = IVEC_LORXINTB;
337 escc_update_irq(s);
340 static inline void set_txint(ChannelState *s)
342 s->txint = 1;
343 if (!s->rxint_under_svc) {
344 s->txint_under_svc = 1;
345 if (s->chn == chn_a) {
346 if (s->wregs[W_INTR] & INTR_TXINT) {
347 s->rregs[R_INTR] |= INTR_TXINTA;
349 if (s->wregs[W_MINTR] & MINTR_STATUSHI)
350 s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA;
351 else
352 s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA;
353 } else {
354 s->rregs[R_IVEC] = IVEC_TXINTB;
355 if (s->wregs[W_INTR] & INTR_TXINT) {
356 s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
359 escc_update_irq(s);
363 static inline void clr_rxint(ChannelState *s)
365 s->rxint = 0;
366 s->rxint_under_svc = 0;
367 if (s->chn == chn_a) {
368 if (s->wregs[W_MINTR] & MINTR_STATUSHI)
369 s->otherchn->rregs[R_IVEC] = IVEC_HINOINT;
370 else
371 s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
372 s->rregs[R_INTR] &= ~INTR_RXINTA;
373 } else {
374 if (s->wregs[W_MINTR] & MINTR_STATUSHI)
375 s->rregs[R_IVEC] = IVEC_HINOINT;
376 else
377 s->rregs[R_IVEC] = IVEC_LONOINT;
378 s->otherchn->rregs[R_INTR] &= ~INTR_RXINTB;
380 if (s->txint)
381 set_txint(s);
382 escc_update_irq(s);
385 static inline void clr_txint(ChannelState *s)
387 s->txint = 0;
388 s->txint_under_svc = 0;
389 if (s->chn == chn_a) {
390 if (s->wregs[W_MINTR] & MINTR_STATUSHI)
391 s->otherchn->rregs[R_IVEC] = IVEC_HINOINT;
392 else
393 s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
394 s->rregs[R_INTR] &= ~INTR_TXINTA;
395 } else {
396 s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
397 if (s->wregs[W_MINTR] & MINTR_STATUSHI)
398 s->rregs[R_IVEC] = IVEC_HINOINT;
399 else
400 s->rregs[R_IVEC] = IVEC_LONOINT;
401 s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
403 if (s->rxint)
404 set_rxint(s);
405 escc_update_irq(s);
408 static void escc_update_parameters(ChannelState *s)
410 int speed, parity, data_bits, stop_bits;
411 QEMUSerialSetParams ssp;
413 if (!s->chr || s->type != ser)
414 return;
416 if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREN) {
417 if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREV)
418 parity = 'E';
419 else
420 parity = 'O';
421 } else {
422 parity = 'N';
424 if ((s->wregs[W_TXCTRL1] & TXCTRL1_STPMSK) == TXCTRL1_2STOP)
425 stop_bits = 2;
426 else
427 stop_bits = 1;
428 switch (s->wregs[W_TXCTRL2] & TXCTRL2_BITMSK) {
429 case TXCTRL2_5BITS:
430 data_bits = 5;
431 break;
432 case TXCTRL2_7BITS:
433 data_bits = 7;
434 break;
435 case TXCTRL2_6BITS:
436 data_bits = 6;
437 break;
438 default:
439 case TXCTRL2_8BITS:
440 data_bits = 8;
441 break;
443 speed = s->clock / ((s->wregs[W_BRGLO] | (s->wregs[W_BRGHI] << 8)) + 2);
444 switch (s->wregs[W_TXCTRL1] & TXCTRL1_CLKMSK) {
445 case TXCTRL1_CLK1X:
446 break;
447 case TXCTRL1_CLK16X:
448 speed /= 16;
449 break;
450 case TXCTRL1_CLK32X:
451 speed /= 32;
452 break;
453 default:
454 case TXCTRL1_CLK64X:
455 speed /= 64;
456 break;
458 ssp.speed = speed;
459 ssp.parity = parity;
460 ssp.data_bits = data_bits;
461 ssp.stop_bits = stop_bits;
462 trace_escc_update_parameters(CHN_C(s), speed, parity, data_bits, stop_bits);
463 qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
466 static void escc_mem_write(void *opaque, target_phys_addr_t addr,
467 uint64_t val, unsigned size)
469 SerialState *serial = opaque;
470 ChannelState *s;
471 uint32_t saddr;
472 int newreg, channel;
474 val &= 0xff;
475 saddr = (addr >> serial->it_shift) & 1;
476 channel = (addr >> (serial->it_shift + 1)) & 1;
477 s = &serial->chn[channel];
478 switch (saddr) {
479 case SERIAL_CTRL:
480 trace_escc_mem_writeb_ctrl(CHN_C(s), s->reg, val & 0xff);
481 newreg = 0;
482 switch (s->reg) {
483 case W_CMD:
484 newreg = val & CMD_PTR_MASK;
485 val &= CMD_CMD_MASK;
486 switch (val) {
487 case CMD_HI:
488 newreg |= CMD_HI;
489 break;
490 case CMD_CLR_TXINT:
491 clr_txint(s);
492 break;
493 case CMD_CLR_IUS:
494 if (s->rxint_under_svc) {
495 s->rxint_under_svc = 0;
496 if (s->txint) {
497 set_txint(s);
499 } else if (s->txint_under_svc) {
500 s->txint_under_svc = 0;
502 escc_update_irq(s);
503 break;
504 default:
505 break;
507 break;
508 case W_INTR ... W_RXCTRL:
509 case W_SYNC1 ... W_TXBUF:
510 case W_MISC1 ... W_CLOCK:
511 case W_MISC2 ... W_EXTINT:
512 s->wregs[s->reg] = val;
513 break;
514 case W_TXCTRL1:
515 case W_TXCTRL2:
516 s->wregs[s->reg] = val;
517 escc_update_parameters(s);
518 break;
519 case W_BRGLO:
520 case W_BRGHI:
521 s->wregs[s->reg] = val;
522 s->rregs[s->reg] = val;
523 escc_update_parameters(s);
524 break;
525 case W_MINTR:
526 switch (val & MINTR_RST_MASK) {
527 case 0:
528 default:
529 break;
530 case MINTR_RST_B:
531 escc_reset_chn(&serial->chn[0]);
532 return;
533 case MINTR_RST_A:
534 escc_reset_chn(&serial->chn[1]);
535 return;
536 case MINTR_RST_ALL:
537 escc_reset(&serial->busdev.qdev);
538 return;
540 break;
541 default:
542 break;
544 if (s->reg == 0)
545 s->reg = newreg;
546 else
547 s->reg = 0;
548 break;
549 case SERIAL_DATA:
550 trace_escc_mem_writeb_data(CHN_C(s), val);
551 s->tx = val;
552 if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
553 if (s->chr)
554 qemu_chr_write(s->chr, &s->tx, 1);
555 else if (s->type == kbd && !s->disabled) {
556 handle_kbd_command(s, val);
559 s->rregs[R_STATUS] |= STATUS_TXEMPTY; // Tx buffer empty
560 s->rregs[R_SPEC] |= SPEC_ALLSENT; // All sent
561 set_txint(s);
562 break;
563 default:
564 break;
568 static uint64_t escc_mem_read(void *opaque, target_phys_addr_t addr,
569 unsigned size)
571 SerialState *serial = opaque;
572 ChannelState *s;
573 uint32_t saddr;
574 uint32_t ret;
575 int channel;
577 saddr = (addr >> serial->it_shift) & 1;
578 channel = (addr >> (serial->it_shift + 1)) & 1;
579 s = &serial->chn[channel];
580 switch (saddr) {
581 case SERIAL_CTRL:
582 trace_escc_mem_readb_ctrl(CHN_C(s), s->reg, s->rregs[s->reg]);
583 ret = s->rregs[s->reg];
584 s->reg = 0;
585 return ret;
586 case SERIAL_DATA:
587 s->rregs[R_STATUS] &= ~STATUS_RXAV;
588 clr_rxint(s);
589 if (s->type == kbd || s->type == mouse)
590 ret = get_queue(s);
591 else
592 ret = s->rx;
593 trace_escc_mem_readb_data(CHN_C(s), ret);
594 if (s->chr)
595 qemu_chr_accept_input(s->chr);
596 return ret;
597 default:
598 break;
600 return 0;
603 static const MemoryRegionOps escc_mem_ops = {
604 .read = escc_mem_read,
605 .write = escc_mem_write,
606 .endianness = DEVICE_NATIVE_ENDIAN,
607 .valid = {
608 .min_access_size = 1,
609 .max_access_size = 1,
613 static int serial_can_receive(void *opaque)
615 ChannelState *s = opaque;
616 int ret;
618 if (((s->wregs[W_RXCTRL] & RXCTRL_RXEN) == 0) // Rx not enabled
619 || ((s->rregs[R_STATUS] & STATUS_RXAV) == STATUS_RXAV))
620 // char already available
621 ret = 0;
622 else
623 ret = 1;
624 return ret;
627 static void serial_receive_byte(ChannelState *s, int ch)
629 trace_escc_serial_receive_byte(CHN_C(s), ch);
630 s->rregs[R_STATUS] |= STATUS_RXAV;
631 s->rx = ch;
632 set_rxint(s);
635 static void serial_receive_break(ChannelState *s)
637 s->rregs[R_STATUS] |= STATUS_BRK;
638 escc_update_irq(s);
641 static void serial_receive1(void *opaque, const uint8_t *buf, int size)
643 ChannelState *s = opaque;
644 serial_receive_byte(s, buf[0]);
647 static void serial_event(void *opaque, int event)
649 ChannelState *s = opaque;
650 if (event == CHR_EVENT_BREAK)
651 serial_receive_break(s);
654 static const VMStateDescription vmstate_escc_chn = {
655 .name ="escc_chn",
656 .version_id = 2,
657 .minimum_version_id = 1,
658 .minimum_version_id_old = 1,
659 .fields = (VMStateField []) {
660 VMSTATE_UINT32(vmstate_dummy, ChannelState),
661 VMSTATE_UINT32(reg, ChannelState),
662 VMSTATE_UINT32(rxint, ChannelState),
663 VMSTATE_UINT32(txint, ChannelState),
664 VMSTATE_UINT32(rxint_under_svc, ChannelState),
665 VMSTATE_UINT32(txint_under_svc, ChannelState),
666 VMSTATE_UINT8(rx, ChannelState),
667 VMSTATE_UINT8(tx, ChannelState),
668 VMSTATE_BUFFER(wregs, ChannelState),
669 VMSTATE_BUFFER(rregs, ChannelState),
670 VMSTATE_END_OF_LIST()
674 static const VMStateDescription vmstate_escc = {
675 .name ="escc",
676 .version_id = 2,
677 .minimum_version_id = 1,
678 .minimum_version_id_old = 1,
679 .fields = (VMStateField []) {
680 VMSTATE_STRUCT_ARRAY(chn, SerialState, 2, 2, vmstate_escc_chn,
681 ChannelState),
682 VMSTATE_END_OF_LIST()
686 MemoryRegion *escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB,
687 CharDriverState *chrA, CharDriverState *chrB,
688 int clock, int it_shift)
690 DeviceState *dev;
691 SysBusDevice *s;
692 SerialState *d;
694 dev = qdev_create(NULL, "escc");
695 qdev_prop_set_uint32(dev, "disabled", 0);
696 qdev_prop_set_uint32(dev, "frequency", clock);
697 qdev_prop_set_uint32(dev, "it_shift", it_shift);
698 qdev_prop_set_chr(dev, "chrB", chrB);
699 qdev_prop_set_chr(dev, "chrA", chrA);
700 qdev_prop_set_uint32(dev, "chnBtype", ser);
701 qdev_prop_set_uint32(dev, "chnAtype", ser);
702 qdev_init_nofail(dev);
703 s = sysbus_from_qdev(dev);
704 sysbus_connect_irq(s, 0, irqB);
705 sysbus_connect_irq(s, 1, irqA);
706 if (base) {
707 sysbus_mmio_map(s, 0, base);
710 d = FROM_SYSBUS(SerialState, s);
711 return &d->mmio;
714 static const uint8_t keycodes[128] = {
715 127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53,
716 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78,
717 79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103,
718 104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12,
719 14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112,
720 113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0,
721 90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66,
722 0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67,
725 static const uint8_t e0_keycodes[128] = {
726 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
727 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 76, 0, 0,
728 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
729 0, 0, 0, 0, 0, 109, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0,
730 0, 0, 0, 0, 0, 0, 0, 68, 69, 70, 0, 91, 0, 93, 0, 112,
731 113, 114, 94, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
732 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
733 1, 3, 25, 26, 49, 52, 72, 73, 97, 99, 111, 118, 120, 122, 67, 0,
736 static void sunkbd_event(void *opaque, int ch)
738 ChannelState *s = opaque;
739 int release = ch & 0x80;
741 trace_escc_sunkbd_event_in(ch);
742 switch (ch) {
743 case 58: // Caps lock press
744 s->caps_lock_mode ^= 1;
745 if (s->caps_lock_mode == 2)
746 return; // Drop second press
747 break;
748 case 69: // Num lock press
749 s->num_lock_mode ^= 1;
750 if (s->num_lock_mode == 2)
751 return; // Drop second press
752 break;
753 case 186: // Caps lock release
754 s->caps_lock_mode ^= 2;
755 if (s->caps_lock_mode == 3)
756 return; // Drop first release
757 break;
758 case 197: // Num lock release
759 s->num_lock_mode ^= 2;
760 if (s->num_lock_mode == 3)
761 return; // Drop first release
762 break;
763 case 0xe0:
764 s->e0_mode = 1;
765 return;
766 default:
767 break;
769 if (s->e0_mode) {
770 s->e0_mode = 0;
771 ch = e0_keycodes[ch & 0x7f];
772 } else {
773 ch = keycodes[ch & 0x7f];
775 trace_escc_sunkbd_event_out(ch);
776 put_queue(s, ch | release);
779 static void handle_kbd_command(ChannelState *s, int val)
781 trace_escc_kbd_command(val);
782 if (s->led_mode) { // Ignore led byte
783 s->led_mode = 0;
784 return;
786 switch (val) {
787 case 1: // Reset, return type code
788 clear_queue(s);
789 put_queue(s, 0xff);
790 put_queue(s, 4); // Type 4
791 put_queue(s, 0x7f);
792 break;
793 case 0xe: // Set leds
794 s->led_mode = 1;
795 break;
796 case 7: // Query layout
797 case 0xf:
798 clear_queue(s);
799 put_queue(s, 0xfe);
800 put_queue(s, 0); // XXX, layout?
801 break;
802 default:
803 break;
807 static void sunmouse_event(void *opaque,
808 int dx, int dy, int dz, int buttons_state)
810 ChannelState *s = opaque;
811 int ch;
813 trace_escc_sunmouse_event(dx, dy, buttons_state);
814 ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
816 if (buttons_state & MOUSE_EVENT_LBUTTON)
817 ch ^= 0x4;
818 if (buttons_state & MOUSE_EVENT_MBUTTON)
819 ch ^= 0x2;
820 if (buttons_state & MOUSE_EVENT_RBUTTON)
821 ch ^= 0x1;
823 put_queue(s, ch);
825 ch = dx;
827 if (ch > 127)
828 ch = 127;
829 else if (ch < -127)
830 ch = -127;
832 put_queue(s, ch & 0xff);
834 ch = -dy;
836 if (ch > 127)
837 ch = 127;
838 else if (ch < -127)
839 ch = -127;
841 put_queue(s, ch & 0xff);
843 // MSC protocol specify two extra motion bytes
845 put_queue(s, 0);
846 put_queue(s, 0);
849 void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq,
850 int disabled, int clock, int it_shift)
852 DeviceState *dev;
853 SysBusDevice *s;
855 dev = qdev_create(NULL, "escc");
856 qdev_prop_set_uint32(dev, "disabled", disabled);
857 qdev_prop_set_uint32(dev, "frequency", clock);
858 qdev_prop_set_uint32(dev, "it_shift", it_shift);
859 qdev_prop_set_chr(dev, "chrB", NULL);
860 qdev_prop_set_chr(dev, "chrA", NULL);
861 qdev_prop_set_uint32(dev, "chnBtype", mouse);
862 qdev_prop_set_uint32(dev, "chnAtype", kbd);
863 qdev_init_nofail(dev);
864 s = sysbus_from_qdev(dev);
865 sysbus_connect_irq(s, 0, irq);
866 sysbus_connect_irq(s, 1, irq);
867 sysbus_mmio_map(s, 0, base);
870 static int escc_init1(SysBusDevice *dev)
872 SerialState *s = FROM_SYSBUS(SerialState, dev);
873 unsigned int i;
875 s->chn[0].disabled = s->disabled;
876 s->chn[1].disabled = s->disabled;
877 for (i = 0; i < 2; i++) {
878 sysbus_init_irq(dev, &s->chn[i].irq);
879 s->chn[i].chn = 1 - i;
880 s->chn[i].clock = s->frequency / 2;
881 if (s->chn[i].chr) {
882 qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive,
883 serial_receive1, serial_event, &s->chn[i]);
886 s->chn[0].otherchn = &s->chn[1];
887 s->chn[1].otherchn = &s->chn[0];
889 memory_region_init_io(&s->mmio, &escc_mem_ops, s, "escc",
890 ESCC_SIZE << s->it_shift);
891 sysbus_init_mmio_region(dev, &s->mmio);
893 if (s->chn[0].type == mouse) {
894 qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0,
895 "QEMU Sun Mouse");
897 if (s->chn[1].type == kbd) {
898 qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
901 return 0;
904 static SysBusDeviceInfo escc_info = {
905 .init = escc_init1,
906 .qdev.name = "escc",
907 .qdev.size = sizeof(SerialState),
908 .qdev.vmsd = &vmstate_escc,
909 .qdev.reset = escc_reset,
910 .qdev.props = (Property[]) {
911 DEFINE_PROP_UINT32("frequency", SerialState, frequency, 0),
912 DEFINE_PROP_UINT32("it_shift", SerialState, it_shift, 0),
913 DEFINE_PROP_UINT32("disabled", SerialState, disabled, 0),
914 DEFINE_PROP_UINT32("disabled", SerialState, disabled, 0),
915 DEFINE_PROP_UINT32("chnBtype", SerialState, chn[0].type, 0),
916 DEFINE_PROP_UINT32("chnAtype", SerialState, chn[1].type, 0),
917 DEFINE_PROP_CHR("chrB", SerialState, chn[0].chr),
918 DEFINE_PROP_CHR("chrA", SerialState, chn[1].chr),
919 DEFINE_PROP_END_OF_LIST(),
923 static void escc_register_devices(void)
925 sysbus_register_withprop(&escc_info);
928 device_init(escc_register_devices)