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