From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mailman by lists.gnu.org with tmda-scanned (Exim 4.43) id 1EeNwN-00044a-MX for qemu-devel@nongnu.org; Mon, 21 Nov 2005 21:31:27 -0500 Received: from exim by lists.gnu.org with spam-scanned (Exim 4.43) id 1EeNwM-00043S-CM for qemu-devel@nongnu.org; Mon, 21 Nov 2005 21:31:27 -0500 Received: from [199.232.76.173] (helo=monty-python.gnu.org) by lists.gnu.org with esmtp (Exim 4.43) id 1EeNwM-00043G-8h for qemu-devel@nongnu.org; Mon, 21 Nov 2005 21:31:26 -0500 Received: from [65.74.133.11] (helo=mail.codesourcery.com) by monty-python.gnu.org with esmtp (TLS-1.0:DHE_RSA_3DES_EDE_CBC_SHA:24) (Exim 4.34) id 1EeNwL-0008RO-40 for qemu-devel@nongnu.org; Mon, 21 Nov 2005 21:31:26 -0500 From: Paul Brook Date: Tue, 22 Nov 2005 02:31:14 +0000 MIME-Version: 1.0 Content-Type: Multipart/Mixed; boundary="Boundary-00=_0LogDPZsMmt0csh" Message-Id: <200511220231.16133.paul@codesourcery.com> Subject: [Qemu-devel] Arm system emulation Reply-To: qemu-devel@nongnu.org List-Id: qemu-devel.nongnu.org List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , To: qemu-devel@nongnu.org, Fabrice Bellard --Boundary-00=_0LogDPZsMmt0csh Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline The attached patch implements Arm system emulation. Also attached is the prerequisite PS/2 emulation separation patch. The emulated hardware is based on an Arm Integrator/CP board with an arm1026ej-s cpu. This is an embedded development board that supports a variety of core modules and peripherals. Currently timers, interrupt controller and UART(x2) are implemented. Network should follow shortly. In the medium term I plan to extend this to also emulate an Integrator/AP board. This is similar but includes which includes a PCI bus, so existing PCI peripherals can be used. Longer term these boards can be used as a base for future ARM cpus, including SMP support. Generally speaking Arm boards don't have a BIOS.The kernel/bootloader is loaded directly from flash. The -kernel option can be used to load linux kernels (and probably any other image). For anyone wanting to try this, there's a kernel image and small initrd filesystem at: https://nowt.dyndns.org/integratorcp.zImage https://nowt.dyndns.org/arm_root.img There's nothing special about these. Just a vanilla 2.6.14 kernel configured with a serial console and busybox+bash from a Debian arm-linux install. Paul --Boundary-00=_0LogDPZsMmt0csh Content-Type: application/x-bzip2; name="patch.qemu_arm_system.bz2" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="patch.qemu_arm_system.bz2" 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 leuJAP7RdyRThQkE9utbcA== --Boundary-00=_0LogDPZsMmt0csh Content-Type: text/x-diff; charset="us-ascii"; name="patch.qemu_ps2" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="patch.qemu_ps2" Index: Makefile.target =================================================================== RCS file: /cvsroot/qemu/qemu/Makefile.target,v retrieving revision 1.86 diff -u -p -r1.86 Makefile.target --- Makefile.target 6 Nov 2005 16:52:11 -0000 1.86 +++ Makefile.target 20 Nov 2005 15:13:51 -0000 @@ -298,13 +298,13 @@ VL_OBJS+= usb.o usb-uhci.o usb-linux.o u ifeq ($(TARGET_BASE_ARCH), i386) # Hardware support -VL_OBJS+= ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) +VL_OBJS+= ide.o ne2000.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= fdc.o mc146818rtc.o serial.o i8259.o i8254.o pc.o VL_OBJS+= cirrus_vga.o mixeng.o apic.o parallel.o DEFINES += -DHAS_AUDIO endif ifeq ($(TARGET_BASE_ARCH), ppc) -VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) +VL_OBJS+= ppc.o ide.o ne2000.o pckbd.o ps2.o vga.o $(SOUND_HW) dma.o $(AUDIODRV) VL_OBJS+= mc146818rtc.o serial.o i8259.o i8254.o fdc.o m48t59.o VL_OBJS+= ppc_prep.o ppc_chrp.o cuda.o adb.o openpic.o heathrow_pic.o mixeng.o DEFINES += -DHAS_AUDIO @@ -315,7 +315,7 @@ VL_OBJS+= mips_r4k.o dma.o vga.o serial. endif ifeq ($(TARGET_BASE_ARCH), sparc) ifeq ($(TARGET_ARCH), sparc64) -VL_OBJS+= sun4u.o ide.o ne2000.o pckbd.o vga.o +VL_OBJS+= sun4u.o ide.o ne2000.o pckbd.o ps2.o vga.o VL_OBJS+= fdc.o mc146818rtc.o serial.o m48t59.o VL_OBJS+= cirrus_vga.o parallel.o VL_OBJS+= magic-load.o Index: vl.h =================================================================== RCS file: /cvsroot/qemu/qemu/vl.h,v retrieving revision 1.91 diff -u -p -r1.91 vl.h --- vl.h 15 Nov 2005 22:16:05 -0000 1.91 +++ vl.h 20 Nov 2005 15:13:55 -0000 @@ -916,6 +916,14 @@ void do_usb_add(const char *devname); void do_usb_del(const char *devname); void usb_info(void); +/* ps2.c */ +void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg); +void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg); +void ps2_write_mouse(void *, int val); +void ps2_write_keyboard(void *, int val); +uint32_t ps2_read_data(void *); +void ps2_queue(void *, int b); + #endif /* defined(QEMU_TOOL) */ /* monitor.c */ Index: hw/pckbd.c =================================================================== RCS file: /cvsroot/qemu/qemu/hw/pckbd.c,v retrieving revision 1.11 diff -u -p -r1.11 pckbd.c --- hw/pckbd.c 27 Jan 2005 22:32:51 -0000 1.11 +++ hw/pckbd.c 20 Nov 2005 15:13:55 -0000 @@ -110,32 +110,17 @@ #define KBD_QUEUE_SIZE 256 -typedef struct { - uint8_t aux[KBD_QUEUE_SIZE]; - uint8_t data[KBD_QUEUE_SIZE]; - int rptr, wptr, count; -} KBDQueue; +#define KBD_PENDING_KBD 1 +#define KBD_PENDING_AUX 2 typedef struct KBDState { - KBDQueue queue; uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ uint8_t status; uint8_t mode; - /* keyboard state */ - int kbd_write_cmd; - int scan_enabled; - /* mouse state */ - int mouse_write_cmd; - uint8_t mouse_status; - uint8_t mouse_resolution; - uint8_t mouse_sample_rate; - uint8_t mouse_wrap; - uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ - uint8_t mouse_detect_state; - int mouse_dx; /* current values, needed for 'poll' mode */ - int mouse_dy; - int mouse_dz; - uint8_t mouse_buttons; + /* Bitmask of devices with data available. */ + int pending; + void *kbd; + void *mouse; } KBDState; KBDState kbd_state; @@ -145,15 +130,15 @@ KBDState kbd_state; incorrect, but it avoids having to simulate exact delays */ static void kbd_update_irq(KBDState *s) { - KBDQueue *q = &s->queue; int irq12_level, irq1_level; irq1_level = 0; irq12_level = 0; s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); - if (q->count != 0) { + if (s->pending) { s->status |= KBD_STAT_OBF; - if (q->aux[q->rptr]) { + /* kdb data takes priority over aux data. */ + if (s->pending == KBD_PENDING_AUX) { s->status |= KBD_STAT_MOUSE_OBF; if (s->mode & KBD_MODE_MOUSE_INT) irq12_level = 1; @@ -167,32 +152,26 @@ static void kbd_update_irq(KBDState *s) pic_set_irq(12, irq12_level); } -static void kbd_queue(KBDState *s, int b, int aux) +static void kbd_update_kbd_irq(void *opaque, int level) { - KBDQueue *q = &s->queue; + KBDState *s = (KBDState *)opaque; -#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD) - if (aux) - printf("mouse event: 0x%02x\n", b); -#ifdef DEBUG_KBD + if (level) + s->pending |= KBD_PENDING_KBD; else - printf("kbd event: 0x%02x\n", b); -#endif -#endif - if (q->count >= KBD_QUEUE_SIZE) - return; - q->aux[q->wptr] = aux; - q->data[q->wptr] = b; - if (++q->wptr == KBD_QUEUE_SIZE) - q->wptr = 0; - q->count++; + s->pending &= ~KBD_PENDING_KBD; kbd_update_irq(s); } -static void pc_kbd_put_keycode(void *opaque, int keycode) +static void kbd_update_aux_irq(void *opaque, int level) { - KBDState *s = opaque; - kbd_queue(s, keycode, 0); + KBDState *s = (KBDState *)opaque; + + if (level) + s->pending |= KBD_PENDING_AUX; + else + s->pending &= ~KBD_PENDING_AUX; + kbd_update_irq(s); } static uint32_t kbd_read_status(void *opaque, uint32_t addr) @@ -206,6 +185,14 @@ static uint32_t kbd_read_status(void *op return val; } +static void kbd_queue(KBDState *s, int b, int aux) +{ + if (aux) + ps2_queue(s->mouse, b); + else + ps2_queue(s->kbd, b); +} + static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val) { KBDState *s = opaque; @@ -287,304 +274,11 @@ static void kbd_write_command(void *opaq static uint32_t kbd_read_data(void *opaque, uint32_t addr) { KBDState *s = opaque; - KBDQueue *q; - int val, index, aux; - - q = &s->queue; - if (q->count == 0) { - /* NOTE: if no data left, we return the last keyboard one - (needed for EMM386) */ - /* XXX: need a timer to do things correctly */ - index = q->rptr - 1; - if (index < 0) - index = KBD_QUEUE_SIZE - 1; - val = q->data[index]; - } else { - aux = q->aux[q->rptr]; - val = q->data[q->rptr]; - if (++q->rptr == KBD_QUEUE_SIZE) - q->rptr = 0; - q->count--; - /* reading deasserts IRQ */ - if (aux) - pic_set_irq(12, 0); - else - pic_set_irq(1, 0); - } - /* reassert IRQs if data left */ - kbd_update_irq(s); -#ifdef DEBUG_KBD - printf("kbd: read data=0x%02x\n", val); -#endif - return val; -} -static void kbd_reset_keyboard(KBDState *s) -{ - s->scan_enabled = 1; -} + if (s->pending == KBD_PENDING_AUX) + return ps2_read_data(s->mouse); -static void kbd_write_keyboard(KBDState *s, int val) -{ - switch(s->kbd_write_cmd) { - default: - case -1: - switch(val) { - case 0x00: - kbd_queue(s, KBD_REPLY_ACK, 0); - break; - case 0x05: - kbd_queue(s, KBD_REPLY_RESEND, 0); - break; - case KBD_CMD_GET_ID: - kbd_queue(s, KBD_REPLY_ACK, 0); - kbd_queue(s, 0xab, 0); - kbd_queue(s, 0x83, 0); - break; - case KBD_CMD_ECHO: - kbd_queue(s, KBD_CMD_ECHO, 0); - break; - case KBD_CMD_ENABLE: - s->scan_enabled = 1; - kbd_queue(s, KBD_REPLY_ACK, 0); - break; - case KBD_CMD_SET_LEDS: - case KBD_CMD_SET_RATE: - s->kbd_write_cmd = val; - kbd_queue(s, KBD_REPLY_ACK, 0); - break; - case KBD_CMD_RESET_DISABLE: - kbd_reset_keyboard(s); - s->scan_enabled = 0; - kbd_queue(s, KBD_REPLY_ACK, 0); - break; - case KBD_CMD_RESET_ENABLE: - kbd_reset_keyboard(s); - s->scan_enabled = 1; - kbd_queue(s, KBD_REPLY_ACK, 0); - break; - case KBD_CMD_RESET: - kbd_reset_keyboard(s); - kbd_queue(s, KBD_REPLY_ACK, 0); - kbd_queue(s, KBD_REPLY_POR, 0); - break; - default: - kbd_queue(s, KBD_REPLY_ACK, 0); - break; - } - break; - case KBD_CMD_SET_LEDS: - kbd_queue(s, KBD_REPLY_ACK, 0); - s->kbd_write_cmd = -1; - break; - case KBD_CMD_SET_RATE: - kbd_queue(s, KBD_REPLY_ACK, 0); - s->kbd_write_cmd = -1; - break; - } -} - -static void kbd_mouse_send_packet(KBDState *s) -{ - unsigned int b; - int dx1, dy1, dz1; - - dx1 = s->mouse_dx; - dy1 = s->mouse_dy; - dz1 = s->mouse_dz; - /* XXX: increase range to 8 bits ? */ - if (dx1 > 127) - dx1 = 127; - else if (dx1 < -127) - dx1 = -127; - if (dy1 > 127) - dy1 = 127; - else if (dy1 < -127) - dy1 = -127; - b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); - kbd_queue(s, b, 1); - kbd_queue(s, dx1 & 0xff, 1); - kbd_queue(s, dy1 & 0xff, 1); - /* extra byte for IMPS/2 or IMEX */ - switch(s->mouse_type) { - default: - break; - case 3: - if (dz1 > 127) - dz1 = 127; - else if (dz1 < -127) - dz1 = -127; - kbd_queue(s, dz1 & 0xff, 1); - break; - case 4: - if (dz1 > 7) - dz1 = 7; - else if (dz1 < -7) - dz1 = -7; - b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); - kbd_queue(s, b, 1); - break; - } - - /* update deltas */ - s->mouse_dx -= dx1; - s->mouse_dy -= dy1; - s->mouse_dz -= dz1; -} - -static void pc_kbd_mouse_event(void *opaque, - int dx, int dy, int dz, int buttons_state) -{ - KBDState *s = opaque; - - /* check if deltas are recorded when disabled */ - if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) - return; - - s->mouse_dx += dx; - s->mouse_dy -= dy; - s->mouse_dz += dz; - /* XXX: SDL sometimes generates nul events: we delete them */ - if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 && - s->mouse_buttons == buttons_state) - return; - s->mouse_buttons = buttons_state; - - if (!(s->mouse_status & MOUSE_STATUS_REMOTE) && - (s->queue.count < (KBD_QUEUE_SIZE - 16))) { - for(;;) { - /* if not remote, send event. Multiple events are sent if - too big deltas */ - kbd_mouse_send_packet(s); - if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) - break; - } - } -} - -static void kbd_write_mouse(KBDState *s, int val) -{ -#ifdef DEBUG_MOUSE - printf("kbd: write mouse 0x%02x\n", val); -#endif - switch(s->mouse_write_cmd) { - default: - case -1: - /* mouse command */ - if (s->mouse_wrap) { - if (val == AUX_RESET_WRAP) { - s->mouse_wrap = 0; - kbd_queue(s, AUX_ACK, 1); - return; - } else if (val != AUX_RESET) { - kbd_queue(s, val, 1); - return; - } - } - switch(val) { - case AUX_SET_SCALE11: - s->mouse_status &= ~MOUSE_STATUS_SCALE21; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_SET_SCALE21: - s->mouse_status |= MOUSE_STATUS_SCALE21; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_SET_STREAM: - s->mouse_status &= ~MOUSE_STATUS_REMOTE; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_SET_WRAP: - s->mouse_wrap = 1; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_SET_REMOTE: - s->mouse_status |= MOUSE_STATUS_REMOTE; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_GET_TYPE: - kbd_queue(s, AUX_ACK, 1); - kbd_queue(s, s->mouse_type, 1); - break; - case AUX_SET_RES: - case AUX_SET_SAMPLE: - s->mouse_write_cmd = val; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_GET_SCALE: - kbd_queue(s, AUX_ACK, 1); - kbd_queue(s, s->mouse_status, 1); - kbd_queue(s, s->mouse_resolution, 1); - kbd_queue(s, s->mouse_sample_rate, 1); - break; - case AUX_POLL: - kbd_queue(s, AUX_ACK, 1); - kbd_mouse_send_packet(s); - break; - case AUX_ENABLE_DEV: - s->mouse_status |= MOUSE_STATUS_ENABLED; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_DISABLE_DEV: - s->mouse_status &= ~MOUSE_STATUS_ENABLED; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_SET_DEFAULT: - s->mouse_sample_rate = 100; - s->mouse_resolution = 2; - s->mouse_status = 0; - kbd_queue(s, AUX_ACK, 1); - break; - case AUX_RESET: - s->mouse_sample_rate = 100; - s->mouse_resolution = 2; - s->mouse_status = 0; - s->mouse_type = 0; - kbd_queue(s, AUX_ACK, 1); - kbd_queue(s, 0xaa, 1); - kbd_queue(s, s->mouse_type, 1); - break; - default: - break; - } - break; - case AUX_SET_SAMPLE: - s->mouse_sample_rate = val; - /* detect IMPS/2 or IMEX */ - switch(s->mouse_detect_state) { - default: - case 0: - if (val == 200) - s->mouse_detect_state = 1; - break; - case 1: - if (val == 100) - s->mouse_detect_state = 2; - else if (val == 200) - s->mouse_detect_state = 3; - else - s->mouse_detect_state = 0; - break; - case 2: - if (val == 80) - s->mouse_type = 3; /* IMPS/2 */ - s->mouse_detect_state = 0; - break; - case 3: - if (val == 80) - s->mouse_type = 4; /* IMEX */ - s->mouse_detect_state = 0; - break; - } - kbd_queue(s, AUX_ACK, 1); - s->mouse_write_cmd = -1; - break; - case AUX_SET_RES: - s->mouse_resolution = val; - kbd_queue(s, AUX_ACK, 1); - s->mouse_write_cmd = -1; - break; - } + return ps2_read_data(s->kbd); } void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) @@ -597,10 +291,11 @@ void kbd_write_data(void *opaque, uint32 switch(s->write_cmd) { case 0: - kbd_write_keyboard(s, val); + ps2_write_keyboard(s->kbd, val); break; case KBD_CCMD_WRITE_MODE: s->mode = val; + /* ??? */ kbd_update_irq(s); break; case KBD_CCMD_WRITE_OBUF: @@ -618,7 +313,7 @@ void kbd_write_data(void *opaque, uint32 } break; case KBD_CCMD_WRITE_MOUSE: - kbd_write_mouse(s, val); + ps2_write_mouse(s->mouse, val); break; default: break; @@ -629,16 +324,9 @@ void kbd_write_data(void *opaque, uint32 static void kbd_reset(void *opaque) { KBDState *s = opaque; - KBDQueue *q; - s->kbd_write_cmd = -1; - s->mouse_write_cmd = -1; s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT; s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED; - q = &s->queue; - q->rptr = 0; - q->wptr = 0; - q->count = 0; } static void kbd_save(QEMUFile* f, void* opaque) @@ -648,6 +336,7 @@ static void kbd_save(QEMUFile* f, void* qemu_put_8s(f, &s->write_cmd); qemu_put_8s(f, &s->status); qemu_put_8s(f, &s->mode); + /* qemu_put_be32s(f, &s->kbd_write_cmd); qemu_put_be32s(f, &s->scan_enabled); qemu_put_be32s(f, &s->mouse_write_cmd); @@ -661,30 +350,18 @@ static void kbd_save(QEMUFile* f, void* qemu_put_be32s(f, &s->mouse_dy); qemu_put_be32s(f, &s->mouse_dz); qemu_put_8s(f, &s->mouse_buttons); + */ } static int kbd_load(QEMUFile* f, void* opaque, int version_id) { KBDState *s = (KBDState*)opaque; - if (version_id != 1) + if (version_id != 2) return -EINVAL; qemu_get_8s(f, &s->write_cmd); qemu_get_8s(f, &s->status); qemu_get_8s(f, &s->mode); - qemu_get_be32s(f, &s->kbd_write_cmd); - qemu_get_be32s(f, &s->scan_enabled); - qemu_get_be32s(f, &s->mouse_write_cmd); - qemu_get_8s(f, &s->mouse_status); - qemu_get_8s(f, &s->mouse_resolution); - qemu_get_8s(f, &s->mouse_sample_rate); - qemu_get_8s(f, &s->mouse_wrap); - qemu_get_8s(f, &s->mouse_type); - qemu_get_8s(f, &s->mouse_detect_state); - qemu_get_be32s(f, &s->mouse_dx); - qemu_get_be32s(f, &s->mouse_dy); - qemu_get_be32s(f, &s->mouse_dz); - qemu_get_8s(f, &s->mouse_buttons); return 0; } @@ -693,13 +370,13 @@ void kbd_init(void) KBDState *s = &kbd_state; kbd_reset(s); - register_savevm("pckbd", 0, 1, kbd_save, kbd_load, s); + register_savevm("pckbd", 0, 2, kbd_save, kbd_load, s); register_ioport_read(0x60, 1, 1, kbd_read_data, s); register_ioport_write(0x60, 1, 1, kbd_write_data, s); register_ioport_read(0x64, 1, 1, kbd_read_status, s); register_ioport_write(0x64, 1, 1, kbd_write_command, s); - qemu_add_kbd_event_handler(pc_kbd_put_keycode, s); - qemu_add_mouse_event_handler(pc_kbd_mouse_event, s); + s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s); + s->mouse = ps2_mouse_init(kbd_update_aux_irq, s); qemu_register_reset(kbd_reset, s); } Index: hw/ps2.c =================================================================== RCS file: hw/ps2.c diff -N hw/ps2.c --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ hw/ps2.c 20 Nov 2005 15:13:55 -0000 @@ -0,0 +1,512 @@ +/* + * QEMU PS/2 keyboard/mouse emulation + * + * Copyright (c) 2003 Fabrice Bellard + * + * 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. + */ +#include "vl.h" + +/* debug PC keyboard */ +//#define DEBUG_KBD + +/* debug PC keyboard : only mouse */ +//#define DEBUG_MOUSE + +/* Keyboard Commands */ +#define KBD_CMD_SET_LEDS 0xED /* Set keyboard leds */ +#define KBD_CMD_ECHO 0xEE +#define KBD_CMD_GET_ID 0xF2 /* get keyboard ID */ +#define KBD_CMD_SET_RATE 0xF3 /* Set typematic rate */ +#define KBD_CMD_ENABLE 0xF4 /* Enable scanning */ +#define KBD_CMD_RESET_DISABLE 0xF5 /* reset and disable scanning */ +#define KBD_CMD_RESET_ENABLE 0xF6 /* reset and enable scanning */ +#define KBD_CMD_RESET 0xFF /* Reset */ + +/* Keyboard Replies */ +#define KBD_REPLY_POR 0xAA /* Power on reset */ +#define KBD_REPLY_ACK 0xFA /* Command ACK */ +#define KBD_REPLY_RESEND 0xFE /* Command NACK, send the cmd again */ + +/* Mouse Commands */ +#define AUX_SET_SCALE11 0xE6 /* Set 1:1 scaling */ +#define AUX_SET_SCALE21 0xE7 /* Set 2:1 scaling */ +#define AUX_SET_RES 0xE8 /* Set resolution */ +#define AUX_GET_SCALE 0xE9 /* Get scaling factor */ +#define AUX_SET_STREAM 0xEA /* Set stream mode */ +#define AUX_POLL 0xEB /* Poll */ +#define AUX_RESET_WRAP 0xEC /* Reset wrap mode */ +#define AUX_SET_WRAP 0xEE /* Set wrap mode */ +#define AUX_SET_REMOTE 0xF0 /* Set remote mode */ +#define AUX_GET_TYPE 0xF2 /* Get type */ +#define AUX_SET_SAMPLE 0xF3 /* Set sample rate */ +#define AUX_ENABLE_DEV 0xF4 /* Enable aux device */ +#define AUX_DISABLE_DEV 0xF5 /* Disable aux device */ +#define AUX_SET_DEFAULT 0xF6 +#define AUX_RESET 0xFF /* Reset aux device */ +#define AUX_ACK 0xFA /* Command byte ACK. */ + +#define MOUSE_STATUS_REMOTE 0x40 +#define MOUSE_STATUS_ENABLED 0x20 +#define MOUSE_STATUS_SCALE21 0x10 + +#define PS2_QUEUE_SIZE 256 + +typedef struct { + uint8_t data[PS2_QUEUE_SIZE]; + int rptr, wptr, count; +} PS2Queue; + +typedef struct { + PS2Queue queue; + int32_t write_cmd; + void (*update_irq)(void *, int); + void *update_arg; +} PS2State; + +typedef struct { + PS2State common; + int scan_enabled; +} PS2KbdState; + +typedef struct { + PS2State common; + uint8_t mouse_status; + uint8_t mouse_resolution; + uint8_t mouse_sample_rate; + uint8_t mouse_wrap; + uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */ + uint8_t mouse_detect_state; + int mouse_dx; /* current values, needed for 'poll' mode */ + int mouse_dy; + int mouse_dz; + uint8_t mouse_buttons; +} PS2MouseState; + +void ps2_queue(void *opaque, int b) +{ + PS2State *s = (PS2State *)opaque; + PS2Queue *q = &s->queue; + + if (q->count >= PS2_QUEUE_SIZE) + return; + q->data[q->wptr] = b; + if (++q->wptr == PS2_QUEUE_SIZE) + q->wptr = 0; + q->count++; + s->update_irq(s->update_arg, 1); +} + +static void ps2_put_keycode(void *opaque, int keycode) +{ + PS2MouseState *s = opaque; + ps2_queue(&s->common, keycode); +} + +uint32_t ps2_read_data(void *opaque) +{ + PS2State *s = (PS2State *)opaque; + PS2Queue *q; + int val, index; + + q = &s->queue; + if (q->count == 0) { + /* NOTE: if no data left, we return the last keyboard one + (needed for EMM386) */ + /* XXX: need a timer to do things correctly */ + index = q->rptr - 1; + if (index < 0) + index = PS2_QUEUE_SIZE - 1; + val = q->data[index]; + } else { + val = q->data[q->rptr]; + if (++q->rptr == PS2_QUEUE_SIZE) + q->rptr = 0; + q->count--; + /* reading deasserts IRQ */ + s->update_irq(s->update_arg, 0); + /* reassert IRQs if data left */ + s->update_irq(s->update_arg, q->count != 0); + } + return val; +} + +static void ps2_reset_keyboard(PS2KbdState *s) +{ + s->scan_enabled = 1; +} + +void ps2_write_keyboard(void *opaque, int val) +{ + PS2KbdState *s = (PS2KbdState *)opaque; + + switch(s->common.write_cmd) { + default: + case -1: + switch(val) { + case 0x00: + ps2_queue(&s->common, KBD_REPLY_ACK); + break; + case 0x05: + ps2_queue(&s->common, KBD_REPLY_RESEND); + break; + case KBD_CMD_GET_ID: + ps2_queue(&s->common, KBD_REPLY_ACK); + ps2_queue(&s->common, 0xab); + ps2_queue(&s->common, 0x83); + break; + case KBD_CMD_ECHO: + ps2_queue(&s->common, KBD_CMD_ECHO); + break; + case KBD_CMD_ENABLE: + s->scan_enabled = 1; + ps2_queue(&s->common, KBD_REPLY_ACK); + break; + case KBD_CMD_SET_LEDS: + case KBD_CMD_SET_RATE: + s->common.write_cmd = val; + ps2_queue(&s->common, KBD_REPLY_ACK); + break; + case KBD_CMD_RESET_DISABLE: + ps2_reset_keyboard(s); + s->scan_enabled = 0; + ps2_queue(&s->common, KBD_REPLY_ACK); + break; + case KBD_CMD_RESET_ENABLE: + ps2_reset_keyboard(s); + s->scan_enabled = 1; + ps2_queue(&s->common, KBD_REPLY_ACK); + break; + case KBD_CMD_RESET: + ps2_reset_keyboard(s); + ps2_queue(&s->common, KBD_REPLY_ACK); + ps2_queue(&s->common, KBD_REPLY_POR); + break; + default: + ps2_queue(&s->common, KBD_REPLY_ACK); + break; + } + break; + case KBD_CMD_SET_LEDS: + ps2_queue(&s->common, KBD_REPLY_ACK); + s->common.write_cmd = -1; + break; + case KBD_CMD_SET_RATE: + ps2_queue(&s->common, KBD_REPLY_ACK); + s->common.write_cmd = -1; + break; + } +} + +static void ps2_mouse_send_packet(PS2MouseState *s) +{ + unsigned int b; + int dx1, dy1, dz1; + + dx1 = s->mouse_dx; + dy1 = s->mouse_dy; + dz1 = s->mouse_dz; + /* XXX: increase range to 8 bits ? */ + if (dx1 > 127) + dx1 = 127; + else if (dx1 < -127) + dx1 = -127; + if (dy1 > 127) + dy1 = 127; + else if (dy1 < -127) + dy1 = -127; + b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07); + ps2_queue(&s->common, b); + ps2_queue(&s->common, dx1 & 0xff); + ps2_queue(&s->common, dy1 & 0xff); + /* extra byte for IMPS/2 or IMEX */ + switch(s->mouse_type) { + default: + break; + case 3: + if (dz1 > 127) + dz1 = 127; + else if (dz1 < -127) + dz1 = -127; + ps2_queue(&s->common, dz1 & 0xff); + break; + case 4: + if (dz1 > 7) + dz1 = 7; + else if (dz1 < -7) + dz1 = -7; + b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1); + ps2_queue(&s->common, b); + break; + } + + /* update deltas */ + s->mouse_dx -= dx1; + s->mouse_dy -= dy1; + s->mouse_dz -= dz1; +} + +static void ps2_mouse_event(void *opaque, + int dx, int dy, int dz, int buttons_state) +{ + PS2MouseState *s = opaque; + + /* check if deltas are recorded when disabled */ + if (!(s->mouse_status & MOUSE_STATUS_ENABLED)) + return; + + s->mouse_dx += dx; + s->mouse_dy -= dy; + s->mouse_dz += dz; + /* XXX: SDL sometimes generates nul events: we delete them */ + if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 && + s->mouse_buttons == buttons_state) + return; + s->mouse_buttons = buttons_state; + + if (!(s->mouse_status & MOUSE_STATUS_REMOTE) && + (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) { + for(;;) { + /* if not remote, send event. Multiple events are sent if + too big deltas */ + ps2_mouse_send_packet(s); + if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0) + break; + } + } +} + +void ps2_write_mouse(void *opaque, int val) +{ + PS2MouseState *s = (PS2MouseState *)opaque; +#ifdef DEBUG_MOUSE + printf("kbd: write mouse 0x%02x\n", val); +#endif + switch(s->common.write_cmd) { + default: + case -1: + /* mouse command */ + if (s->mouse_wrap) { + if (val == AUX_RESET_WRAP) { + s->mouse_wrap = 0; + ps2_queue(&s->common, AUX_ACK); + return; + } else if (val != AUX_RESET) { + ps2_queue(&s->common, val); + return; + } + } + switch(val) { + case AUX_SET_SCALE11: + s->mouse_status &= ~MOUSE_STATUS_SCALE21; + ps2_queue(&s->common, AUX_ACK); + break; + case AUX_SET_SCALE21: + s->mouse_status |= MOUSE_STATUS_SCALE21; + ps2_queue(&s->common, AUX_ACK); + break; + case AUX_SET_STREAM: + s->mouse_status &= ~MOUSE_STATUS_REMOTE; + ps2_queue(&s->common, AUX_ACK); + break; + case AUX_SET_WRAP: + s->mouse_wrap = 1; + ps2_queue(&s->common, AUX_ACK); + break; + case AUX_SET_REMOTE: + s->mouse_status |= MOUSE_STATUS_REMOTE; + ps2_queue(&s->common, AUX_ACK); + break; + case AUX_GET_TYPE: + ps2_queue(&s->common, AUX_ACK); + ps2_queue(&s->common, s->mouse_type); + break; + case AUX_SET_RES: + case AUX_SET_SAMPLE: + s->common.write_cmd = val; + ps2_queue(&s->common, AUX_ACK); + break; + case AUX_GET_SCALE: + ps2_queue(&s->common, AUX_ACK); + ps2_queue(&s->common, s->mouse_status); + ps2_queue(&s->common, s->mouse_resolution); + ps2_queue(&s->common, s->mouse_sample_rate); + break; + case AUX_POLL: + ps2_queue(&s->common, AUX_ACK); + ps2_mouse_send_packet(s); + break; + case AUX_ENABLE_DEV: + s->mouse_status |= MOUSE_STATUS_ENABLED; + ps2_queue(&s->common, AUX_ACK); + break; + case AUX_DISABLE_DEV: + s->mouse_status &= ~MOUSE_STATUS_ENABLED; + ps2_queue(&s->common, AUX_ACK); + break; + case AUX_SET_DEFAULT: + s->mouse_sample_rate = 100; + s->mouse_resolution = 2; + s->mouse_status = 0; + ps2_queue(&s->common, AUX_ACK); + break; + case AUX_RESET: + s->mouse_sample_rate = 100; + s->mouse_resolution = 2; + s->mouse_status = 0; + s->mouse_type = 0; + ps2_queue(&s->common, AUX_ACK); + ps2_queue(&s->common, 0xaa); + ps2_queue(&s->common, s->mouse_type); + break; + default: + break; + } + break; + case AUX_SET_SAMPLE: + s->mouse_sample_rate = val; + /* detect IMPS/2 or IMEX */ + switch(s->mouse_detect_state) { + default: + case 0: + if (val == 200) + s->mouse_detect_state = 1; + break; + case 1: + if (val == 100) + s->mouse_detect_state = 2; + else if (val == 200) + s->mouse_detect_state = 3; + else + s->mouse_detect_state = 0; + break; + case 2: + if (val == 80) + s->mouse_type = 3; /* IMPS/2 */ + s->mouse_detect_state = 0; + break; + case 3: + if (val == 80) + s->mouse_type = 4; /* IMEX */ + s->mouse_detect_state = 0; + break; + } + ps2_queue(&s->common, AUX_ACK); + s->common.write_cmd = -1; + break; + case AUX_SET_RES: + s->mouse_resolution = val; + ps2_queue(&s->common, AUX_ACK); + s->common.write_cmd = -1; + break; + } +} + +static void ps2_reset(void *opaque) +{ + PS2State *s = (PS2State *)opaque; + PS2Queue *q; + s->write_cmd = -1; + q = &s->queue; + q->rptr = 0; + q->wptr = 0; + q->count = 0; +} + +static void ps2_kbd_save(QEMUFile* f, void* opaque) +{ + PS2KbdState *s = (PS2KbdState*)opaque; + + qemu_put_be32s(f, &s->common.write_cmd); + qemu_put_be32s(f, &s->scan_enabled); +} + +static void ps2_mouse_save(QEMUFile* f, void* opaque) +{ + PS2MouseState *s = (PS2MouseState*)opaque; + + qemu_put_be32s(f, &s->common.write_cmd); + qemu_put_8s(f, &s->mouse_status); + qemu_put_8s(f, &s->mouse_resolution); + qemu_put_8s(f, &s->mouse_sample_rate); + qemu_put_8s(f, &s->mouse_wrap); + qemu_put_8s(f, &s->mouse_type); + qemu_put_8s(f, &s->mouse_detect_state); + qemu_put_be32s(f, &s->mouse_dx); + qemu_put_be32s(f, &s->mouse_dy); + qemu_put_be32s(f, &s->mouse_dz); + qemu_put_8s(f, &s->mouse_buttons); +} + +static int ps2_kbd_load(QEMUFile* f, void* opaque, int version_id) +{ + PS2KbdState *s = (PS2KbdState*)opaque; + + if (version_id != 1) + return -EINVAL; + qemu_get_be32s(f, &s->common.write_cmd); + qemu_get_be32s(f, &s->scan_enabled); + return 0; +} + +static int ps2_mouse_load(QEMUFile* f, void* opaque, int version_id) +{ + PS2MouseState *s = (PS2MouseState*)opaque; + + if (version_id != 1) + return -EINVAL; + qemu_get_be32s(f, &s->common.write_cmd); + qemu_get_8s(f, &s->mouse_status); + qemu_get_8s(f, &s->mouse_resolution); + qemu_get_8s(f, &s->mouse_sample_rate); + qemu_get_8s(f, &s->mouse_wrap); + qemu_get_8s(f, &s->mouse_type); + qemu_get_8s(f, &s->mouse_detect_state); + qemu_get_be32s(f, &s->mouse_dx); + qemu_get_be32s(f, &s->mouse_dy); + qemu_get_be32s(f, &s->mouse_dz); + qemu_get_8s(f, &s->mouse_buttons); + return 0; +} + +void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg) +{ + PS2KbdState *s = (PS2KbdState *)qemu_mallocz(sizeof(PS2KbdState)); + + s->common.update_irq = update_irq; + s->common.update_arg = update_arg; + ps2_reset(&s->common); + register_savevm("ps2kbd", 0, 1, ps2_kbd_save, ps2_kbd_load, s); + qemu_add_kbd_event_handler(ps2_put_keycode, s); + qemu_register_reset(ps2_reset, &s->common); + return s; +} + +void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg) +{ + PS2MouseState *s = (PS2MouseState *)qemu_mallocz(sizeof(PS2MouseState)); + + s->common.update_irq = update_irq; + s->common.update_arg = update_arg; + ps2_reset(&s->common); + register_savevm("ps2mouse", 0, 1, ps2_mouse_save, ps2_mouse_load, s); + qemu_add_mouse_event_handler(ps2_mouse_event, s); + qemu_register_reset(ps2_reset, &s->common); + return s; +} --Boundary-00=_0LogDPZsMmt0csh--