blob: 4d8a8e88867e613f90cd03583104c44a76d7f2d0 [file] [log] [blame]
bellarde80cfcf2004-12-19 23:18:01 +00001/*
blueswir1b4ed08e2009-01-12 17:38:28 +00002 * QEMU ESCC (Z8030/Z8530/Z85C30/SCC/ESCC) serial port emulation
ths5fafdf22007-09-16 21:08:06 +00003 *
bellard8be1f5c2005-04-06 20:42:35 +00004 * Copyright (c) 2003-2005 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
bellarde80cfcf2004-12-19 23:18:01 +00006 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22 * THE SOFTWARE.
23 */
Blue Swirl6c319c82009-07-15 08:51:32 +000024
pbrook87ecb682007-11-17 17:14:51 +000025#include "hw.h"
Blue Swirl6c319c82009-07-15 08:51:32 +000026#include "sysbus.h"
blueswir1b4ed08e2009-01-12 17:38:28 +000027#include "escc.h"
pbrook87ecb682007-11-17 17:14:51 +000028#include "qemu-char.h"
29#include "console.h"
Blue Swirl30c2f232011-08-07 11:01:05 +000030#include "trace.h"
bellarde80cfcf2004-12-19 23:18:01 +000031
32/*
Blue Swirl09330e92009-10-24 16:09:01 +000033 * Chipset docs:
34 * "Z80C30/Z85C30/Z80230/Z85230/Z85233 SCC/ESCC User Manual",
35 * http://www.zilog.com/docs/serial/scc_escc_um.pdf
36 *
blueswir1b4ed08e2009-01-12 17:38:28 +000037 * On Sparc32 this is the serial port, mouse and keyboard part of chip STP2001
bellarde80cfcf2004-12-19 23:18:01 +000038 * (Slave I/O), also produced as NCR89C105. See
39 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
ths5fafdf22007-09-16 21:08:06 +000040 *
bellarde80cfcf2004-12-19 23:18:01 +000041 * 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.
44 *
blueswir1b4ed08e2009-01-12 17:38:28 +000045 * 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
bellarde80cfcf2004-12-19 23:18:01 +000053 */
54
bellard715748f2006-09-09 11:35:47 +000055/*
56 * Modifications:
57 * 2006-Aug-10 Igor Kovalenko : Renamed KBDQueue to SERIOQueue, implemented
58 * serial mouse queue.
59 * Implemented serial mouse protocol.
Artyom Tarasenko9fc391f2010-08-15 16:04:41 +020060 *
61 * 2010-May-23 Artyom Tarasenko: Reworked IUS logic
bellard715748f2006-09-09 11:35:47 +000062 */
63
bellard8be1f5c2005-04-06 20:42:35 +000064typedef enum {
65 chn_a, chn_b,
Blue Swirl8e39a032010-02-07 08:05:47 +000066} ChnID;
bellard8be1f5c2005-04-06 20:42:35 +000067
bellard35db0992006-09-09 12:17:15 +000068#define CHN_C(s) ((s)->chn == chn_b? 'b' : 'a')
69
bellard8be1f5c2005-04-06 20:42:35 +000070typedef enum {
71 ser, kbd, mouse,
Blue Swirl8e39a032010-02-07 08:05:47 +000072} ChnType;
bellard8be1f5c2005-04-06 20:42:35 +000073
bellard715748f2006-09-09 11:35:47 +000074#define SERIO_QUEUE_SIZE 256
bellard8be1f5c2005-04-06 20:42:35 +000075
76typedef struct {
bellard715748f2006-09-09 11:35:47 +000077 uint8_t data[SERIO_QUEUE_SIZE];
bellard8be1f5c2005-04-06 20:42:35 +000078 int rptr, wptr, count;
bellard715748f2006-09-09 11:35:47 +000079} SERIOQueue;
bellard8be1f5c2005-04-06 20:42:35 +000080
blueswir112abac82007-12-10 20:05:09 +000081#define SERIAL_REGS 16
bellarde80cfcf2004-12-19 23:18:01 +000082typedef struct ChannelState {
pbrookd537cf62007-04-07 18:14:41 +000083 qemu_irq irq;
blueswir122548762008-05-10 10:12:00 +000084 uint32_t rxint, txint, rxint_under_svc, txint_under_svc;
bellard8be1f5c2005-04-06 20:42:35 +000085 struct ChannelState *otherchn;
Blue Swirld7b95532011-08-07 19:55:23 +000086 uint32_t reg;
87 uint8_t wregs[SERIAL_REGS], rregs[SERIAL_REGS];
bellard715748f2006-09-09 11:35:47 +000088 SERIOQueue queue;
bellarde80cfcf2004-12-19 23:18:01 +000089 CharDriverState *chr;
blueswir1bbbb2f02007-09-23 11:48:47 +000090 int e0_mode, led_mode, caps_lock_mode, num_lock_mode;
blueswir1577390f2007-12-04 20:58:31 +000091 int disabled;
blueswir1b4ed08e2009-01-12 17:38:28 +000092 int clock;
Blue Swirlbdb78ca2009-10-24 16:07:10 +000093 uint32_t vmstate_dummy;
Blue Swirld7b95532011-08-07 19:55:23 +000094 ChnID chn; // this channel, A (base+4) or B (base+0)
95 ChnType type;
96 uint8_t rx, tx;
bellarde80cfcf2004-12-19 23:18:01 +000097} ChannelState;
98
99struct SerialState {
Blue Swirl6c319c82009-07-15 08:51:32 +0000100 SysBusDevice busdev;
bellarde80cfcf2004-12-19 23:18:01 +0000101 struct ChannelState chn[2];
Gerd Hoffmannec02f7d2009-08-03 17:35:23 +0200102 uint32_t it_shift;
Avi Kivity23c5e4c2011-08-08 16:09:17 +0300103 MemoryRegion mmio;
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200104 uint32_t disabled;
105 uint32_t frequency;
bellarde80cfcf2004-12-19 23:18:01 +0000106};
107
blueswir112abac82007-12-10 20:05:09 +0000108#define SERIAL_CTRL 0
109#define SERIAL_DATA 1
110
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
167
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
bellarde80cfcf2004-12-19 23:18:01 +0000209
bellard8be1f5c2005-04-06 20:42:35 +0000210static void handle_kbd_command(ChannelState *s, int val);
211static int serial_can_receive(void *opaque);
212static void serial_receive_byte(ChannelState *s, int ch);
213
blueswir167deb562007-04-18 19:21:38 +0000214static void clear_queue(void *opaque)
215{
216 ChannelState *s = opaque;
217 SERIOQueue *q = &s->queue;
218 q->rptr = q->wptr = q->count = 0;
219}
220
bellard8be1f5c2005-04-06 20:42:35 +0000221static void put_queue(void *opaque, int b)
222{
223 ChannelState *s = opaque;
bellard715748f2006-09-09 11:35:47 +0000224 SERIOQueue *q = &s->queue;
bellard8be1f5c2005-04-06 20:42:35 +0000225
Blue Swirl30c2f232011-08-07 11:01:05 +0000226 trace_escc_put_queue(CHN_C(s), b);
bellard715748f2006-09-09 11:35:47 +0000227 if (q->count >= SERIO_QUEUE_SIZE)
bellard8be1f5c2005-04-06 20:42:35 +0000228 return;
229 q->data[q->wptr] = b;
bellard715748f2006-09-09 11:35:47 +0000230 if (++q->wptr == SERIO_QUEUE_SIZE)
bellard8be1f5c2005-04-06 20:42:35 +0000231 q->wptr = 0;
232 q->count++;
233 serial_receive_byte(s, 0);
234}
235
236static uint32_t get_queue(void *opaque)
237{
238 ChannelState *s = opaque;
bellard715748f2006-09-09 11:35:47 +0000239 SERIOQueue *q = &s->queue;
bellard8be1f5c2005-04-06 20:42:35 +0000240 int val;
ths3b46e622007-09-17 08:09:54 +0000241
bellard8be1f5c2005-04-06 20:42:35 +0000242 if (q->count == 0) {
blueswir1f930d072007-10-06 11:28:21 +0000243 return 0;
bellard8be1f5c2005-04-06 20:42:35 +0000244 } else {
245 val = q->data[q->rptr];
bellard715748f2006-09-09 11:35:47 +0000246 if (++q->rptr == SERIO_QUEUE_SIZE)
bellard8be1f5c2005-04-06 20:42:35 +0000247 q->rptr = 0;
248 q->count--;
249 }
Blue Swirl30c2f232011-08-07 11:01:05 +0000250 trace_escc_get_queue(CHN_C(s), val);
bellard8be1f5c2005-04-06 20:42:35 +0000251 if (q->count > 0)
blueswir1f930d072007-10-06 11:28:21 +0000252 serial_receive_byte(s, 0);
bellard8be1f5c2005-04-06 20:42:35 +0000253 return val;
254}
255
blueswir1b4ed08e2009-01-12 17:38:28 +0000256static int escc_update_irq_chn(ChannelState *s)
bellarde80cfcf2004-12-19 23:18:01 +0000257{
Artyom Tarasenko9fc391f2010-08-15 16:04:41 +0200258 if ((((s->wregs[W_INTR] & INTR_TXINT) && (s->txint == 1)) ||
blueswir112abac82007-12-10 20:05:09 +0000259 // tx ints enabled, pending
260 ((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) ||
261 ((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) &&
blueswir1f930d072007-10-06 11:28:21 +0000262 s->rxint == 1) || // rx ints enabled, pending
blueswir112abac82007-12-10 20:05:09 +0000263 ((s->wregs[W_EXTINT] & EXTINT_BRKINT) &&
264 (s->rregs[R_STATUS] & STATUS_BRK)))) { // break int e&p
bellarde4a89052006-09-09 11:38:11 +0000265 return 1;
bellarde80cfcf2004-12-19 23:18:01 +0000266 }
bellarde4a89052006-09-09 11:38:11 +0000267 return 0;
268}
269
blueswir1b4ed08e2009-01-12 17:38:28 +0000270static void escc_update_irq(ChannelState *s)
bellarde4a89052006-09-09 11:38:11 +0000271{
272 int irq;
273
blueswir1b4ed08e2009-01-12 17:38:28 +0000274 irq = escc_update_irq_chn(s);
275 irq |= escc_update_irq_chn(s->otherchn);
bellarde4a89052006-09-09 11:38:11 +0000276
Blue Swirl30c2f232011-08-07 11:01:05 +0000277 trace_escc_update_irq(irq);
pbrookd537cf62007-04-07 18:14:41 +0000278 qemu_set_irq(s->irq, irq);
bellarde80cfcf2004-12-19 23:18:01 +0000279}
280
blueswir1b4ed08e2009-01-12 17:38:28 +0000281static void escc_reset_chn(ChannelState *s)
bellarde80cfcf2004-12-19 23:18:01 +0000282{
283 int i;
284
285 s->reg = 0;
blueswir18f180a42009-01-12 17:31:29 +0000286 for (i = 0; i < SERIAL_REGS; i++) {
blueswir1f930d072007-10-06 11:28:21 +0000287 s->rregs[i] = 0;
288 s->wregs[i] = 0;
bellarde80cfcf2004-12-19 23:18:01 +0000289 }
blueswir112abac82007-12-10 20:05:09 +0000290 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
blueswir1577390f2007-12-04 20:58:31 +0000296 if (s->disabled)
blueswir112abac82007-12-10 20:05:09 +0000297 s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_DCD | STATUS_SYNC |
298 STATUS_CTS | STATUS_TXUNDRN;
blueswir1577390f2007-12-04 20:58:31 +0000299 else
blueswir112abac82007-12-10 20:05:09 +0000300 s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_TXUNDRN;
blueswir1f48c5372007-12-27 20:24:15 +0000301 s->rregs[R_SPEC] = SPEC_BITS8 | SPEC_ALLSENT;
bellarde80cfcf2004-12-19 23:18:01 +0000302
303 s->rx = s->tx = 0;
304 s->rxint = s->txint = 0;
bellarde4a89052006-09-09 11:38:11 +0000305 s->rxint_under_svc = s->txint_under_svc = 0;
blueswir1bbbb2f02007-09-23 11:48:47 +0000306 s->e0_mode = s->led_mode = s->caps_lock_mode = s->num_lock_mode = 0;
blueswir167deb562007-04-18 19:21:38 +0000307 clear_queue(s);
bellarde80cfcf2004-12-19 23:18:01 +0000308}
309
Blue Swirlbdb78ca2009-10-24 16:07:10 +0000310static void escc_reset(DeviceState *d)
bellarde80cfcf2004-12-19 23:18:01 +0000311{
Blue Swirlbdb78ca2009-10-24 16:07:10 +0000312 SerialState *s = container_of(d, SerialState, busdev.qdev);
313
blueswir1b4ed08e2009-01-12 17:38:28 +0000314 escc_reset_chn(&s->chn[0]);
315 escc_reset_chn(&s->chn[1]);
bellarde80cfcf2004-12-19 23:18:01 +0000316}
317
bellardba3c64f2005-12-05 20:31:52 +0000318static inline void set_rxint(ChannelState *s)
319{
320 s->rxint = 1;
Artyom Tarasenko9fc391f2010-08-15 16:04:41 +0200321 /* 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) {
blueswir112abac82007-12-10 20:05:09 +0000325 s->rregs[R_INTR] |= INTR_RXINTA;
Artyom Tarasenko9fc391f2010-08-15 16:04:41 +0200326 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 {
blueswir112abac82007-12-10 20:05:09 +0000331 s->otherchn->rregs[R_INTR] |= INTR_RXINTB;
Artyom Tarasenko9fc391f2010-08-15 16:04:41 +0200332 if (s->wregs[W_MINTR] & MINTR_STATUSHI)
333 s->rregs[R_IVEC] = IVEC_HIRXINTB;
334 else
335 s->rregs[R_IVEC] = IVEC_LORXINTB;
336 }
blueswir1b4ed08e2009-01-12 17:38:28 +0000337 escc_update_irq(s);
bellardba3c64f2005-12-05 20:31:52 +0000338}
339
blueswir180637a62008-01-17 21:07:04 +0000340static inline void set_txint(ChannelState *s)
341{
342 s->txint = 1;
343 if (!s->rxint_under_svc) {
344 s->txint_under_svc = 1;
345 if (s->chn == chn_a) {
Aurelien Jarnof53671c2011-01-27 08:21:35 +0100346 if (s->wregs[W_INTR] & INTR_TXINT) {
347 s->rregs[R_INTR] |= INTR_TXINTA;
348 }
blueswir180637a62008-01-17 21:07:04 +0000349 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;
Aurelien Jarnof53671c2011-01-27 08:21:35 +0100355 if (s->wregs[W_INTR] & INTR_TXINT) {
356 s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
357 }
blueswir180637a62008-01-17 21:07:04 +0000358 }
blueswir1b4ed08e2009-01-12 17:38:28 +0000359 escc_update_irq(s);
Artyom Tarasenko9fc391f2010-08-15 16:04:41 +0200360 }
blueswir180637a62008-01-17 21:07:04 +0000361}
362
363static inline void clr_rxint(ChannelState *s)
364{
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;
379 }
380 if (s->txint)
381 set_txint(s);
blueswir1b4ed08e2009-01-12 17:38:28 +0000382 escc_update_irq(s);
blueswir180637a62008-01-17 21:07:04 +0000383}
384
bellardba3c64f2005-12-05 20:31:52 +0000385static inline void clr_txint(ChannelState *s)
386{
387 s->txint = 0;
bellarde4a89052006-09-09 11:38:11 +0000388 s->txint_under_svc = 0;
blueswir1b9652ca2007-04-20 19:35:25 +0000389 if (s->chn == chn_a) {
blueswir112abac82007-12-10 20:05:09 +0000390 if (s->wregs[W_MINTR] & MINTR_STATUSHI)
391 s->otherchn->rregs[R_IVEC] = IVEC_HINOINT;
blueswir1b9652ca2007-04-20 19:35:25 +0000392 else
blueswir112abac82007-12-10 20:05:09 +0000393 s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
394 s->rregs[R_INTR] &= ~INTR_TXINTA;
blueswir1b9652ca2007-04-20 19:35:25 +0000395 } else {
Artyom Tarasenko9fc391f2010-08-15 16:04:41 +0200396 s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
blueswir112abac82007-12-10 20:05:09 +0000397 if (s->wregs[W_MINTR] & MINTR_STATUSHI)
398 s->rregs[R_IVEC] = IVEC_HINOINT;
blueswir1b9652ca2007-04-20 19:35:25 +0000399 else
blueswir112abac82007-12-10 20:05:09 +0000400 s->rregs[R_IVEC] = IVEC_LONOINT;
401 s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
blueswir1b9652ca2007-04-20 19:35:25 +0000402 }
bellarde4a89052006-09-09 11:38:11 +0000403 if (s->rxint)
404 set_rxint(s);
blueswir1b4ed08e2009-01-12 17:38:28 +0000405 escc_update_irq(s);
bellardba3c64f2005-12-05 20:31:52 +0000406}
407
blueswir1b4ed08e2009-01-12 17:38:28 +0000408static void escc_update_parameters(ChannelState *s)
bellard35db0992006-09-09 12:17:15 +0000409{
410 int speed, parity, data_bits, stop_bits;
411 QEMUSerialSetParams ssp;
412
413 if (!s->chr || s->type != ser)
414 return;
415
blueswir112abac82007-12-10 20:05:09 +0000416 if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREN) {
417 if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREV)
bellard35db0992006-09-09 12:17:15 +0000418 parity = 'E';
419 else
420 parity = 'O';
421 } else {
422 parity = 'N';
423 }
blueswir112abac82007-12-10 20:05:09 +0000424 if ((s->wregs[W_TXCTRL1] & TXCTRL1_STPMSK) == TXCTRL1_2STOP)
bellard35db0992006-09-09 12:17:15 +0000425 stop_bits = 2;
426 else
427 stop_bits = 1;
blueswir112abac82007-12-10 20:05:09 +0000428 switch (s->wregs[W_TXCTRL2] & TXCTRL2_BITMSK) {
429 case TXCTRL2_5BITS:
bellard35db0992006-09-09 12:17:15 +0000430 data_bits = 5;
431 break;
blueswir112abac82007-12-10 20:05:09 +0000432 case TXCTRL2_7BITS:
bellard35db0992006-09-09 12:17:15 +0000433 data_bits = 7;
434 break;
blueswir112abac82007-12-10 20:05:09 +0000435 case TXCTRL2_6BITS:
bellard35db0992006-09-09 12:17:15 +0000436 data_bits = 6;
437 break;
438 default:
blueswir112abac82007-12-10 20:05:09 +0000439 case TXCTRL2_8BITS:
bellard35db0992006-09-09 12:17:15 +0000440 data_bits = 8;
441 break;
442 }
blueswir1b4ed08e2009-01-12 17:38:28 +0000443 speed = s->clock / ((s->wregs[W_BRGLO] | (s->wregs[W_BRGHI] << 8)) + 2);
blueswir112abac82007-12-10 20:05:09 +0000444 switch (s->wregs[W_TXCTRL1] & TXCTRL1_CLKMSK) {
445 case TXCTRL1_CLK1X:
bellard35db0992006-09-09 12:17:15 +0000446 break;
blueswir112abac82007-12-10 20:05:09 +0000447 case TXCTRL1_CLK16X:
bellard35db0992006-09-09 12:17:15 +0000448 speed /= 16;
449 break;
blueswir112abac82007-12-10 20:05:09 +0000450 case TXCTRL1_CLK32X:
bellard35db0992006-09-09 12:17:15 +0000451 speed /= 32;
452 break;
453 default:
blueswir112abac82007-12-10 20:05:09 +0000454 case TXCTRL1_CLK64X:
bellard35db0992006-09-09 12:17:15 +0000455 speed /= 64;
456 break;
457 }
458 ssp.speed = speed;
459 ssp.parity = parity;
460 ssp.data_bits = data_bits;
461 ssp.stop_bits = stop_bits;
Blue Swirl30c2f232011-08-07 11:01:05 +0000462 trace_escc_update_parameters(CHN_C(s), speed, parity, data_bits, stop_bits);
Anthony Liguori41084f12011-08-15 11:17:34 -0500463 qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
bellard35db0992006-09-09 12:17:15 +0000464}
465
Avi Kivity23c5e4c2011-08-08 16:09:17 +0300466static void escc_mem_write(void *opaque, target_phys_addr_t addr,
467 uint64_t val, unsigned size)
bellarde80cfcf2004-12-19 23:18:01 +0000468{
blueswir1b3ceef22007-06-25 19:56:13 +0000469 SerialState *serial = opaque;
bellarde80cfcf2004-12-19 23:18:01 +0000470 ChannelState *s;
471 uint32_t saddr;
472 int newreg, channel;
473
474 val &= 0xff;
blueswir1b4ed08e2009-01-12 17:38:28 +0000475 saddr = (addr >> serial->it_shift) & 1;
476 channel = (addr >> (serial->it_shift + 1)) & 1;
blueswir1b3ceef22007-06-25 19:56:13 +0000477 s = &serial->chn[channel];
bellarde80cfcf2004-12-19 23:18:01 +0000478 switch (saddr) {
blueswir112abac82007-12-10 20:05:09 +0000479 case SERIAL_CTRL:
Blue Swirl30c2f232011-08-07 11:01:05 +0000480 trace_escc_mem_writeb_ctrl(CHN_C(s), s->reg, val & 0xff);
blueswir1f930d072007-10-06 11:28:21 +0000481 newreg = 0;
482 switch (s->reg) {
blueswir112abac82007-12-10 20:05:09 +0000483 case W_CMD:
484 newreg = val & CMD_PTR_MASK;
485 val &= CMD_CMD_MASK;
blueswir1f930d072007-10-06 11:28:21 +0000486 switch (val) {
blueswir112abac82007-12-10 20:05:09 +0000487 case CMD_HI:
488 newreg |= CMD_HI;
blueswir1f930d072007-10-06 11:28:21 +0000489 break;
blueswir112abac82007-12-10 20:05:09 +0000490 case CMD_CLR_TXINT:
bellardba3c64f2005-12-05 20:31:52 +0000491 clr_txint(s);
blueswir1f930d072007-10-06 11:28:21 +0000492 break;
blueswir112abac82007-12-10 20:05:09 +0000493 case CMD_CLR_IUS:
Artyom Tarasenko9fc391f2010-08-15 16:04:41 +0200494 if (s->rxint_under_svc) {
495 s->rxint_under_svc = 0;
496 if (s->txint) {
497 set_txint(s);
498 }
499 } else if (s->txint_under_svc) {
500 s->txint_under_svc = 0;
501 }
502 escc_update_irq(s);
blueswir1f930d072007-10-06 11:28:21 +0000503 break;
504 default:
505 break;
506 }
507 break;
blueswir112abac82007-12-10 20:05:09 +0000508 case W_INTR ... W_RXCTRL:
509 case W_SYNC1 ... W_TXBUF:
510 case W_MISC1 ... W_CLOCK:
511 case W_MISC2 ... W_EXTINT:
blueswir1f930d072007-10-06 11:28:21 +0000512 s->wregs[s->reg] = val;
513 break;
blueswir112abac82007-12-10 20:05:09 +0000514 case W_TXCTRL1:
515 case W_TXCTRL2:
blueswir1796d8282008-04-12 08:47:27 +0000516 s->wregs[s->reg] = val;
blueswir1b4ed08e2009-01-12 17:38:28 +0000517 escc_update_parameters(s);
blueswir1796d8282008-04-12 08:47:27 +0000518 break;
blueswir112abac82007-12-10 20:05:09 +0000519 case W_BRGLO:
520 case W_BRGHI:
blueswir1f930d072007-10-06 11:28:21 +0000521 s->wregs[s->reg] = val;
blueswir1796d8282008-04-12 08:47:27 +0000522 s->rregs[s->reg] = val;
blueswir1b4ed08e2009-01-12 17:38:28 +0000523 escc_update_parameters(s);
blueswir1f930d072007-10-06 11:28:21 +0000524 break;
blueswir112abac82007-12-10 20:05:09 +0000525 case W_MINTR:
526 switch (val & MINTR_RST_MASK) {
blueswir1f930d072007-10-06 11:28:21 +0000527 case 0:
528 default:
529 break;
blueswir112abac82007-12-10 20:05:09 +0000530 case MINTR_RST_B:
blueswir1b4ed08e2009-01-12 17:38:28 +0000531 escc_reset_chn(&serial->chn[0]);
blueswir1f930d072007-10-06 11:28:21 +0000532 return;
blueswir112abac82007-12-10 20:05:09 +0000533 case MINTR_RST_A:
blueswir1b4ed08e2009-01-12 17:38:28 +0000534 escc_reset_chn(&serial->chn[1]);
blueswir1f930d072007-10-06 11:28:21 +0000535 return;
blueswir112abac82007-12-10 20:05:09 +0000536 case MINTR_RST_ALL:
Blue Swirlbdb78ca2009-10-24 16:07:10 +0000537 escc_reset(&serial->busdev.qdev);
blueswir1f930d072007-10-06 11:28:21 +0000538 return;
539 }
540 break;
541 default:
542 break;
543 }
544 if (s->reg == 0)
545 s->reg = newreg;
546 else
547 s->reg = 0;
548 break;
blueswir112abac82007-12-10 20:05:09 +0000549 case SERIAL_DATA:
Blue Swirl30c2f232011-08-07 11:01:05 +0000550 trace_escc_mem_writeb_data(CHN_C(s), val);
blueswir196c4f562007-08-11 07:54:26 +0000551 s->tx = val;
blueswir112abac82007-12-10 20:05:09 +0000552 if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
blueswir1f930d072007-10-06 11:28:21 +0000553 if (s->chr)
Anthony Liguori2cc6e0a2011-08-15 11:17:28 -0500554 qemu_chr_fe_write(s->chr, &s->tx, 1);
blueswir1577390f2007-12-04 20:58:31 +0000555 else if (s->type == kbd && !s->disabled) {
blueswir1f930d072007-10-06 11:28:21 +0000556 handle_kbd_command(s, val);
557 }
558 }
blueswir112abac82007-12-10 20:05:09 +0000559 s->rregs[R_STATUS] |= STATUS_TXEMPTY; // Tx buffer empty
560 s->rregs[R_SPEC] |= SPEC_ALLSENT; // All sent
blueswir196c4f562007-08-11 07:54:26 +0000561 set_txint(s);
blueswir1f930d072007-10-06 11:28:21 +0000562 break;
bellarde80cfcf2004-12-19 23:18:01 +0000563 default:
blueswir1f930d072007-10-06 11:28:21 +0000564 break;
bellarde80cfcf2004-12-19 23:18:01 +0000565 }
566}
567
Avi Kivity23c5e4c2011-08-08 16:09:17 +0300568static uint64_t escc_mem_read(void *opaque, target_phys_addr_t addr,
569 unsigned size)
bellarde80cfcf2004-12-19 23:18:01 +0000570{
blueswir1b3ceef22007-06-25 19:56:13 +0000571 SerialState *serial = opaque;
bellarde80cfcf2004-12-19 23:18:01 +0000572 ChannelState *s;
573 uint32_t saddr;
574 uint32_t ret;
575 int channel;
576
blueswir1b4ed08e2009-01-12 17:38:28 +0000577 saddr = (addr >> serial->it_shift) & 1;
578 channel = (addr >> (serial->it_shift + 1)) & 1;
blueswir1b3ceef22007-06-25 19:56:13 +0000579 s = &serial->chn[channel];
bellarde80cfcf2004-12-19 23:18:01 +0000580 switch (saddr) {
blueswir112abac82007-12-10 20:05:09 +0000581 case SERIAL_CTRL:
Blue Swirl30c2f232011-08-07 11:01:05 +0000582 trace_escc_mem_readb_ctrl(CHN_C(s), s->reg, s->rregs[s->reg]);
blueswir1f930d072007-10-06 11:28:21 +0000583 ret = s->rregs[s->reg];
584 s->reg = 0;
585 return ret;
blueswir112abac82007-12-10 20:05:09 +0000586 case SERIAL_DATA:
587 s->rregs[R_STATUS] &= ~STATUS_RXAV;
bellardba3c64f2005-12-05 20:31:52 +0000588 clr_rxint(s);
blueswir1f930d072007-10-06 11:28:21 +0000589 if (s->type == kbd || s->type == mouse)
590 ret = get_queue(s);
591 else
592 ret = s->rx;
Blue Swirl30c2f232011-08-07 11:01:05 +0000593 trace_escc_mem_readb_data(CHN_C(s), ret);
blueswir1b76482e2007-11-25 08:48:16 +0000594 if (s->chr)
595 qemu_chr_accept_input(s->chr);
blueswir1f930d072007-10-06 11:28:21 +0000596 return ret;
bellarde80cfcf2004-12-19 23:18:01 +0000597 default:
blueswir1f930d072007-10-06 11:28:21 +0000598 break;
bellarde80cfcf2004-12-19 23:18:01 +0000599 }
600 return 0;
601}
602
Avi Kivity23c5e4c2011-08-08 16:09:17 +0300603static 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,
610 },
611};
612
bellarde80cfcf2004-12-19 23:18:01 +0000613static int serial_can_receive(void *opaque)
614{
615 ChannelState *s = opaque;
bellarde4a89052006-09-09 11:38:11 +0000616 int ret;
617
blueswir112abac82007-12-10 20:05:09 +0000618 if (((s->wregs[W_RXCTRL] & RXCTRL_RXEN) == 0) // Rx not enabled
619 || ((s->rregs[R_STATUS] & STATUS_RXAV) == STATUS_RXAV))
620 // char already available
blueswir1f930d072007-10-06 11:28:21 +0000621 ret = 0;
bellarde80cfcf2004-12-19 23:18:01 +0000622 else
blueswir1f930d072007-10-06 11:28:21 +0000623 ret = 1;
bellarde4a89052006-09-09 11:38:11 +0000624 return ret;
bellarde80cfcf2004-12-19 23:18:01 +0000625}
626
627static void serial_receive_byte(ChannelState *s, int ch)
628{
Blue Swirl30c2f232011-08-07 11:01:05 +0000629 trace_escc_serial_receive_byte(CHN_C(s), ch);
blueswir112abac82007-12-10 20:05:09 +0000630 s->rregs[R_STATUS] |= STATUS_RXAV;
bellarde80cfcf2004-12-19 23:18:01 +0000631 s->rx = ch;
bellardba3c64f2005-12-05 20:31:52 +0000632 set_rxint(s);
bellarde80cfcf2004-12-19 23:18:01 +0000633}
634
635static void serial_receive_break(ChannelState *s)
636{
blueswir112abac82007-12-10 20:05:09 +0000637 s->rregs[R_STATUS] |= STATUS_BRK;
blueswir1b4ed08e2009-01-12 17:38:28 +0000638 escc_update_irq(s);
bellarde80cfcf2004-12-19 23:18:01 +0000639}
640
641static void serial_receive1(void *opaque, const uint8_t *buf, int size)
642{
643 ChannelState *s = opaque;
644 serial_receive_byte(s, buf[0]);
645}
646
647static void serial_event(void *opaque, int event)
648{
649 ChannelState *s = opaque;
650 if (event == CHR_EVENT_BREAK)
651 serial_receive_break(s);
652}
653
Blue Swirlbdb78ca2009-10-24 16:07:10 +0000654static 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()
bellarde4a89052006-09-09 11:38:11 +0000671 }
Blue Swirlbdb78ca2009-10-24 16:07:10 +0000672};
bellarde80cfcf2004-12-19 23:18:01 +0000673
Blue Swirlbdb78ca2009-10-24 16:07:10 +0000674static 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()
683 }
684};
bellarde80cfcf2004-12-19 23:18:01 +0000685
Avi Kivity23c5e4c2011-08-08 16:09:17 +0300686MemoryRegion *escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB,
aurel32aeeb69c2009-01-14 14:47:56 +0000687 CharDriverState *chrA, CharDriverState *chrB,
688 int clock, int it_shift)
bellarde80cfcf2004-12-19 23:18:01 +0000689{
Blue Swirl6c319c82009-07-15 08:51:32 +0000690 DeviceState *dev;
691 SysBusDevice *s;
692 SerialState *d;
bellarde80cfcf2004-12-19 23:18:01 +0000693
Blue Swirl6c319c82009-07-15 08:51:32 +0000694 dev = qdev_create(NULL, "escc");
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200695 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);
Blue Swirlbc19fca2009-08-13 16:26:52 +0000698 qdev_prop_set_chr(dev, "chrB", chrB);
699 qdev_prop_set_chr(dev, "chrA", chrA);
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200700 qdev_prop_set_uint32(dev, "chnBtype", ser);
701 qdev_prop_set_uint32(dev, "chnAtype", ser);
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200702 qdev_init_nofail(dev);
Blue Swirl6c319c82009-07-15 08:51:32 +0000703 s = sysbus_from_qdev(dev);
Aurelien Jarnoe1a0e472009-09-16 00:13:15 +0200704 sysbus_connect_irq(s, 0, irqB);
705 sysbus_connect_irq(s, 1, irqA);
Blue Swirl6c319c82009-07-15 08:51:32 +0000706 if (base) {
707 sysbus_mmio_map(s, 0, base);
bellarde80cfcf2004-12-19 23:18:01 +0000708 }
Blue Swirl6c319c82009-07-15 08:51:32 +0000709
710 d = FROM_SYSBUS(SerialState, s);
Avi Kivity23c5e4c2011-08-08 16:09:17 +0300711 return &d->mmio;
bellarde80cfcf2004-12-19 23:18:01 +0000712}
713
bellard8be1f5c2005-04-06 20:42:35 +0000714static 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,
723};
724
blueswir143febf42007-09-21 19:09:35 +0000725static 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,
blueswir1c0b5b102008-06-22 07:45:42 +0000733 1, 3, 25, 26, 49, 52, 72, 73, 97, 99, 111, 118, 120, 122, 67, 0,
blueswir143febf42007-09-21 19:09:35 +0000734};
735
bellarde80cfcf2004-12-19 23:18:01 +0000736static void sunkbd_event(void *opaque, int ch)
737{
738 ChannelState *s = opaque;
bellard8be1f5c2005-04-06 20:42:35 +0000739 int release = ch & 0x80;
740
Blue Swirl30c2f232011-08-07 11:01:05 +0000741 trace_escc_sunkbd_event_in(ch);
blueswir1bbbb2f02007-09-23 11:48:47 +0000742 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:
blueswir143febf42007-09-21 19:09:35 +0000764 s->e0_mode = 1;
765 return;
blueswir1bbbb2f02007-09-23 11:48:47 +0000766 default:
767 break;
blueswir143febf42007-09-21 19:09:35 +0000768 }
769 if (s->e0_mode) {
770 s->e0_mode = 0;
771 ch = e0_keycodes[ch & 0x7f];
772 } else {
773 ch = keycodes[ch & 0x7f];
774 }
Blue Swirl30c2f232011-08-07 11:01:05 +0000775 trace_escc_sunkbd_event_out(ch);
bellard8be1f5c2005-04-06 20:42:35 +0000776 put_queue(s, ch | release);
777}
778
779static void handle_kbd_command(ChannelState *s, int val)
780{
Blue Swirl30c2f232011-08-07 11:01:05 +0000781 trace_escc_kbd_command(val);
blueswir143febf42007-09-21 19:09:35 +0000782 if (s->led_mode) { // Ignore led byte
783 s->led_mode = 0;
784 return;
785 }
bellard8be1f5c2005-04-06 20:42:35 +0000786 switch (val) {
787 case 1: // Reset, return type code
blueswir167deb562007-04-18 19:21:38 +0000788 clear_queue(s);
blueswir1f930d072007-10-06 11:28:21 +0000789 put_queue(s, 0xff);
790 put_queue(s, 4); // Type 4
791 put_queue(s, 0x7f);
792 break;
blueswir143febf42007-09-21 19:09:35 +0000793 case 0xe: // Set leds
794 s->led_mode = 1;
795 break;
bellard8be1f5c2005-04-06 20:42:35 +0000796 case 7: // Query layout
blueswir167deb562007-04-18 19:21:38 +0000797 case 0xf:
798 clear_queue(s);
blueswir1f930d072007-10-06 11:28:21 +0000799 put_queue(s, 0xfe);
800 put_queue(s, 0); // XXX, layout?
801 break;
bellard8be1f5c2005-04-06 20:42:35 +0000802 default:
blueswir1f930d072007-10-06 11:28:21 +0000803 break;
bellard8be1f5c2005-04-06 20:42:35 +0000804 }
bellarde80cfcf2004-12-19 23:18:01 +0000805}
806
ths5fafdf22007-09-16 21:08:06 +0000807static void sunmouse_event(void *opaque,
bellarde80cfcf2004-12-19 23:18:01 +0000808 int dx, int dy, int dz, int buttons_state)
809{
810 ChannelState *s = opaque;
811 int ch;
812
Blue Swirl30c2f232011-08-07 11:01:05 +0000813 trace_escc_sunmouse_event(dx, dy, buttons_state);
bellard715748f2006-09-09 11:35:47 +0000814 ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
815
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;
822
823 put_queue(s, ch);
824
825 ch = dx;
826
827 if (ch > 127)
Michael S. Tsirkina0d98a72009-09-30 19:43:55 +0200828 ch = 127;
bellard715748f2006-09-09 11:35:47 +0000829 else if (ch < -127)
Michael S. Tsirkina0d98a72009-09-30 19:43:55 +0200830 ch = -127;
bellard715748f2006-09-09 11:35:47 +0000831
832 put_queue(s, ch & 0xff);
833
834 ch = -dy;
835
836 if (ch > 127)
Michael S. Tsirkin084bd072009-09-30 18:56:44 +0000837 ch = 127;
bellard715748f2006-09-09 11:35:47 +0000838 else if (ch < -127)
Michael S. Tsirkin084bd072009-09-30 18:56:44 +0000839 ch = -127;
bellard715748f2006-09-09 11:35:47 +0000840
841 put_queue(s, ch & 0xff);
842
843 // MSC protocol specify two extra motion bytes
844
845 put_queue(s, 0);
846 put_queue(s, 0);
bellarde80cfcf2004-12-19 23:18:01 +0000847}
848
Anthony Liguoric227f092009-10-01 16:12:16 -0500849void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq,
blueswir1b4ed08e2009-01-12 17:38:28 +0000850 int disabled, int clock, int it_shift)
bellarde80cfcf2004-12-19 23:18:01 +0000851{
Blue Swirl6c319c82009-07-15 08:51:32 +0000852 DeviceState *dev;
853 SysBusDevice *s;
bellarde80cfcf2004-12-19 23:18:01 +0000854
Blue Swirl6c319c82009-07-15 08:51:32 +0000855 dev = qdev_create(NULL, "escc");
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200856 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);
Blue Swirlbc19fca2009-08-13 16:26:52 +0000859 qdev_prop_set_chr(dev, "chrB", NULL);
860 qdev_prop_set_chr(dev, "chrA", NULL);
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200861 qdev_prop_set_uint32(dev, "chnBtype", mouse);
862 qdev_prop_set_uint32(dev, "chnAtype", kbd);
Markus Armbrustere23a1b32009-10-07 01:15:58 +0200863 qdev_init_nofail(dev);
Blue Swirl6c319c82009-07-15 08:51:32 +0000864 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);
868}
blueswir1b4ed08e2009-01-12 17:38:28 +0000869
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200870static int escc_init1(SysBusDevice *dev)
Blue Swirl6c319c82009-07-15 08:51:32 +0000871{
872 SerialState *s = FROM_SYSBUS(SerialState, dev);
Blue Swirl6c319c82009-07-15 08:51:32 +0000873 unsigned int i;
Blue Swirl6c319c82009-07-15 08:51:32 +0000874
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200875 s->chn[0].disabled = s->disabled;
876 s->chn[1].disabled = s->disabled;
bellard8be1f5c2005-04-06 20:42:35 +0000877 for (i = 0; i < 2; i++) {
Blue Swirl6c319c82009-07-15 08:51:32 +0000878 sysbus_init_irq(dev, &s->chn[i].irq);
blueswir1f930d072007-10-06 11:28:21 +0000879 s->chn[i].chn = 1 - i;
Gerd Hoffmannee6847d2009-07-15 13:43:31 +0200880 s->chn[i].clock = s->frequency / 2;
Blue Swirl6c319c82009-07-15 08:51:32 +0000881 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]);
884 }
bellard8be1f5c2005-04-06 20:42:35 +0000885 }
886 s->chn[0].otherchn = &s->chn[1];
887 s->chn[1].otherchn = &s->chn[0];
bellarde80cfcf2004-12-19 23:18:01 +0000888
Avi Kivity23c5e4c2011-08-08 16:09:17 +0300889 memory_region_init_io(&s->mmio, &escc_mem_ops, s, "escc",
890 ESCC_SIZE << s->it_shift);
Avi Kivity750ecd42011-11-27 11:38:10 +0200891 sysbus_init_mmio(dev, &s->mmio);
bellarde80cfcf2004-12-19 23:18:01 +0000892
Blue Swirl6c319c82009-07-15 08:51:32 +0000893 if (s->chn[0].type == mouse) {
894 qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0,
895 "QEMU Sun Mouse");
896 }
897 if (s->chn[1].type == kbd) {
898 qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
899 }
Blue Swirlbdb78ca2009-10-24 16:07:10 +0000900
Gerd Hoffmann81a322d2009-08-14 10:36:05 +0200901 return 0;
bellarde80cfcf2004-12-19 23:18:01 +0000902}
Blue Swirl6c319c82009-07-15 08:51:32 +0000903
Anthony Liguori999e12b2012-01-24 13:12:29 -0600904static Property escc_properties[] = {
905 DEFINE_PROP_UINT32("frequency", SerialState, frequency, 0),
906 DEFINE_PROP_UINT32("it_shift", SerialState, it_shift, 0),
907 DEFINE_PROP_UINT32("disabled", SerialState, disabled, 0),
908 DEFINE_PROP_UINT32("disabled", SerialState, disabled, 0),
909 DEFINE_PROP_UINT32("chnBtype", SerialState, chn[0].type, 0),
910 DEFINE_PROP_UINT32("chnAtype", SerialState, chn[1].type, 0),
911 DEFINE_PROP_CHR("chrB", SerialState, chn[0].chr),
912 DEFINE_PROP_CHR("chrA", SerialState, chn[1].chr),
913 DEFINE_PROP_END_OF_LIST(),
914};
915
916static void escc_class_init(ObjectClass *klass, void *data)
917{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600918 DeviceClass *dc = DEVICE_CLASS(klass);
Anthony Liguori999e12b2012-01-24 13:12:29 -0600919 SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
920
921 k->init = escc_init1;
Anthony Liguori39bffca2011-12-07 21:34:16 -0600922 dc->reset = escc_reset;
923 dc->vmsd = &vmstate_escc;
924 dc->props = escc_properties;
Anthony Liguori999e12b2012-01-24 13:12:29 -0600925}
926
Anthony Liguori39bffca2011-12-07 21:34:16 -0600927static TypeInfo escc_info = {
928 .name = "escc",
929 .parent = TYPE_SYS_BUS_DEVICE,
930 .instance_size = sizeof(SerialState),
931 .class_init = escc_class_init,
Blue Swirl6c319c82009-07-15 08:51:32 +0000932};
933
Andreas Färber83f7d432012-02-09 15:20:55 +0100934static void escc_register_types(void)
Blue Swirl6c319c82009-07-15 08:51:32 +0000935{
Anthony Liguori39bffca2011-12-07 21:34:16 -0600936 type_register_static(&escc_info);
Blue Swirl6c319c82009-07-15 08:51:32 +0000937}
938
Andreas Färber83f7d432012-02-09 15:20:55 +0100939type_init(escc_register_types)