Statistics
| Branch: | Revision:

root / hw / pckbd.c @ 546fa6ab

History | View | Annotate | Download (20.7 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

    
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
    KBDQueue *q = &s->queue;
149
    int irq12_level, irq1_level;
150

    
151
    irq1_level = 0;    
152
    irq12_level = 0;    
153
    s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
154
    if (q->count != 0) {
155
        s->status |= KBD_STAT_OBF;
156
        if (q->aux[q->rptr]) {
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->queue;
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->aux[q->wptr] = aux;
185
    q->data[q->wptr] = b;
186
    if (++q->wptr == KBD_QUEUE_SIZE)
187
        q->wptr = 0;
188
    q->count++;
189
    kbd_update_irq(s);
190
}
191

    
192
static void pc_kbd_put_keycode(void *opaque, int keycode)
193
{
194
    KBDState *s = opaque;
195
    kbd_queue(s, keycode, 0);
196
}
197

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

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

    
213
#ifdef DEBUG_KBD
214
    printf("kbd: write cmd=0x%02x\n", val);
215
#endif
216
    switch(val) {
217
    case KBD_CCMD_READ_MODE:
218
        kbd_queue(s, s->mode, 0);
219
        break;
220
    case KBD_CCMD_WRITE_MODE:
221
    case KBD_CCMD_WRITE_OBUF:
222
    case KBD_CCMD_WRITE_AUX_OBUF:
223
    case KBD_CCMD_WRITE_MOUSE:
224
    case KBD_CCMD_WRITE_OUTPORT:
225
        s->write_cmd = val;
226
        break;
227
    case KBD_CCMD_MOUSE_DISABLE:
228
        s->mode |= KBD_MODE_DISABLE_MOUSE;
229
        break;
230
    case KBD_CCMD_MOUSE_ENABLE:
231
        s->mode &= ~KBD_MODE_DISABLE_MOUSE;
232
        break;
233
    case KBD_CCMD_TEST_MOUSE:
234
        kbd_queue(s, 0x00, 0);
235
        break;
236
    case KBD_CCMD_SELF_TEST:
237
        s->status |= KBD_STAT_SELFTEST;
238
        kbd_queue(s, 0x55, 0);
239
        break;
240
    case KBD_CCMD_KBD_TEST:
241
        kbd_queue(s, 0x00, 0);
242
        break;
243
    case KBD_CCMD_KBD_DISABLE:
244
        s->mode |= KBD_MODE_DISABLE_KBD;
245
        kbd_update_irq(s);
246
        break;
247
    case KBD_CCMD_KBD_ENABLE:
248
        s->mode &= ~KBD_MODE_DISABLE_KBD;
249
        kbd_update_irq(s);
250
        break;
251
    case KBD_CCMD_READ_INPORT:
252
        kbd_queue(s, 0x00, 0);
253
        break;
254
    case KBD_CCMD_READ_OUTPORT:
255
        /* XXX: check that */
256
#ifdef TARGET_I386
257
        val = 0x01 | (((cpu_single_env->a20_mask >> 20) & 1) << 1);
258
#else
259
        val = 0x01;
260
#endif
261
        if (s->status & KBD_STAT_OBF)
262
            val |= 0x10;
263
        if (s->status & KBD_STAT_MOUSE_OBF)
264
            val |= 0x20;
265
        kbd_queue(s, val, 0);
266
        break;
267
#ifdef TARGET_I386
268
    case KBD_CCMD_ENABLE_A20:
269
        cpu_x86_set_a20(cpu_single_env, 1);
270
        break;
271
    case KBD_CCMD_DISABLE_A20:
272
        cpu_x86_set_a20(cpu_single_env, 0);
273
        break;
274
#endif
275
    case KBD_CCMD_RESET:
276
        qemu_system_reset_request();
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, aux;
292
    
293
    q = &s->queue;
294
    if (q->count == 0) {
295
        /* NOTE: if no data left, we return the last keyboard one
296
           (needed for EMM386) */
297
        /* XXX: need a timer to do things correctly */
298
        index = q->rptr - 1;
299
        if (index < 0)
300
            index = KBD_QUEUE_SIZE - 1;
301
        val = q->data[index];
302
    } else {
303
        aux = q->aux[q->rptr];
304
        val = q->data[q->rptr];
305
        if (++q->rptr == KBD_QUEUE_SIZE)
306
            q->rptr = 0;
307
        q->count--;
308
        /* reading deasserts IRQ */
309
        if (aux)
310
            pic_set_irq(12, 0);
311
        else
312
            pic_set_irq(1, 0);
313
    }
314
    /* reassert IRQs if data left */
315
    kbd_update_irq(s);
316
#ifdef DEBUG_KBD
317
    printf("kbd: read data=0x%02x\n", val);
318
#endif
319
    return val;
320
}
321

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

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

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

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

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

    
435
static void pc_kbd_mouse_event(void *opaque, 
436
                               int dx, int dy, int dz, int buttons_state)
437
{
438
    KBDState *s = opaque;
439

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

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

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

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

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

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

    
630
static void kbd_reset(void *opaque)
631
{
632
    KBDState *s = opaque;
633
    KBDQueue *q;
634

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

    
645
static void kbd_save(QEMUFile* f, void* opaque)
646
{
647
    KBDState *s = (KBDState*)opaque;
648
    
649
    qemu_put_8s(f, &s->write_cmd);
650
    qemu_put_8s(f, &s->status);
651
    qemu_put_8s(f, &s->mode);
652
    qemu_put_be32s(f, &s->kbd_write_cmd);
653
    qemu_put_be32s(f, &s->scan_enabled);
654
    qemu_put_be32s(f, &s->mouse_write_cmd);
655
    qemu_put_8s(f, &s->mouse_status);
656
    qemu_put_8s(f, &s->mouse_resolution);
657
    qemu_put_8s(f, &s->mouse_sample_rate);
658
    qemu_put_8s(f, &s->mouse_wrap);
659
    qemu_put_8s(f, &s->mouse_type);
660
    qemu_put_8s(f, &s->mouse_detect_state);
661
    qemu_put_be32s(f, &s->mouse_dx);
662
    qemu_put_be32s(f, &s->mouse_dy);
663
    qemu_put_be32s(f, &s->mouse_dz);
664
    qemu_put_8s(f, &s->mouse_buttons);
665
}
666

    
667
static int kbd_load(QEMUFile* f, void* opaque, int version_id)
668
{
669
    KBDState *s = (KBDState*)opaque;
670
    
671
    if (version_id != 1)
672
        return -EINVAL;
673
    qemu_get_8s(f, &s->write_cmd);
674
    qemu_get_8s(f, &s->status);
675
    qemu_get_8s(f, &s->mode);
676
    qemu_get_be32s(f, &s->kbd_write_cmd);
677
    qemu_get_be32s(f, &s->scan_enabled);
678
    qemu_get_be32s(f, &s->mouse_write_cmd);
679
    qemu_get_8s(f, &s->mouse_status);
680
    qemu_get_8s(f, &s->mouse_resolution);
681
    qemu_get_8s(f, &s->mouse_sample_rate);
682
    qemu_get_8s(f, &s->mouse_wrap);
683
    qemu_get_8s(f, &s->mouse_type);
684
    qemu_get_8s(f, &s->mouse_detect_state);
685
    qemu_get_be32s(f, &s->mouse_dx);
686
    qemu_get_be32s(f, &s->mouse_dy);
687
    qemu_get_be32s(f, &s->mouse_dz);
688
    qemu_get_8s(f, &s->mouse_buttons);
689
    return 0;
690
}
691

    
692
void kbd_init(void)
693
{
694
    KBDState *s = &kbd_state;
695
    
696
    kbd_reset(s);
697
    register_savevm("pckbd", 0, 1, kbd_save, kbd_load, s);
698
    register_ioport_read(0x60, 1, 1, kbd_read_data, s);
699
    register_ioport_write(0x60, 1, 1, kbd_write_data, s);
700
    register_ioport_read(0x64, 1, 1, kbd_read_status, s);
701
    register_ioport_write(0x64, 1, 1, kbd_write_command, s);
702

    
703
    qemu_add_kbd_event_handler(pc_kbd_put_keycode, s);
704
    qemu_add_mouse_event_handler(pc_kbd_mouse_event, s);
705
    qemu_register_reset(kbd_reset, s);
706
}