| 110 |
|
|
| 111 |
#define KBD_QUEUE_SIZE 256 |
#define KBD_QUEUE_SIZE 256 |
| 112 |
|
|
| 113 |
typedef struct { |
#define KBD_PENDING_KBD 1 |
| 114 |
uint8_t aux[KBD_QUEUE_SIZE]; |
#define KBD_PENDING_AUX 2 |
|
uint8_t data[KBD_QUEUE_SIZE]; |
|
|
int rptr, wptr, count; |
|
|
} KBDQueue; |
|
| 115 |
|
|
| 116 |
typedef struct KBDState { |
typedef struct KBDState { |
|
KBDQueue queue; |
|
| 117 |
uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ |
uint8_t write_cmd; /* if non zero, write data to port 60 is expected */ |
| 118 |
uint8_t status; |
uint8_t status; |
| 119 |
uint8_t mode; |
uint8_t mode; |
| 120 |
/* keyboard state */ |
/* Bitmask of devices with data available. */ |
| 121 |
int kbd_write_cmd; |
int pending; |
| 122 |
int scan_enabled; |
void *kbd; |
| 123 |
/* mouse state */ |
void *mouse; |
|
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; |
|
| 124 |
} KBDState; |
} KBDState; |
| 125 |
|
|
| 126 |
KBDState kbd_state; |
KBDState kbd_state; |
| 130 |
incorrect, but it avoids having to simulate exact delays */ |
incorrect, but it avoids having to simulate exact delays */ |
| 131 |
static void kbd_update_irq(KBDState *s) |
static void kbd_update_irq(KBDState *s) |
| 132 |
{ |
{ |
|
KBDQueue *q = &s->queue; |
|
| 133 |
int irq12_level, irq1_level; |
int irq12_level, irq1_level; |
| 134 |
|
|
| 135 |
irq1_level = 0; |
irq1_level = 0; |
| 136 |
irq12_level = 0; |
irq12_level = 0; |
| 137 |
s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); |
s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF); |
| 138 |
if (q->count != 0) { |
if (s->pending) { |
| 139 |
s->status |= KBD_STAT_OBF; |
s->status |= KBD_STAT_OBF; |
| 140 |
if (q->aux[q->rptr]) { |
/* kdb data takes priority over aux data. */ |
| 141 |
|
if (s->pending == KBD_PENDING_AUX) { |
| 142 |
s->status |= KBD_STAT_MOUSE_OBF; |
s->status |= KBD_STAT_MOUSE_OBF; |
| 143 |
if (s->mode & KBD_MODE_MOUSE_INT) |
if (s->mode & KBD_MODE_MOUSE_INT) |
| 144 |
irq12_level = 1; |
irq12_level = 1; |
| 152 |
pic_set_irq(12, irq12_level); |
pic_set_irq(12, irq12_level); |
| 153 |
} |
} |
| 154 |
|
|
| 155 |
static void kbd_queue(KBDState *s, int b, int aux) |
static void kbd_update_kbd_irq(void *opaque, int level) |
| 156 |
{ |
{ |
| 157 |
KBDQueue *q = &s->queue; |
KBDState *s = (KBDState *)opaque; |
| 158 |
|
|
| 159 |
#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD) |
if (level) |
| 160 |
if (aux) |
s->pending |= KBD_PENDING_KBD; |
|
printf("mouse event: 0x%02x\n", b); |
|
|
#ifdef DEBUG_KBD |
|
| 161 |
else |
else |
| 162 |
printf("kbd event: 0x%02x\n", b); |
s->pending &= ~KBD_PENDING_KBD; |
|
#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++; |
|
| 163 |
kbd_update_irq(s); |
kbd_update_irq(s); |
| 164 |
} |
} |
| 165 |
|
|
| 166 |
static void pc_kbd_put_keycode(void *opaque, int keycode) |
static void kbd_update_aux_irq(void *opaque, int level) |
| 167 |
{ |
{ |
| 168 |
KBDState *s = opaque; |
KBDState *s = (KBDState *)opaque; |
| 169 |
kbd_queue(s, keycode, 0); |
|
| 170 |
|
if (level) |
| 171 |
|
s->pending |= KBD_PENDING_AUX; |
| 172 |
|
else |
| 173 |
|
s->pending &= ~KBD_PENDING_AUX; |
| 174 |
|
kbd_update_irq(s); |
| 175 |
} |
} |
| 176 |
|
|
| 177 |
static uint32_t kbd_read_status(void *opaque, uint32_t addr) |
static uint32_t kbd_read_status(void *opaque, uint32_t addr) |
| 185 |
return val; |
return val; |
| 186 |
} |
} |
| 187 |
|
|
| 188 |
|
static void kbd_queue(KBDState *s, int b, int aux) |
| 189 |
|
{ |
| 190 |
|
if (aux) |
| 191 |
|
ps2_queue(s->mouse, b); |
| 192 |
|
else |
| 193 |
|
ps2_queue(s->kbd, b); |
| 194 |
|
} |
| 195 |
|
|
| 196 |
static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val) |
static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val) |
| 197 |
{ |
{ |
| 198 |
KBDState *s = opaque; |
KBDState *s = opaque; |
| 274 |
static uint32_t kbd_read_data(void *opaque, uint32_t addr) |
static uint32_t kbd_read_data(void *opaque, uint32_t addr) |
| 275 |
{ |
{ |
| 276 |
KBDState *s = opaque; |
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; |
|
|
} |
|
| 277 |
|
|
| 278 |
static void kbd_reset_keyboard(KBDState *s) |
if (s->pending == KBD_PENDING_AUX) |
| 279 |
{ |
return ps2_read_data(s->mouse); |
|
s->scan_enabled = 1; |
|
|
} |
|
| 280 |
|
|
| 281 |
static void kbd_write_keyboard(KBDState *s, int val) |
return ps2_read_data(s->kbd); |
|
{ |
|
|
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; |
|
|
} |
|
| 282 |
} |
} |
| 283 |
|
|
| 284 |
void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) |
void kbd_write_data(void *opaque, uint32_t addr, uint32_t val) |
| 291 |
|
|
| 292 |
switch(s->write_cmd) { |
switch(s->write_cmd) { |
| 293 |
case 0: |
case 0: |
| 294 |
kbd_write_keyboard(s, val); |
ps2_write_keyboard(s->kbd, val); |
| 295 |
break; |
break; |
| 296 |
case KBD_CCMD_WRITE_MODE: |
case KBD_CCMD_WRITE_MODE: |
| 297 |
s->mode = val; |
s->mode = val; |
| 298 |
|
/* ??? */ |
| 299 |
kbd_update_irq(s); |
kbd_update_irq(s); |
| 300 |
break; |
break; |
| 301 |
case KBD_CCMD_WRITE_OBUF: |
case KBD_CCMD_WRITE_OBUF: |
| 313 |
} |
} |
| 314 |
break; |
break; |
| 315 |
case KBD_CCMD_WRITE_MOUSE: |
case KBD_CCMD_WRITE_MOUSE: |
| 316 |
kbd_write_mouse(s, val); |
ps2_write_mouse(s->mouse, val); |
| 317 |
break; |
break; |
| 318 |
default: |
default: |
| 319 |
break; |
break; |
| 324 |
static void kbd_reset(void *opaque) |
static void kbd_reset(void *opaque) |
| 325 |
{ |
{ |
| 326 |
KBDState *s = opaque; |
KBDState *s = opaque; |
|
KBDQueue *q; |
|
| 327 |
|
|
|
s->kbd_write_cmd = -1; |
|
|
s->mouse_write_cmd = -1; |
|
| 328 |
s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT; |
s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT; |
| 329 |
s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED; |
s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED; |
|
q = &s->queue; |
|
|
q->rptr = 0; |
|
|
q->wptr = 0; |
|
|
q->count = 0; |
|
| 330 |
} |
} |
| 331 |
|
|
| 332 |
static void kbd_save(QEMUFile* f, void* opaque) |
static void kbd_save(QEMUFile* f, void* opaque) |
| 336 |
qemu_put_8s(f, &s->write_cmd); |
qemu_put_8s(f, &s->write_cmd); |
| 337 |
qemu_put_8s(f, &s->status); |
qemu_put_8s(f, &s->status); |
| 338 |
qemu_put_8s(f, &s->mode); |
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); |
|
| 339 |
} |
} |
| 340 |
|
|
| 341 |
static int kbd_load(QEMUFile* f, void* opaque, int version_id) |
static int kbd_load(QEMUFile* f, void* opaque, int version_id) |
| 342 |
{ |
{ |
| 343 |
KBDState *s = (KBDState*)opaque; |
KBDState *s = (KBDState*)opaque; |
| 344 |
|
|
| 345 |
if (version_id != 1) |
if (version_id != 2) |
| 346 |
return -EINVAL; |
return -EINVAL; |
| 347 |
qemu_get_8s(f, &s->write_cmd); |
qemu_get_8s(f, &s->write_cmd); |
| 348 |
qemu_get_8s(f, &s->status); |
qemu_get_8s(f, &s->status); |
| 349 |
qemu_get_8s(f, &s->mode); |
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); |
|
| 350 |
return 0; |
return 0; |
| 351 |
} |
} |
| 352 |
|
|
| 355 |
KBDState *s = &kbd_state; |
KBDState *s = &kbd_state; |
| 356 |
|
|
| 357 |
kbd_reset(s); |
kbd_reset(s); |
| 358 |
register_savevm("pckbd", 0, 1, kbd_save, kbd_load, s); |
register_savevm("pckbd", 0, 2, kbd_save, kbd_load, s); |
| 359 |
register_ioport_read(0x60, 1, 1, kbd_read_data, s); |
register_ioport_read(0x60, 1, 1, kbd_read_data, s); |
| 360 |
register_ioport_write(0x60, 1, 1, kbd_write_data, s); |
register_ioport_write(0x60, 1, 1, kbd_write_data, s); |
| 361 |
register_ioport_read(0x64, 1, 1, kbd_read_status, s); |
register_ioport_read(0x64, 1, 1, kbd_read_status, s); |
| 362 |
register_ioport_write(0x64, 1, 1, kbd_write_command, s); |
register_ioport_write(0x64, 1, 1, kbd_write_command, s); |
| 363 |
|
|
| 364 |
qemu_add_kbd_event_handler(pc_kbd_put_keycode, s); |
s->kbd = ps2_kbd_init(kbd_update_kbd_irq, s); |
| 365 |
qemu_add_mouse_event_handler(pc_kbd_mouse_event, s); |
s->mouse = ps2_mouse_init(kbd_update_aux_irq, s); |
| 366 |
qemu_register_reset(kbd_reset, s); |
qemu_register_reset(kbd_reset, s); |
| 367 |
} |
} |