diff options
Diffstat (limited to 'hw/pckbd.c')
-rw-r--r-- | hw/pckbd.c | 418 |
1 files changed, 40 insertions, 378 deletions
diff --git a/hw/pckbd.c b/hw/pckbd.c index 1be1560eff..61f8a63a82 100644 --- a/hw/pckbd.c +++ b/hw/pckbd.c @@ -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 *opaque, uint32_t addr) 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 *opaque, uint32_t addr, uint32_t val) 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; - } - } -} + if (s->pending == KBD_PENDING_AUX) + return ps2_read_data(s->mouse); -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_t addr, uint32_t val) 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_t addr, uint32_t val) } 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_t addr, uint32_t val) 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,43 +336,17 @@ static void kbd_save(QEMUFile* f, void* 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) + 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 +355,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); } |