Statistics
| Branch: | Revision:

root / hw / pckbd.c @ 80cabfad

History | View | Annotate | Download (19.3 kB)

1
/*
2
 * QEMU PC keyboard emulation
3
 * 
4
 * Copyright (c) 2003 Fabrice Bellard
5
 * 
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
#include <stdlib.h>
25
#include <stdio.h>
26
#include <stdarg.h>
27
#include <string.h>
28
#include <getopt.h>
29
#include <inttypes.h>
30
#include <unistd.h>
31
#include <sys/mman.h>
32
#include <fcntl.h>
33
#include <signal.h>
34
#include <time.h>
35
#include <sys/time.h>
36
#include <malloc.h>
37
#include <termios.h>
38
#include <sys/poll.h>
39
#include <errno.h>
40
#include <sys/wait.h>
41
#include <netinet/in.h>
42

    
43
#include "cpu.h"
44
#include "vl.h"
45

    
46
/* debug PC keyboard */
47
//#define DEBUG_KBD
48

    
49
/* debug PC keyboard : only mouse */
50
//#define DEBUG_MOUSE
51

    
52
/*        Keyboard Controller Commands */
53
#define KBD_CCMD_READ_MODE        0x20        /* Read mode bits */
54
#define KBD_CCMD_WRITE_MODE        0x60        /* Write mode bits */
55
#define KBD_CCMD_GET_VERSION        0xA1        /* Get controller version */
56
#define KBD_CCMD_MOUSE_DISABLE        0xA7        /* Disable mouse interface */
57
#define KBD_CCMD_MOUSE_ENABLE        0xA8        /* Enable mouse interface */
58
#define KBD_CCMD_TEST_MOUSE        0xA9        /* Mouse interface test */
59
#define KBD_CCMD_SELF_TEST        0xAA        /* Controller self test */
60
#define KBD_CCMD_KBD_TEST        0xAB        /* Keyboard interface test */
61
#define KBD_CCMD_KBD_DISABLE        0xAD        /* Keyboard interface disable */
62
#define KBD_CCMD_KBD_ENABLE        0xAE        /* Keyboard interface enable */
63
#define KBD_CCMD_READ_INPORT    0xC0    /* read input port */
64
#define KBD_CCMD_READ_OUTPORT        0xD0    /* read output port */
65
#define KBD_CCMD_WRITE_OUTPORT        0xD1    /* write output port */
66
#define KBD_CCMD_WRITE_OBUF        0xD2
67
#define KBD_CCMD_WRITE_AUX_OBUF        0xD3    /* Write to output buffer as if
68
                                           initiated by the auxiliary device */
69
#define KBD_CCMD_WRITE_MOUSE        0xD4        /* Write the following byte to the mouse */
70
#define KBD_CCMD_DISABLE_A20    0xDD    /* HP vectra only ? */
71
#define KBD_CCMD_ENABLE_A20     0xDF    /* HP vectra only ? */
72
#define KBD_CCMD_RESET                0xFE
73

    
74
/* Keyboard Commands */
75
#define KBD_CMD_SET_LEDS        0xED        /* Set keyboard leds */
76
#define KBD_CMD_ECHO             0xEE
77
#define KBD_CMD_GET_ID                 0xF2        /* get keyboard ID */
78
#define KBD_CMD_SET_RATE        0xF3        /* Set typematic rate */
79
#define KBD_CMD_ENABLE                0xF4        /* Enable scanning */
80
#define KBD_CMD_RESET_DISABLE        0xF5        /* reset and disable scanning */
81
#define KBD_CMD_RESET_ENABLE           0xF6    /* reset and enable scanning */
82
#define KBD_CMD_RESET                0xFF        /* Reset */
83

    
84
/* Keyboard Replies */
85
#define KBD_REPLY_POR                0xAA        /* Power on reset */
86
#define KBD_REPLY_ACK                0xFA        /* Command ACK */
87
#define KBD_REPLY_RESEND        0xFE        /* Command NACK, send the cmd again */
88

    
89
/* Status Register Bits */
90
#define KBD_STAT_OBF                 0x01        /* Keyboard output buffer full */
91
#define KBD_STAT_IBF                 0x02        /* Keyboard input buffer full */
92
#define KBD_STAT_SELFTEST        0x04        /* Self test successful */
93
#define KBD_STAT_CMD                0x08        /* Last write was a command write (0=data) */
94
#define KBD_STAT_UNLOCKED        0x10        /* Zero if keyboard locked */
95
#define KBD_STAT_MOUSE_OBF        0x20        /* Mouse output buffer full */
96
#define KBD_STAT_GTO                 0x40        /* General receive/xmit timeout */
97
#define KBD_STAT_PERR                 0x80        /* Parity error */
98

    
99
/* Controller Mode Register Bits */
100
#define KBD_MODE_KBD_INT        0x01        /* Keyboard data generate IRQ1 */
101
#define KBD_MODE_MOUSE_INT        0x02        /* Mouse data generate IRQ12 */
102
#define KBD_MODE_SYS                 0x04        /* The system flag (?) */
103
#define KBD_MODE_NO_KEYLOCK        0x08        /* The keylock doesn't affect the keyboard if set */
104
#define KBD_MODE_DISABLE_KBD        0x10        /* Disable keyboard interface */
105
#define KBD_MODE_DISABLE_MOUSE        0x20        /* Disable mouse interface */
106
#define KBD_MODE_KCC                 0x40        /* Scan code conversion to PC format */
107
#define KBD_MODE_RFU                0x80
108

    
109
/* Mouse Commands */
110
#define AUX_SET_SCALE11                0xE6        /* Set 1:1 scaling */
111
#define AUX_SET_SCALE21                0xE7        /* Set 2:1 scaling */
112
#define AUX_SET_RES                0xE8        /* Set resolution */
113
#define AUX_GET_SCALE                0xE9        /* Get scaling factor */
114
#define AUX_SET_STREAM                0xEA        /* Set stream mode */
115
#define AUX_POLL                0xEB        /* Poll */
116
#define AUX_RESET_WRAP                0xEC        /* Reset wrap mode */
117
#define AUX_SET_WRAP                0xEE        /* Set wrap mode */
118
#define AUX_SET_REMOTE                0xF0        /* Set remote mode */
119
#define AUX_GET_TYPE                0xF2        /* Get type */
120
#define AUX_SET_SAMPLE                0xF3        /* Set sample rate */
121
#define AUX_ENABLE_DEV                0xF4        /* Enable aux device */
122
#define AUX_DISABLE_DEV                0xF5        /* Disable aux device */
123
#define AUX_SET_DEFAULT                0xF6
124
#define AUX_RESET                0xFF        /* Reset aux device */
125
#define AUX_ACK                        0xFA        /* Command byte ACK. */
126

    
127
#define MOUSE_STATUS_REMOTE     0x40
128
#define MOUSE_STATUS_ENABLED    0x20
129
#define MOUSE_STATUS_SCALE21    0x10
130

    
131
#define KBD_QUEUE_SIZE 256
132

    
133
typedef struct {
134
    uint8_t data[KBD_QUEUE_SIZE];
135
    int rptr, wptr, count;
136
} KBDQueue;
137

    
138
typedef struct KBDState {
139
    KBDQueue queues[2];
140
    uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
141
    uint8_t status;
142
    uint8_t mode;
143
    /* keyboard state */
144
    int kbd_write_cmd;
145
    int scan_enabled;
146
    /* mouse state */
147
    int mouse_write_cmd;
148
    uint8_t mouse_status;
149
    uint8_t mouse_resolution;
150
    uint8_t mouse_sample_rate;
151
    uint8_t mouse_wrap;
152
    uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
153
    uint8_t mouse_detect_state;
154
    int mouse_dx; /* current values, needed for 'poll' mode */
155
    int mouse_dy;
156
    int mouse_dz;
157
    uint8_t mouse_buttons;
158
} KBDState;
159

    
160
KBDState kbd_state;
161
int reset_requested;
162

    
163
/* update irq and KBD_STAT_[MOUSE_]OBF */
164
/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
165
   incorrect, but it avoids having to simulate exact delays */
166
static void kbd_update_irq(KBDState *s)
167
{
168
    int irq12_level, irq1_level;
169

    
170
    irq1_level = 0;    
171
    irq12_level = 0;    
172
    s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
173
    if (s->queues[0].count != 0 ||
174
        s->queues[1].count != 0) {
175
        s->status |= KBD_STAT_OBF;
176
        if (s->queues[1].count != 0) {
177
            s->status |= KBD_STAT_MOUSE_OBF;
178
            if (s->mode & KBD_MODE_MOUSE_INT)
179
                irq12_level = 1;
180
        } else {
181
            if ((s->mode & KBD_MODE_KBD_INT) && 
182
                !(s->mode & KBD_MODE_DISABLE_KBD))
183
                irq1_level = 1;
184
        }
185
    }
186
    pic_set_irq(1, irq1_level);
187
    pic_set_irq(12, irq12_level);
188
}
189

    
190
static void kbd_queue(KBDState *s, int b, int aux)
191
{
192
    KBDQueue *q = &kbd_state.queues[aux];
193

    
194
#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD)
195
    if (aux)
196
        printf("mouse event: 0x%02x\n", b);
197
#ifdef DEBUG_KBD
198
    else
199
        printf("kbd event: 0x%02x\n", b);
200
#endif
201
#endif
202
    if (q->count >= KBD_QUEUE_SIZE)
203
        return;
204
    q->data[q->wptr] = b;
205
    if (++q->wptr == KBD_QUEUE_SIZE)
206
        q->wptr = 0;
207
    q->count++;
208
    kbd_update_irq(s);
209
}
210

    
211
void kbd_put_keycode(int keycode)
212
{
213
    KBDState *s = &kbd_state;
214
    kbd_queue(s, keycode, 0);
215
}
216

    
217
static uint32_t kbd_read_status(CPUState *env, uint32_t addr)
218
{
219
    KBDState *s = &kbd_state;
220
    int val;
221
    val = s->status;
222
#if defined(DEBUG_KBD)
223
    printf("kbd: read status=0x%02x\n", val);
224
#endif
225
    return val;
226
}
227

    
228
static void kbd_write_command(CPUState *env, uint32_t addr, uint32_t val)
229
{
230
    KBDState *s = &kbd_state;
231

    
232
#ifdef DEBUG_KBD
233
    printf("kbd: write cmd=0x%02x\n", val);
234
#endif
235
    switch(val) {
236
    case KBD_CCMD_READ_MODE:
237
        kbd_queue(s, s->mode, 0);
238
        break;
239
    case KBD_CCMD_WRITE_MODE:
240
    case KBD_CCMD_WRITE_OBUF:
241
    case KBD_CCMD_WRITE_AUX_OBUF:
242
    case KBD_CCMD_WRITE_MOUSE:
243
    case KBD_CCMD_WRITE_OUTPORT:
244
        s->write_cmd = val;
245
        break;
246
    case KBD_CCMD_MOUSE_DISABLE:
247
        s->mode |= KBD_MODE_DISABLE_MOUSE;
248
        break;
249
    case KBD_CCMD_MOUSE_ENABLE:
250
        s->mode &= ~KBD_MODE_DISABLE_MOUSE;
251
        break;
252
    case KBD_CCMD_TEST_MOUSE:
253
        kbd_queue(s, 0x00, 0);
254
        break;
255
    case KBD_CCMD_SELF_TEST:
256
        s->status |= KBD_STAT_SELFTEST;
257
        kbd_queue(s, 0x55, 0);
258
        break;
259
    case KBD_CCMD_KBD_TEST:
260
        kbd_queue(s, 0x00, 0);
261
        break;
262
    case KBD_CCMD_KBD_DISABLE:
263
        s->mode |= KBD_MODE_DISABLE_KBD;
264
        kbd_update_irq(s);
265
        break;
266
    case KBD_CCMD_KBD_ENABLE:
267
        s->mode &= ~KBD_MODE_DISABLE_KBD;
268
        kbd_update_irq(s);
269
        break;
270
    case KBD_CCMD_READ_INPORT:
271
        kbd_queue(s, 0x00, 0);
272
        break;
273
    case KBD_CCMD_READ_OUTPORT:
274
        /* XXX: check that */
275
#ifdef TARGET_I386
276
        val = 0x01 | (((cpu_single_env->a20_mask >> 20) & 1) << 1);
277
#else
278
        val = 0x01;
279
#endif
280
        if (s->status & KBD_STAT_OBF)
281
            val |= 0x10;
282
        if (s->status & KBD_STAT_MOUSE_OBF)
283
            val |= 0x20;
284
        kbd_queue(s, val, 0);
285
        break;
286
#ifdef TARGET_I386
287
    case KBD_CCMD_ENABLE_A20:
288
        cpu_x86_set_a20(env, 1);
289
        break;
290
    case KBD_CCMD_DISABLE_A20:
291
        cpu_x86_set_a20(env, 0);
292
        break;
293
#endif
294
    case KBD_CCMD_RESET:
295
        reset_requested = 1;
296
        cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
297
        break;
298
    case 0xff:
299
        /* ignore that - I don't know what is its use */
300
        break;
301
    default:
302
        fprintf(stderr, "qemu: unsupported keyboard cmd=0x%02x\n", val);
303
        break;
304
    }
305
}
306

    
307
static uint32_t kbd_read_data(CPUState *env, uint32_t addr)
308
{
309
    KBDState *s = &kbd_state;
310
    KBDQueue *q;
311
    int val, index;
312
    
313
    q = &s->queues[0]; /* first check KBD data */
314
    if (q->count == 0)
315
        q = &s->queues[1]; /* then check AUX data */
316
    if (q->count == 0) {
317
        /* NOTE: if no data left, we return the last keyboard one
318
           (needed for EMM386) */
319
        /* XXX: need a timer to do things correctly */
320
        q = &s->queues[0];
321
        index = q->rptr - 1;
322
        if (index < 0)
323
            index = KBD_QUEUE_SIZE - 1;
324
        val = q->data[index];
325
    } else {
326
        val = q->data[q->rptr];
327
        if (++q->rptr == KBD_QUEUE_SIZE)
328
            q->rptr = 0;
329
        q->count--;
330
        /* reading deasserts IRQ */
331
        if (q == &s->queues[0])
332
            pic_set_irq(1, 0);
333
        else
334
            pic_set_irq(12, 0);
335
    }
336
    /* reassert IRQs if data left */
337
    kbd_update_irq(s);
338
#ifdef DEBUG_KBD
339
    printf("kbd: read data=0x%02x\n", val);
340
#endif
341
    return val;
342
}
343

    
344
static void kbd_reset_keyboard(KBDState *s)
345
{
346
    s->scan_enabled = 1;
347
}
348

    
349
static void kbd_write_keyboard(KBDState *s, int val)
350
{
351
    switch(s->kbd_write_cmd) {
352
    default:
353
    case -1:
354
        switch(val) {
355
        case 0x00:
356
            kbd_queue(s, KBD_REPLY_ACK, 0);
357
            break;
358
        case 0x05:
359
            kbd_queue(s, KBD_REPLY_RESEND, 0);
360
            break;
361
        case KBD_CMD_GET_ID:
362
            kbd_queue(s, KBD_REPLY_ACK, 0);
363
            kbd_queue(s, 0xab, 0);
364
            kbd_queue(s, 0x83, 0);
365
            break;
366
        case KBD_CMD_ECHO:
367
            kbd_queue(s, KBD_CMD_ECHO, 0);
368
            break;
369
        case KBD_CMD_ENABLE:
370
            s->scan_enabled = 1;
371
            kbd_queue(s, KBD_REPLY_ACK, 0);
372
            break;
373
        case KBD_CMD_SET_LEDS:
374
        case KBD_CMD_SET_RATE:
375
            s->kbd_write_cmd = val;
376
            kbd_queue(s, KBD_REPLY_ACK, 0);
377
            break;
378
        case KBD_CMD_RESET_DISABLE:
379
            kbd_reset_keyboard(s);
380
            s->scan_enabled = 0;
381
            kbd_queue(s, KBD_REPLY_ACK, 0);
382
            break;
383
        case KBD_CMD_RESET_ENABLE:
384
            kbd_reset_keyboard(s);
385
            s->scan_enabled = 1;
386
            kbd_queue(s, KBD_REPLY_ACK, 0);
387
            break;
388
        case KBD_CMD_RESET:
389
            kbd_reset_keyboard(s);
390
            kbd_queue(s, KBD_REPLY_ACK, 0);
391
            kbd_queue(s, KBD_REPLY_POR, 0);
392
            break;
393
        default:
394
            kbd_queue(s, KBD_REPLY_ACK, 0);
395
            break;
396
        }
397
        break;
398
    case KBD_CMD_SET_LEDS:
399
        kbd_queue(s, KBD_REPLY_ACK, 0);
400
        s->kbd_write_cmd = -1;
401
        break;
402
    case KBD_CMD_SET_RATE:
403
        kbd_queue(s, KBD_REPLY_ACK, 0);
404
        s->kbd_write_cmd = -1;
405
        break;
406
    }
407
}
408

    
409
static void kbd_mouse_send_packet(KBDState *s)
410
{
411
    unsigned int b;
412
    int dx1, dy1, dz1;
413

    
414
    dx1 = s->mouse_dx;
415
    dy1 = s->mouse_dy;
416
    dz1 = s->mouse_dz;
417
    /* XXX: increase range to 8 bits ? */
418
    if (dx1 > 127)
419
        dx1 = 127;
420
    else if (dx1 < -127)
421
        dx1 = -127;
422
    if (dy1 > 127)
423
        dy1 = 127;
424
    else if (dy1 < -127)
425
        dy1 = -127;
426
    b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
427
    kbd_queue(s, b, 1);
428
    kbd_queue(s, dx1 & 0xff, 1);
429
    kbd_queue(s, dy1 & 0xff, 1);
430
    /* extra byte for IMPS/2 or IMEX */
431
    switch(s->mouse_type) {
432
    default:
433
        break;
434
    case 3:
435
        if (dz1 > 127)
436
            dz1 = 127;
437
        else if (dz1 < -127)
438
                dz1 = -127;
439
        kbd_queue(s, dz1 & 0xff, 1);
440
        break;
441
    case 4:
442
        if (dz1 > 7)
443
            dz1 = 7;
444
        else if (dz1 < -7)
445
            dz1 = -7;
446
        b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
447
        kbd_queue(s, b, 1);
448
        break;
449
    }
450

    
451
    /* update deltas */
452
    s->mouse_dx -= dx1;
453
    s->mouse_dy -= dy1;
454
    s->mouse_dz -= dz1;
455
}
456

    
457
void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
458
{
459
    KBDState *s = &kbd_state;
460

    
461
    /* check if deltas are recorded when disabled */
462
    if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
463
        return;
464

    
465
    s->mouse_dx += dx;
466
    s->mouse_dy -= dy;
467
    s->mouse_dz += dz;
468
    s->mouse_buttons = buttons_state;
469
    
470
    if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
471
        (s->queues[1].count < (KBD_QUEUE_SIZE - 16))) {
472
        for(;;) {
473
            /* if not remote, send event. Multiple events are sent if
474
               too big deltas */
475
            kbd_mouse_send_packet(s);
476
            if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
477
                break;
478
        }
479
    }
480
}
481

    
482
static void kbd_write_mouse(KBDState *s, int val)
483
{
484
#ifdef DEBUG_MOUSE
485
    printf("kbd: write mouse 0x%02x\n", val);
486
#endif
487
    switch(s->mouse_write_cmd) {
488
    default:
489
    case -1:
490
        /* mouse command */
491
        if (s->mouse_wrap) {
492
            if (val == AUX_RESET_WRAP) {
493
                s->mouse_wrap = 0;
494
                kbd_queue(s, AUX_ACK, 1);
495
                return;
496
            } else if (val != AUX_RESET) {
497
                kbd_queue(s, val, 1);
498
                return;
499
            }
500
        }
501
        switch(val) {
502
        case AUX_SET_SCALE11:
503
            s->mouse_status &= ~MOUSE_STATUS_SCALE21;
504
            kbd_queue(s, AUX_ACK, 1);
505
            break;
506
        case AUX_SET_SCALE21:
507
            s->mouse_status |= MOUSE_STATUS_SCALE21;
508
            kbd_queue(s, AUX_ACK, 1);
509
            break;
510
        case AUX_SET_STREAM:
511
            s->mouse_status &= ~MOUSE_STATUS_REMOTE;
512
            kbd_queue(s, AUX_ACK, 1);
513
            break;
514
        case AUX_SET_WRAP:
515
            s->mouse_wrap = 1;
516
            kbd_queue(s, AUX_ACK, 1);
517
            break;
518
        case AUX_SET_REMOTE:
519
            s->mouse_status |= MOUSE_STATUS_REMOTE;
520
            kbd_queue(s, AUX_ACK, 1);
521
            break;
522
        case AUX_GET_TYPE:
523
            kbd_queue(s, AUX_ACK, 1);
524
            kbd_queue(s, s->mouse_type, 1);
525
            break;
526
        case AUX_SET_RES:
527
        case AUX_SET_SAMPLE:
528
            s->mouse_write_cmd = val;
529
            kbd_queue(s, AUX_ACK, 1);
530
            break;
531
        case AUX_GET_SCALE:
532
            kbd_queue(s, AUX_ACK, 1);
533
            kbd_queue(s, s->mouse_status, 1);
534
            kbd_queue(s, s->mouse_resolution, 1);
535
            kbd_queue(s, s->mouse_sample_rate, 1);
536
            break;
537
        case AUX_POLL:
538
            kbd_queue(s, AUX_ACK, 1);
539
            kbd_mouse_send_packet(s);
540
            break;
541
        case AUX_ENABLE_DEV:
542
            s->mouse_status |= MOUSE_STATUS_ENABLED;
543
            kbd_queue(s, AUX_ACK, 1);
544
            break;
545
        case AUX_DISABLE_DEV:
546
            s->mouse_status &= ~MOUSE_STATUS_ENABLED;
547
            kbd_queue(s, AUX_ACK, 1);
548
            break;
549
        case AUX_SET_DEFAULT:
550
            s->mouse_sample_rate = 100;
551
            s->mouse_resolution = 2;
552
            s->mouse_status = 0;
553
            kbd_queue(s, AUX_ACK, 1);
554
            break;
555
        case AUX_RESET:
556
            s->mouse_sample_rate = 100;
557
            s->mouse_resolution = 2;
558
            s->mouse_status = 0;
559
            kbd_queue(s, AUX_ACK, 1);
560
            kbd_queue(s, 0xaa, 1);
561
            kbd_queue(s, s->mouse_type, 1);
562
            break;
563
        default:
564
            break;
565
        }
566
        break;
567
    case AUX_SET_SAMPLE:
568
        s->mouse_sample_rate = val;
569
#if 0
570
        /* detect IMPS/2 or IMEX */
571
        switch(s->mouse_detect_state) {
572
        default:
573
        case 0:
574
            if (val == 200)
575
                s->mouse_detect_state = 1;
576
            break;
577
        case 1:
578
            if (val == 100)
579
                s->mouse_detect_state = 2;
580
            else if (val == 200)
581
                s->mouse_detect_state = 3;
582
            else
583
                s->mouse_detect_state = 0;
584
            break;
585
        case 2:
586
            if (val == 80) 
587
                s->mouse_type = 3; /* IMPS/2 */
588
            s->mouse_detect_state = 0;
589
            break;
590
        case 3:
591
            if (val == 80) 
592
                s->mouse_type = 4; /* IMEX */
593
            s->mouse_detect_state = 0;
594
            break;
595
        }
596
#endif
597
        kbd_queue(s, AUX_ACK, 1);
598
        s->mouse_write_cmd = -1;
599
        break;
600
    case AUX_SET_RES:
601
        s->mouse_resolution = val;
602
        kbd_queue(s, AUX_ACK, 1);
603
        s->mouse_write_cmd = -1;
604
        break;
605
    }
606
}
607

    
608
void kbd_write_data(CPUState *env, uint32_t addr, uint32_t val)
609
{
610
    KBDState *s = &kbd_state;
611

    
612
#ifdef DEBUG_KBD
613
    printf("kbd: write data=0x%02x\n", val);
614
#endif
615

    
616
    switch(s->write_cmd) {
617
    case 0:
618
        kbd_write_keyboard(s, val);
619
        break;
620
    case KBD_CCMD_WRITE_MODE:
621
        s->mode = val;
622
        kbd_update_irq(s);
623
        break;
624
    case KBD_CCMD_WRITE_OBUF:
625
        kbd_queue(s, val, 0);
626
        break;
627
    case KBD_CCMD_WRITE_AUX_OBUF:
628
        kbd_queue(s, val, 1);
629
        break;
630
    case KBD_CCMD_WRITE_OUTPORT:
631
#ifdef TARGET_I386
632
        cpu_x86_set_a20(env, (val >> 1) & 1);
633
#endif
634
        if (!(val & 1)) {
635
            reset_requested = 1;
636
            cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
637
        }
638
        break;
639
    case KBD_CCMD_WRITE_MOUSE:
640
        kbd_write_mouse(s, val);
641
        break;
642
    default:
643
        break;
644
    }
645
    s->write_cmd = 0;
646
}
647

    
648
void kbd_reset(KBDState *s)
649
{
650
    KBDQueue *q;
651
    int i;
652

    
653
    s->kbd_write_cmd = -1;
654
    s->mouse_write_cmd = -1;
655
    s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
656
    s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
657
    for(i = 0; i < 2; i++) {
658
        q = &s->queues[i];
659
        q->rptr = 0;
660
        q->wptr = 0;
661
        q->count = 0;
662
    }
663
}
664

    
665
void kbd_init(void)
666
{
667
    kbd_reset(&kbd_state);
668
    register_ioport_read(0x60, 1, kbd_read_data, 1);
669
    register_ioport_write(0x60, 1, kbd_write_data, 1);
670
    register_ioport_read(0x64, 1, kbd_read_status, 1);
671
    register_ioport_write(0x64, 1, kbd_write_command, 1);
672
}