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 |
} |
} |