[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Qemu-devel] [patch] Split PS2 emulation from PC keyboard controller
From: |
Paul Brook |
Subject: |
[Qemu-devel] [patch] Split PS2 emulation from PC keyboard controller |
Date: |
Sun, 6 Nov 2005 16:15:56 +0000 |
User-agent: |
KMail/1.8.2 |
The attached patch splits the PS/2 device emulation from the PC keyboard
controller emulation. The Arm board I'm working on uses PS/2 keyboard+mouse
with a custom host controller.
Paul
Index: vl.h
===================================================================
RCS file: /cvsroot/qemu/qemu/vl.h,v
retrieving revision 1.83
diff -u -p -r1.83 vl.h
--- vl.h 30 Oct 2005 18:58:21 -0000 1.83
+++ vl.h 6 Nov 2005 15:53:43 -0000
@@ -859,6 +859,14 @@ void adb_mouse_init(ADBBusState *bus);
extern ADBBusState adb_bus;
int cuda_init(SetIRQFunc *set_irq, void *irq_opaque, int irq);
+/* ps2.c */
+typedef struct PS2State PS2State;
+PS2State *ps2_init(void (*update_irq)(void *, int, int), void *update_arg);
+void ps2_write_mouse(PS2State *s, int val);
+void ps2_write_keyboard(PS2State *s, int val);
+uint32_t ps2_read_data(PS2State *s);
+void ps2_queue(PS2State *s, int b, int aux);
+
#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 6 Nov 2005 15:53:43 -0000
@@ -110,32 +110,13 @@
#define KBD_QUEUE_SIZE 256
-typedef struct {
- uint8_t aux[KBD_QUEUE_SIZE];
- uint8_t data[KBD_QUEUE_SIZE];
- int rptr, wptr, count;
-} KBDQueue;
-
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;
+ int pending;
+ int pending_aux;
+ PS2State *ps2;
} KBDState;
KBDState kbd_state;
@@ -143,17 +124,17 @@ KBDState kbd_state;
/* update irq and KBD_STAT_[MOUSE_]OBF */
/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
incorrect, but it avoids having to simulate exact delays */
-static void kbd_update_irq(KBDState *s)
+static void kbd_update_irq(void *opaque, int aux, int level)
{
- KBDQueue *q = &s->queue;
+ KBDState *s = (KBDState *)opaque;
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 (level) {
s->status |= KBD_STAT_OBF;
- if (q->aux[q->rptr]) {
+ if (aux) {
s->status |= KBD_STAT_MOUSE_OBF;
if (s->mode & KBD_MODE_MOUSE_INT)
irq12_level = 1;
@@ -163,38 +144,12 @@ static void kbd_update_irq(KBDState *s)
irq1_level = 1;
}
}
+ s->pending = level;
+ s->pending_aux = aux;
pic_set_irq(1, irq1_level);
pic_set_irq(12, irq12_level);
}
-static void kbd_queue(KBDState *s, int b, int aux)
-{
- KBDQueue *q = &s->queue;
-
-#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD)
- if (aux)
- printf("mouse event: 0x%02x\n", b);
-#ifdef DEBUG_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++;
- kbd_update_irq(s);
-}
-
-static void pc_kbd_put_keycode(void *opaque, int keycode)
-{
- KBDState *s = opaque;
- kbd_queue(s, keycode, 0);
-}
-
static uint32_t kbd_read_status(void *opaque, uint32_t addr)
{
KBDState *s = opaque;
@@ -206,6 +161,11 @@ static uint32_t kbd_read_status(void *op
return val;
}
+static void kbd_queue(KBDState *s, int b, int aux)
+{
+ ps2_queue(s->ps2, b, aux);
+}
+
static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
{
KBDState *s = opaque;
@@ -242,11 +202,11 @@ static void kbd_write_command(void *opaq
break;
case KBD_CCMD_KBD_DISABLE:
s->mode |= KBD_MODE_DISABLE_KBD;
- kbd_update_irq(s);
+ kbd_update_irq(s, s->pending_aux, s->pending);
break;
case KBD_CCMD_KBD_ENABLE:
s->mode &= ~KBD_MODE_DISABLE_KBD;
- kbd_update_irq(s);
+ kbd_update_irq(s, s->pending_aux, s->pending);
break;
case KBD_CCMD_READ_INPORT:
kbd_queue(s, 0x00, 0);
@@ -287,304 +247,8 @@ 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;
-}
-
-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->ps2);
}
void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
@@ -597,11 +261,12 @@ void kbd_write_data(void *opaque, uint32
switch(s->write_cmd) {
case 0:
- kbd_write_keyboard(s, val);
+ ps2_write_keyboard(s->ps2, val);
break;
case KBD_CCMD_WRITE_MODE:
s->mode = val;
- kbd_update_irq(s);
+ /* ??? */
+ kbd_update_irq(s, s->pending_aux, s->pending);
break;
case KBD_CCMD_WRITE_OBUF:
kbd_queue(s, val, 0);
@@ -618,7 +283,7 @@ void kbd_write_data(void *opaque, uint32
}
break;
case KBD_CCMD_WRITE_MOUSE:
- kbd_write_mouse(s, val);
+ ps2_write_mouse(s->ps2, val);
break;
default:
break;
@@ -629,16 +294,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 +306,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,17 +320,19 @@ 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);
@@ -685,6 +346,7 @@ static int kbd_load(QEMUFile* f, void* o
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 +355,12 @@ 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->ps2 = ps2_init(kbd_update_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 6 Nov 2005 15:53:43 -0000
@@ -0,0 +1,493 @@
+/*
+ * 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 KBD_QUEUE_SIZE 256
+
+typedef struct {
+ uint8_t aux[KBD_QUEUE_SIZE];
+ uint8_t data[KBD_QUEUE_SIZE];
+ int rptr, wptr, count;
+} PS2Queue;
+
+struct PS2State {
+ PS2Queue queue;
+ /* 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;
+ void (*update_irq)(void *, int, int);
+ void *update_arg;
+};
+
+void ps2_queue(PS2State *s, int b, int aux)
+{
+ PS2Queue *q = &s->queue;
+
+#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD)
+ if (aux)
+ printf("mouse event: 0x%02x\n", b);
+#ifdef DEBUG_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->update_irq(s->update_arg, q->aux[q->rptr], 1);
+}
+
+static void ps2_put_keycode(void *opaque, int keycode)
+{
+ PS2State *s = opaque;
+ ps2_queue(s, keycode, 0);
+}
+
+uint32_t ps2_read_data(PS2State *s)
+{
+ PS2Queue *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 */
+ s->update_irq(s->update_arg, aux, 0);
+ if (aux)
+ pic_set_irq(12, 0);
+ else
+ pic_set_irq(1, 0);
+ }
+ /* reassert IRQs if data left */
+ s->update_irq(s->update_arg, q->aux[q->rptr], q->count != 0);
+#ifdef DEBUG_KBD
+ printf("kbd: read data=0x%02x\n", val);
+#endif
+ return val;
+}
+
+static void ps2_reset_keyboard(PS2State *s)
+{
+ s->scan_enabled = 1;
+}
+
+void ps2_write_keyboard(PS2State *s, int val)
+{
+ switch(s->kbd_write_cmd) {
+ default:
+ case -1:
+ switch(val) {
+ case 0x00:
+ ps2_queue(s, KBD_REPLY_ACK, 0);
+ break;
+ case 0x05:
+ ps2_queue(s, KBD_REPLY_RESEND, 0);
+ break;
+ case KBD_CMD_GET_ID:
+ ps2_queue(s, KBD_REPLY_ACK, 0);
+ ps2_queue(s, 0xab, 0);
+ ps2_queue(s, 0x83, 0);
+ break;
+ case KBD_CMD_ECHO:
+ ps2_queue(s, KBD_CMD_ECHO, 0);
+ break;
+ case KBD_CMD_ENABLE:
+ s->scan_enabled = 1;
+ ps2_queue(s, KBD_REPLY_ACK, 0);
+ break;
+ case KBD_CMD_SET_LEDS:
+ case KBD_CMD_SET_RATE:
+ s->kbd_write_cmd = val;
+ ps2_queue(s, KBD_REPLY_ACK, 0);
+ break;
+ case KBD_CMD_RESET_DISABLE:
+ ps2_reset_keyboard(s);
+ s->scan_enabled = 0;
+ ps2_queue(s, KBD_REPLY_ACK, 0);
+ break;
+ case KBD_CMD_RESET_ENABLE:
+ ps2_reset_keyboard(s);
+ s->scan_enabled = 1;
+ ps2_queue(s, KBD_REPLY_ACK, 0);
+ break;
+ case KBD_CMD_RESET:
+ ps2_reset_keyboard(s);
+ ps2_queue(s, KBD_REPLY_ACK, 0);
+ ps2_queue(s, KBD_REPLY_POR, 0);
+ break;
+ default:
+ ps2_queue(s, KBD_REPLY_ACK, 0);
+ break;
+ }
+ break;
+ case KBD_CMD_SET_LEDS:
+ ps2_queue(s, KBD_REPLY_ACK, 0);
+ s->kbd_write_cmd = -1;
+ break;
+ case KBD_CMD_SET_RATE:
+ ps2_queue(s, KBD_REPLY_ACK, 0);
+ s->kbd_write_cmd = -1;
+ break;
+ }
+}
+
+static void ps2_mouse_send_packet(PS2State *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, b, 1);
+ ps2_queue(s, dx1 & 0xff, 1);
+ ps2_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;
+ ps2_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);
+ ps2_queue(s, b, 1);
+ 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)
+{
+ PS2State *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 */
+ ps2_mouse_send_packet(s);
+ if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
+ break;
+ }
+ }
+}
+
+void ps2_write_mouse(PS2State *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;
+ ps2_queue(s, AUX_ACK, 1);
+ return;
+ } else if (val != AUX_RESET) {
+ ps2_queue(s, val, 1);
+ return;
+ }
+ }
+ switch(val) {
+ case AUX_SET_SCALE11:
+ s->mouse_status &= ~MOUSE_STATUS_SCALE21;
+ ps2_queue(s, AUX_ACK, 1);
+ break;
+ case AUX_SET_SCALE21:
+ s->mouse_status |= MOUSE_STATUS_SCALE21;
+ ps2_queue(s, AUX_ACK, 1);
+ break;
+ case AUX_SET_STREAM:
+ s->mouse_status &= ~MOUSE_STATUS_REMOTE;
+ ps2_queue(s, AUX_ACK, 1);
+ break;
+ case AUX_SET_WRAP:
+ s->mouse_wrap = 1;
+ ps2_queue(s, AUX_ACK, 1);
+ break;
+ case AUX_SET_REMOTE:
+ s->mouse_status |= MOUSE_STATUS_REMOTE;
+ ps2_queue(s, AUX_ACK, 1);
+ break;
+ case AUX_GET_TYPE:
+ ps2_queue(s, AUX_ACK, 1);
+ ps2_queue(s, s->mouse_type, 1);
+ break;
+ case AUX_SET_RES:
+ case AUX_SET_SAMPLE:
+ s->mouse_write_cmd = val;
+ ps2_queue(s, AUX_ACK, 1);
+ break;
+ case AUX_GET_SCALE:
+ ps2_queue(s, AUX_ACK, 1);
+ ps2_queue(s, s->mouse_status, 1);
+ ps2_queue(s, s->mouse_resolution, 1);
+ ps2_queue(s, s->mouse_sample_rate, 1);
+ break;
+ case AUX_POLL:
+ ps2_queue(s, AUX_ACK, 1);
+ ps2_mouse_send_packet(s);
+ break;
+ case AUX_ENABLE_DEV:
+ s->mouse_status |= MOUSE_STATUS_ENABLED;
+ ps2_queue(s, AUX_ACK, 1);
+ break;
+ case AUX_DISABLE_DEV:
+ s->mouse_status &= ~MOUSE_STATUS_ENABLED;
+ ps2_queue(s, AUX_ACK, 1);
+ break;
+ case AUX_SET_DEFAULT:
+ s->mouse_sample_rate = 100;
+ s->mouse_resolution = 2;
+ s->mouse_status = 0;
+ ps2_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;
+ ps2_queue(s, AUX_ACK, 1);
+ ps2_queue(s, 0xaa, 1);
+ ps2_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;
+ }
+ ps2_queue(s, AUX_ACK, 1);
+ s->mouse_write_cmd = -1;
+ break;
+ case AUX_SET_RES:
+ s->mouse_resolution = val;
+ ps2_queue(s, AUX_ACK, 1);
+ s->mouse_write_cmd = -1;
+ break;
+ }
+}
+
+static void ps2_reset(void *opaque)
+{
+ PS2State *s = (PS2State *)opaque;
+ PS2Queue *q;
+ s->kbd_write_cmd = -1;
+ s->mouse_write_cmd = -1;
+ q = &s->queue;
+ q->rptr = 0;
+ q->wptr = 0;
+ q->count = 0;
+}
+
+static void ps2_save(QEMUFile* f, void* opaque)
+{
+ PS2State *s = (PS2State*)opaque;
+
+ qemu_put_be32s(f, &s->kbd_write_cmd);
+ qemu_put_be32s(f, &s->scan_enabled);
+ qemu_put_be32s(f, &s->mouse_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_load(QEMUFile* f, void* opaque, int version_id)
+{
+ PS2State *s = (PS2State*)opaque;
+
+ if (version_id != 1)
+ return -EINVAL;
+ 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;
+}
+PS2State *ps2_init(void (*update_irq)(void *, int, int), void *update_arg)
+{
+ PS2State *s = (PS2State *)qemu_mallocz(sizeof(PS2State));
+
+ s->update_irq = update_irq;
+ s->update_arg = update_arg;
+ ps2_reset(s);
+ register_savevm("ps2", 0, 1, ps2_save, ps2_load, s);
+ qemu_add_kbd_event_handler(ps2_put_keycode, s);
+ qemu_add_mouse_event_handler(ps2_mouse_event, s);
+ qemu_register_reset(ps2_reset, s);
+ return s;
+}
Index: hw/pckbd.c
===================================================================
--- Makefile.target (revision 1795)
+++ Makefile.target (local)
@@ -240,6 +240,9 @@
ifeq ($(findstring arm, $(TARGET_ARCH) $(ARCH)),arm)
LIBOBJS+=arm-dis.o
endif
+ifeq ($(findstring m68k, $(TARGET_ARCH) $(ARCH)),m68k)
+LIBOBJS+=m68k-dis.o
+endif
ifeq ($(ARCH),ia64)
OBJS += ia64-syscall.o
@@ -292,25 +295,25 @@
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
VL_OBJS+= usb.o usb-uhci.o usb-linux.o usb-hid.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
endif
ifeq ($(TARGET_ARCH), mips)
VL_OBJS+= mips_r4k.o dma.o vga.o serial.o ne2000.o i8254.o i8259.o
-#VL_OBJS+= #ide.o pckbd.o fdc.o m48t59.o
+#VL_OBJS+= #ide.o pckbd.o ps2.o fdc.o m48t59.o
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
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Qemu-devel] [patch] Split PS2 emulation from PC keyboard controller,
Paul Brook <=