|
1
|
/*
|
|
2
|
* QEMU ESCC (Z8030/Z8530/Z85C30/SCC/ESCC) serial port emulation
|
ths
authored
|
3
|
*
|
|
4
|
* Copyright (c) 2003-2005 Fabrice Bellard
|
ths
authored
|
5
|
*
|
|
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
|
|
24
|
#include "hw.h"
|
|
25
|
#include "escc.h"
|
|
26
27
28
|
#include "qemu-char.h"
#include "console.h"
|
|
29
|
/* debug serial */
|
|
30
31
32
33
34
|
//#define DEBUG_SERIAL
/* debug keyboard */
//#define DEBUG_KBD
|
|
35
|
/* debug mouse */
|
|
36
37
38
|
//#define DEBUG_MOUSE
/*
|
|
39
|
* On Sparc32 this is the serial port, mouse and keyboard part of chip STP2001
|
|
40
41
|
* (Slave I/O), also produced as NCR89C105. See
* http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
|
ths
authored
|
42
|
*
|
|
43
44
45
46
|
* The serial ports implement full AMD AM8530 or Zilog Z8530 chips,
* mouse and keyboard ports don't implement all functions and they are
* only asynchronous. There is no DMA.
*
|
|
47
48
49
50
51
52
53
54
|
* Z85C30 is also used on PowerMacs. There are some small differences
* between Sparc version (sunzilog) and PowerMac (pmac):
* Offset between control and data registers
* There is some kind of lockup bug, but we can ignore it
* CTS is inverted
* DMA on pmac using DBDMA chip
* pmac can do IRDA and faster rates, sunzilog can only do 38400
* pmac baud rate generator clock is 3.6864 MHz, sunzilog 4.9152 MHz
|
|
55
56
|
*/
|
|
57
58
59
60
61
62
63
|
/*
* Modifications:
* 2006-Aug-10 Igor Kovalenko : Renamed KBDQueue to SERIOQueue, implemented
* serial mouse queue.
* Implemented serial mouse protocol.
*/
|
|
64
|
#ifdef DEBUG_SERIAL
|
|
65
66
|
#define SER_DPRINTF(fmt, ...) \
do { printf("SER: " fmt , ## __VA_ARGS__); } while (0)
|
|
67
|
#else
|
|
68
|
#define SER_DPRINTF(fmt, ...)
|
|
69
70
|
#endif
#ifdef DEBUG_KBD
|
|
71
72
|
#define KBD_DPRINTF(fmt, ...) \
do { printf("KBD: " fmt , ## __VA_ARGS__); } while (0)
|
|
73
|
#else
|
|
74
|
#define KBD_DPRINTF(fmt, ...)
|
|
75
76
|
#endif
#ifdef DEBUG_MOUSE
|
|
77
78
|
#define MS_DPRINTF(fmt, ...) \
do { printf("MSC: " fmt , ## __VA_ARGS__); } while (0)
|
|
79
|
#else
|
|
80
|
#define MS_DPRINTF(fmt, ...)
|
|
81
82
83
84
85
86
|
#endif
typedef enum {
chn_a, chn_b,
} chn_id_t;
|
|
87
88
|
#define CHN_C(s) ((s)->chn == chn_b? 'b' : 'a')
|
|
89
90
91
92
|
typedef enum {
ser, kbd, mouse,
} chn_type_t;
|
|
93
|
#define SERIO_QUEUE_SIZE 256
|
|
94
95
|
typedef struct {
|
|
96
|
uint8_t data[SERIO_QUEUE_SIZE];
|
|
97
|
int rptr, wptr, count;
|
|
98
|
} SERIOQueue;
|
|
99
|
|
|
100
|
#define SERIAL_REGS 16
|
|
101
|
typedef struct ChannelState {
|
|
102
|
qemu_irq irq;
|
|
103
104
|
uint32_t reg;
uint32_t rxint, txint, rxint_under_svc, txint_under_svc;
|
|
105
106
107
|
chn_id_t chn; // this channel, A (base+4) or B (base+0)
chn_type_t type;
struct ChannelState *otherchn;
|
|
108
|
uint8_t rx, tx, wregs[SERIAL_REGS], rregs[SERIAL_REGS];
|
|
109
|
SERIOQueue queue;
|
|
110
|
CharDriverState *chr;
|
|
111
|
int e0_mode, led_mode, caps_lock_mode, num_lock_mode;
|
|
112
|
int disabled;
|
|
113
|
int clock;
|
|
114
115
116
117
|
} ChannelState;
struct SerialState {
struct ChannelState chn[2];
|
|
118
|
int it_shift;
|
|
119
120
|
};
|
|
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
|
#define SERIAL_CTRL 0
#define SERIAL_DATA 1
#define W_CMD 0
#define CMD_PTR_MASK 0x07
#define CMD_CMD_MASK 0x38
#define CMD_HI 0x08
#define CMD_CLR_TXINT 0x28
#define CMD_CLR_IUS 0x38
#define W_INTR 1
#define INTR_INTALL 0x01
#define INTR_TXINT 0x02
#define INTR_RXMODEMSK 0x18
#define INTR_RXINT1ST 0x08
#define INTR_RXINTALL 0x10
#define W_IVEC 2
#define W_RXCTRL 3
#define RXCTRL_RXEN 0x01
#define W_TXCTRL1 4
#define TXCTRL1_PAREN 0x01
#define TXCTRL1_PAREV 0x02
#define TXCTRL1_1STOP 0x04
#define TXCTRL1_1HSTOP 0x08
#define TXCTRL1_2STOP 0x0c
#define TXCTRL1_STPMSK 0x0c
#define TXCTRL1_CLK1X 0x00
#define TXCTRL1_CLK16X 0x40
#define TXCTRL1_CLK32X 0x80
#define TXCTRL1_CLK64X 0xc0
#define TXCTRL1_CLKMSK 0xc0
#define W_TXCTRL2 5
#define TXCTRL2_TXEN 0x08
#define TXCTRL2_BITMSK 0x60
#define TXCTRL2_5BITS 0x00
#define TXCTRL2_7BITS 0x20
#define TXCTRL2_6BITS 0x40
#define TXCTRL2_8BITS 0x60
#define W_SYNC1 6
#define W_SYNC2 7
#define W_TXBUF 8
#define W_MINTR 9
#define MINTR_STATUSHI 0x10
#define MINTR_RST_MASK 0xc0
#define MINTR_RST_B 0x40
#define MINTR_RST_A 0x80
#define MINTR_RST_ALL 0xc0
#define W_MISC1 10
#define W_CLOCK 11
#define CLOCK_TRXC 0x08
#define W_BRGLO 12
#define W_BRGHI 13
#define W_MISC2 14
#define MISC2_PLLDIS 0x30
#define W_EXTINT 15
#define EXTINT_DCD 0x08
#define EXTINT_SYNCINT 0x10
#define EXTINT_CTSINT 0x20
#define EXTINT_TXUNDRN 0x40
#define EXTINT_BRKINT 0x80
#define R_STATUS 0
#define STATUS_RXAV 0x01
#define STATUS_ZERO 0x02
#define STATUS_TXEMPTY 0x04
#define STATUS_DCD 0x08
#define STATUS_SYNC 0x10
#define STATUS_CTS 0x20
#define STATUS_TXUNDRN 0x40
#define STATUS_BRK 0x80
#define R_SPEC 1
#define SPEC_ALLSENT 0x01
#define SPEC_BITS8 0x06
#define R_IVEC 2
#define IVEC_TXINTB 0x00
#define IVEC_LONOINT 0x06
#define IVEC_LORXINTA 0x0c
#define IVEC_LORXINTB 0x04
#define IVEC_LOTXINTA 0x08
#define IVEC_HINOINT 0x60
#define IVEC_HIRXINTA 0x30
#define IVEC_HIRXINTB 0x20
#define IVEC_HITXINTA 0x10
#define R_INTR 3
#define INTR_EXTINTB 0x01
#define INTR_TXINTB 0x02
#define INTR_RXINTB 0x04
#define INTR_EXTINTA 0x08
#define INTR_TXINTA 0x10
#define INTR_RXINTA 0x20
#define R_IPEN 4
#define R_TXCTRL1 5
#define R_TXCTRL2 6
#define R_BC 7
#define R_RXBUF 8
#define R_RXCTRL 9
#define R_MISC 10
#define R_MISC1 11
#define R_BRGLO 12
#define R_BRGHI 13
#define R_MISC1I 14
#define R_EXTINT 15
|
|
222
|
|
|
223
224
225
226
|
static void handle_kbd_command(ChannelState *s, int val);
static int serial_can_receive(void *opaque);
static void serial_receive_byte(ChannelState *s, int ch);
|
|
227
228
229
230
231
232
233
|
static void clear_queue(void *opaque)
{
ChannelState *s = opaque;
SERIOQueue *q = &s->queue;
q->rptr = q->wptr = q->count = 0;
}
|
|
234
235
236
|
static void put_queue(void *opaque, int b)
{
ChannelState *s = opaque;
|
|
237
|
SERIOQueue *q = &s->queue;
|
|
238
|
|
|
239
|
SER_DPRINTF("channel %c put: 0x%02x\n", CHN_C(s), b);
|
|
240
|
if (q->count >= SERIO_QUEUE_SIZE)
|
|
241
242
|
return;
q->data[q->wptr] = b;
|
|
243
|
if (++q->wptr == SERIO_QUEUE_SIZE)
|
|
244
245
246
247
248
249
250
251
|
q->wptr = 0;
q->count++;
serial_receive_byte(s, 0);
}
static uint32_t get_queue(void *opaque)
{
ChannelState *s = opaque;
|
|
252
|
SERIOQueue *q = &s->queue;
|
|
253
|
int val;
|
ths
authored
|
254
|
|
|
255
|
if (q->count == 0) {
|
|
256
|
return 0;
|
|
257
258
|
} else {
val = q->data[q->rptr];
|
|
259
|
if (++q->rptr == SERIO_QUEUE_SIZE)
|
|
260
261
262
|
q->rptr = 0;
q->count--;
}
|
|
263
|
SER_DPRINTF("channel %c get 0x%02x\n", CHN_C(s), val);
|
|
264
|
if (q->count > 0)
|
|
265
|
serial_receive_byte(s, 0);
|
|
266
267
268
|
return val;
}
|
|
269
|
static int escc_update_irq_chn(ChannelState *s)
|
|
270
|
{
|
|
271
|
if ((((s->wregs[W_INTR] & INTR_TXINT) && s->txint == 1) ||
|
|
272
273
274
|
// tx ints enabled, pending
((((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINT1ST) ||
((s->wregs[W_INTR] & INTR_RXMODEMSK) == INTR_RXINTALL)) &&
|
|
275
|
s->rxint == 1) || // rx ints enabled, pending
|
|
276
277
|
((s->wregs[W_EXTINT] & EXTINT_BRKINT) &&
(s->rregs[R_STATUS] & STATUS_BRK)))) { // break int e&p
|
|
278
|
return 1;
|
|
279
|
}
|
|
280
281
282
|
return 0;
}
|
|
283
|
static void escc_update_irq(ChannelState *s)
|
|
284
285
286
|
{
int irq;
|
|
287
288
|
irq = escc_update_irq_chn(s);
irq |= escc_update_irq_chn(s->otherchn);
|
|
289
|
|
|
290
291
|
SER_DPRINTF("IRQ = %d\n", irq);
qemu_set_irq(s->irq, irq);
|
|
292
293
|
}
|
|
294
|
static void escc_reset_chn(ChannelState *s)
|
|
295
296
297
298
|
{
int i;
s->reg = 0;
|
|
299
|
for (i = 0; i < SERIAL_REGS; i++) {
|
|
300
301
|
s->rregs[i] = 0;
s->wregs[i] = 0;
|
|
302
|
}
|
|
303
304
305
306
307
308
|
s->wregs[W_TXCTRL1] = TXCTRL1_1STOP; // 1X divisor, 1 stop bit, no parity
s->wregs[W_MINTR] = MINTR_RST_ALL;
s->wregs[W_CLOCK] = CLOCK_TRXC; // Synch mode tx clock = TRxC
s->wregs[W_MISC2] = MISC2_PLLDIS; // PLL disabled
s->wregs[W_EXTINT] = EXTINT_DCD | EXTINT_SYNCINT | EXTINT_CTSINT |
EXTINT_TXUNDRN | EXTINT_BRKINT; // Enable most interrupts
|
|
309
|
if (s->disabled)
|
|
310
311
|
s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_DCD | STATUS_SYNC |
STATUS_CTS | STATUS_TXUNDRN;
|
|
312
|
else
|
|
313
|
s->rregs[R_STATUS] = STATUS_TXEMPTY | STATUS_TXUNDRN;
|
|
314
|
s->rregs[R_SPEC] = SPEC_BITS8 | SPEC_ALLSENT;
|
|
315
316
317
|
s->rx = s->tx = 0;
s->rxint = s->txint = 0;
|
|
318
|
s->rxint_under_svc = s->txint_under_svc = 0;
|
|
319
|
s->e0_mode = s->led_mode = s->caps_lock_mode = s->num_lock_mode = 0;
|
|
320
|
clear_queue(s);
|
|
321
322
|
}
|
|
323
|
static void escc_reset(void *opaque)
|
|
324
325
|
{
SerialState *s = opaque;
|
|
326
327
|
escc_reset_chn(&s->chn[0]);
escc_reset_chn(&s->chn[1]);
|
|
328
329
|
}
|
|
330
331
332
|
static inline void set_rxint(ChannelState *s)
{
s->rxint = 1;
|
|
333
334
|
if (!s->txint_under_svc) {
s->rxint_under_svc = 1;
|
|
335
|
if (s->chn == chn_a) {
|
|
336
337
|
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
s->otherchn->rregs[R_IVEC] = IVEC_HIRXINTA;
|
|
338
|
else
|
|
339
|
s->otherchn->rregs[R_IVEC] = IVEC_LORXINTA;
|
|
340
|
} else {
|
|
341
342
|
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
s->rregs[R_IVEC] = IVEC_HIRXINTB;
|
|
343
|
else
|
|
344
|
s->rregs[R_IVEC] = IVEC_LORXINTB;
|
|
345
|
}
|
|
346
|
}
|
|
347
|
if (s->chn == chn_a)
|
|
348
|
s->rregs[R_INTR] |= INTR_RXINTA;
|
|
349
|
else
|
|
350
|
s->otherchn->rregs[R_INTR] |= INTR_RXINTB;
|
|
351
|
escc_update_irq(s);
|
|
352
353
|
}
|
|
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
|
static inline void set_txint(ChannelState *s)
{
s->txint = 1;
if (!s->rxint_under_svc) {
s->txint_under_svc = 1;
if (s->chn == chn_a) {
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
s->otherchn->rregs[R_IVEC] = IVEC_HITXINTA;
else
s->otherchn->rregs[R_IVEC] = IVEC_LOTXINTA;
} else {
s->rregs[R_IVEC] = IVEC_TXINTB;
}
}
if (s->chn == chn_a)
s->rregs[R_INTR] |= INTR_TXINTA;
else
s->otherchn->rregs[R_INTR] |= INTR_TXINTB;
|
|
372
|
escc_update_irq(s);
|
|
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
|
}
static inline void clr_rxint(ChannelState *s)
{
s->rxint = 0;
s->rxint_under_svc = 0;
if (s->chn == chn_a) {
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
s->otherchn->rregs[R_IVEC] = IVEC_HINOINT;
else
s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
s->rregs[R_INTR] &= ~INTR_RXINTA;
} else {
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
s->rregs[R_IVEC] = IVEC_HINOINT;
else
s->rregs[R_IVEC] = IVEC_LONOINT;
s->otherchn->rregs[R_INTR] &= ~INTR_RXINTB;
}
if (s->txint)
set_txint(s);
|
|
394
|
escc_update_irq(s);
|
|
395
396
|
}
|
|
397
398
399
|
static inline void clr_txint(ChannelState *s)
{
s->txint = 0;
|
|
400
|
s->txint_under_svc = 0;
|
|
401
|
if (s->chn == chn_a) {
|
|
402
403
|
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
s->otherchn->rregs[R_IVEC] = IVEC_HINOINT;
|
|
404
|
else
|
|
405
406
|
s->otherchn->rregs[R_IVEC] = IVEC_LONOINT;
s->rregs[R_INTR] &= ~INTR_TXINTA;
|
|
407
|
} else {
|
|
408
409
|
if (s->wregs[W_MINTR] & MINTR_STATUSHI)
s->rregs[R_IVEC] = IVEC_HINOINT;
|
|
410
|
else
|
|
411
412
|
s->rregs[R_IVEC] = IVEC_LONOINT;
s->otherchn->rregs[R_INTR] &= ~INTR_TXINTB;
|
|
413
|
}
|
|
414
415
|
if (s->rxint)
set_rxint(s);
|
|
416
|
escc_update_irq(s);
|
|
417
418
|
}
|
|
419
|
static void escc_update_parameters(ChannelState *s)
|
|
420
421
422
423
424
425
426
|
{
int speed, parity, data_bits, stop_bits;
QEMUSerialSetParams ssp;
if (!s->chr || s->type != ser)
return;
|
|
427
428
|
if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREN) {
if (s->wregs[W_TXCTRL1] & TXCTRL1_PAREV)
|
|
429
430
431
432
433
434
|
parity = 'E';
else
parity = 'O';
} else {
parity = 'N';
}
|
|
435
|
if ((s->wregs[W_TXCTRL1] & TXCTRL1_STPMSK) == TXCTRL1_2STOP)
|
|
436
437
438
|
stop_bits = 2;
else
stop_bits = 1;
|
|
439
440
|
switch (s->wregs[W_TXCTRL2] & TXCTRL2_BITMSK) {
case TXCTRL2_5BITS:
|
|
441
442
|
data_bits = 5;
break;
|
|
443
|
case TXCTRL2_7BITS:
|
|
444
445
|
data_bits = 7;
break;
|
|
446
|
case TXCTRL2_6BITS:
|
|
447
448
449
|
data_bits = 6;
break;
default:
|
|
450
|
case TXCTRL2_8BITS:
|
|
451
452
453
|
data_bits = 8;
break;
}
|
|
454
|
speed = s->clock / ((s->wregs[W_BRGLO] | (s->wregs[W_BRGHI] << 8)) + 2);
|
|
455
456
|
switch (s->wregs[W_TXCTRL1] & TXCTRL1_CLKMSK) {
case TXCTRL1_CLK1X:
|
|
457
|
break;
|
|
458
|
case TXCTRL1_CLK16X:
|
|
459
460
|
speed /= 16;
break;
|
|
461
|
case TXCTRL1_CLK32X:
|
|
462
463
464
|
speed /= 32;
break;
default:
|
|
465
|
case TXCTRL1_CLK64X:
|
|
466
467
468
469
470
471
472
473
474
475
476
477
|
speed /= 64;
break;
}
ssp.speed = speed;
ssp.parity = parity;
ssp.data_bits = data_bits;
ssp.stop_bits = stop_bits;
SER_DPRINTF("channel %c: speed=%d parity=%c data=%d stop=%d\n", CHN_C(s),
speed, parity, data_bits, stop_bits);
qemu_chr_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
}
|
|
478
|
static void escc_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
|
|
479
|
{
|
|
480
|
SerialState *serial = opaque;
|
|
481
482
483
484
485
|
ChannelState *s;
uint32_t saddr;
int newreg, channel;
val &= 0xff;
|
|
486
487
|
saddr = (addr >> serial->it_shift) & 1;
channel = (addr >> (serial->it_shift + 1)) & 1;
|
|
488
|
s = &serial->chn[channel];
|
|
489
|
switch (saddr) {
|
|
490
491
492
|
case SERIAL_CTRL:
SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg,
val & 0xff);
|
|
493
494
|
newreg = 0;
switch (s->reg) {
|
|
495
496
497
|
case W_CMD:
newreg = val & CMD_PTR_MASK;
val &= CMD_CMD_MASK;
|
|
498
|
switch (val) {
|
|
499
500
|
case CMD_HI:
newreg |= CMD_HI;
|
|
501
|
break;
|
|
502
|
case CMD_CLR_TXINT:
|
|
503
|
clr_txint(s);
|
|
504
|
break;
|
|
505
|
case CMD_CLR_IUS:
|
|
506
507
508
509
|
if (s->rxint_under_svc)
clr_rxint(s);
else if (s->txint_under_svc)
clr_txint(s);
|
|
510
511
512
513
514
|
break;
default:
break;
}
break;
|
|
515
516
517
518
|
case W_INTR ... W_RXCTRL:
case W_SYNC1 ... W_TXBUF:
case W_MISC1 ... W_CLOCK:
case W_MISC2 ... W_EXTINT:
|
|
519
520
|
s->wregs[s->reg] = val;
break;
|
|
521
522
|
case W_TXCTRL1:
case W_TXCTRL2:
|
|
523
|
s->wregs[s->reg] = val;
|
|
524
|
escc_update_parameters(s);
|
|
525
|
break;
|
|
526
527
|
case W_BRGLO:
case W_BRGHI:
|
|
528
|
s->wregs[s->reg] = val;
|
|
529
|
s->rregs[s->reg] = val;
|
|
530
|
escc_update_parameters(s);
|
|
531
|
break;
|
|
532
533
|
case W_MINTR:
switch (val & MINTR_RST_MASK) {
|
|
534
535
536
|
case 0:
default:
break;
|
|
537
|
case MINTR_RST_B:
|
|
538
|
escc_reset_chn(&serial->chn[0]);
|
|
539
|
return;
|
|
540
|
case MINTR_RST_A:
|
|
541
|
escc_reset_chn(&serial->chn[1]);
|
|
542
|
return;
|
|
543
|
case MINTR_RST_ALL:
|
|
544
|
escc_reset(serial);
|
|
545
546
547
548
549
550
551
552
553
554
555
|
return;
}
break;
default:
break;
}
if (s->reg == 0)
s->reg = newreg;
else
s->reg = 0;
break;
|
|
556
|
case SERIAL_DATA:
|
|
557
|
SER_DPRINTF("Write channel %c, ch %d\n", CHN_C(s), val);
|
|
558
|
s->tx = val;
|
|
559
|
if (s->wregs[W_TXCTRL2] & TXCTRL2_TXEN) { // tx enabled
|
|
560
561
|
if (s->chr)
qemu_chr_write(s->chr, &s->tx, 1);
|
|
562
|
else if (s->type == kbd && !s->disabled) {
|
|
563
564
565
|
handle_kbd_command(s, val);
}
}
|
|
566
567
|
s->rregs[R_STATUS] |= STATUS_TXEMPTY; // Tx buffer empty
s->rregs[R_SPEC] |= SPEC_ALLSENT; // All sent
|
|
568
|
set_txint(s);
|
|
569
|
break;
|
|
570
|
default:
|
|
571
|
break;
|
|
572
573
574
|
}
}
|
|
575
|
static uint32_t escc_mem_readb(void *opaque, target_phys_addr_t addr)
|
|
576
|
{
|
|
577
|
SerialState *serial = opaque;
|
|
578
579
580
581
582
|
ChannelState *s;
uint32_t saddr;
uint32_t ret;
int channel;
|
|
583
584
|
saddr = (addr >> serial->it_shift) & 1;
channel = (addr >> (serial->it_shift + 1)) & 1;
|
|
585
|
s = &serial->chn[channel];
|
|
586
|
switch (saddr) {
|
|
587
588
589
|
case SERIAL_CTRL:
SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", CHN_C(s), s->reg,
s->rregs[s->reg]);
|
|
590
591
592
|
ret = s->rregs[s->reg];
s->reg = 0;
return ret;
|
|
593
594
|
case SERIAL_DATA:
s->rregs[R_STATUS] &= ~STATUS_RXAV;
|
|
595
|
clr_rxint(s);
|
|
596
597
598
599
600
|
if (s->type == kbd || s->type == mouse)
ret = get_queue(s);
else
ret = s->rx;
SER_DPRINTF("Read channel %c, ch %d\n", CHN_C(s), ret);
|
|
601
602
|
if (s->chr)
qemu_chr_accept_input(s->chr);
|
|
603
|
return ret;
|
|
604
|
default:
|
|
605
|
break;
|
|
606
607
608
609
610
611
612
|
}
return 0;
}
static int serial_can_receive(void *opaque)
{
ChannelState *s = opaque;
|
|
613
614
|
int ret;
|
|
615
616
617
|
if (((s->wregs[W_RXCTRL] & RXCTRL_RXEN) == 0) // Rx not enabled
|| ((s->rregs[R_STATUS] & STATUS_RXAV) == STATUS_RXAV))
// char already available
|
|
618
|
ret = 0;
|
|
619
|
else
|
|
620
|
ret = 1;
|
|
621
|
return ret;
|
|
622
623
624
625
|
}
static void serial_receive_byte(ChannelState *s, int ch)
{
|
|
626
|
SER_DPRINTF("channel %c put ch %d\n", CHN_C(s), ch);
|
|
627
|
s->rregs[R_STATUS] |= STATUS_RXAV;
|
|
628
|
s->rx = ch;
|
|
629
|
set_rxint(s);
|
|
630
631
632
633
|
}
static void serial_receive_break(ChannelState *s)
{
|
|
634
|
s->rregs[R_STATUS] |= STATUS_BRK;
|
|
635
|
escc_update_irq(s);
|
|
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
|
}
static void serial_receive1(void *opaque, const uint8_t *buf, int size)
{
ChannelState *s = opaque;
serial_receive_byte(s, buf[0]);
}
static void serial_event(void *opaque, int event)
{
ChannelState *s = opaque;
if (event == CHR_EVENT_BREAK)
serial_receive_break(s);
}
|
|
651
652
|
static CPUReadMemoryFunc *escc_mem_read[3] = {
escc_mem_readb,
|
|
653
654
|
NULL,
NULL,
|
|
655
656
|
};
|
|
657
658
|
static CPUWriteMemoryFunc *escc_mem_write[3] = {
escc_mem_writeb,
|
|
659
660
|
NULL,
NULL,
|
|
661
662
|
};
|
|
663
|
static void escc_save_chn(QEMUFile *f, ChannelState *s)
|
|
664
|
{
|
|
665
666
|
uint32_t tmp = 0;
|
|
667
|
qemu_put_be32s(f, &tmp); /* unused, was IRQ. */
|
|
668
669
670
|
qemu_put_be32s(f, &s->reg);
qemu_put_be32s(f, &s->rxint);
qemu_put_be32s(f, &s->txint);
|
|
671
672
|
qemu_put_be32s(f, &s->rxint_under_svc);
qemu_put_be32s(f, &s->txint_under_svc);
|
|
673
674
|
qemu_put_8s(f, &s->rx);
qemu_put_8s(f, &s->tx);
|
|
675
676
|
qemu_put_buffer(f, s->wregs, SERIAL_REGS);
qemu_put_buffer(f, s->rregs, SERIAL_REGS);
|
|
677
678
|
}
|
|
679
|
static void escc_save(QEMUFile *f, void *opaque)
|
|
680
681
682
|
{
SerialState *s = opaque;
|
|
683
684
|
escc_save_chn(f, &s->chn[0]);
escc_save_chn(f, &s->chn[1]);
|
|
685
686
|
}
|
|
687
|
static int escc_load_chn(QEMUFile *f, ChannelState *s, int version_id)
|
|
688
|
{
|
|
689
|
uint32_t tmp;
|
|
690
|
|
|
691
|
if (version_id > 2)
|
|
692
693
|
return -EINVAL;
|
|
694
|
qemu_get_be32s(f, &tmp); /* unused */
|
|
695
696
697
|
qemu_get_be32s(f, &s->reg);
qemu_get_be32s(f, &s->rxint);
qemu_get_be32s(f, &s->txint);
|
|
698
699
700
701
|
if (version_id >= 2) {
qemu_get_be32s(f, &s->rxint_under_svc);
qemu_get_be32s(f, &s->txint_under_svc);
}
|
|
702
703
|
qemu_get_8s(f, &s->rx);
qemu_get_8s(f, &s->tx);
|
|
704
705
|
qemu_get_buffer(f, s->wregs, SERIAL_REGS);
qemu_get_buffer(f, s->rregs, SERIAL_REGS);
|
|
706
707
708
|
return 0;
}
|
|
709
|
static int escc_load(QEMUFile *f, void *opaque, int version_id)
|
|
710
711
712
713
|
{
SerialState *s = opaque;
int ret;
|
|
714
|
ret = escc_load_chn(f, &s->chn[0], version_id);
|
|
715
|
if (ret != 0)
|
|
716
|
return ret;
|
|
717
|
ret = escc_load_chn(f, &s->chn[1], version_id);
|
|
718
719
720
721
|
return ret;
}
|
|
722
723
724
|
int escc_init(target_phys_addr_t base, qemu_irq irqA, qemu_irq irqB,
CharDriverState *chrA, CharDriverState *chrB,
int clock, int it_shift)
|
|
725
|
{
|
|
726
|
int escc_io_memory, i;
|
|
727
728
729
730
|
SerialState *s;
s = qemu_mallocz(sizeof(SerialState));
|
|
731
732
733
734
735
736
|
escc_io_memory = cpu_register_io_memory(0, escc_mem_read,
escc_mem_write,
s);
if (base)
cpu_register_physical_memory(base, ESCC_SIZE << it_shift,
escc_io_memory);
|
|
737
|
|
|
738
|
s->it_shift = it_shift;
|
|
739
740
|
s->chn[0].chr = chrB;
s->chn[1].chr = chrA;
|
|
741
742
|
s->chn[0].disabled = 0;
s->chn[1].disabled = 0;
|
|
743
744
|
s->chn[0].irq = irqB;
s->chn[1].irq = irqA;
|
|
745
746
|
for (i = 0; i < 2; i++) {
|
|
747
748
|
s->chn[i].chn = 1 - i;
s->chn[i].type = ser;
|
|
749
|
s->chn[i].clock = clock / 2;
|
|
750
751
|
if (s->chn[i].chr) {
qemu_chr_add_handlers(s->chn[i].chr, serial_can_receive,
|
|
752
|
serial_receive1, serial_event, &s->chn[i]);
|
|
753
|
}
|
|
754
|
}
|
|
755
756
|
s->chn[0].otherchn = &s->chn[1];
s->chn[1].otherchn = &s->chn[0];
|
|
757
758
759
760
761
762
763
|
if (base)
register_savevm("escc", base, 2, escc_save, escc_load, s);
else
register_savevm("escc", -1, 2, escc_save, escc_load, s);
qemu_register_reset(escc_reset, s);
escc_reset(s);
return escc_io_memory;
|
|
764
765
|
}
|
|
766
767
768
769
770
771
772
773
774
775
776
|
static const uint8_t keycodes[128] = {
127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53,
54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78,
79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12,
14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112,
113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0,
90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66,
0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67,
};
|
|
777
778
779
780
781
782
783
784
|
static const uint8_t e0_keycodes[128] = {
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 90, 76, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 109, 0, 0, 13, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 68, 69, 70, 0, 91, 0, 93, 0, 112,
113, 114, 94, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
785
|
1, 3, 25, 26, 49, 52, 72, 73, 97, 99, 111, 118, 120, 122, 67, 0,
|
|
786
787
|
};
|
|
788
789
790
|
static void sunkbd_event(void *opaque, int ch)
{
ChannelState *s = opaque;
|
|
791
792
|
int release = ch & 0x80;
|
|
793
794
|
KBD_DPRINTF("Untranslated keycode %2.2x (%s)\n", ch, release? "release" :
"press");
|
|
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
|
switch (ch) {
case 58: // Caps lock press
s->caps_lock_mode ^= 1;
if (s->caps_lock_mode == 2)
return; // Drop second press
break;
case 69: // Num lock press
s->num_lock_mode ^= 1;
if (s->num_lock_mode == 2)
return; // Drop second press
break;
case 186: // Caps lock release
s->caps_lock_mode ^= 2;
if (s->caps_lock_mode == 3)
return; // Drop first release
break;
case 197: // Num lock release
s->num_lock_mode ^= 2;
if (s->num_lock_mode == 3)
return; // Drop first release
break;
case 0xe0:
|
|
817
818
|
s->e0_mode = 1;
return;
|
|
819
820
|
default:
break;
|
|
821
822
823
824
825
826
827
828
|
}
if (s->e0_mode) {
s->e0_mode = 0;
ch = e0_keycodes[ch & 0x7f];
} else {
ch = keycodes[ch & 0x7f];
}
KBD_DPRINTF("Translated keycode %2.2x\n", ch);
|
|
829
830
831
832
833
834
|
put_queue(s, ch | release);
}
static void handle_kbd_command(ChannelState *s, int val)
{
KBD_DPRINTF("Command %d\n", val);
|
|
835
836
837
838
|
if (s->led_mode) { // Ignore led byte
s->led_mode = 0;
return;
}
|
|
839
840
|
switch (val) {
case 1: // Reset, return type code
|
|
841
|
clear_queue(s);
|
|
842
843
844
845
|
put_queue(s, 0xff);
put_queue(s, 4); // Type 4
put_queue(s, 0x7f);
break;
|
|
846
847
848
|
case 0xe: // Set leds
s->led_mode = 1;
break;
|
|
849
|
case 7: // Query layout
|
|
850
851
|
case 0xf:
clear_queue(s);
|
|
852
853
854
|
put_queue(s, 0xfe);
put_queue(s, 0); // XXX, layout?
break;
|
|
855
|
default:
|
|
856
|
break;
|
|
857
|
}
|
|
858
859
|
}
|
ths
authored
|
860
|
static void sunmouse_event(void *opaque,
|
|
861
862
863
864
865
|
int dx, int dy, int dz, int buttons_state)
{
ChannelState *s = opaque;
int ch;
|
|
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
|
MS_DPRINTF("dx=%d dy=%d buttons=%01x\n", dx, dy, buttons_state);
ch = 0x80 | 0x7; /* protocol start byte, no buttons pressed */
if (buttons_state & MOUSE_EVENT_LBUTTON)
ch ^= 0x4;
if (buttons_state & MOUSE_EVENT_MBUTTON)
ch ^= 0x2;
if (buttons_state & MOUSE_EVENT_RBUTTON)
ch ^= 0x1;
put_queue(s, ch);
ch = dx;
if (ch > 127)
ch=127;
else if (ch < -127)
ch=-127;
put_queue(s, ch & 0xff);
ch = -dy;
if (ch > 127)
ch=127;
else if (ch < -127)
ch=-127;
put_queue(s, ch & 0xff);
// MSC protocol specify two extra motion bytes
put_queue(s, 0);
put_queue(s, 0);
|
|
901
902
|
}
|
|
903
|
void slavio_serial_ms_kbd_init(target_phys_addr_t base, qemu_irq irq,
|
|
904
|
int disabled, int clock, int it_shift)
|
|
905
|
{
|
|
906
|
int slavio_serial_io_memory, i;
|
|
907
908
909
|
SerialState *s;
s = qemu_mallocz(sizeof(SerialState));
|
|
910
911
|
s->it_shift = it_shift;
|
|
912
|
for (i = 0; i < 2; i++) {
|
|
913
914
915
|
s->chn[i].irq = irq;
s->chn[i].chn = 1 - i;
s->chn[i].chr = NULL;
|
|
916
|
s->chn[i].clock = clock / 2;
|
|
917
918
919
920
921
|
}
s->chn[0].otherchn = &s->chn[1];
s->chn[1].otherchn = &s->chn[0];
s->chn[0].type = mouse;
s->chn[1].type = kbd;
|
|
922
923
|
s->chn[0].disabled = disabled;
s->chn[1].disabled = disabled;
|
|
924
|
|
|
925
926
|
slavio_serial_io_memory = cpu_register_io_memory(0, escc_mem_read,
escc_mem_write,
|
|
927
|
s);
|
|
928
929
|
cpu_register_physical_memory(base, ESCC_SIZE << it_shift,
slavio_serial_io_memory);
|
|
930
|
|
|
931
932
|
qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0], 0,
"QEMU Sun Mouse");
|
|
933
|
qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
|
|
934
935
936
|
register_savevm("slavio_serial_mouse", base, 2, escc_save, escc_load, s);
qemu_register_reset(escc_reset, s);
escc_reset(s);
|
|
937
|
}
|