Statistics
| Branch: | Revision:

root / hw / ps2.c @ 5fafdf24

History | View | Annotate | Download (17 kB)

1
/*
2
 * QEMU PS/2 keyboard/mouse 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 Commands */
33
#define KBD_CMD_SET_LEDS        0xED        /* Set keyboard leds */
34
#define KBD_CMD_ECHO             0xEE
35
#define KBD_CMD_GET_ID                 0xF2        /* get keyboard ID */
36
#define KBD_CMD_SET_RATE        0xF3        /* Set typematic rate */
37
#define KBD_CMD_ENABLE                0xF4        /* Enable scanning */
38
#define KBD_CMD_RESET_DISABLE        0xF5        /* reset and disable scanning */
39
#define KBD_CMD_RESET_ENABLE           0xF6    /* reset and enable scanning */
40
#define KBD_CMD_RESET                0xFF        /* Reset */
41

    
42
/* Keyboard Replies */
43
#define KBD_REPLY_POR                0xAA        /* Power on reset */
44
#define KBD_REPLY_ACK                0xFA        /* Command ACK */
45
#define KBD_REPLY_RESEND        0xFE        /* Command NACK, send the cmd again */
46

    
47
/* Mouse Commands */
48
#define AUX_SET_SCALE11                0xE6        /* Set 1:1 scaling */
49
#define AUX_SET_SCALE21                0xE7        /* Set 2:1 scaling */
50
#define AUX_SET_RES                0xE8        /* Set resolution */
51
#define AUX_GET_SCALE                0xE9        /* Get scaling factor */
52
#define AUX_SET_STREAM                0xEA        /* Set stream mode */
53
#define AUX_POLL                0xEB        /* Poll */
54
#define AUX_RESET_WRAP                0xEC        /* Reset wrap mode */
55
#define AUX_SET_WRAP                0xEE        /* Set wrap mode */
56
#define AUX_SET_REMOTE                0xF0        /* Set remote mode */
57
#define AUX_GET_TYPE                0xF2        /* Get type */
58
#define AUX_SET_SAMPLE                0xF3        /* Set sample rate */
59
#define AUX_ENABLE_DEV                0xF4        /* Enable aux device */
60
#define AUX_DISABLE_DEV                0xF5        /* Disable aux device */
61
#define AUX_SET_DEFAULT                0xF6
62
#define AUX_RESET                0xFF        /* Reset aux device */
63
#define AUX_ACK                        0xFA        /* Command byte ACK. */
64

    
65
#define MOUSE_STATUS_REMOTE     0x40
66
#define MOUSE_STATUS_ENABLED    0x20
67
#define MOUSE_STATUS_SCALE21    0x10
68

    
69
#define PS2_QUEUE_SIZE 256
70

    
71
typedef struct {
72
    uint8_t data[PS2_QUEUE_SIZE];
73
    int rptr, wptr, count;
74
} PS2Queue;
75

    
76
typedef struct {
77
    PS2Queue queue;
78
    int32_t write_cmd;
79
    void (*update_irq)(void *, int);
80
    void *update_arg;
81
} PS2State;
82

    
83
typedef struct {
84
    PS2State common;
85
    int scan_enabled;
86
    /* Qemu uses translated PC scancodes internally.  To avoid multiple
87
       conversions we do the translation (if any) in the PS/2 emulation
88
       not the keyboard controller.  */
89
    int translate;
90
} PS2KbdState;
91

    
92
typedef struct {
93
    PS2State common;
94
    uint8_t mouse_status;
95
    uint8_t mouse_resolution;
96
    uint8_t mouse_sample_rate;
97
    uint8_t mouse_wrap;
98
    uint8_t mouse_type; /* 0 = PS2, 3 = IMPS/2, 4 = IMEX */
99
    uint8_t mouse_detect_state;
100
    int mouse_dx; /* current values, needed for 'poll' mode */
101
    int mouse_dy;
102
    int mouse_dz;
103
    uint8_t mouse_buttons;
104
} PS2MouseState;
105

    
106
/* Table to convert from PC scancodes to raw scancodes.  */
107
static const unsigned char ps2_raw_keycode[128] = {
108
          0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
109
         21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
110
         35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
111
         50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88,  5,  6,  4, 12,  3,
112
         11,  2, 10,  1,  9,119,126,108,117,125,123,107,115,116,121,105,
113
        114,122,112,113,127, 96, 97,120,  7, 15, 23, 31, 39, 47, 55, 63,
114
         71, 79, 86, 94,  8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
115
         19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
116
};
117

    
118
void ps2_queue(void *opaque, int b)
119
{
120
    PS2State *s = (PS2State *)opaque;
121
    PS2Queue *q = &s->queue;
122

    
123
    if (q->count >= PS2_QUEUE_SIZE)
124
        return;
125
    q->data[q->wptr] = b;
126
    if (++q->wptr == PS2_QUEUE_SIZE)
127
        q->wptr = 0;
128
    q->count++;
129
    s->update_irq(s->update_arg, 1);
130
}
131

    
132
static void ps2_put_keycode(void *opaque, int keycode)
133
{
134
    PS2KbdState *s = opaque;
135
    if (!s->translate && keycode < 0xe0)
136
      {
137
        if (keycode & 0x80)
138
            ps2_queue(&s->common, 0xf0);
139
        keycode = ps2_raw_keycode[keycode & 0x7f];
140
      }
141
    ps2_queue(&s->common, keycode);
142
}
143

    
144
uint32_t ps2_read_data(void *opaque)
145
{
146
    PS2State *s = (PS2State *)opaque;
147
    PS2Queue *q;
148
    int val, index;
149
   
150
    q = &s->queue;
151
    if (q->count == 0) {
152
        /* NOTE: if no data left, we return the last keyboard one
153
           (needed for EMM386) */
154
        /* XXX: need a timer to do things correctly */
155
        index = q->rptr - 1;
156
        if (index < 0)
157
            index = PS2_QUEUE_SIZE - 1;
158
        val = q->data[index];
159
    } else {
160
        val = q->data[q->rptr];
161
        if (++q->rptr == PS2_QUEUE_SIZE)
162
            q->rptr = 0;
163
        q->count--;
164
        /* reading deasserts IRQ */
165
        s->update_irq(s->update_arg, 0);
166
        /* reassert IRQs if data left */
167
        s->update_irq(s->update_arg, q->count != 0);
168
    }
169
    return val;
170
}
171

    
172
static void ps2_reset_keyboard(PS2KbdState *s)
173
{
174
    s->scan_enabled = 1;
175
}
176

    
177
void ps2_write_keyboard(void *opaque, int val)
178
{
179
    PS2KbdState *s = (PS2KbdState *)opaque;
180

    
181
    switch(s->common.write_cmd) {
182
    default:
183
    case -1:
184
        switch(val) {
185
        case 0x00:
186
            ps2_queue(&s->common, KBD_REPLY_ACK);
187
            break;
188
        case 0x05:
189
            ps2_queue(&s->common, KBD_REPLY_RESEND);
190
            break;
191
        case KBD_CMD_GET_ID:
192
            ps2_queue(&s->common, KBD_REPLY_ACK);
193
            ps2_queue(&s->common, 0xab);
194
            ps2_queue(&s->common, 0x83);
195
            break;
196
        case KBD_CMD_ECHO:
197
            ps2_queue(&s->common, KBD_CMD_ECHO);
198
            break;
199
        case KBD_CMD_ENABLE:
200
            s->scan_enabled = 1;
201
            ps2_queue(&s->common, KBD_REPLY_ACK);
202
            break;
203
        case KBD_CMD_SET_LEDS:
204
        case KBD_CMD_SET_RATE:
205
            s->common.write_cmd = val;
206
            ps2_queue(&s->common, KBD_REPLY_ACK);
207
            break;
208
        case KBD_CMD_RESET_DISABLE:
209
            ps2_reset_keyboard(s);
210
            s->scan_enabled = 0;
211
            ps2_queue(&s->common, KBD_REPLY_ACK);
212
            break;
213
        case KBD_CMD_RESET_ENABLE:
214
            ps2_reset_keyboard(s);
215
            s->scan_enabled = 1;
216
            ps2_queue(&s->common, KBD_REPLY_ACK);
217
            break;
218
        case KBD_CMD_RESET:
219
            ps2_reset_keyboard(s);
220
            ps2_queue(&s->common, KBD_REPLY_ACK);
221
            ps2_queue(&s->common, KBD_REPLY_POR);
222
            break;
223
        default:
224
            ps2_queue(&s->common, KBD_REPLY_ACK);
225
            break;
226
        }
227
        break;
228
    case KBD_CMD_SET_LEDS:
229
        ps2_queue(&s->common, KBD_REPLY_ACK);
230
        s->common.write_cmd = -1;
231
        break;
232
    case KBD_CMD_SET_RATE:
233
        ps2_queue(&s->common, KBD_REPLY_ACK);
234
        s->common.write_cmd = -1;
235
        break;
236
    }
237
}
238

    
239
/* Set the scancode translation mode.
240
   0 = raw scancodes.
241
   1 = translated scancodes (used by qemu internally).  */
242

    
243
void ps2_keyboard_set_translation(void *opaque, int mode)
244
{
245
    PS2KbdState *s = (PS2KbdState *)opaque;
246
    s->translate = mode;
247
}
248

    
249
static void ps2_mouse_send_packet(PS2MouseState *s)
250
{
251
    unsigned int b;
252
    int dx1, dy1, dz1;
253

    
254
    dx1 = s->mouse_dx;
255
    dy1 = s->mouse_dy;
256
    dz1 = s->mouse_dz;
257
    /* XXX: increase range to 8 bits ? */
258
    if (dx1 > 127)
259
        dx1 = 127;
260
    else if (dx1 < -127)
261
        dx1 = -127;
262
    if (dy1 > 127)
263
        dy1 = 127;
264
    else if (dy1 < -127)
265
        dy1 = -127;
266
    b = 0x08 | ((dx1 < 0) << 4) | ((dy1 < 0) << 5) | (s->mouse_buttons & 0x07);
267
    ps2_queue(&s->common, b);
268
    ps2_queue(&s->common, dx1 & 0xff);
269
    ps2_queue(&s->common, dy1 & 0xff);
270
    /* extra byte for IMPS/2 or IMEX */
271
    switch(s->mouse_type) {
272
    default:
273
        break;
274
    case 3:
275
        if (dz1 > 127)
276
            dz1 = 127;
277
        else if (dz1 < -127)
278
                dz1 = -127;
279
        ps2_queue(&s->common, dz1 & 0xff);
280
        break;
281
    case 4:
282
        if (dz1 > 7)
283
            dz1 = 7;
284
        else if (dz1 < -7)
285
            dz1 = -7;
286
        b = (dz1 & 0x0f) | ((s->mouse_buttons & 0x18) << 1);
287
        ps2_queue(&s->common, b);
288
        break;
289
    }
290

    
291
    /* update deltas */
292
    s->mouse_dx -= dx1;
293
    s->mouse_dy -= dy1;
294
    s->mouse_dz -= dz1;
295
}
296

    
297
static void ps2_mouse_event(void *opaque,
298
                            int dx, int dy, int dz, int buttons_state)
299
{
300
    PS2MouseState *s = opaque;
301

    
302
    /* check if deltas are recorded when disabled */
303
    if (!(s->mouse_status & MOUSE_STATUS_ENABLED))
304
        return;
305

    
306
    s->mouse_dx += dx;
307
    s->mouse_dy -= dy;
308
    s->mouse_dz += dz;
309
    /* XXX: SDL sometimes generates nul events: we delete them */
310
    if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0 &&
311
        s->mouse_buttons == buttons_state)
312
        return;
313
    s->mouse_buttons = buttons_state;
314
   
315
    if (!(s->mouse_status & MOUSE_STATUS_REMOTE) &&
316
        (s->common.queue.count < (PS2_QUEUE_SIZE - 16))) {
317
        for(;;) {
318
            /* if not remote, send event. Multiple events are sent if
319
               too big deltas */
320
            ps2_mouse_send_packet(s);
321
            if (s->mouse_dx == 0 && s->mouse_dy == 0 && s->mouse_dz == 0)
322
                break;
323
        }
324
    }
325
}
326

    
327
void ps2_mouse_fake_event(void *opaque)
328
{
329
    ps2_mouse_event(opaque, 1, 0, 0, 0);
330
}
331

    
332
void ps2_write_mouse(void *opaque, int val)
333
{
334
    PS2MouseState *s = (PS2MouseState *)opaque;
335
#ifdef DEBUG_MOUSE
336
    printf("kbd: write mouse 0x%02x\n", val);
337
#endif
338
    switch(s->common.write_cmd) {
339
    default:
340
    case -1:
341
        /* mouse command */
342
        if (s->mouse_wrap) {
343
            if (val == AUX_RESET_WRAP) {
344
                s->mouse_wrap = 0;
345
                ps2_queue(&s->common, AUX_ACK);
346
                return;
347
            } else if (val != AUX_RESET) {
348
                ps2_queue(&s->common, val);
349
                return;
350
            }
351
        }
352
        switch(val) {
353
        case AUX_SET_SCALE11:
354
            s->mouse_status &= ~MOUSE_STATUS_SCALE21;
355
            ps2_queue(&s->common, AUX_ACK);
356
            break;
357
        case AUX_SET_SCALE21:
358
            s->mouse_status |= MOUSE_STATUS_SCALE21;
359
            ps2_queue(&s->common, AUX_ACK);
360
            break;
361
        case AUX_SET_STREAM:
362
            s->mouse_status &= ~MOUSE_STATUS_REMOTE;
363
            ps2_queue(&s->common, AUX_ACK);
364
            break;
365
        case AUX_SET_WRAP:
366
            s->mouse_wrap = 1;
367
            ps2_queue(&s->common, AUX_ACK);
368
            break;
369
        case AUX_SET_REMOTE:
370
            s->mouse_status |= MOUSE_STATUS_REMOTE;
371
            ps2_queue(&s->common, AUX_ACK);
372
            break;
373
        case AUX_GET_TYPE:
374
            ps2_queue(&s->common, AUX_ACK);
375
            ps2_queue(&s->common, s->mouse_type);
376
            break;
377
        case AUX_SET_RES:
378
        case AUX_SET_SAMPLE:
379
            s->common.write_cmd = val;
380
            ps2_queue(&s->common, AUX_ACK);
381
            break;
382
        case AUX_GET_SCALE:
383
            ps2_queue(&s->common, AUX_ACK);
384
            ps2_queue(&s->common, s->mouse_status);
385
            ps2_queue(&s->common, s->mouse_resolution);
386
            ps2_queue(&s->common, s->mouse_sample_rate);
387
            break;
388
        case AUX_POLL:
389
            ps2_queue(&s->common, AUX_ACK);
390
            ps2_mouse_send_packet(s);
391
            break;
392
        case AUX_ENABLE_DEV:
393
            s->mouse_status |= MOUSE_STATUS_ENABLED;
394
            ps2_queue(&s->common, AUX_ACK);
395
            break;
396
        case AUX_DISABLE_DEV:
397
            s->mouse_status &= ~MOUSE_STATUS_ENABLED;
398
            ps2_queue(&s->common, AUX_ACK);
399
            break;
400
        case AUX_SET_DEFAULT:
401
            s->mouse_sample_rate = 100;
402
            s->mouse_resolution = 2;
403
            s->mouse_status = 0;
404
            ps2_queue(&s->common, AUX_ACK);
405
            break;
406
        case AUX_RESET:
407
            s->mouse_sample_rate = 100;
408
            s->mouse_resolution = 2;
409
            s->mouse_status = 0;
410
            s->mouse_type = 0;
411
            ps2_queue(&s->common, AUX_ACK);
412
            ps2_queue(&s->common, 0xaa);
413
            ps2_queue(&s->common, s->mouse_type);
414
            break;
415
        default:
416
            break;
417
        }
418
        break;
419
    case AUX_SET_SAMPLE:
420
        s->mouse_sample_rate = val;
421
        /* detect IMPS/2 or IMEX */
422
        switch(s->mouse_detect_state) {
423
        default:
424
        case 0:
425
            if (val == 200)
426
                s->mouse_detect_state = 1;
427
            break;
428
        case 1:
429
            if (val == 100)
430
                s->mouse_detect_state = 2;
431
            else if (val == 200)
432
                s->mouse_detect_state = 3;
433
            else
434
                s->mouse_detect_state = 0;
435
            break;
436
        case 2:
437
            if (val == 80)
438
                s->mouse_type = 3; /* IMPS/2 */
439
            s->mouse_detect_state = 0;
440
            break;
441
        case 3:
442
            if (val == 80)
443
                s->mouse_type = 4; /* IMEX */
444
            s->mouse_detect_state = 0;
445
            break;
446
        }
447
        ps2_queue(&s->common, AUX_ACK);
448
        s->common.write_cmd = -1;
449
        break;
450
    case AUX_SET_RES:
451
        s->mouse_resolution = val;
452
        ps2_queue(&s->common, AUX_ACK);
453
        s->common.write_cmd = -1;
454
        break;
455
    }
456
}
457

    
458
static void ps2_reset(void *opaque)
459
{
460
    PS2State *s = (PS2State *)opaque;
461
    PS2Queue *q;
462
    s->write_cmd = -1;
463
    q = &s->queue;
464
    q->rptr = 0;
465
    q->wptr = 0;
466
    q->count = 0;
467
}
468

    
469
static void ps2_common_save (QEMUFile *f, PS2State *s)
470
{
471
    qemu_put_be32s (f, &s->write_cmd);
472
    qemu_put_be32s (f, &s->queue.rptr);
473
    qemu_put_be32s (f, &s->queue.wptr);
474
    qemu_put_be32s (f, &s->queue.count);
475
    qemu_put_buffer (f, s->queue.data, sizeof (s->queue.data));
476
}
477

    
478
static void ps2_common_load (QEMUFile *f, PS2State *s)
479
{
480
    qemu_get_be32s (f, &s->write_cmd);
481
    qemu_get_be32s (f, &s->queue.rptr);
482
    qemu_get_be32s (f, &s->queue.wptr);
483
    qemu_get_be32s (f, &s->queue.count);
484
    qemu_get_buffer (f, s->queue.data, sizeof (s->queue.data));
485
}
486

    
487
static void ps2_kbd_save(QEMUFile* f, void* opaque)
488
{
489
    PS2KbdState *s = (PS2KbdState*)opaque;
490

    
491
    ps2_common_save (f, &s->common);
492
    qemu_put_be32s(f, &s->scan_enabled);
493
    qemu_put_be32s(f, &s->translate);
494
}
495

    
496
static void ps2_mouse_save(QEMUFile* f, void* opaque)
497
{
498
    PS2MouseState *s = (PS2MouseState*)opaque;
499

    
500
    ps2_common_save (f, &s->common);
501
    qemu_put_8s(f, &s->mouse_status);
502
    qemu_put_8s(f, &s->mouse_resolution);
503
    qemu_put_8s(f, &s->mouse_sample_rate);
504
    qemu_put_8s(f, &s->mouse_wrap);
505
    qemu_put_8s(f, &s->mouse_type);
506
    qemu_put_8s(f, &s->mouse_detect_state);
507
    qemu_put_be32s(f, &s->mouse_dx);
508
    qemu_put_be32s(f, &s->mouse_dy);
509
    qemu_put_be32s(f, &s->mouse_dz);
510
    qemu_put_8s(f, &s->mouse_buttons);
511
}
512

    
513
static int ps2_kbd_load(QEMUFile* f, void* opaque, int version_id)
514
{
515
    PS2KbdState *s = (PS2KbdState*)opaque;
516

    
517
    if (version_id != 2)
518
        return -EINVAL;
519

    
520
    ps2_common_load (f, &s->common);
521
    qemu_get_be32s(f, &s->scan_enabled);
522
    qemu_get_be32s(f, &s->translate);
523
    return 0;
524
}
525

    
526
static int ps2_mouse_load(QEMUFile* f, void* opaque, int version_id)
527
{
528
    PS2MouseState *s = (PS2MouseState*)opaque;
529

    
530
    if (version_id != 2)
531
        return -EINVAL;
532

    
533
    ps2_common_load (f, &s->common);
534
    qemu_get_8s(f, &s->mouse_status);
535
    qemu_get_8s(f, &s->mouse_resolution);
536
    qemu_get_8s(f, &s->mouse_sample_rate);
537
    qemu_get_8s(f, &s->mouse_wrap);
538
    qemu_get_8s(f, &s->mouse_type);
539
    qemu_get_8s(f, &s->mouse_detect_state);
540
    qemu_get_be32s(f, &s->mouse_dx);
541
    qemu_get_be32s(f, &s->mouse_dy);
542
    qemu_get_be32s(f, &s->mouse_dz);
543
    qemu_get_8s(f, &s->mouse_buttons);
544
    return 0;
545
}
546

    
547
void *ps2_kbd_init(void (*update_irq)(void *, int), void *update_arg)
548
{
549
    PS2KbdState *s = (PS2KbdState *)qemu_mallocz(sizeof(PS2KbdState));
550

    
551
    s->common.update_irq = update_irq;
552
    s->common.update_arg = update_arg;
553
    ps2_reset(&s->common);
554
    register_savevm("ps2kbd", 0, 2, ps2_kbd_save, ps2_kbd_load, s);
555
    qemu_add_kbd_event_handler(ps2_put_keycode, s);
556
    qemu_register_reset(ps2_reset, &s->common);
557
    return s;
558
}
559

    
560
void *ps2_mouse_init(void (*update_irq)(void *, int), void *update_arg)
561
{
562
    PS2MouseState *s = (PS2MouseState *)qemu_mallocz(sizeof(PS2MouseState));
563

    
564
    s->common.update_irq = update_irq;
565
    s->common.update_arg = update_arg;
566
    ps2_reset(&s->common);
567
    register_savevm("ps2mouse", 0, 2, ps2_mouse_save, ps2_mouse_load, s);
568
    qemu_add_mouse_event_handler(ps2_mouse_event, s, 0, "QEMU PS/2 Mouse");
569
    qemu_register_reset(ps2_reset, &s->common);
570
    return s;
571
}