Statistics
| Branch: | Revision:

root / hw / pckbd.c @ 92cb7d54

History | View | Annotate | Download (19.2 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 data[KBD_QUEUE_SIZE];
115
    int rptr, wptr, count;
116
} KBDQueue;
117

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

    
140
KBDState kbd_state;
141
int reset_requested;
142

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

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

    
170
static void kbd_queue(KBDState *s, int b, int aux)
171
{
172
    KBDQueue *q = &s->queues[aux];
173

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

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

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

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

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

    
287
static uint32_t kbd_read_data(void *opaque, uint32_t addr)
288
{
289
    KBDState *s = opaque;
290
    KBDQueue *q;
291
    int val, index;
292
    
293
    q = &s->queues[1]; /* first check AUX data */
294
    if (q->count == 0)
295
        q = &s->queues[0]; /* then check KBD data */
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
        q = &s->queues[0];
301
        index = q->rptr - 1;
302
        if (index < 0)
303
            index = KBD_QUEUE_SIZE - 1;
304
        val = q->data[index];
305
    } else {
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 (q == &s->queues[0])
312
            pic_set_irq(1, 0);
313
        else
314
            pic_set_irq(12, 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->queues[1].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
    int i;
636

    
637
    s->kbd_write_cmd = -1;
638
    s->mouse_write_cmd = -1;
639
    s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
640
    s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
641
    for(i = 0; i < 2; i++) {
642
        q = &s->queues[i];
643
        q->rptr = 0;
644
        q->wptr = 0;
645
        q->count = 0;
646
    }
647
}
648

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