#include "hw.h"
#include "ps2.h"
#include "console.h"
+#include "sysemu.h"
/* debug PC keyboard */
//#define DEBUG_KBD
typedef struct {
PS2State common;
int scan_enabled;
- /* Qemu uses translated PC scancodes internally. To avoid multiple
+ /* QEMU uses translated PC scancodes internally. To avoid multiple
conversions we do the translation (if any) in the PS/2 emulation
not the keyboard controller. */
int translate;
int scancode_set; /* 1=XT, 2=AT, 3=PS/2 */
+ int ledstate;
} PS2KbdState;
typedef struct {
/* Table to convert from PC scancodes to raw scancodes. */
static const unsigned char ps2_raw_keycode[128] = {
- 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
- 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
- 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
- 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
- 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
- 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
- 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
- 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
+ 0, 118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85, 102, 13,
+ 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
+ 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
+ 50, 49, 58, 65, 73, 74, 89, 124, 17, 41, 88, 5, 6, 4, 12, 3,
+ 11, 2, 10, 1, 9, 119, 126, 108, 117, 125, 123, 107, 115, 116, 121, 105,
+114, 122, 112, 113, 127, 96, 97, 120, 7, 15, 23, 31, 39, 47, 55, 63,
+ 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87, 111,
+ 19, 25, 57, 81, 83, 92, 95, 98, 99, 100, 101, 103, 104, 106, 109, 110
+};
+static const unsigned char ps2_raw_keycode_set3[128] = {
+ 0, 8, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85, 102, 13,
+ 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 17, 28, 27,
+ 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 92, 26, 34, 33, 42,
+ 50, 49, 58, 65, 73, 74, 89, 126, 25, 41, 20, 7, 15, 23, 31, 39,
+ 47, 2, 63, 71, 79, 118, 95, 108, 117, 125, 132, 107, 115, 116, 124, 105,
+114, 122, 112, 113, 127, 96, 97, 86, 94, 15, 23, 31, 39, 47, 55, 63,
+ 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87, 111,
+ 19, 25, 57, 81, 83, 92, 95, 98, 99, 100, 101, 103, 104, 106, 109, 110
};
void ps2_queue(void *opaque, int b)
{
PS2KbdState *s = opaque;
- /* XXX: add support for scancode sets 1 and 3 */
- if (!s->translate && keycode < 0xe0 && s->scancode_set == 2)
- {
- if (keycode & 0x80)
+ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+ /* XXX: add support for scancode set 1 */
+ if (!s->translate && keycode < 0xe0 && s->scancode_set > 1) {
+ if (keycode & 0x80) {
ps2_queue(&s->common, 0xf0);
- keycode = ps2_raw_keycode[keycode & 0x7f];
+ }
+ if (s->scancode_set == 2) {
+ keycode = ps2_raw_keycode[keycode & 0x7f];
+ } else if (s->scancode_set == 3) {
+ keycode = ps2_raw_keycode_set3[keycode & 0x7f];
+ }
}
ps2_queue(&s->common, keycode);
}
return val;
}
+static void ps2_set_ledstate(PS2KbdState *s, int ledstate)
+{
+ s->ledstate = ledstate;
+ kbd_put_ledstate(ledstate);
+}
+
static void ps2_reset_keyboard(PS2KbdState *s)
{
s->scan_enabled = 1;
s->scancode_set = 2;
+ ps2_set_ledstate(s, 0);
}
void ps2_write_keyboard(void *opaque, int val)
s->common.write_cmd = -1;
break;
case KBD_CMD_SET_LEDS:
+ ps2_set_ledstate(s, val);
ps2_queue(&s->common, KBD_REPLY_ACK);
s->common.write_cmd = -1;
break;
return;
s->mouse_buttons = buttons_state;
+ if (buttons_state) {
+ qemu_system_wakeup_request(QEMU_WAKEUP_REASON_OTHER);
+ }
+
if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
(s->common.queue.count < (PS2_QUEUE_SIZE - 16))) {
for(;;) {
}
}
-static void ps2_reset(void *opaque)
+static void ps2_common_reset(PS2State *s)
{
- PS2State *s = (PS2State *)opaque;
PS2Queue *q;
s->write_cmd = -1;
q = &s->queue;
s->update_irq(s->update_arg, 0);
}
-static void ps2_common_save (QEMUFile *f, PS2State *s)
+static void ps2_kbd_reset(void *opaque)
{
- qemu_put_be32 (f, s->write_cmd);
- qemu_put_be32 (f, s->queue.rptr);
- qemu_put_be32 (f, s->queue.wptr);
- qemu_put_be32 (f, s->queue.count);
- qemu_put_buffer (f, s->queue.data, sizeof (s->queue.data));
+ PS2KbdState *s = (PS2KbdState *) opaque;
+
+ ps2_common_reset(&s->common);
+ s->scan_enabled = 0;
+ s->translate = 0;
+ s->scancode_set = 0;
}
-static void ps2_common_load (QEMUFile *f, PS2State *s)
+static void ps2_mouse_reset(void *opaque)
{
- s->write_cmd=qemu_get_be32 (f);
- s->queue.rptr=qemu_get_be32 (f);
- s->queue.wptr=qemu_get_be32 (f);
- s->queue.count=qemu_get_be32 (f);
- qemu_get_buffer (f, s->queue.data, sizeof (s->queue.data));
+ PS2MouseState *s = (PS2MouseState *) opaque;
+
+ ps2_common_reset(&s->common);
+ s->mouse_status = 0;
+ s->mouse_resolution = 0;
+ s->mouse_sample_rate = 0;
+ s->mouse_wrap = 0;
+ s->mouse_type = 0;
+ s->mouse_detect_state = 0;
+ s->mouse_dx = 0;
+ s->mouse_dy = 0;
+ s->mouse_dz = 0;
+ s->mouse_buttons = 0;
}
-static void ps2_kbd_save(QEMUFile* f, void* opaque)
+static const VMStateDescription vmstate_ps2_common = {
+ .name = "PS2 Common State",
+ .version_id = 3,
+ .minimum_version_id = 2,
+ .minimum_version_id_old = 2,
+ .fields = (VMStateField []) {
+ VMSTATE_INT32(write_cmd, PS2State),
+ VMSTATE_INT32(queue.rptr, PS2State),
+ VMSTATE_INT32(queue.wptr, PS2State),
+ VMSTATE_INT32(queue.count, PS2State),
+ VMSTATE_BUFFER(queue.data, PS2State),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static bool ps2_keyboard_ledstate_needed(void *opaque)
{
- PS2KbdState *s = (PS2KbdState*)opaque;
+ PS2KbdState *s = opaque;
- ps2_common_save (f, &s->common);
- qemu_put_be32(f, s->scan_enabled);
- qemu_put_be32(f, s->translate);
- qemu_put_be32(f, s->scancode_set);
+ return s->ledstate != 0; /* 0 is default state */
}
-static void ps2_mouse_save(QEMUFile* f, void* opaque)
+static int ps2_kbd_ledstate_post_load(void *opaque, int version_id)
{
- PS2MouseState *s = (PS2MouseState*)opaque;
-
- ps2_common_save (f, &s->common);
- 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_be32(f, s->mouse_dx);
- qemu_put_be32(f, s->mouse_dy);
- qemu_put_be32(f, s->mouse_dz);
- qemu_put_8s(f, &s->mouse_buttons);
+ PS2KbdState *s = opaque;
+
+ kbd_put_ledstate(s->ledstate);
+ return 0;
}
-static int ps2_kbd_load(QEMUFile* f, void* opaque, int version_id)
+static const VMStateDescription vmstate_ps2_keyboard_ledstate = {
+ .name = "ps2kbd/ledstate",
+ .version_id = 3,
+ .minimum_version_id = 2,
+ .minimum_version_id_old = 2,
+ .post_load = ps2_kbd_ledstate_post_load,
+ .fields = (VMStateField []) {
+ VMSTATE_INT32(ledstate, PS2KbdState),
+ VMSTATE_END_OF_LIST()
+ }
+};
+
+static int ps2_kbd_post_load(void* opaque, int version_id)
{
PS2KbdState *s = (PS2KbdState*)opaque;
- if (version_id != 2 && version_id != 3)
- return -EINVAL;
-
- ps2_common_load (f, &s->common);
- s->scan_enabled=qemu_get_be32(f);
- s->translate=qemu_get_be32(f);
- if (version_id == 3)
- s->scancode_set=qemu_get_be32(f);
- else
+ if (version_id == 2)
s->scancode_set=2;
return 0;
}
-static int ps2_mouse_load(QEMUFile* f, void* opaque, int version_id)
-{
- PS2MouseState *s = (PS2MouseState*)opaque;
-
- if (version_id != 2)
- return -EINVAL;
-
- ps2_common_load (f, &s->common);
- 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);
- s->mouse_dx=qemu_get_be32(f);
- s->mouse_dy=qemu_get_be32(f);
- s->mouse_dz=qemu_get_be32(f);
- qemu_get_8s(f, &s->mouse_buttons);
- return 0;
-}
+static const VMStateDescription vmstate_ps2_keyboard = {
+ .name = "ps2kbd",
+ .version_id = 3,
+ .minimum_version_id = 2,
+ .minimum_version_id_old = 2,
+ .post_load = ps2_kbd_post_load,
+ .fields = (VMStateField []) {
+ VMSTATE_STRUCT(common, PS2KbdState, 0, vmstate_ps2_common, PS2State),
+ VMSTATE_INT32(scan_enabled, PS2KbdState),
+ VMSTATE_INT32(translate, PS2KbdState),
+ VMSTATE_INT32_V(scancode_set, PS2KbdState,3),
+ VMSTATE_END_OF_LIST()
+ },
+ .subsections = (VMStateSubsection []) {
+ {
+ .vmsd = &vmstate_ps2_keyboard_ledstate,
+ .needed = ps2_keyboard_ledstate_needed,
+ }, {
+ /* empty */
+ }
+ }
+};
+
+static const VMStateDescription vmstate_ps2_mouse = {
+ .name = "ps2mouse",
+ .version_id = 2,
+ .minimum_version_id = 2,
+ .minimum_version_id_old = 2,
+ .fields = (VMStateField []) {
+ VMSTATE_STRUCT(common, PS2MouseState, 0, vmstate_ps2_common, PS2State),
+ VMSTATE_UINT8(mouse_status, PS2MouseState),
+ VMSTATE_UINT8(mouse_resolution, PS2MouseState),
+ VMSTATE_UINT8(mouse_sample_rate, PS2MouseState),
+ VMSTATE_UINT8(mouse_wrap, PS2MouseState),
+ VMSTATE_UINT8(mouse_type, PS2MouseState),
+ VMSTATE_UINT8(mouse_detect_state, PS2MouseState),
+ VMSTATE_INT32(mouse_dx, PS2MouseState),
+ VMSTATE_INT32(mouse_dy, PS2MouseState),
+ VMSTATE_INT32(mouse_dz, PS2MouseState),
+ VMSTATE_UINT8(mouse_buttons, PS2MouseState),
+ VMSTATE_END_OF_LIST()
+ }
+};
void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
{
- PS2KbdState *s = (PS2KbdState *)qemu_mallocz(sizeof(PS2KbdState));
+ PS2KbdState *s = (PS2KbdState *)g_malloc0(sizeof(PS2KbdState));
s->common.update_irq = update_irq;
s->common.update_arg = update_arg;
s->scancode_set = 2;
- ps2_reset(&s->common);
- register_savevm("ps2kbd", 0, 3, ps2_kbd_save, ps2_kbd_load, s);
+ vmstate_register(NULL, 0, &vmstate_ps2_keyboard, s);
qemu_add_kbd_event_handler(ps2_put_keycode, s);
- qemu_register_reset(ps2_reset, &s->common);
+ qemu_register_reset(ps2_kbd_reset, s);
return s;
}
void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
{
- PS2MouseState *s = (PS2MouseState *)qemu_mallocz(sizeof(PS2MouseState));
+ PS2MouseState *s = (PS2MouseState *)g_malloc0(sizeof(PS2MouseState));
s->common.update_irq = update_irq;
s->common.update_arg = update_arg;
- ps2_reset(&s->common);
- register_savevm("ps2mouse", 0, 2, ps2_mouse_save, ps2_mouse_load, s);
+ vmstate_register(NULL, 0, &vmstate_ps2_mouse, s);
qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse");
- qemu_register_reset(ps2_reset, &s->common);
+ qemu_register_reset(ps2_mouse_reset, s);
return s;
}