Statistics
| Branch: | Revision:

root / hw / pckbd.c @ fb6cf1d0

History | View | Annotate | Download (19 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 "vl.h"
25

    
26
/* debug PC keyboard */
27
//#define DEBUG_KBD
28

    
29
/* debug PC keyboard : only mouse */
30
//#define DEBUG_MOUSE
31

    
32
/*        Keyboard Controller Commands */
33
#define KBD_CCMD_READ_MODE        0x20        /* Read mode bits */
34
#define KBD_CCMD_WRITE_MODE        0x60        /* Write mode bits */
35
#define KBD_CCMD_GET_VERSION        0xA1        /* Get controller version */
36
#define KBD_CCMD_MOUSE_DISABLE        0xA7        /* Disable mouse interface */
37
#define KBD_CCMD_MOUSE_ENABLE        0xA8        /* Enable mouse interface */
38
#define KBD_CCMD_TEST_MOUSE        0xA9        /* Mouse interface test */
39
#define KBD_CCMD_SELF_TEST        0xAA        /* Controller self test */
40
#define KBD_CCMD_KBD_TEST        0xAB        /* Keyboard interface test */
41
#define KBD_CCMD_KBD_DISABLE        0xAD        /* Keyboard interface disable */
42
#define KBD_CCMD_KBD_ENABLE        0xAE        /* Keyboard interface enable */
43
#define KBD_CCMD_READ_INPORT    0xC0    /* read input port */
44
#define KBD_CCMD_READ_OUTPORT        0xD0    /* read output port */
45
#define KBD_CCMD_WRITE_OUTPORT        0xD1    /* write output port */
46
#define KBD_CCMD_WRITE_OBUF        0xD2
47
#define KBD_CCMD_WRITE_AUX_OBUF        0xD3    /* Write to output buffer as if
48
                                           initiated by the auxiliary device */
49
#define KBD_CCMD_WRITE_MOUSE        0xD4        /* Write the following byte to the mouse */
50
#define KBD_CCMD_DISABLE_A20    0xDD    /* HP vectra only ? */
51
#define KBD_CCMD_ENABLE_A20     0xDF    /* HP vectra only ? */
52
#define KBD_CCMD_RESET                0xFE
53

    
54
/* Keyboard Commands */
55
#define KBD_CMD_SET_LEDS        0xED        /* Set keyboard leds */
56
#define KBD_CMD_ECHO             0xEE
57
#define KBD_CMD_GET_ID                 0xF2        /* get keyboard ID */
58
#define KBD_CMD_SET_RATE        0xF3        /* Set typematic rate */
59
#define KBD_CMD_ENABLE                0xF4        /* Enable scanning */
60
#define KBD_CMD_RESET_DISABLE        0xF5        /* reset and disable scanning */
61
#define KBD_CMD_RESET_ENABLE           0xF6    /* reset and enable scanning */
62
#define KBD_CMD_RESET                0xFF        /* Reset */
63

    
64
/* Keyboard Replies */
65
#define KBD_REPLY_POR                0xAA        /* Power on reset */
66
#define KBD_REPLY_ACK                0xFA        /* Command ACK */
67
#define KBD_REPLY_RESEND        0xFE        /* Command NACK, send the cmd again */
68

    
69
/* Status Register Bits */
70
#define KBD_STAT_OBF                 0x01        /* Keyboard output buffer full */
71
#define KBD_STAT_IBF                 0x02        /* Keyboard input buffer full */
72
#define KBD_STAT_SELFTEST        0x04        /* Self test successful */
73
#define KBD_STAT_CMD                0x08        /* Last write was a command write (0=data) */
74
#define KBD_STAT_UNLOCKED        0x10        /* Zero if keyboard locked */
75
#define KBD_STAT_MOUSE_OBF        0x20        /* Mouse output buffer full */
76
#define KBD_STAT_GTO                 0x40        /* General receive/xmit timeout */
77
#define KBD_STAT_PERR                 0x80        /* Parity error */
78

    
79
/* Controller Mode Register Bits */
80
#define KBD_MODE_KBD_INT        0x01        /* Keyboard data generate IRQ1 */
81
#define KBD_MODE_MOUSE_INT        0x02        /* Mouse data generate IRQ12 */
82
#define KBD_MODE_SYS                 0x04        /* The system flag (?) */
83
#define KBD_MODE_NO_KEYLOCK        0x08        /* The keylock doesn't affect the keyboard if set */
84
#define KBD_MODE_DISABLE_KBD        0x10        /* Disable keyboard interface */
85
#define KBD_MODE_DISABLE_MOUSE        0x20        /* Disable mouse interface */
86
#define KBD_MODE_KCC                 0x40        /* Scan code conversion to PC format */
87
#define KBD_MODE_RFU                0x80
88

    
89
/* Mouse Commands */
90
#define AUX_SET_SCALE11                0xE6        /* Set 1:1 scaling */
91
#define AUX_SET_SCALE21                0xE7        /* Set 2:1 scaling */
92
#define AUX_SET_RES                0xE8        /* Set resolution */
93
#define AUX_GET_SCALE                0xE9        /* Get scaling factor */
94
#define AUX_SET_STREAM                0xEA        /* Set stream mode */
95
#define AUX_POLL                0xEB        /* Poll */
96
#define AUX_RESET_WRAP                0xEC        /* Reset wrap mode */
97
#define AUX_SET_WRAP                0xEE        /* Set wrap mode */
98
#define AUX_SET_REMOTE                0xF0        /* Set remote mode */
99
#define AUX_GET_TYPE                0xF2        /* Get type */
100
#define AUX_SET_SAMPLE                0xF3        /* Set sample rate */
101
#define AUX_ENABLE_DEV                0xF4        /* Enable aux device */
102
#define AUX_DISABLE_DEV                0xF5        /* Disable aux device */
103
#define AUX_SET_DEFAULT                0xF6
104
#define AUX_RESET                0xFF        /* Reset aux device */
105
#define AUX_ACK                        0xFA        /* Command byte ACK. */
106

    
107
#define MOUSE_STATUS_REMOTE     0x40
108
#define MOUSE_STATUS_ENABLED    0x20
109
#define MOUSE_STATUS_SCALE21    0x10
110

    
111
#define KBD_QUEUE_SIZE 256
112

    
113
typedef struct {
114
    uint8_t aux[KBD_QUEUE_SIZE];
115
    uint8_t data[KBD_QUEUE_SIZE];
116
    int rptr, wptr, count;
117
} KBDQueue;
118

    
119
typedef struct KBDState {
120
    KBDQueue queue;
121
    uint8_t write_cmd; /* if non zero, write data to port 60 is expected */
122
    uint8_t status;
123
    uint8_t mode;
124
    /* keyboard state */
125
    int kbd_write_cmd;
126
    int scan_enabled;
127
    /* mouse state */
128
    int mouse_write_cmd;
129
    uint8_t mouse_status;
130
    uint8_t mouse_resolution;
131
    uint8_t mouse_sample_rate;
132
    uint8_t mouse_wrap;
133
    uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
134
    uint8_t mouse_detect_state;
135
    int mouse_dx; /* current values, needed for 'poll' mode */
136
    int mouse_dy;
137
    int mouse_dz;
138
    uint8_t mouse_buttons;
139
} KBDState;
140

    
141
KBDState kbd_state;
142
int reset_requested;
143

    
144
/* update irq and KBD_STAT_[MOUSE_]OBF */
145
/* XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
146
   incorrect, but it avoids having to simulate exact delays */
147
static void kbd_update_irq(KBDState *s)
148
{
149
    KBDQueue *q = &s->queue;
150
    int irq12_level, irq1_level;
151

    
152
    irq1_level = 0;    
153
    irq12_level = 0;    
154
    s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
155
    if (q->count != 0) {
156
        s->status |= KBD_STAT_OBF;
157
        if (q->aux[q->rptr]) {
158
            s->status |= KBD_STAT_MOUSE_OBF;
159
            if (s->mode & KBD_MODE_MOUSE_INT)
160
                irq12_level = 1;
161
        } else {
162
            if ((s->mode & KBD_MODE_KBD_INT) && 
163
                !(s->mode & KBD_MODE_DISABLE_KBD))
164
                irq1_level = 1;
165
        }
166
    }
167
    pic_set_irq(1, irq1_level);
168
    pic_set_irq(12, irq12_level);
169
}
170

    
171
static void kbd_queue(KBDState *s, int b, int aux)
172
{
173
    KBDQueue *q = &s->queue;
174

    
175
#if defined(DEBUG_MOUSE) || defined(DEBUG_KBD)
176
    if (aux)
177
        printf("mouse event: 0x%02x\n", b);
178
#ifdef DEBUG_KBD
179
    else
180
        printf("kbd event: 0x%02x\n", b);
181
#endif
182
#endif
183
    if (q->count >= KBD_QUEUE_SIZE)
184
        return;
185
    q->aux[q->wptr] = aux;
186
    q->data[q->wptr] = b;
187
    if (++q->wptr == KBD_QUEUE_SIZE)
188
        q->wptr = 0;
189
    q->count++;
190
    kbd_update_irq(s);
191
}
192

    
193
void kbd_put_keycode(int keycode)
194
{
195
    KBDState *s = &kbd_state;
196
    kbd_queue(s, keycode, 0);
197
}
198

    
199
static uint32_t kbd_read_status(void *opaque, uint32_t addr)
200
{
201
    KBDState *s = opaque;
202
    int val;
203
    val = s->status;
204
#if defined(DEBUG_KBD)
205
    printf("kbd: read status=0x%02x\n", val);
206
#endif
207
    return val;
208
}
209

    
210
static void kbd_write_command(void *opaque, uint32_t addr, uint32_t val)
211
{
212
    KBDState *s = opaque;
213

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

    
289
static uint32_t kbd_read_data(void *opaque, uint32_t addr)
290
{
291
    KBDState *s = opaque;
292
    KBDQueue *q;
293
    int val, index, aux;
294
    
295
    q = &s->queue;
296
    if (q->count == 0) {
297
        /* NOTE: if no data left, we return the last keyboard one
298
           (needed for EMM386) */
299
        /* XXX: need a timer to do things correctly */
300
        index = q->rptr - 1;
301
        if (index < 0)
302
            index = KBD_QUEUE_SIZE - 1;
303
        val = q->data[index];
304
    } else {
305
        aux = q->aux[q->rptr];
306
        val = q->data[q->rptr];
307
        if (++q->rptr == KBD_QUEUE_SIZE)
308
            q->rptr = 0;
309
        q->count--;
310
        /* reading deasserts IRQ */
311
        if (aux)
312
            pic_set_irq(12, 0);
313
        else
314
            pic_set_irq(1, 0);
315
    }
316
    /* reassert IRQs if data left */
317
    kbd_update_irq(s);
318
#ifdef DEBUG_KBD
319
    printf("kbd: read data=0x%02x\n", val);
320
#endif
321
    return val;
322
}
323

    
324
static void kbd_reset_keyboard(KBDState *s)
325
{
326
    s->scan_enabled = 1;
327
}
328

    
329
static void kbd_write_keyboard(KBDState *s, int val)
330
{
331
    switch(s->kbd_write_cmd) {
332
    default:
333
    case -1:
334
        switch(val) {
335
        case 0x00:
336
            kbd_queue(s, KBD_REPLY_ACK, 0);
337
            break;
338
        case 0x05:
339
            kbd_queue(s, KBD_REPLY_RESEND, 0);
340
            break;
341
        case KBD_CMD_GET_ID:
342
            kbd_queue(s, KBD_REPLY_ACK, 0);
343
            kbd_queue(s, 0xab, 0);
344
            kbd_queue(s, 0x83, 0);
345
            break;
346
        case KBD_CMD_ECHO:
347
            kbd_queue(s, KBD_CMD_ECHO, 0);
348
            break;
349
        case KBD_CMD_ENABLE:
350
            s->scan_enabled = 1;
351
            kbd_queue(s, KBD_REPLY_ACK, 0);
352
            break;
353
        case KBD_CMD_SET_LEDS:
354
        case KBD_CMD_SET_RATE:
355
            s->kbd_write_cmd = val;
356
            kbd_queue(s, KBD_REPLY_ACK, 0);
357
            break;
358
        case KBD_CMD_RESET_DISABLE:
359
            kbd_reset_keyboard(s);
360
            s->scan_enabled = 0;
361
            kbd_queue(s, KBD_REPLY_ACK, 0);
362
            break;
363
        case KBD_CMD_RESET_ENABLE:
364
            kbd_reset_keyboard(s);
365
            s->scan_enabled = 1;
366
            kbd_queue(s, KBD_REPLY_ACK, 0);
367
            break;
368
        case KBD_CMD_RESET:
369
            kbd_reset_keyboard(s);
370
            kbd_queue(s, KBD_REPLY_ACK, 0);
371
            kbd_queue(s, KBD_REPLY_POR, 0);
372
            break;
373
        default:
374
            kbd_queue(s, KBD_REPLY_ACK, 0);
375
            break;
376
        }
377
        break;
378
    case KBD_CMD_SET_LEDS:
379
        kbd_queue(s, KBD_REPLY_ACK, 0);
380
        s->kbd_write_cmd = -1;
381
        break;
382
    case KBD_CMD_SET_RATE:
383
        kbd_queue(s, KBD_REPLY_ACK, 0);
384
        s->kbd_write_cmd = -1;
385
        break;
386
    }
387
}
388

    
389
static void kbd_mouse_send_packet(KBDState *s)
390
{
391
    unsigned int b;
392
    int dx1, dy1, dz1;
393

    
394
    dx1 = s->mouse_dx;
395
    dy1 = s->mouse_dy;
396
    dz1 = s->mouse_dz;
397
    /* XXX: increase range to 8 bits ? */
398
    if (dx1 > 127)
399
        dx1 = 127;
400
    else if (dx1 < -127)
401
        dx1 = -127;
402
    if (dy1 > 127)
403
        dy1 = 127;
404
    else if (dy1 < -127)
405
        dy1 = -127;
406
    b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
407
    kbd_queue(s, b, 1);
408
    kbd_queue(s, dx1 & 0xff, 1);
409
    kbd_queue(s, dy1 & 0xff, 1);
410
    /* extra byte for IMPS/2 or IMEX */
411
    switch(s->mouse_type) {
412
    default:
413
        break;
414
    case 3:
415
        if (dz1 > 127)
416
            dz1 = 127;
417
        else if (dz1 < -127)
418
                dz1 = -127;
419
        kbd_queue(s, dz1 & 0xff, 1);
420
        break;
421
    case 4:
422
        if (dz1 > 7)
423
            dz1 = 7;
424
        else if (dz1 < -7)
425
            dz1 = -7;
426
        b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
427
        kbd_queue(s, b, 1);
428
        break;
429
    }
430

    
431
    /* update deltas */
432
    s->mouse_dx -= dx1;
433
    s->mouse_dy -= dy1;
434
    s->mouse_dz -= dz1;
435
}
436

    
437
void kbd_mouse_event(int dx, int dy, int dz, int buttons_state)
438
{
439
    KBDState *s = &kbd_state;
440

    
441
    /* check if deltas are recorded when disabled */
442
    if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
443
        return;
444

    
445
    s->mouse_dx += dx;
446
    s->mouse_dy -= dy;
447
    s->mouse_dz += dz;
448
    /* XXX: SDL sometimes generates nul events: we delete them */
449
    if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
450
        s->mouse_buttons == buttons_state)
451
        return;
452
    s->mouse_buttons = buttons_state;
453
    
454
    if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
455
        (s->queue.count < (KBD_QUEUE_SIZE - 16))) {
456
        for(;;) {
457
            /* if not remote, send event. Multiple events are sent if
458
               too big deltas */
459
            kbd_mouse_send_packet(s);
460
            if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
461
                break;
462
        }
463
    }
464
}
465

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

    
592
void kbd_write_data(void *opaque, uint32_t addr, uint32_t val)
593
{
594
    KBDState *s = opaque;
595

    
596
#ifdef DEBUG_KBD
597
    printf("kbd: write data=0x%02x\n", val);
598
#endif
599

    
600
    switch(s->write_cmd) {
601
    case 0:
602
        kbd_write_keyboard(s, val);
603
        break;
604
    case KBD_CCMD_WRITE_MODE:
605
        s->mode = val;
606
        kbd_update_irq(s);
607
        break;
608
    case KBD_CCMD_WRITE_OBUF:
609
        kbd_queue(s, val, 0);
610
        break;
611
    case KBD_CCMD_WRITE_AUX_OBUF:
612
        kbd_queue(s, val, 1);
613
        break;
614
    case KBD_CCMD_WRITE_OUTPORT:
615
#ifdef TARGET_I386
616
        cpu_x86_set_a20(cpu_single_env, (val >> 1) & 1);
617
#endif
618
        if (!(val & 1)) {
619
            reset_requested = 1;
620
            cpu_interrupt(cpu_single_env, CPU_INTERRUPT_EXIT);
621
        }
622
        break;
623
    case KBD_CCMD_WRITE_MOUSE:
624
        kbd_write_mouse(s, val);
625
        break;
626
    default:
627
        break;
628
    }
629
    s->write_cmd = 0;
630
}
631

    
632
void kbd_reset(KBDState *s)
633
{
634
    KBDQueue *q;
635

    
636
    s->kbd_write_cmd = -1;
637
    s->mouse_write_cmd = -1;
638
    s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
639
    s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
640
    q = &s->queue;
641
    q->rptr = 0;
642
    q->wptr = 0;
643
    q->count = 0;
644
}
645

    
646
void kbd_init(void)
647
{
648
    KBDState *s = &kbd_state;
649
    
650
    kbd_reset(s);
651
    register_ioport_read(0x60, 1, 1, kbd_read_data, s);
652
    register_ioport_write(0x60, 1, 1, kbd_write_data, s);
653
    register_ioport_read(0x64, 1, 1, kbd_read_status, s);
654
    register_ioport_write(0x64, 1, 1, kbd_write_command, s);
655
}