#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 queues[2];
+ KBDQueue queue;
uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
uint8_t status;
uint8_t mode;
} KBDState;
KBDState kbd_state;
-int reset_requested;
/* 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)
{
+ 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 (s->queues[0].count != 0 ||
- s->queues[1].count != 0) {
+ if (q->count != 0) {
s->status |= KBD_STAT_OBF;
- if (s->queues[1].count != 0) {
+ if (q->aux[q->rptr]) {
s->status |= KBD_STAT_MOUSE_OBF;
if (s->mode & KBD_MODE_MOUSE_INT)
irq12_level = 1;
static void kbd_queue(KBDState *s, int b, int aux)
{
- KBDQueue *q = &s->queues[aux];
+ KBDQueue *q = &s->queue;
#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD)
if (aux)
#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;
kbd_update_irq(s);
}
-void kbd_put_keycode(int keycode)
+static void pc_kbd_put_keycode(void *opaque, int keycode)
{
- KBDState *s = &kbd_state;
+ KBDState *s = opaque;
kbd_queue(s, keycode, 0);
}
break;
#endif
case KBD_CCMD_RESET:
- reset_requested = 1;
- cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
+ qemu_system_reset_request();
break;
case 0xff:
/* ignore that - I don't know what is its use */
{
KBDState *s = opaque;
KBDQueue *q;
- int val, index;
+ int val, index, aux;
- q = &s->queues[0]; /* first check KBD data */
- if (q->count == 0)
- q = &s->queues[1]; /* then check AUX data */
+ 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 */
- q = &s->queues[0];
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 (q == &s->queues[0])
- pic_set_irq(1, 0);
- else
+ if (aux)
pic_set_irq(12, 0);
+ else
+ pic_set_irq(1, 0);
}
/* reassert IRQs if data left */
kbd_update_irq(s);
s->mouse_dz -= dz1;
}
-void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
+static void pc_kbd_mouse_event(void *opaque,
+ int dx, int dy, int dz, int buttons_state)
{
- KBDState *s = &kbd_state;
+ KBDState *s = opaque;
/* check if deltas are recorded when disabled */
if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
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->queues[1].count < (KBD_QUEUE_SIZE - 16))) {
+ (s->queue.count < (KBD_QUEUE_SIZE - 16))) {
for(;;) {
/* if not remote, send event. Multiple events are sent if
too big deltas */
cpu_x86_set_a20(cpu_single_env, (val >> 1) & 1);
#endif
if (!(val & 1)) {
- reset_requested = 1;
- cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
+ qemu_system_reset_request();
}
break;
case KBD_CCMD_WRITE_MOUSE:
s->write_cmd = 0;
}
-void kbd_reset(KBDState *s)
+static void kbd_reset(void *opaque)
{
+ KBDState *s = opaque;
KBDQueue *q;
- int i;
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;
- for(i = 0; i < 2; i++) {
- q = &s->queues[i];
- q->rptr = 0;
- q->wptr = 0;
- q->count = 0;
- }
+ q = &s->queue;
+ q->rptr = 0;
+ q->wptr = 0;
+ q->count = 0;
+}
+
+static void kbd_save(QEMUFile* f, void* opaque)
+{
+ KBDState *s = (KBDState*)opaque;
+
+ 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);
+ 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 kbd_load(QEMUFile* f, void* opaque, int version_id)
+{
+ KBDState *s = (KBDState*)opaque;
+
+ if (version_id != 1)
+ 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;
}
void kbd_init(void)
KBDState *s = &kbd_state;
kbd_reset(s);
+ register_savevm("pckbd", 0, 1, 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);
+ qemu_register_reset(kbd_reset, s);
}