xref: /qemu/hw/char/escc.c (revision 300b1fc68c47478f36705f23a93dce77ac3e429a)
1e80cfcfcSbellard /*
2b4ed08e0Sblueswir1  * QEMU ESCC (Z8030/Z8530/Z85C30/SCC/ESCC) serial port emulation
3e80cfcfcSbellard  *
48be1f5c8Sbellard  * Copyright (c) 2003-2005 Fabrice Bellard
5e80cfcfcSbellard  *
6e80cfcfcSbellard  * Permission is hereby granted, free of charge, to any person obtaining a copy
7e80cfcfcSbellard  * of this software and associated documentation files (the "Software"), to deal
8e80cfcfcSbellard  * in the Software without restriction, including without limitation the rights
9e80cfcfcSbellard  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10e80cfcfcSbellard  * copies of the Software, and to permit persons to whom the Software is
11e80cfcfcSbellard  * furnished to do so, subject to the following conditions:
12e80cfcfcSbellard  *
13e80cfcfcSbellard  * The above copyright notice and this permission notice shall be included in
14e80cfcfcSbellard  * all copies or substantial portions of the Software.
15e80cfcfcSbellard  *
16e80cfcfcSbellard  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17e80cfcfcSbellard  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18e80cfcfcSbellard  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19e80cfcfcSbellard  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20e80cfcfcSbellard  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21e80cfcfcSbellard  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22e80cfcfcSbellard  * THE SOFTWARE.
23e80cfcfcSbellard  */
246c319c82SBlue Swirl 
2583c9f4caSPaolo Bonzini #include "hw/hw.h"
2683c9f4caSPaolo Bonzini #include "hw/sysbus.h"
270d09e41aSPaolo Bonzini #include "hw/char/escc.h"
28dccfcd0eSPaolo Bonzini #include "sysemu/char.h"
2928ecbaeeSPaolo Bonzini #include "ui/console.h"
3030c2f238SBlue Swirl #include "trace.h"
31e80cfcfcSbellard 
32e80cfcfcSbellard /*
3309330e90SBlue Swirl  * Chipset docs:
3409330e90SBlue Swirl  * "Z80C30/Z85C30/Z80230/Z85230/Z85233 SCC/ESCC User Manual",
3509330e90SBlue Swirl  * http://www.zilog.com/docs/serial/scc_escc_um.pdf
3609330e90SBlue Swirl  *
37b4ed08e0Sblueswir1  * On Sparc32 this is the serial port, mouse and keyboard part of chip STP2001
38e80cfcfcSbellard  * (Slave I/O), also produced as NCR89C105. See
39e80cfcfcSbellard  * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
40e80cfcfcSbellard  *
41e80cfcfcSbellard  * The serial ports implement full AMD AM8530 or Zilog Z8530 chips,
42e80cfcfcSbellard  * mouse and keyboard ports don't implement all functions and they are
43e80cfcfcSbellard  * only asynchronous. There is no DMA.
44e80cfcfcSbellard  *
45b4ed08e0Sblueswir1  * Z85C30 is also used on PowerMacs. There are some small differences
46b4ed08e0Sblueswir1  * between Sparc version (sunzilog) and PowerMac (pmac):
47b4ed08e0Sblueswir1  *  Offset between control and data registers
48b4ed08e0Sblueswir1  *  There is some kind of lockup bug, but we can ignore it
49b4ed08e0Sblueswir1  *  CTS is inverted
50b4ed08e0Sblueswir1  *  DMA on pmac using DBDMA chip
51b4ed08e0Sblueswir1  *  pmac can do IRDA and faster rates, sunzilog can only do 38400
52b4ed08e0Sblueswir1  *  pmac baud rate generator clock is 3.6864 MHz, sunzilog 4.9152 MHz
53e80cfcfcSbellard  */
54e80cfcfcSbellard 
55715748faSbellard /*
56715748faSbellard  * Modifications:
57715748faSbellard  *  2006-Aug-10  Igor Kovalenko :   Renamed KBDQueue to SERIOQueue, implemented
58715748faSbellard  *                                  serial mouse queue.
59715748faSbellard  *                                  Implemented serial mouse protocol.
609fc391f8SArtyom Tarasenko  *
619fc391f8SArtyom Tarasenko  *  2010-May-23  Artyom Tarasenko:  Reworked IUS logic
62715748faSbellard  */
63715748faSbellard 
648be1f5c8Sbellard typedef enum {
658be1f5c8Sbellard     chn_a, chn_b,
668e39a033SBlue Swirl } ChnID;
678be1f5c8Sbellard 
6835db099dSbellard #define CHN_C(s) ((s)->chn == chn_b? 'b' : 'a')
6935db099dSbellard 
708be1f5c8Sbellard typedef enum {
718be1f5c8Sbellard     ser, kbd, mouse,
728e39a033SBlue Swirl } ChnType;
738be1f5c8Sbellard 
74715748faSbellard #define SERIO_QUEUE_SIZE 256
758be1f5c8Sbellard 
768be1f5c8Sbellard typedef struct {
77715748faSbellard     uint8_t data[SERIO_QUEUE_SIZE];
788be1f5c8Sbellard     int rptr, wptr, count;
79715748faSbellard } SERIOQueue;
808be1f5c8Sbellard 
8112abac85Sblueswir1 #define SERIAL_REGS 16
82e80cfcfcSbellard typedef struct ChannelState {
83d537cf6cSpbrook     qemu_irq irq;
8422548760Sblueswir1     uint32_t rxint, txint, rxint_under_svc, txint_under_svc;
858be1f5c8Sbellard     struct ChannelState *otherchn;
86d7b95534SBlue Swirl     uint32_t reg;
87d7b95534SBlue Swirl     uint8_t wregs[SERIAL_REGS], rregs[SERIAL_REGS];
88715748faSbellard     SERIOQueue queue;
89e80cfcfcSbellard     CharDriverState *chr;
90bbbb2f0aSblueswir1     int e0_mode, led_mode, caps_lock_mode, num_lock_mode;
91577390ffSblueswir1     int disabled;
92b4ed08e0Sblueswir1     int clock;
93bdb78caeSBlue Swirl     uint32_t vmstate_dummy;
94d7b95534SBlue Swirl     ChnID chn; // this channel, A (base+4) or B (base+0)
95d7b95534SBlue Swirl     ChnType type;
96d7b95534SBlue Swirl     uint8_t rx, tx;
97e80cfcfcSbellard } ChannelState;
98e80cfcfcSbellard 
993cf63ff2SPaolo Bonzini typedef struct ESCCState {
1006c319c82SBlue Swirl     SysBusDevice busdev;
101e80cfcfcSbellard     struct ChannelState chn[2];
102ec02f7deSGerd Hoffmann     uint32_t it_shift;
10323c5e4caSAvi Kivity     MemoryRegion mmio;
104ee6847d1SGerd Hoffmann     uint32_t disabled;
105ee6847d1SGerd Hoffmann     uint32_t frequency;
1063cf63ff2SPaolo Bonzini } ESCCState;
107e80cfcfcSbellard 
10812abac85Sblueswir1 #define SERIAL_CTRL 0
10912abac85Sblueswir1 #define SERIAL_DATA 1
11012abac85Sblueswir1 
11112abac85Sblueswir1 #define W_CMD     0
11212abac85Sblueswir1 #define CMD_PTR_MASK   0x07
11312abac85Sblueswir1 #define CMD_CMD_MASK   0x38
11412abac85Sblueswir1 #define CMD_HI         0x08
11512abac85Sblueswir1 #define CMD_CLR_TXINT  0x28
11612abac85Sblueswir1 #define CMD_CLR_IUS    0x38
11712abac85Sblueswir1 #define W_INTR    1
11812abac85Sblueswir1 #define INTR_INTALL    0x01
11912abac85Sblueswir1 #define INTR_TXINT     0x02
12012abac85Sblueswir1 #define INTR_RXMODEMSK 0x18
12112abac85Sblueswir1 #define INTR_RXINT1ST  0x08
12212abac85Sblueswir1 #define INTR_RXINTALL  0x10
12312abac85Sblueswir1 #define W_IVEC    2
12412abac85Sblueswir1 #define W_RXCTRL  3
12512abac85Sblueswir1 #define RXCTRL_RXEN    0x01
12612abac85Sblueswir1 #define W_TXCTRL1 4
12712abac85Sblueswir1 #define TXCTRL1_PAREN  0x01
12812abac85Sblueswir1 #define TXCTRL1_PAREV  0x02
12912abac85Sblueswir1 #define TXCTRL1_1STOP  0x04
13012abac85Sblueswir1 #define TXCTRL1_1HSTOP 0x08
13112abac85Sblueswir1 #define TXCTRL1_2STOP  0x0c
13212abac85Sblueswir1 #define TXCTRL1_STPMSK 0x0c
13312abac85Sblueswir1 #define TXCTRL1_CLK1X  0x00
13412abac85Sblueswir1 #define TXCTRL1_CLK16X 0x40
13512abac85Sblueswir1 #define TXCTRL1_CLK32X 0x80
13612abac85Sblueswir1 #define TXCTRL1_CLK64X 0xc0
13712abac85Sblueswir1 #define TXCTRL1_CLKMSK 0xc0
13812abac85Sblueswir1 #define W_TXCTRL2 5
13912abac85Sblueswir1 #define TXCTRL2_TXEN   0x08
14012abac85Sblueswir1 #define TXCTRL2_BITMSK 0x60
14112abac85Sblueswir1 #define TXCTRL2_5BITS  0x00
14212abac85Sblueswir1 #define TXCTRL2_7BITS  0x20
14312abac85Sblueswir1 #define TXCTRL2_6BITS  0x40
14412abac85Sblueswir1 #define TXCTRL2_8BITS  0x60
14512abac85Sblueswir1 #define W_SYNC1   6
14612abac85Sblueswir1 #define W_SYNC2   7
14712abac85Sblueswir1 #define W_TXBUF   8
14812abac85Sblueswir1 #define W_MINTR   9
14912abac85Sblueswir1 #define MINTR_STATUSHI 0x10
15012abac85Sblueswir1 #define MINTR_RST_MASK 0xc0
15112abac85Sblueswir1 #define MINTR_RST_B    0x40
15212abac85Sblueswir1 #define MINTR_RST_A    0x80
15312abac85Sblueswir1 #define MINTR_RST_ALL  0xc0
15412abac85Sblueswir1 #define W_MISC1  10
15512abac85Sblueswir1 #define W_CLOCK  11
15612abac85Sblueswir1 #define CLOCK_TRXC     0x08
15712abac85Sblueswir1 #define W_BRGLO  12
15812abac85Sblueswir1 #define W_BRGHI  13
15912abac85Sblueswir1 #define W_MISC2  14
16012abac85Sblueswir1 #define MISC2_PLLDIS   0x30
16112abac85Sblueswir1 #define W_EXTINT 15
16212abac85Sblueswir1 #define EXTINT_DCD     0x08
16312abac85Sblueswir1 #define EXTINT_SYNCINT 0x10
16412abac85Sblueswir1 #define EXTINT_CTSINT  0x20
16512abac85Sblueswir1 #define EXTINT_TXUNDRN 0x40
16612abac85Sblueswir1 #define EXTINT_BRKINT  0x80
16712abac85Sblueswir1 
16812abac85Sblueswir1 #define R_STATUS  0
16912abac85Sblueswir1 #define STATUS_RXAV    0x01
17012abac85Sblueswir1 #define STATUS_ZERO    0x02
17112abac85Sblueswir1 #define STATUS_TXEMPTY 0x04
17212abac85Sblueswir1 #define STATUS_DCD     0x08
17312abac85Sblueswir1 #define STATUS_SYNC    0x10
17412abac85Sblueswir1 #define STATUS_CTS     0x20
17512abac85Sblueswir1 #define STATUS_TXUNDRN 0x40
17612abac85Sblueswir1 #define STATUS_BRK     0x80
17712abac85Sblueswir1 #define R_SPEC    1
17812abac85Sblueswir1 #define SPEC_ALLSENT   0x01
17912abac85Sblueswir1 #define SPEC_BITS8     0x06
18012abac85Sblueswir1 #define R_IVEC    2
18112abac85Sblueswir1 #define IVEC_TXINTB    0x00
18212abac85Sblueswir1 #define IVEC_LONOINT   0x06
18312abac85Sblueswir1 #define IVEC_LORXINTA  0x0c
18412abac85Sblueswir1 #define IVEC_LORXINTB  0x04
18512abac85Sblueswir1 #define IVEC_LOTXINTA  0x08
18612abac85Sblueswir1 #define IVEC_HINOINT   0x60
18712abac85Sblueswir1 #define IVEC_HIRXINTA  0x30
18812abac85Sblueswir1 #define IVEC_HIRXINTB  0x20
18912abac85Sblueswir1 #define IVEC_HITXINTA  0x10
19012abac85Sblueswir1 #define R_INTR    3
19112abac85Sblueswir1 #define INTR_EXTINTB   0x01
19212abac85Sblueswir1 #define INTR_TXINTB    0x02
19312abac85Sblueswir1 #define INTR_RXINTB    0x04
19412abac85Sblueswir1 #define INTR_EXTINTA   0x08
19512abac85Sblueswir1 #define INTR_TXINTA    0x10
19612abac85Sblueswir1 #define INTR_RXINTA    0x20
19712abac85Sblueswir1 #define R_IPEN    4
19812abac85Sblueswir1 #define R_TXCTRL1 5
19912abac85Sblueswir1 #define R_TXCTRL2 6
20012abac85Sblueswir1 #define R_BC      7
20112abac85Sblueswir1 #define R_RXBUF   8
20212abac85Sblueswir1 #define R_RXCTRL  9
20312abac85Sblueswir1 #define R_MISC   10
20412abac85Sblueswir1 #define R_MISC1  11
20512abac85Sblueswir1 #define R_BRGLO  12
20612abac85Sblueswir1 #define R_BRGHI  13
20712abac85Sblueswir1 #define R_MISC1I 14
20812abac85Sblueswir1 #define R_EXTINT 15
209e80cfcfcSbellard 
2108be1f5c8Sbellard static void handle_kbd_command(ChannelState *s, int val);
2118be1f5c8Sbellard static int serial_can_receive(void *opaque);
2128be1f5c8Sbellard static void serial_receive_byte(ChannelState *s, int ch);
2138be1f5c8Sbellard 
21467deb562Sblueswir1 static void clear_queue(void *opaque)
21567deb562Sblueswir1 {
21667deb562Sblueswir1     ChannelState *s = opaque;
21767deb562Sblueswir1     SERIOQueue *q = &s->queue;
21867deb562Sblueswir1     q->rptr = q->wptr = q->count = 0;
21967deb562Sblueswir1 }
22067deb562Sblueswir1 
2218be1f5c8Sbellard static void put_queue(void *opaque, int b)
2228be1f5c8Sbellard {
2238be1f5c8Sbellard     ChannelState *s = opaque;
224715748faSbellard     SERIOQueue *q = &s->queue;
2258be1f5c8Sbellard 
22630c2f238SBlue Swirl     trace_escc_put_queue(CHN_C(s), b);
227715748faSbellard     if (q->count >= SERIO_QUEUE_SIZE)
2288be1f5c8Sbellard         return;
2298be1f5c8Sbellard     q->data[q->wptr] = b;
230715748faSbellard     if (++q->wptr == SERIO_QUEUE_SIZE)
2318be1f5c8Sbellard         q->wptr = 0;
2328be1f5c8Sbellard     q->count++;
2338be1f5c8Sbellard     serial_receive_byte(s, 0);
2348be1f5c8Sbellard }
2358be1f5c8Sbellard 
2368be1f5c8Sbellard static uint32_t get_queue(void *opaque)
2378be1f5c8Sbellard {
2388be1f5c8Sbellard     ChannelState *s = opaque;
239715748faSbellard     SERIOQueue *q = &s->queue;
2408be1f5c8Sbellard     int val;
2418be1f5c8Sbellard 
2428be1f5c8Sbellard     if (q->count == 0) {
2438be1f5c8Sbellard         return 0;
2448be1f5c8Sbellard     } else {
2458be1f5c8Sbellard         val = q->data[q->rptr];
246715748faSbellard         if (++q->rptr == SERIO_QUEUE_SIZE)
2478be1f5c8Sbellard             q->rptr = 0;
2488be1f5c8Sbellard         q->count--;
2498be1f5c8Sbellard     }
25030c2f238SBlue Swirl     trace_escc_get_queue(CHN_C(s), val);
2518be1f5c8Sbellard     if (q->count > 0)
2528be1f5c8Sbellard         serial_receive_byte(s, 0);
2538be1f5c8Sbellard     return val;
2548be1f5c8Sbellard }
2558be1f5c8Sbellard 
256b4ed08e0Sblueswir1 static int escc_update_irq_chn(ChannelState *s)
257e80cfcfcSbellard {
2589fc391f8SArtyom Tarasenko     if ((((s->wregs[W_INTR] & INTR_TXINT) && (s->txint == 1)) ||
25912abac85Sblueswir1          // tx ints enabled, pending
26012abac85Sblueswir1          ((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) ||
26112abac85Sblueswir1            ((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) &&
262e80cfcfcSbellard           s->rxint == 1) || // rx ints enabled, pending
26312abac85Sblueswir1          ((s->wregs[W_EXTINT] & EXTINT_BRKINT) &&
26412abac85Sblueswir1           (s->rregs[R_STATUS] & STATUS_BRK)))) { // break int e&p
265e4a89056Sbellard         return 1;
266e80cfcfcSbellard     }
267e4a89056Sbellard     return 0;
268e4a89056Sbellard }
269e4a89056Sbellard 
270b4ed08e0Sblueswir1 static void escc_update_irq(ChannelState *s)
271e4a89056Sbellard {
272e4a89056Sbellard     int irq;
273e4a89056Sbellard 
274b4ed08e0Sblueswir1     irq = escc_update_irq_chn(s);
275b4ed08e0Sblueswir1     irq |= escc_update_irq_chn(s->otherchn);
276e4a89056Sbellard 
27730c2f238SBlue Swirl     trace_escc_update_irq(irq);
278d537cf6cSpbrook     qemu_set_irq(s->irq, irq);
279e80cfcfcSbellard }
280e80cfcfcSbellard 
281b4ed08e0Sblueswir1 static void escc_reset_chn(ChannelState *s)
282e80cfcfcSbellard {
283e80cfcfcSbellard     int i;
284e80cfcfcSbellard 
285e80cfcfcSbellard     s->reg = 0;
2868f180a43Sblueswir1     for (i = 0; i < SERIAL_REGS; i++) {
287e80cfcfcSbellard         s->rregs[i] = 0;
288e80cfcfcSbellard         s->wregs[i] = 0;
289e80cfcfcSbellard     }
29012abac85Sblueswir1     s->wregs[W_TXCTRL1] = TXCTRL1_1STOP; // 1X divisor, 1 stop bit, no parity
29112abac85Sblueswir1     s->wregs[W_MINTR] = MINTR_RST_ALL;
29212abac85Sblueswir1     s->wregs[W_CLOCK] = CLOCK_TRXC; // Synch mode tx clock = TRxC
29312abac85Sblueswir1     s->wregs[W_MISC2] = MISC2_PLLDIS; // PLL disabled
29412abac85Sblueswir1     s->wregs[W_EXTINT] = EXTINT_DCD | EXTINT_SYNCINT | EXTINT_CTSINT |
29512abac85Sblueswir1         EXTINT_TXUNDRN | EXTINT_BRKINT; // Enable most interrupts
296577390ffSblueswir1     if (s->disabled)
29712abac85Sblueswir1         s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_DCD | STATUS_SYNC |
29812abac85Sblueswir1             STATUS_CTS | STATUS_TXUNDRN;
299577390ffSblueswir1     else
30012abac85Sblueswir1         s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_TXUNDRN;
301f48c537dSblueswir1     s->rregs[R_SPEC] = SPEC_BITS8 | SPEC_ALLSENT;
302e80cfcfcSbellard 
303e80cfcfcSbellard     s->rx = s->tx = 0;
304e80cfcfcSbellard     s->rxint = s->txint = 0;
305e4a89056Sbellard     s->rxint_under_svc = s->txint_under_svc = 0;
306bbbb2f0aSblueswir1     s->e0_mode = s->led_mode = s->caps_lock_mode = s->num_lock_mode = 0;
30767deb562Sblueswir1     clear_queue(s);
308e80cfcfcSbellard }
309e80cfcfcSbellard 
310bdb78caeSBlue Swirl static void escc_reset(DeviceState *d)
311e80cfcfcSbellard {
3123cf63ff2SPaolo Bonzini     ESCCState *s = container_of(d, ESCCState, busdev.qdev);
313bdb78caeSBlue Swirl 
314b4ed08e0Sblueswir1     escc_reset_chn(&s->chn[0]);
315b4ed08e0Sblueswir1     escc_reset_chn(&s->chn[1]);
316e80cfcfcSbellard }
317e80cfcfcSbellard 
318ba3c64fbSbellard static inline void set_rxint(ChannelState *s)
319ba3c64fbSbellard {
320ba3c64fbSbellard     s->rxint = 1;
3219fc391f8SArtyom Tarasenko     /* XXX: missing daisy chainnig: chn_b rx should have a lower priority
3229fc391f8SArtyom Tarasenko        than chn_a rx/tx/special_condition service*/
323e4a89056Sbellard     s->rxint_under_svc = 1;
32467deb562Sblueswir1     if (s->chn == chn_a) {
3259fc391f8SArtyom Tarasenko         s->rregs[R_INTR] |= INTR_RXINTA;
32612abac85Sblueswir1         if (s->wregs[W_MINTR] & MINTR_STATUSHI)
32712abac85Sblueswir1             s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
32835db099dSbellard         else
32912abac85Sblueswir1             s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
33067deb562Sblueswir1     } else {
3319fc391f8SArtyom Tarasenko         s->otherchn->rregs[R_INTR] |= INTR_RXINTB;
33212abac85Sblueswir1         if (s->wregs[W_MINTR] & MINTR_STATUSHI)
33312abac85Sblueswir1             s->rregs[R_IVEC] = IVEC_HIRXINTB;
33467deb562Sblueswir1         else
33512abac85Sblueswir1             s->rregs[R_IVEC] = IVEC_LORXINTB;
336b9652ca3Sblueswir1     }
337b4ed08e0Sblueswir1     escc_update_irq(s);
338ba3c64fbSbellard }
339ba3c64fbSbellard 
34080637a6aSblueswir1 static inline void set_txint(ChannelState *s)
34180637a6aSblueswir1 {
34280637a6aSblueswir1     s->txint = 1;
34380637a6aSblueswir1     if (!s->rxint_under_svc) {
34480637a6aSblueswir1         s->txint_under_svc = 1;
34580637a6aSblueswir1         if (s->chn == chn_a) {
346f53671c0SAurelien Jarno             if (s->wregs[W_INTR] & INTR_TXINT) {
3479fc391f8SArtyom Tarasenko                 s->rregs[R_INTR] |= INTR_TXINTA;
348f53671c0SAurelien Jarno             }
34980637a6aSblueswir1             if (s->wregs[W_MINTR] & MINTR_STATUSHI)
35080637a6aSblueswir1                 s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA;
35180637a6aSblueswir1             else
35280637a6aSblueswir1                 s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA;
35380637a6aSblueswir1         } else {
35480637a6aSblueswir1             s->rregs[R_IVEC] = IVEC_TXINTB;
355f53671c0SAurelien Jarno             if (s->wregs[W_INTR] & INTR_TXINT) {
35680637a6aSblueswir1                 s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
3579fc391f8SArtyom Tarasenko             }
358f53671c0SAurelien Jarno         }
359b4ed08e0Sblueswir1     escc_update_irq(s);
36080637a6aSblueswir1     }
3619fc391f8SArtyom Tarasenko }
36280637a6aSblueswir1 
36380637a6aSblueswir1 static inline void clr_rxint(ChannelState *s)
36480637a6aSblueswir1 {
36580637a6aSblueswir1     s->rxint = 0;
36680637a6aSblueswir1     s->rxint_under_svc = 0;
36780637a6aSblueswir1     if (s->chn == chn_a) {
36880637a6aSblueswir1         if (s->wregs[W_MINTR] & MINTR_STATUSHI)
36980637a6aSblueswir1             s->otherchn->rregs[R_IVEC] = IVEC_HINOINT;
37080637a6aSblueswir1         else
37180637a6aSblueswir1             s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
37280637a6aSblueswir1         s->rregs[R_INTR] &= ~INTR_RXINTA;
37380637a6aSblueswir1     } else {
37480637a6aSblueswir1         if (s->wregs[W_MINTR] & MINTR_STATUSHI)
37580637a6aSblueswir1             s->rregs[R_IVEC] = IVEC_HINOINT;
37680637a6aSblueswir1         else
37780637a6aSblueswir1             s->rregs[R_IVEC] = IVEC_LONOINT;
37880637a6aSblueswir1         s->otherchn->rregs[R_INTR] &= ~INTR_RXINTB;
37980637a6aSblueswir1     }
38080637a6aSblueswir1     if (s->txint)
38180637a6aSblueswir1         set_txint(s);
382b4ed08e0Sblueswir1     escc_update_irq(s);
38380637a6aSblueswir1 }
38480637a6aSblueswir1 
385ba3c64fbSbellard static inline void clr_txint(ChannelState *s)
386ba3c64fbSbellard {
387ba3c64fbSbellard     s->txint = 0;
388e4a89056Sbellard     s->txint_under_svc = 0;
389b9652ca3Sblueswir1     if (s->chn == chn_a) {
39012abac85Sblueswir1         if (s->wregs[W_MINTR] & MINTR_STATUSHI)
39112abac85Sblueswir1             s->otherchn->rregs[R_IVEC] = IVEC_HINOINT;
39235db099dSbellard         else
39312abac85Sblueswir1             s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
39412abac85Sblueswir1         s->rregs[R_INTR] &= ~INTR_TXINTA;
395b9652ca3Sblueswir1     } else {
3969fc391f8SArtyom Tarasenko         s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
39712abac85Sblueswir1         if (s->wregs[W_MINTR] & MINTR_STATUSHI)
39812abac85Sblueswir1             s->rregs[R_IVEC] = IVEC_HINOINT;
399b9652ca3Sblueswir1         else
40012abac85Sblueswir1             s->rregs[R_IVEC] = IVEC_LONOINT;
40112abac85Sblueswir1         s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
402b9652ca3Sblueswir1     }
403e4a89056Sbellard     if (s->rxint)
404e4a89056Sbellard         set_rxint(s);
405b4ed08e0Sblueswir1     escc_update_irq(s);
406ba3c64fbSbellard }
407ba3c64fbSbellard 
408b4ed08e0Sblueswir1 static void escc_update_parameters(ChannelState *s)
40935db099dSbellard {
41035db099dSbellard     int speed, parity, data_bits, stop_bits;
41135db099dSbellard     QEMUSerialSetParams ssp;
41235db099dSbellard 
41335db099dSbellard     if (!s->chr || s->type != ser)
41435db099dSbellard         return;
41535db099dSbellard 
41612abac85Sblueswir1     if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREN) {
41712abac85Sblueswir1         if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREV)
41835db099dSbellard             parity = 'E';
41935db099dSbellard         else
42035db099dSbellard             parity = 'O';
42135db099dSbellard     } else {
42235db099dSbellard         parity = 'N';
42335db099dSbellard     }
42412abac85Sblueswir1     if ((s->wregs[W_TXCTRL1] & TXCTRL1_STPMSK) == TXCTRL1_2STOP)
42535db099dSbellard         stop_bits = 2;
42635db099dSbellard     else
42735db099dSbellard         stop_bits = 1;
42812abac85Sblueswir1     switch (s->wregs[W_TXCTRL2] & TXCTRL2_BITMSK) {
42912abac85Sblueswir1     case TXCTRL2_5BITS:
43035db099dSbellard         data_bits = 5;
43135db099dSbellard         break;
43212abac85Sblueswir1     case TXCTRL2_7BITS:
43335db099dSbellard         data_bits = 7;
43435db099dSbellard         break;
43512abac85Sblueswir1     case TXCTRL2_6BITS:
43635db099dSbellard         data_bits = 6;
43735db099dSbellard         break;
43835db099dSbellard     default:
43912abac85Sblueswir1     case TXCTRL2_8BITS:
44035db099dSbellard         data_bits = 8;
44135db099dSbellard         break;
44235db099dSbellard     }
443b4ed08e0Sblueswir1     speed = s->clock / ((s->wregs[W_BRGLO] | (s->wregs[W_BRGHI] << 8)) + 2);
44412abac85Sblueswir1     switch (s->wregs[W_TXCTRL1] & TXCTRL1_CLKMSK) {
44512abac85Sblueswir1     case TXCTRL1_CLK1X:
44635db099dSbellard         break;
44712abac85Sblueswir1     case TXCTRL1_CLK16X:
44835db099dSbellard         speed /= 16;
44935db099dSbellard         break;
45012abac85Sblueswir1     case TXCTRL1_CLK32X:
45135db099dSbellard         speed /= 32;
45235db099dSbellard         break;
45335db099dSbellard     default:
45412abac85Sblueswir1     case TXCTRL1_CLK64X:
45535db099dSbellard         speed /= 64;
45635db099dSbellard         break;
45735db099dSbellard     }
45835db099dSbellard     ssp.speed = speed;
45935db099dSbellard     ssp.parity = parity;
46035db099dSbellard     ssp.data_bits = data_bits;
46135db099dSbellard     ssp.stop_bits = stop_bits;
46230c2f238SBlue Swirl     trace_escc_update_parameters(CHN_C(s), speed, parity, data_bits, stop_bits);
46341084f1bSAnthony Liguori     qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
46435db099dSbellard }
46535db099dSbellard 
466a8170e5eSAvi Kivity static void escc_mem_write(void *opaque, hwaddr addr,
46723c5e4caSAvi Kivity                            uint64_t val, unsigned size)
468e80cfcfcSbellard {
4693cf63ff2SPaolo Bonzini     ESCCState *serial = opaque;
470e80cfcfcSbellard     ChannelState *s;
471e80cfcfcSbellard     uint32_t saddr;
472e80cfcfcSbellard     int newreg, channel;
473e80cfcfcSbellard 
474e80cfcfcSbellard     val &= 0xff;
475b4ed08e0Sblueswir1     saddr = (addr >> serial->it_shift) & 1;
476b4ed08e0Sblueswir1     channel = (addr >> (serial->it_shift + 1)) & 1;
477b3ceef24Sblueswir1     s = &serial->chn[channel];
478e80cfcfcSbellard     switch (saddr) {
47912abac85Sblueswir1     case SERIAL_CTRL:
48030c2f238SBlue Swirl         trace_escc_mem_writeb_ctrl(CHN_C(s), s->reg, val & 0xff);
481e80cfcfcSbellard         newreg = 0;
482e80cfcfcSbellard         switch (s->reg) {
48312abac85Sblueswir1         case W_CMD:
48412abac85Sblueswir1             newreg = val & CMD_PTR_MASK;
48512abac85Sblueswir1             val &= CMD_CMD_MASK;
486e80cfcfcSbellard             switch (val) {
48712abac85Sblueswir1             case CMD_HI:
48812abac85Sblueswir1                 newreg |= CMD_HI;
489e80cfcfcSbellard                 break;
49012abac85Sblueswir1             case CMD_CLR_TXINT:
491ba3c64fbSbellard                 clr_txint(s);
492ba3c64fbSbellard                 break;
49312abac85Sblueswir1             case CMD_CLR_IUS:
4949fc391f8SArtyom Tarasenko                 if (s->rxint_under_svc) {
4959fc391f8SArtyom Tarasenko                     s->rxint_under_svc = 0;
4969fc391f8SArtyom Tarasenko                     if (s->txint) {
4979fc391f8SArtyom Tarasenko                         set_txint(s);
4989fc391f8SArtyom Tarasenko                     }
4999fc391f8SArtyom Tarasenko                 } else if (s->txint_under_svc) {
5009fc391f8SArtyom Tarasenko                     s->txint_under_svc = 0;
5019fc391f8SArtyom Tarasenko                 }
5029fc391f8SArtyom Tarasenko                 escc_update_irq(s);
503e80cfcfcSbellard                 break;
504e80cfcfcSbellard             default:
505e80cfcfcSbellard                 break;
506e80cfcfcSbellard             }
507e80cfcfcSbellard             break;
50812abac85Sblueswir1         case W_INTR ... W_RXCTRL:
50912abac85Sblueswir1         case W_SYNC1 ... W_TXBUF:
51012abac85Sblueswir1         case W_MISC1 ... W_CLOCK:
51112abac85Sblueswir1         case W_MISC2 ... W_EXTINT:
512e80cfcfcSbellard             s->wregs[s->reg] = val;
513e80cfcfcSbellard             break;
51412abac85Sblueswir1         case W_TXCTRL1:
51512abac85Sblueswir1         case W_TXCTRL2:
516796d8286Sblueswir1             s->wregs[s->reg] = val;
517b4ed08e0Sblueswir1             escc_update_parameters(s);
518796d8286Sblueswir1             break;
51912abac85Sblueswir1         case W_BRGLO:
52012abac85Sblueswir1         case W_BRGHI:
52135db099dSbellard             s->wregs[s->reg] = val;
522796d8286Sblueswir1             s->rregs[s->reg] = val;
523b4ed08e0Sblueswir1             escc_update_parameters(s);
52435db099dSbellard             break;
52512abac85Sblueswir1         case W_MINTR:
52612abac85Sblueswir1             switch (val & MINTR_RST_MASK) {
527e80cfcfcSbellard             case 0:
528e80cfcfcSbellard             default:
529e80cfcfcSbellard                 break;
53012abac85Sblueswir1             case MINTR_RST_B:
531b4ed08e0Sblueswir1                 escc_reset_chn(&serial->chn[0]);
532e80cfcfcSbellard                 return;
53312abac85Sblueswir1             case MINTR_RST_A:
534b4ed08e0Sblueswir1                 escc_reset_chn(&serial->chn[1]);
535e80cfcfcSbellard                 return;
53612abac85Sblueswir1             case MINTR_RST_ALL:
537bdb78caeSBlue Swirl                 escc_reset(&serial->busdev.qdev);
538e80cfcfcSbellard                 return;
539e80cfcfcSbellard             }
540e80cfcfcSbellard             break;
541e80cfcfcSbellard         default:
542e80cfcfcSbellard             break;
543e80cfcfcSbellard         }
544e80cfcfcSbellard         if (s->reg == 0)
545e80cfcfcSbellard             s->reg = newreg;
546e80cfcfcSbellard         else
547e80cfcfcSbellard             s->reg = 0;
548e80cfcfcSbellard         break;
54912abac85Sblueswir1     case SERIAL_DATA:
55030c2f238SBlue Swirl         trace_escc_mem_writeb_data(CHN_C(s), val);
551e80cfcfcSbellard         s->tx = val;
55212abac85Sblueswir1         if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
553e80cfcfcSbellard             if (s->chr)
5542cc6e0a1SAnthony Liguori                 qemu_chr_fe_write(s->chr, &s->tx, 1);
555577390ffSblueswir1             else if (s->type == kbd && !s->disabled) {
5568be1f5c8Sbellard                 handle_kbd_command(s, val);
5578be1f5c8Sbellard             }
55896c4f569Sblueswir1         }
55912abac85Sblueswir1         s->rregs[R_STATUS] |= STATUS_TXEMPTY; // Tx buffer empty
56012abac85Sblueswir1         s->rregs[R_SPEC] |= SPEC_ALLSENT; // All sent
561ba3c64fbSbellard         set_txint(s);
562e80cfcfcSbellard         break;
563e80cfcfcSbellard     default:
564e80cfcfcSbellard         break;
565e80cfcfcSbellard     }
566e80cfcfcSbellard }
567e80cfcfcSbellard 
568a8170e5eSAvi Kivity static uint64_t escc_mem_read(void *opaque, hwaddr addr,
56923c5e4caSAvi Kivity                               unsigned size)
570e80cfcfcSbellard {
5713cf63ff2SPaolo Bonzini     ESCCState *serial = opaque;
572e80cfcfcSbellard     ChannelState *s;
573e80cfcfcSbellard     uint32_t saddr;
574e80cfcfcSbellard     uint32_t ret;
575e80cfcfcSbellard     int channel;
576e80cfcfcSbellard 
577b4ed08e0Sblueswir1     saddr = (addr >> serial->it_shift) & 1;
578b4ed08e0Sblueswir1     channel = (addr >> (serial->it_shift + 1)) & 1;
579b3ceef24Sblueswir1     s = &serial->chn[channel];
580e80cfcfcSbellard     switch (saddr) {
58112abac85Sblueswir1     case SERIAL_CTRL:
58230c2f238SBlue Swirl         trace_escc_mem_readb_ctrl(CHN_C(s), s->reg, s->rregs[s->reg]);
583e80cfcfcSbellard         ret = s->rregs[s->reg];
584e80cfcfcSbellard         s->reg = 0;
585e80cfcfcSbellard         return ret;
58612abac85Sblueswir1     case SERIAL_DATA:
58712abac85Sblueswir1         s->rregs[R_STATUS] &= ~STATUS_RXAV;
588ba3c64fbSbellard         clr_rxint(s);
589715748faSbellard         if (s->type == kbd || s->type == mouse)
5908be1f5c8Sbellard             ret = get_queue(s);
5918be1f5c8Sbellard         else
5928be1f5c8Sbellard             ret = s->rx;
59330c2f238SBlue Swirl         trace_escc_mem_readb_data(CHN_C(s), ret);
594b76482e7Sblueswir1         if (s->chr)
595bd9bdce6Sbalrog             qemu_chr_accept_input(s->chr);
5968be1f5c8Sbellard         return ret;
597e80cfcfcSbellard     default:
598e80cfcfcSbellard         break;
599e80cfcfcSbellard     }
600e80cfcfcSbellard     return 0;
601e80cfcfcSbellard }
602e80cfcfcSbellard 
60323c5e4caSAvi Kivity static const MemoryRegionOps escc_mem_ops = {
60423c5e4caSAvi Kivity     .read = escc_mem_read,
60523c5e4caSAvi Kivity     .write = escc_mem_write,
60623c5e4caSAvi Kivity     .endianness = DEVICE_NATIVE_ENDIAN,
60723c5e4caSAvi Kivity     .valid = {
60823c5e4caSAvi Kivity         .min_access_size = 1,
60923c5e4caSAvi Kivity         .max_access_size = 1,
61023c5e4caSAvi Kivity     },
61123c5e4caSAvi Kivity };
61223c5e4caSAvi Kivity 
613e80cfcfcSbellard static int serial_can_receive(void *opaque)
614e80cfcfcSbellard {
615e80cfcfcSbellard     ChannelState *s = opaque;
616e4a89056Sbellard     int ret;
617e4a89056Sbellard 
61812abac85Sblueswir1     if (((s->wregs[W_RXCTRL] & RXCTRL_RXEN) == 0) // Rx not enabled
61912abac85Sblueswir1         || ((s->rregs[R_STATUS] & STATUS_RXAV) == STATUS_RXAV))
62012abac85Sblueswir1         // char already available
621e4a89056Sbellard         ret = 0;
622e80cfcfcSbellard     else
623e4a89056Sbellard         ret = 1;
624e4a89056Sbellard     return ret;
625e80cfcfcSbellard }
626e80cfcfcSbellard 
627e80cfcfcSbellard static void serial_receive_byte(ChannelState *s, int ch)
628e80cfcfcSbellard {
62930c2f238SBlue Swirl     trace_escc_serial_receive_byte(CHN_C(s), ch);
63012abac85Sblueswir1     s->rregs[R_STATUS] |= STATUS_RXAV;
631e80cfcfcSbellard     s->rx = ch;
632ba3c64fbSbellard     set_rxint(s);
633e80cfcfcSbellard }
634e80cfcfcSbellard 
635e80cfcfcSbellard static void serial_receive_break(ChannelState *s)
636e80cfcfcSbellard {
63712abac85Sblueswir1     s->rregs[R_STATUS] |= STATUS_BRK;
638b4ed08e0Sblueswir1     escc_update_irq(s);
639e80cfcfcSbellard }
640e80cfcfcSbellard 
641e80cfcfcSbellard static void serial_receive1(void *opaque, const uint8_t *buf, int size)
642e80cfcfcSbellard {
643e80cfcfcSbellard     ChannelState *s = opaque;
644e80cfcfcSbellard     serial_receive_byte(s, buf[0]);
645e80cfcfcSbellard }
646e80cfcfcSbellard 
647e80cfcfcSbellard static void serial_event(void *opaque, int event)
648e80cfcfcSbellard {
649e80cfcfcSbellard     ChannelState *s = opaque;
650e80cfcfcSbellard     if (event == CHR_EVENT_BREAK)
651e80cfcfcSbellard         serial_receive_break(s);
652e80cfcfcSbellard }
653e80cfcfcSbellard 
654bdb78caeSBlue Swirl static const VMStateDescription vmstate_escc_chn = {
655bdb78caeSBlue Swirl     .name ="escc_chn",
656bdb78caeSBlue Swirl     .version_id = 2,
657bdb78caeSBlue Swirl     .minimum_version_id = 1,
658bdb78caeSBlue Swirl     .minimum_version_id_old = 1,
659bdb78caeSBlue Swirl     .fields      = (VMStateField []) {
660bdb78caeSBlue Swirl         VMSTATE_UINT32(vmstate_dummy, ChannelState),
661bdb78caeSBlue Swirl         VMSTATE_UINT32(reg, ChannelState),
662bdb78caeSBlue Swirl         VMSTATE_UINT32(rxint, ChannelState),
663bdb78caeSBlue Swirl         VMSTATE_UINT32(txint, ChannelState),
664bdb78caeSBlue Swirl         VMSTATE_UINT32(rxint_under_svc, ChannelState),
665bdb78caeSBlue Swirl         VMSTATE_UINT32(txint_under_svc, ChannelState),
666bdb78caeSBlue Swirl         VMSTATE_UINT8(rx, ChannelState),
667bdb78caeSBlue Swirl         VMSTATE_UINT8(tx, ChannelState),
668bdb78caeSBlue Swirl         VMSTATE_BUFFER(wregs, ChannelState),
669bdb78caeSBlue Swirl         VMSTATE_BUFFER(rregs, ChannelState),
670bdb78caeSBlue Swirl         VMSTATE_END_OF_LIST()
671e80cfcfcSbellard     }
672bdb78caeSBlue Swirl };
673e80cfcfcSbellard 
674bdb78caeSBlue Swirl static const VMStateDescription vmstate_escc = {
675bdb78caeSBlue Swirl     .name ="escc",
676bdb78caeSBlue Swirl     .version_id = 2,
677bdb78caeSBlue Swirl     .minimum_version_id = 1,
678bdb78caeSBlue Swirl     .minimum_version_id_old = 1,
679bdb78caeSBlue Swirl     .fields      = (VMStateField []) {
6803cf63ff2SPaolo Bonzini         VMSTATE_STRUCT_ARRAY(chn, ESCCState, 2, 2, vmstate_escc_chn,
681bdb78caeSBlue Swirl                              ChannelState),
682bdb78caeSBlue Swirl         VMSTATE_END_OF_LIST()
683e80cfcfcSbellard     }
684bdb78caeSBlue Swirl };
685e80cfcfcSbellard 
686a8170e5eSAvi Kivity MemoryRegion *escc_init(hwaddr base, qemu_irq irqA, qemu_irq irqB,
687aeeb69c7Saurel32               CharDriverState *chrA, CharDriverState *chrB,
688aeeb69c7Saurel32               int clock, int it_shift)
689e80cfcfcSbellard {
6906c319c82SBlue Swirl     DeviceState *dev;
6916c319c82SBlue Swirl     SysBusDevice *s;
6923cf63ff2SPaolo Bonzini     ESCCState *d;
693e80cfcfcSbellard 
6946c319c82SBlue Swirl     dev = qdev_create(NULL, "escc");
695ee6847d1SGerd Hoffmann     qdev_prop_set_uint32(dev, "disabled", 0);
696ee6847d1SGerd Hoffmann     qdev_prop_set_uint32(dev, "frequency", clock);
697ee6847d1SGerd Hoffmann     qdev_prop_set_uint32(dev, "it_shift", it_shift);
698bc19fcaaSBlue Swirl     qdev_prop_set_chr(dev, "chrB", chrB);
699bc19fcaaSBlue Swirl     qdev_prop_set_chr(dev, "chrA", chrA);
700ee6847d1SGerd Hoffmann     qdev_prop_set_uint32(dev, "chnBtype", ser);
701ee6847d1SGerd Hoffmann     qdev_prop_set_uint32(dev, "chnAtype", ser);
702e23a1b33SMarkus Armbruster     qdev_init_nofail(dev);
7031356b98dSAndreas Färber     s = SYS_BUS_DEVICE(dev);
704e1a0e47fSAurelien Jarno     sysbus_connect_irq(s, 0, irqB);
705e1a0e47fSAurelien Jarno     sysbus_connect_irq(s, 1, irqA);
7066c319c82SBlue Swirl     if (base) {
7076c319c82SBlue Swirl         sysbus_mmio_map(s, 0, base);
708e80cfcfcSbellard     }
7096c319c82SBlue Swirl 
7103cf63ff2SPaolo Bonzini     d = FROM_SYSBUS(ESCCState, s);
71123c5e4caSAvi Kivity     return &d->mmio;
712e80cfcfcSbellard }
713e80cfcfcSbellard 
7148be1f5c8Sbellard static const uint8_t keycodes[128] = {
7158be1f5c8Sbellard     127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53,
7168be1f5c8Sbellard     54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78,
7178be1f5c8Sbellard     79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103,
7188be1f5c8Sbellard     104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12,
7198be1f5c8Sbellard     14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112,
7208be1f5c8Sbellard     113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0,
7218be1f5c8Sbellard     90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66,
7228be1f5c8Sbellard     0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67,
7238be1f5c8Sbellard };
7248be1f5c8Sbellard 
72543febf49Sblueswir1 static const uint8_t e0_keycodes[128] = {
72643febf49Sblueswir1     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
72743febf49Sblueswir1     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 76, 0, 0,
72843febf49Sblueswir1     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
72943febf49Sblueswir1     0, 0, 0, 0, 0, 109, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0,
73043febf49Sblueswir1     0, 0, 0, 0, 0, 0, 0, 68, 69, 70, 0, 91, 0, 93, 0, 112,
73143febf49Sblueswir1     113, 114, 94, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
73243febf49Sblueswir1     0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
733c0b5b109Sblueswir1     1, 3, 25, 26, 49, 52, 72, 73, 97, 99, 111, 118, 120, 122, 67, 0,
73443febf49Sblueswir1 };
73543febf49Sblueswir1 
736e80cfcfcSbellard static void sunkbd_event(void *opaque, int ch)
737e80cfcfcSbellard {
738e80cfcfcSbellard     ChannelState *s = opaque;
7398be1f5c8Sbellard     int release = ch & 0x80;
7408be1f5c8Sbellard 
74130c2f238SBlue Swirl     trace_escc_sunkbd_event_in(ch);
742bbbb2f0aSblueswir1     switch (ch) {
743bbbb2f0aSblueswir1     case 58: // Caps lock press
744bbbb2f0aSblueswir1         s->caps_lock_mode ^= 1;
745bbbb2f0aSblueswir1         if (s->caps_lock_mode == 2)
746bbbb2f0aSblueswir1             return; // Drop second press
747bbbb2f0aSblueswir1         break;
748bbbb2f0aSblueswir1     case 69: // Num lock press
749bbbb2f0aSblueswir1         s->num_lock_mode ^= 1;
750bbbb2f0aSblueswir1         if (s->num_lock_mode == 2)
751bbbb2f0aSblueswir1             return; // Drop second press
752bbbb2f0aSblueswir1         break;
753bbbb2f0aSblueswir1     case 186: // Caps lock release
754bbbb2f0aSblueswir1         s->caps_lock_mode ^= 2;
755bbbb2f0aSblueswir1         if (s->caps_lock_mode == 3)
756bbbb2f0aSblueswir1             return; // Drop first release
757bbbb2f0aSblueswir1         break;
758bbbb2f0aSblueswir1     case 197: // Num lock release
759bbbb2f0aSblueswir1         s->num_lock_mode ^= 2;
760bbbb2f0aSblueswir1         if (s->num_lock_mode == 3)
761bbbb2f0aSblueswir1             return; // Drop first release
762bbbb2f0aSblueswir1         break;
763bbbb2f0aSblueswir1     case 0xe0:
76443febf49Sblueswir1         s->e0_mode = 1;
76543febf49Sblueswir1         return;
766bbbb2f0aSblueswir1     default:
767bbbb2f0aSblueswir1         break;
76843febf49Sblueswir1     }
76943febf49Sblueswir1     if (s->e0_mode) {
77043febf49Sblueswir1         s->e0_mode = 0;
77143febf49Sblueswir1         ch = e0_keycodes[ch & 0x7f];
77243febf49Sblueswir1     } else {
7738be1f5c8Sbellard         ch = keycodes[ch & 0x7f];
77443febf49Sblueswir1     }
77530c2f238SBlue Swirl     trace_escc_sunkbd_event_out(ch);
7768be1f5c8Sbellard     put_queue(s, ch | release);
7778be1f5c8Sbellard }
7788be1f5c8Sbellard 
7798be1f5c8Sbellard static void handle_kbd_command(ChannelState *s, int val)
7808be1f5c8Sbellard {
78130c2f238SBlue Swirl     trace_escc_kbd_command(val);
78243febf49Sblueswir1     if (s->led_mode) { // Ignore led byte
78343febf49Sblueswir1         s->led_mode = 0;
78443febf49Sblueswir1         return;
78543febf49Sblueswir1     }
7868be1f5c8Sbellard     switch (val) {
7878be1f5c8Sbellard     case 1: // Reset, return type code
78867deb562Sblueswir1         clear_queue(s);
7898be1f5c8Sbellard         put_queue(s, 0xff);
79067deb562Sblueswir1         put_queue(s, 4); // Type 4
79143febf49Sblueswir1         put_queue(s, 0x7f);
79243febf49Sblueswir1         break;
79343febf49Sblueswir1     case 0xe: // Set leds
79443febf49Sblueswir1         s->led_mode = 1;
7958be1f5c8Sbellard         break;
7968be1f5c8Sbellard     case 7: // Query layout
79767deb562Sblueswir1     case 0xf:
79867deb562Sblueswir1         clear_queue(s);
7998be1f5c8Sbellard         put_queue(s, 0xfe);
80043febf49Sblueswir1         put_queue(s, 0); // XXX, layout?
8018be1f5c8Sbellard         break;
8028be1f5c8Sbellard     default:
8038be1f5c8Sbellard         break;
8048be1f5c8Sbellard     }
805e80cfcfcSbellard }
806e80cfcfcSbellard 
807e80cfcfcSbellard static void sunmouse_event(void *opaque,
808e80cfcfcSbellard                                int dx, int dy, int dz, int buttons_state)
809e80cfcfcSbellard {
810e80cfcfcSbellard     ChannelState *s = opaque;
811e80cfcfcSbellard     int ch;
812e80cfcfcSbellard 
81330c2f238SBlue Swirl     trace_escc_sunmouse_event(dx, dy, buttons_state);
814715748faSbellard     ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
815715748faSbellard 
816715748faSbellard     if (buttons_state & MOUSE_EVENT_LBUTTON)
817715748faSbellard         ch ^= 0x4;
818715748faSbellard     if (buttons_state & MOUSE_EVENT_MBUTTON)
819715748faSbellard         ch ^= 0x2;
820715748faSbellard     if (buttons_state & MOUSE_EVENT_RBUTTON)
821715748faSbellard         ch ^= 0x1;
822715748faSbellard 
823715748faSbellard     put_queue(s, ch);
824715748faSbellard 
825715748faSbellard     ch = dx;
826715748faSbellard 
827715748faSbellard     if (ch > 127)
828715748faSbellard         ch = 127;
829715748faSbellard     else if (ch < -127)
830715748faSbellard         ch = -127;
831715748faSbellard 
832715748faSbellard     put_queue(s, ch & 0xff);
833715748faSbellard 
834715748faSbellard     ch = -dy;
835715748faSbellard 
836715748faSbellard     if (ch > 127)
837715748faSbellard         ch = 127;
838715748faSbellard     else if (ch < -127)
839715748faSbellard         ch = -127;
840715748faSbellard 
841715748faSbellard     put_queue(s, ch & 0xff);
842715748faSbellard 
843715748faSbellard     // MSC protocol specify two extra motion bytes
844715748faSbellard 
845715748faSbellard     put_queue(s, 0);
846715748faSbellard     put_queue(s, 0);
847e80cfcfcSbellard }
848e80cfcfcSbellard 
849a8170e5eSAvi Kivity void slavio_serial_ms_kbd_init(hwaddr base, qemu_irq irq,
850b4ed08e0Sblueswir1                                int disabled, int clock, int it_shift)
851e80cfcfcSbellard {
8526c319c82SBlue Swirl     DeviceState *dev;
8536c319c82SBlue Swirl     SysBusDevice *s;
854e80cfcfcSbellard 
8556c319c82SBlue Swirl     dev = qdev_create(NULL, "escc");
856ee6847d1SGerd Hoffmann     qdev_prop_set_uint32(dev, "disabled", disabled);
857ee6847d1SGerd Hoffmann     qdev_prop_set_uint32(dev, "frequency", clock);
858ee6847d1SGerd Hoffmann     qdev_prop_set_uint32(dev, "it_shift", it_shift);
859bc19fcaaSBlue Swirl     qdev_prop_set_chr(dev, "chrB", NULL);
860bc19fcaaSBlue Swirl     qdev_prop_set_chr(dev, "chrA", NULL);
861ee6847d1SGerd Hoffmann     qdev_prop_set_uint32(dev, "chnBtype", mouse);
862ee6847d1SGerd Hoffmann     qdev_prop_set_uint32(dev, "chnAtype", kbd);
863e23a1b33SMarkus Armbruster     qdev_init_nofail(dev);
8641356b98dSAndreas Färber     s = SYS_BUS_DEVICE(dev);
8656c319c82SBlue Swirl     sysbus_connect_irq(s, 0, irq);
8666c319c82SBlue Swirl     sysbus_connect_irq(s, 1, irq);
8676c319c82SBlue Swirl     sysbus_mmio_map(s, 0, base);
8686c319c82SBlue Swirl }
869b4ed08e0Sblueswir1 
87081a322d4SGerd Hoffmann static int escc_init1(SysBusDevice *dev)
8716c319c82SBlue Swirl {
8723cf63ff2SPaolo Bonzini     ESCCState *s = FROM_SYSBUS(ESCCState, dev);
8736c319c82SBlue Swirl     unsigned int i;
8746c319c82SBlue Swirl 
875ee6847d1SGerd Hoffmann     s->chn[0].disabled = s->disabled;
876ee6847d1SGerd Hoffmann     s->chn[1].disabled = s->disabled;
8778be1f5c8Sbellard     for (i = 0; i < 2; i++) {
8786c319c82SBlue Swirl         sysbus_init_irq(dev, &s->chn[i].irq);
8798be1f5c8Sbellard         s->chn[i].chn = 1 - i;
880ee6847d1SGerd Hoffmann         s->chn[i].clock = s->frequency / 2;
8816c319c82SBlue Swirl         if (s->chn[i].chr) {
8826c319c82SBlue Swirl             qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive,
8836c319c82SBlue Swirl                                   serial_receive1, serial_event, &s->chn[i]);
8846c319c82SBlue Swirl         }
8858be1f5c8Sbellard     }
8868be1f5c8Sbellard     s->chn[0].otherchn = &s->chn[1];
8878be1f5c8Sbellard     s->chn[1].otherchn = &s->chn[0];
888e80cfcfcSbellard 
889*300b1fc6SPaolo Bonzini     memory_region_init_io(&s->mmio, OBJECT(s), &escc_mem_ops, s, "escc",
89023c5e4caSAvi Kivity                           ESCC_SIZE << s->it_shift);
891750ecd44SAvi Kivity     sysbus_init_mmio(dev, &s->mmio);
892e80cfcfcSbellard 
8936c319c82SBlue Swirl     if (s->chn[0].type == mouse) {
89412abac85Sblueswir1         qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0,
89512abac85Sblueswir1                                      "QEMU Sun Mouse");
8966c319c82SBlue Swirl     }
8976c319c82SBlue Swirl     if (s->chn[1].type == kbd) {
8988be1f5c8Sbellard         qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
8996c319c82SBlue Swirl     }
900bdb78caeSBlue Swirl 
90181a322d4SGerd Hoffmann     return 0;
902e80cfcfcSbellard }
9036c319c82SBlue Swirl 
904999e12bbSAnthony Liguori static Property escc_properties[] = {
9053cf63ff2SPaolo Bonzini     DEFINE_PROP_UINT32("frequency", ESCCState, frequency,   0),
9063cf63ff2SPaolo Bonzini     DEFINE_PROP_UINT32("it_shift",  ESCCState, it_shift,    0),
9073cf63ff2SPaolo Bonzini     DEFINE_PROP_UINT32("disabled",  ESCCState, disabled,    0),
9083cf63ff2SPaolo Bonzini     DEFINE_PROP_UINT32("chnBtype",  ESCCState, chn[0].type, 0),
9093cf63ff2SPaolo Bonzini     DEFINE_PROP_UINT32("chnAtype",  ESCCState, chn[1].type, 0),
9103cf63ff2SPaolo Bonzini     DEFINE_PROP_CHR("chrB", ESCCState, chn[0].chr),
9113cf63ff2SPaolo Bonzini     DEFINE_PROP_CHR("chrA", ESCCState, chn[1].chr),
912ec02f7deSGerd Hoffmann     DEFINE_PROP_END_OF_LIST(),
913999e12bbSAnthony Liguori };
914999e12bbSAnthony Liguori 
915999e12bbSAnthony Liguori static void escc_class_init(ObjectClass *klass, void *data)
916999e12bbSAnthony Liguori {
91739bffca2SAnthony Liguori     DeviceClass *dc = DEVICE_CLASS(klass);
918999e12bbSAnthony Liguori     SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
919999e12bbSAnthony Liguori 
920999e12bbSAnthony Liguori     k->init = escc_init1;
92139bffca2SAnthony Liguori     dc->reset = escc_reset;
92239bffca2SAnthony Liguori     dc->vmsd = &vmstate_escc;
92339bffca2SAnthony Liguori     dc->props = escc_properties;
9246c319c82SBlue Swirl }
925999e12bbSAnthony Liguori 
9268c43a6f0SAndreas Färber static const TypeInfo escc_info = {
927999e12bbSAnthony Liguori     .name          = "escc",
92839bffca2SAnthony Liguori     .parent        = TYPE_SYS_BUS_DEVICE,
9293cf63ff2SPaolo Bonzini     .instance_size = sizeof(ESCCState),
930999e12bbSAnthony Liguori     .class_init    = escc_class_init,
9316c319c82SBlue Swirl };
9326c319c82SBlue Swirl 
93383f7d43aSAndreas Färber static void escc_register_types(void)
9346c319c82SBlue Swirl {
93539bffca2SAnthony Liguori     type_register_static(&escc_info);
9366c319c82SBlue Swirl }
9376c319c82SBlue Swirl 
93883f7d43aSAndreas Färber type_init(escc_register_types)
939