]> git.proxmox.com Git - mirror_qemu.git/blame - hw/slavio_serial.c
cpu_exec_init() change
[mirror_qemu.git] / hw / slavio_serial.c
CommitLineData
e80cfcfc
FB
1/*
2 * QEMU Sparc SLAVIO serial port emulation
3 *
8be1f5c8 4 * Copyright (c) 2003-2005 Fabrice Bellard
e80cfcfc
FB
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a copy
7 * of this software and associated documentation files (the "Software"), to deal
8 * in the Software without restriction, including without limitation the rights
9 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10 * copies of the Software, and to permit persons to whom the Software is
11 * furnished to do so, subject to the following conditions:
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 */
24#include "vl.h"
8be1f5c8 25/* debug serial */
e80cfcfc
FB
26//#define DEBUG_SERIAL
27
28/* debug keyboard */
29//#define DEBUG_KBD
30
8be1f5c8 31/* debug mouse */
e80cfcfc
FB
32//#define DEBUG_MOUSE
33
34/*
35 * This is the serial port, mouse and keyboard part of chip STP2001
36 * (Slave I/O), also produced as NCR89C105. See
37 * http://www.ibiblio.org/pub/historic-linux/early-ports/Sparc/NCR/NCR89C105.txt
38 *
39 * The serial ports implement full AMD AM8530 or Zilog Z8530 chips,
40 * mouse and keyboard ports don't implement all functions and they are
41 * only asynchronous. There is no DMA.
42 *
43 */
44
8be1f5c8
FB
45#ifdef DEBUG_SERIAL
46#define SER_DPRINTF(fmt, args...) \
47do { printf("SER: " fmt , ##args); } while (0)
48#else
49#define SER_DPRINTF(fmt, args...)
50#endif
51#ifdef DEBUG_KBD
52#define KBD_DPRINTF(fmt, args...) \
53do { printf("KBD: " fmt , ##args); } while (0)
54#else
55#define KBD_DPRINTF(fmt, args...)
56#endif
57#ifdef DEBUG_MOUSE
58#define MS_DPRINTF(fmt, args...) \
59do { printf("SER: " fmt , ##args); } while (0)
60#else
61#define MS_DPRINTF(fmt, args...)
62#endif
63
64typedef enum {
65 chn_a, chn_b,
66} chn_id_t;
67
68typedef enum {
69 ser, kbd, mouse,
70} chn_type_t;
71
72#define KBD_QUEUE_SIZE 256
73
74typedef struct {
75 uint8_t data[KBD_QUEUE_SIZE];
76 int rptr, wptr, count;
77} KBDQueue;
78
e80cfcfc
FB
79typedef struct ChannelState {
80 int irq;
81 int reg;
82 int rxint, txint;
8be1f5c8
FB
83 chn_id_t chn; // this channel, A (base+4) or B (base+0)
84 chn_type_t type;
85 struct ChannelState *otherchn;
e80cfcfc 86 uint8_t rx, tx, wregs[16], rregs[16];
8be1f5c8 87 KBDQueue queue;
e80cfcfc
FB
88 CharDriverState *chr;
89} ChannelState;
90
91struct SerialState {
92 struct ChannelState chn[2];
93};
94
95#define SERIAL_MAXADDR 7
96
8be1f5c8
FB
97static void handle_kbd_command(ChannelState *s, int val);
98static int serial_can_receive(void *opaque);
99static void serial_receive_byte(ChannelState *s, int ch);
100
101static void put_queue(void *opaque, int b)
102{
103 ChannelState *s = opaque;
104 KBDQueue *q = &s->queue;
105
106 KBD_DPRINTF("put: 0x%02x\n", b);
107 if (q->count >= KBD_QUEUE_SIZE)
108 return;
109 q->data[q->wptr] = b;
110 if (++q->wptr == KBD_QUEUE_SIZE)
111 q->wptr = 0;
112 q->count++;
113 serial_receive_byte(s, 0);
114}
115
116static uint32_t get_queue(void *opaque)
117{
118 ChannelState *s = opaque;
119 KBDQueue *q = &s->queue;
120 int val;
121
122 if (q->count == 0) {
123 return 0;
124 } else {
125 val = q->data[q->rptr];
126 if (++q->rptr == KBD_QUEUE_SIZE)
127 q->rptr = 0;
128 q->count--;
129 }
130 KBD_DPRINTF("get 0x%02x\n", val);
131 if (q->count > 0)
132 serial_receive_byte(s, 0);
133 return val;
134}
135
e80cfcfc
FB
136static void slavio_serial_update_irq(ChannelState *s)
137{
138 if ((s->wregs[1] & 1) && // interrupts enabled
139 (((s->wregs[1] & 2) && s->txint == 1) || // tx ints enabled, pending
140 ((((s->wregs[1] & 0x18) == 8) || ((s->wregs[1] & 0x18) == 0x10)) &&
141 s->rxint == 1) || // rx ints enabled, pending
142 ((s->wregs[15] & 0x80) && (s->rregs[0] & 0x80)))) { // break int e&p
143 pic_set_irq(s->irq, 1);
144 } else {
145 pic_set_irq(s->irq, 0);
146 }
147}
148
149static void slavio_serial_reset_chn(ChannelState *s)
150{
151 int i;
152
153 s->reg = 0;
154 for (i = 0; i < SERIAL_MAXADDR; i++) {
155 s->rregs[i] = 0;
156 s->wregs[i] = 0;
157 }
158 s->wregs[4] = 4;
159 s->wregs[9] = 0xc0;
160 s->wregs[11] = 8;
161 s->wregs[14] = 0x30;
162 s->wregs[15] = 0xf8;
163 s->rregs[0] = 0x44;
164 s->rregs[1] = 6;
165
166 s->rx = s->tx = 0;
167 s->rxint = s->txint = 0;
168}
169
170static void slavio_serial_reset(void *opaque)
171{
172 SerialState *s = opaque;
173 slavio_serial_reset_chn(&s->chn[0]);
174 slavio_serial_reset_chn(&s->chn[1]);
175}
176
3a5c3138 177static void slavio_serial_mem_writeb(void *opaque, target_phys_addr_t addr, uint32_t val)
e80cfcfc
FB
178{
179 SerialState *ser = opaque;
180 ChannelState *s;
181 uint32_t saddr;
182 int newreg, channel;
183
184 val &= 0xff;
185 saddr = (addr & 3) >> 1;
186 channel = (addr & SERIAL_MAXADDR) >> 2;
187 s = &ser->chn[channel];
188 switch (saddr) {
189 case 0:
8be1f5c8 190 SER_DPRINTF("Write channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, val & 0xff);
e80cfcfc
FB
191 newreg = 0;
192 switch (s->reg) {
193 case 0:
194 newreg = val & 7;
195 val &= 0x38;
196 switch (val) {
197 case 8:
f69a8695 198 newreg |= 0x8;
e80cfcfc
FB
199 break;
200 case 0x20:
201 s->rxint = 0;
202 break;
203 case 0x28:
204 s->txint = 0;
205 break;
206 default:
207 break;
208 }
209 break;
210 case 1 ... 8:
211 case 10 ... 15:
212 s->wregs[s->reg] = val;
213 break;
214 case 9:
215 switch (val & 0xc0) {
216 case 0:
217 default:
218 break;
219 case 0x40:
220 slavio_serial_reset_chn(&ser->chn[1]);
221 return;
222 case 0x80:
223 slavio_serial_reset_chn(&ser->chn[0]);
224 return;
225 case 0xc0:
226 slavio_serial_reset(ser);
227 return;
228 }
229 break;
230 default:
231 break;
232 }
233 if (s->reg == 0)
234 s->reg = newreg;
235 else
236 s->reg = 0;
237 break;
238 case 1:
8be1f5c8 239 SER_DPRINTF("Write channel %c, ch %d\n", channel? 'b' : 'a', val);
e80cfcfc
FB
240 if (s->wregs[5] & 8) { // tx enabled
241 s->tx = val;
242 if (s->chr)
243 qemu_chr_write(s->chr, &s->tx, 1);
8be1f5c8
FB
244 else if (s->type == kbd) {
245 handle_kbd_command(s, val);
246 }
e80cfcfc 247 s->txint = 1;
f69a8695
FB
248 s->rregs[0] |= 4; // Tx buffer empty
249 s->rregs[1] |= 1; // All sent
8be1f5c8
FB
250 // Interrupts reported only on channel A
251 if (s->chn == 0)
252 s->rregs[3] |= 0x10;
253 else {
254 s->otherchn->rregs[3] |= 2;
255 }
256 slavio_serial_update_irq(s);
e80cfcfc
FB
257 }
258 break;
259 default:
260 break;
261 }
262}
263
3a5c3138 264static uint32_t slavio_serial_mem_readb(void *opaque, target_phys_addr_t addr)
e80cfcfc
FB
265{
266 SerialState *ser = opaque;
267 ChannelState *s;
268 uint32_t saddr;
269 uint32_t ret;
270 int channel;
271
272 saddr = (addr & 3) >> 1;
273 channel = (addr & SERIAL_MAXADDR) >> 2;
274 s = &ser->chn[channel];
275 switch (saddr) {
276 case 0:
8be1f5c8 277 SER_DPRINTF("Read channel %c, reg[%d] = %2.2x\n", channel? 'b' : 'a', s->reg, s->rregs[s->reg]);
e80cfcfc
FB
278 ret = s->rregs[s->reg];
279 s->reg = 0;
280 return ret;
281 case 1:
282 s->rregs[0] &= ~1;
8be1f5c8
FB
283 if (s->type == kbd)
284 ret = get_queue(s);
285 else
286 ret = s->rx;
f69a8695 287 SER_DPRINTF("Read channel %c, ch %d\n", channel? 'b' : 'a', ret);
8be1f5c8 288 return ret;
e80cfcfc
FB
289 default:
290 break;
291 }
292 return 0;
293}
294
295static int serial_can_receive(void *opaque)
296{
297 ChannelState *s = opaque;
298 if (((s->wregs[3] & 1) == 0) // Rx not enabled
299 || ((s->rregs[0] & 1) == 1)) // char already available
300 return 0;
301 else
302 return 1;
303}
304
305static void serial_receive_byte(ChannelState *s, int ch)
306{
307 s->rregs[0] |= 1;
8be1f5c8
FB
308 // Interrupts reported only on channel A
309 if (s->chn == 0)
310 s->rregs[3] |= 0x20;
311 else {
312 s->otherchn->rregs[3] |= 4;
313 }
e80cfcfc
FB
314 s->rx = ch;
315 s->rxint = 1;
316 slavio_serial_update_irq(s);
317}
318
319static void serial_receive_break(ChannelState *s)
320{
321 s->rregs[0] |= 0x80;
322 slavio_serial_update_irq(s);
323}
324
325static void serial_receive1(void *opaque, const uint8_t *buf, int size)
326{
327 ChannelState *s = opaque;
328 serial_receive_byte(s, buf[0]);
329}
330
331static void serial_event(void *opaque, int event)
332{
333 ChannelState *s = opaque;
334 if (event == CHR_EVENT_BREAK)
335 serial_receive_break(s);
336}
337
338static CPUReadMemoryFunc *slavio_serial_mem_read[3] = {
339 slavio_serial_mem_readb,
340 slavio_serial_mem_readb,
341 slavio_serial_mem_readb,
342};
343
344static CPUWriteMemoryFunc *slavio_serial_mem_write[3] = {
345 slavio_serial_mem_writeb,
346 slavio_serial_mem_writeb,
347 slavio_serial_mem_writeb,
348};
349
350static void slavio_serial_save_chn(QEMUFile *f, ChannelState *s)
351{
352 qemu_put_be32s(f, &s->irq);
353 qemu_put_be32s(f, &s->reg);
354 qemu_put_be32s(f, &s->rxint);
355 qemu_put_be32s(f, &s->txint);
356 qemu_put_8s(f, &s->rx);
357 qemu_put_8s(f, &s->tx);
358 qemu_put_buffer(f, s->wregs, 16);
359 qemu_put_buffer(f, s->rregs, 16);
360}
361
362static void slavio_serial_save(QEMUFile *f, void *opaque)
363{
364 SerialState *s = opaque;
365
366 slavio_serial_save_chn(f, &s->chn[0]);
367 slavio_serial_save_chn(f, &s->chn[1]);
368}
369
370static int slavio_serial_load_chn(QEMUFile *f, ChannelState *s, int version_id)
371{
372 if (version_id != 1)
373 return -EINVAL;
374
375 qemu_get_be32s(f, &s->irq);
376 qemu_get_be32s(f, &s->reg);
377 qemu_get_be32s(f, &s->rxint);
378 qemu_get_be32s(f, &s->txint);
379 qemu_get_8s(f, &s->rx);
380 qemu_get_8s(f, &s->tx);
381 qemu_get_buffer(f, s->wregs, 16);
382 qemu_get_buffer(f, s->rregs, 16);
383 return 0;
384}
385
386static int slavio_serial_load(QEMUFile *f, void *opaque, int version_id)
387{
388 SerialState *s = opaque;
389 int ret;
390
391 ret = slavio_serial_load_chn(f, &s->chn[0], version_id);
392 if (ret != 0)
393 return ret;
394 ret = slavio_serial_load_chn(f, &s->chn[1], version_id);
395 return ret;
396
397}
398
399SerialState *slavio_serial_init(int base, int irq, CharDriverState *chr1, CharDriverState *chr2)
400{
8be1f5c8 401 int slavio_serial_io_memory, i;
e80cfcfc
FB
402 SerialState *s;
403
404 s = qemu_mallocz(sizeof(SerialState));
405 if (!s)
406 return NULL;
e80cfcfc
FB
407
408 slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s);
409 cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory);
410
8be1f5c8
FB
411 s->chn[0].chr = chr1;
412 s->chn[1].chr = chr2;
413
414 for (i = 0; i < 2; i++) {
415 s->chn[i].irq = irq;
416 s->chn[i].chn = 1 - i;
417 s->chn[i].type = ser;
418 if (s->chn[i].chr) {
419 qemu_chr_add_read_handler(s->chn[i].chr, serial_can_receive, serial_receive1, &s->chn[i]);
420 qemu_chr_add_event_handler(s->chn[i].chr, serial_event);
421 }
e80cfcfc 422 }
8be1f5c8
FB
423 s->chn[0].otherchn = &s->chn[1];
424 s->chn[1].otherchn = &s->chn[0];
e80cfcfc
FB
425 register_savevm("slavio_serial", base, 1, slavio_serial_save, slavio_serial_load, s);
426 qemu_register_reset(slavio_serial_reset, s);
427 slavio_serial_reset(s);
428 return s;
429}
430
8be1f5c8
FB
431static const uint8_t keycodes[128] = {
432 127, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 53,
433 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 89, 76, 77, 78,
434 79, 80, 81, 82, 83, 84, 85, 86, 87, 42, 99, 88, 100, 101, 102, 103,
435 104, 105, 106, 107, 108, 109, 110, 47, 19, 121, 119, 5, 6, 8, 10, 12,
436 14, 16, 17, 18, 7, 98, 23, 68, 69, 70, 71, 91, 92, 93, 125, 112,
437 113, 114, 94, 50, 0, 0, 124, 9, 11, 0, 0, 0, 0, 0, 0, 0,
438 90, 0, 46, 22, 13, 111, 52, 20, 96, 24, 28, 74, 27, 123, 44, 66,
439 0, 45, 2, 4, 48, 0, 0, 21, 0, 0, 0, 0, 0, 120, 122, 67,
440};
441
e80cfcfc
FB
442static void sunkbd_event(void *opaque, int ch)
443{
444 ChannelState *s = opaque;
8be1f5c8
FB
445 int release = ch & 0x80;
446
447 ch = keycodes[ch & 0x7f];
448 KBD_DPRINTF("Keycode %d (%s)\n", ch, release? "release" : "press");
449 put_queue(s, ch | release);
450}
451
452static void handle_kbd_command(ChannelState *s, int val)
453{
454 KBD_DPRINTF("Command %d\n", val);
455 switch (val) {
456 case 1: // Reset, return type code
8be1f5c8
FB
457 put_queue(s, 0xff);
458 put_queue(s, 5); // Type 5
459 break;
460 case 7: // Query layout
461 put_queue(s, 0xfe);
462 put_queue(s, 0x20); // XXX, layout?
463 break;
464 default:
465 break;
466 }
e80cfcfc
FB
467}
468
469static void sunmouse_event(void *opaque,
470 int dx, int dy, int dz, int buttons_state)
471{
472 ChannelState *s = opaque;
473 int ch;
474
475 // XXX
476 ch = 0x42;
477 serial_receive_byte(s, ch);
478}
479
480void slavio_serial_ms_kbd_init(int base, int irq)
481{
8be1f5c8 482 int slavio_serial_io_memory, i;
e80cfcfc
FB
483 SerialState *s;
484
485 s = qemu_mallocz(sizeof(SerialState));
486 if (!s)
487 return;
8be1f5c8
FB
488 for (i = 0; i < 2; i++) {
489 s->chn[i].irq = irq;
490 s->chn[i].chn = 1 - i;
491 s->chn[i].chr = NULL;
492 }
493 s->chn[0].otherchn = &s->chn[1];
494 s->chn[1].otherchn = &s->chn[0];
495 s->chn[0].type = mouse;
496 s->chn[1].type = kbd;
e80cfcfc
FB
497
498 slavio_serial_io_memory = cpu_register_io_memory(0, slavio_serial_mem_read, slavio_serial_mem_write, s);
499 cpu_register_physical_memory(base, SERIAL_MAXADDR, slavio_serial_io_memory);
500
8be1f5c8
FB
501 qemu_add_mouse_event_handler(sunmouse_event, &s->chn[0]);
502 qemu_add_kbd_event_handler(sunkbd_event, &s->chn[1]);
e80cfcfc
FB
503 qemu_register_reset(slavio_serial_reset, s);
504 slavio_serial_reset(s);
505}