Statistics
| Branch: | Revision:

root / hw / pckbd.c @ 4e3e9d0b

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 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
static void pc_kbd_put_keycode(void *opaque, int keycode)
194
{
195
    KBDState *s = opaque;
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
static void pc_kbd_mouse_event(void *opaque, 
438
                               int dx, int dy, int dz, int buttons_state)
439
{
440
    KBDState *s = opaque;
441

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

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

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

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

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

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

    
633
void kbd_reset(KBDState *s)
634
{
635
    KBDQueue *q;
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
    q = &s->queue;
642
    q->rptr = 0;
643
    q->wptr = 0;
644
    q->count = 0;
645
}
646

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

    
657
    qemu_add_kbd_event_handler(pc_kbd_put_keycode, s);
658
    qemu_add_mouse_event_handler(pc_kbd_mouse_event, s);
659
}