qemu

Форк
0
/
pckbd.c 
975 строк · 27.4 Кб
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

25
#include "qemu/osdep.h"
26
#include "qemu/error-report.h"
27
#include "qemu/log.h"
28
#include "qemu/timer.h"
29
#include "qapi/error.h"
30
#include "hw/isa/isa.h"
31
#include "migration/vmstate.h"
32
#include "hw/acpi/acpi_aml_interface.h"
33
#include "hw/input/ps2.h"
34
#include "hw/irq.h"
35
#include "hw/input/i8042.h"
36
#include "hw/qdev-properties.h"
37
#include "sysemu/reset.h"
38
#include "sysemu/runstate.h"
39

40
#include "trace.h"
41

42
/* Keyboard Controller Commands */
43

44
/* Read mode bits */
45
#define KBD_CCMD_READ_MODE         0x20
46
/* Write mode bits */
47
#define KBD_CCMD_WRITE_MODE        0x60
48
/* Get controller version */
49
#define KBD_CCMD_GET_VERSION       0xA1
50
/* Disable mouse interface */
51
#define KBD_CCMD_MOUSE_DISABLE     0xA7
52
/* Enable mouse interface */
53
#define KBD_CCMD_MOUSE_ENABLE      0xA8
54
/* Mouse interface test */
55
#define KBD_CCMD_TEST_MOUSE        0xA9
56
/* Controller self test */
57
#define KBD_CCMD_SELF_TEST         0xAA
58
/* Keyboard interface test */
59
#define KBD_CCMD_KBD_TEST          0xAB
60
/* Keyboard interface disable */
61
#define KBD_CCMD_KBD_DISABLE       0xAD
62
/* Keyboard interface enable */
63
#define KBD_CCMD_KBD_ENABLE        0xAE
64
/* read input port */
65
#define KBD_CCMD_READ_INPORT       0xC0
66
/* read output port */
67
#define KBD_CCMD_READ_OUTPORT      0xD0
68
/* write output port */
69
#define KBD_CCMD_WRITE_OUTPORT     0xD1
70
#define KBD_CCMD_WRITE_OBUF        0xD2
71
/* Write to output buffer as if initiated by the auxiliary device */
72
#define KBD_CCMD_WRITE_AUX_OBUF    0xD3
73
/* Write the following byte to the mouse */
74
#define KBD_CCMD_WRITE_MOUSE       0xD4
75
/* HP vectra only ? */
76
#define KBD_CCMD_DISABLE_A20       0xDD
77
/* HP vectra only ? */
78
#define KBD_CCMD_ENABLE_A20        0xDF
79
/* Pulse bits 3-0 of the output port P2. */
80
#define KBD_CCMD_PULSE_BITS_3_0    0xF0
81
/* Pulse bit 0 of the output port P2 = CPU reset. */
82
#define KBD_CCMD_RESET             0xFE
83
/* Pulse no bits of the output port P2. */
84
#define KBD_CCMD_NO_OP             0xFF
85

86
/* Status Register Bits */
87

88
/* Keyboard output buffer full */
89
#define KBD_STAT_OBF           0x01
90
/* Keyboard input buffer full */
91
#define KBD_STAT_IBF           0x02
92
/* Self test successful */
93
#define KBD_STAT_SELFTEST      0x04
94
/* Last write was a command write (0=data) */
95
#define KBD_STAT_CMD           0x08
96
/* Zero if keyboard locked */
97
#define KBD_STAT_UNLOCKED      0x10
98
/* Mouse output buffer full */
99
#define KBD_STAT_MOUSE_OBF     0x20
100
/* General receive/xmit timeout */
101
#define KBD_STAT_GTO           0x40
102
/* Parity error */
103
#define KBD_STAT_PERR          0x80
104

105
/* Controller Mode Register Bits */
106

107
/* Keyboard data generate IRQ1 */
108
#define KBD_MODE_KBD_INT       0x01
109
/* Mouse data generate IRQ12 */
110
#define KBD_MODE_MOUSE_INT     0x02
111
/* The system flag (?) */
112
#define KBD_MODE_SYS           0x04
113
/* The keylock doesn't affect the keyboard if set */
114
#define KBD_MODE_NO_KEYLOCK    0x08
115
/* Disable keyboard interface */
116
#define KBD_MODE_DISABLE_KBD   0x10
117
/* Disable mouse interface */
118
#define KBD_MODE_DISABLE_MOUSE 0x20
119
/* Scan code conversion to PC format */
120
#define KBD_MODE_KCC           0x40
121
#define KBD_MODE_RFU           0x80
122

123
/* Output Port Bits */
124
#define KBD_OUT_RESET           0x01    /* 1=normal mode, 0=reset */
125
#define KBD_OUT_A20             0x02    /* x86 only */
126
#define KBD_OUT_OBF             0x10    /* Keyboard output buffer full */
127
#define KBD_OUT_MOUSE_OBF       0x20    /* Mouse output buffer full */
128

129
/*
130
 * OSes typically write 0xdd/0xdf to turn the A20 line off and on.
131
 * We make the default value of the outport include these four bits,
132
 * so that the subsection is rarely necessary.
133
 */
134
#define KBD_OUT_ONES            0xcc
135

136
#define KBD_PENDING_KBD_COMPAT  0x01
137
#define KBD_PENDING_AUX_COMPAT  0x02
138
#define KBD_PENDING_CTRL_KBD    0x04
139
#define KBD_PENDING_CTRL_AUX    0x08
140
#define KBD_PENDING_KBD         KBD_MODE_DISABLE_KBD    /* 0x10 */
141
#define KBD_PENDING_AUX         KBD_MODE_DISABLE_MOUSE  /* 0x20 */
142

143
#define KBD_MIGR_TIMER_PENDING  0x1
144

145
#define KBD_OBSRC_KBD           0x01
146
#define KBD_OBSRC_MOUSE         0x02
147
#define KBD_OBSRC_CTRL          0x04
148

149

150
/*
151
 * XXX: not generating the irqs if KBD_MODE_DISABLE_KBD is set may be
152
 * incorrect, but it avoids having to simulate exact delays
153
 */
154
static void kbd_update_irq_lines(KBDState *s)
155
{
156
    int irq_kbd_level, irq_mouse_level;
157

158
    irq_kbd_level = 0;
159
    irq_mouse_level = 0;
160

161
    if (s->status & KBD_STAT_OBF) {
162
        if (s->status & KBD_STAT_MOUSE_OBF) {
163
            if (s->mode & KBD_MODE_MOUSE_INT) {
164
                irq_mouse_level = 1;
165
            }
166
        } else {
167
            if ((s->mode & KBD_MODE_KBD_INT) &&
168
                !(s->mode & KBD_MODE_DISABLE_KBD)) {
169
                irq_kbd_level = 1;
170
            }
171
        }
172
    }
173
    qemu_set_irq(s->irqs[I8042_KBD_IRQ], irq_kbd_level);
174
    qemu_set_irq(s->irqs[I8042_MOUSE_IRQ], irq_mouse_level);
175
}
176

177
static void kbd_deassert_irq(KBDState *s)
178
{
179
    s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
180
    s->outport &= ~(KBD_OUT_OBF | KBD_OUT_MOUSE_OBF);
181
    kbd_update_irq_lines(s);
182
}
183

184
static uint8_t kbd_pending(KBDState *s)
185
{
186
    if (s->extended_state) {
187
        return s->pending & (~s->mode | ~(KBD_PENDING_KBD | KBD_PENDING_AUX));
188
    } else {
189
        return s->pending;
190
    }
191
}
192

193
/* update irq and KBD_STAT_[MOUSE_]OBF */
194
static void kbd_update_irq(KBDState *s)
195
{
196
    uint8_t pending = kbd_pending(s);
197

198
    s->status &= ~(KBD_STAT_OBF | KBD_STAT_MOUSE_OBF);
199
    s->outport &= ~(KBD_OUT_OBF | KBD_OUT_MOUSE_OBF);
200
    if (pending) {
201
        s->status |= KBD_STAT_OBF;
202
        s->outport |= KBD_OUT_OBF;
203
        if (pending & KBD_PENDING_CTRL_KBD) {
204
            s->obsrc = KBD_OBSRC_CTRL;
205
        } else if (pending & KBD_PENDING_CTRL_AUX) {
206
            s->status |= KBD_STAT_MOUSE_OBF;
207
            s->outport |= KBD_OUT_MOUSE_OBF;
208
            s->obsrc = KBD_OBSRC_CTRL;
209
        } else if (pending & KBD_PENDING_KBD) {
210
            s->obsrc = KBD_OBSRC_KBD;
211
        } else {
212
            s->status |= KBD_STAT_MOUSE_OBF;
213
            s->outport |= KBD_OUT_MOUSE_OBF;
214
            s->obsrc = KBD_OBSRC_MOUSE;
215
        }
216
    }
217
    kbd_update_irq_lines(s);
218
}
219

220
static void kbd_safe_update_irq(KBDState *s)
221
{
222
    /*
223
     * with KBD_STAT_OBF set, a call to kbd_read_data() will eventually call
224
     * kbd_update_irq()
225
     */
226
    if (s->status & KBD_STAT_OBF) {
227
        return;
228
    }
229
    /* the throttle timer is pending and will call kbd_update_irq() */
230
    if (s->throttle_timer && timer_pending(s->throttle_timer)) {
231
        return;
232
    }
233
    if (kbd_pending(s)) {
234
        kbd_update_irq(s);
235
    }
236
}
237

238
static void kbd_update_kbd_irq(void *opaque, int level)
239
{
240
    KBDState *s = opaque;
241

242
    if (level) {
243
        s->pending |= KBD_PENDING_KBD;
244
    } else {
245
        s->pending &= ~KBD_PENDING_KBD;
246
    }
247
    kbd_safe_update_irq(s);
248
}
249

250
static void kbd_update_aux_irq(void *opaque, int level)
251
{
252
    KBDState *s = opaque;
253

254
    if (level) {
255
        s->pending |= KBD_PENDING_AUX;
256
    } else {
257
        s->pending &= ~KBD_PENDING_AUX;
258
    }
259
    kbd_safe_update_irq(s);
260
}
261

262
static void kbd_throttle_timeout(void *opaque)
263
{
264
    KBDState *s = opaque;
265

266
    if (kbd_pending(s)) {
267
        kbd_update_irq(s);
268
    }
269
}
270

271
static uint64_t kbd_read_status(void *opaque, hwaddr addr,
272
                                unsigned size)
273
{
274
    KBDState *s = opaque;
275
    int val;
276
    val = s->status;
277
    trace_pckbd_kbd_read_status(val);
278
    return val;
279
}
280

281
static void kbd_queue(KBDState *s, int b, int aux)
282
{
283
    if (s->extended_state) {
284
        s->cbdata = b;
285
        s->pending &= ~KBD_PENDING_CTRL_KBD & ~KBD_PENDING_CTRL_AUX;
286
        s->pending |= aux ? KBD_PENDING_CTRL_AUX : KBD_PENDING_CTRL_KBD;
287
        kbd_safe_update_irq(s);
288
    } else {
289
        ps2_queue(aux ? PS2_DEVICE(&s->ps2mouse) : PS2_DEVICE(&s->ps2kbd), b);
290
    }
291
}
292

293
static uint8_t kbd_dequeue(KBDState *s)
294
{
295
    uint8_t b = s->cbdata;
296

297
    s->pending &= ~KBD_PENDING_CTRL_KBD & ~KBD_PENDING_CTRL_AUX;
298
    if (kbd_pending(s)) {
299
        kbd_update_irq(s);
300
    }
301
    return b;
302
}
303

304
static void outport_write(KBDState *s, uint32_t val)
305
{
306
    trace_pckbd_outport_write(val);
307
    s->outport = val;
308
    qemu_set_irq(s->a20_out, (val >> 1) & 1);
309
    if (!(val & 1)) {
310
        qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
311
    }
312
}
313

314
static void kbd_write_command(void *opaque, hwaddr addr,
315
                              uint64_t val, unsigned size)
316
{
317
    KBDState *s = opaque;
318

319
    trace_pckbd_kbd_write_command(val);
320

321
    /*
322
     * Bits 3-0 of the output port P2 of the keyboard controller may be pulsed
323
     * low for approximately 6 micro seconds. Bits 3-0 of the KBD_CCMD_PULSE
324
     * command specify the output port bits to be pulsed.
325
     * 0: Bit should be pulsed. 1: Bit should not be modified.
326
     * The only useful version of this command is pulsing bit 0,
327
     * which does a CPU reset.
328
     */
329
    if ((val & KBD_CCMD_PULSE_BITS_3_0) == KBD_CCMD_PULSE_BITS_3_0) {
330
        if (!(val & 1)) {
331
            val = KBD_CCMD_RESET;
332
        } else {
333
            val = KBD_CCMD_NO_OP;
334
        }
335
    }
336

337
    switch (val) {
338
    case KBD_CCMD_READ_MODE:
339
        kbd_queue(s, s->mode, 0);
340
        break;
341
    case KBD_CCMD_WRITE_MODE:
342
    case KBD_CCMD_WRITE_OBUF:
343
    case KBD_CCMD_WRITE_AUX_OBUF:
344
    case KBD_CCMD_WRITE_MOUSE:
345
    case KBD_CCMD_WRITE_OUTPORT:
346
        s->write_cmd = val;
347
        break;
348
    case KBD_CCMD_MOUSE_DISABLE:
349
        s->mode |= KBD_MODE_DISABLE_MOUSE;
350
        break;
351
    case KBD_CCMD_MOUSE_ENABLE:
352
        s->mode &= ~KBD_MODE_DISABLE_MOUSE;
353
        kbd_safe_update_irq(s);
354
        break;
355
    case KBD_CCMD_TEST_MOUSE:
356
        kbd_queue(s, 0x00, 0);
357
        break;
358
    case KBD_CCMD_SELF_TEST:
359
        s->status |= KBD_STAT_SELFTEST;
360
        kbd_queue(s, 0x55, 0);
361
        break;
362
    case KBD_CCMD_KBD_TEST:
363
        kbd_queue(s, 0x00, 0);
364
        break;
365
    case KBD_CCMD_KBD_DISABLE:
366
        s->mode |= KBD_MODE_DISABLE_KBD;
367
        break;
368
    case KBD_CCMD_KBD_ENABLE:
369
        s->mode &= ~KBD_MODE_DISABLE_KBD;
370
        kbd_safe_update_irq(s);
371
        break;
372
    case KBD_CCMD_READ_INPORT:
373
        kbd_queue(s, 0x80, 0);
374
        break;
375
    case KBD_CCMD_READ_OUTPORT:
376
        kbd_queue(s, s->outport, 0);
377
        break;
378
    case KBD_CCMD_ENABLE_A20:
379
        qemu_irq_raise(s->a20_out);
380
        s->outport |= KBD_OUT_A20;
381
        break;
382
    case KBD_CCMD_DISABLE_A20:
383
        qemu_irq_lower(s->a20_out);
384
        s->outport &= ~KBD_OUT_A20;
385
        break;
386
    case KBD_CCMD_RESET:
387
        qemu_system_reset_request(SHUTDOWN_CAUSE_GUEST_RESET);
388
        break;
389
    case KBD_CCMD_NO_OP:
390
        /* ignore that */
391
        break;
392
    default:
393
        qemu_log_mask(LOG_GUEST_ERROR,
394
                      "unsupported keyboard cmd=0x%02" PRIx64 "\n", val);
395
        break;
396
    }
397
}
398

399
static uint64_t kbd_read_data(void *opaque, hwaddr addr,
400
                              unsigned size)
401
{
402
    KBDState *s = opaque;
403

404
    if (s->status & KBD_STAT_OBF) {
405
        kbd_deassert_irq(s);
406
        if (s->obsrc & KBD_OBSRC_KBD) {
407
            if (s->throttle_timer) {
408
                timer_mod(s->throttle_timer,
409
                          qemu_clock_get_us(QEMU_CLOCK_VIRTUAL) + 1000);
410
            }
411
            s->obdata = ps2_read_data(PS2_DEVICE(&s->ps2kbd));
412
        } else if (s->obsrc & KBD_OBSRC_MOUSE) {
413
            s->obdata = ps2_read_data(PS2_DEVICE(&s->ps2mouse));
414
        } else if (s->obsrc & KBD_OBSRC_CTRL) {
415
            s->obdata = kbd_dequeue(s);
416
        }
417
    }
418

419
    trace_pckbd_kbd_read_data(s->obdata);
420
    return s->obdata;
421
}
422

423
static void kbd_write_data(void *opaque, hwaddr addr,
424
                           uint64_t val, unsigned size)
425
{
426
    KBDState *s = opaque;
427

428
    trace_pckbd_kbd_write_data(val);
429

430
    switch (s->write_cmd) {
431
    case 0:
432
        ps2_write_keyboard(&s->ps2kbd, val);
433
        /* sending data to the keyboard reenables PS/2 communication */
434
        s->mode &= ~KBD_MODE_DISABLE_KBD;
435
        kbd_safe_update_irq(s);
436
        break;
437
    case KBD_CCMD_WRITE_MODE:
438
        s->mode = val;
439
        ps2_keyboard_set_translation(&s->ps2kbd,
440
                                     (s->mode & KBD_MODE_KCC) != 0);
441
        /*
442
         * a write to the mode byte interrupt enable flags directly updates
443
         * the irq lines
444
         */
445
        kbd_update_irq_lines(s);
446
        /*
447
         * a write to the mode byte disable interface flags may raise
448
         * an irq if there is pending data in the PS/2 queues.
449
         */
450
        kbd_safe_update_irq(s);
451
        break;
452
    case KBD_CCMD_WRITE_OBUF:
453
        kbd_queue(s, val, 0);
454
        break;
455
    case KBD_CCMD_WRITE_AUX_OBUF:
456
        kbd_queue(s, val, 1);
457
        break;
458
    case KBD_CCMD_WRITE_OUTPORT:
459
        outport_write(s, val);
460
        break;
461
    case KBD_CCMD_WRITE_MOUSE:
462
        ps2_write_mouse(&s->ps2mouse, val);
463
        /* sending data to the mouse reenables PS/2 communication */
464
        s->mode &= ~KBD_MODE_DISABLE_MOUSE;
465
        kbd_safe_update_irq(s);
466
        break;
467
    default:
468
        break;
469
    }
470
    s->write_cmd = 0;
471
}
472

473
static void kbd_reset(void *opaque)
474
{
475
    KBDState *s = opaque;
476

477
    s->mode = KBD_MODE_KBD_INT | KBD_MODE_MOUSE_INT;
478
    s->status = KBD_STAT_CMD | KBD_STAT_UNLOCKED;
479
    s->outport = KBD_OUT_RESET | KBD_OUT_A20 | KBD_OUT_ONES;
480
    s->pending = 0;
481
    kbd_deassert_irq(s);
482
    if (s->throttle_timer) {
483
        timer_del(s->throttle_timer);
484
    }
485
}
486

487
static uint8_t kbd_outport_default(KBDState *s)
488
{
489
    return KBD_OUT_RESET | KBD_OUT_A20 | KBD_OUT_ONES
490
           | (s->status & KBD_STAT_OBF ? KBD_OUT_OBF : 0)
491
           | (s->status & KBD_STAT_MOUSE_OBF ? KBD_OUT_MOUSE_OBF : 0);
492
}
493

494
static int kbd_outport_post_load(void *opaque, int version_id)
495
{
496
    KBDState *s = opaque;
497
    s->outport_present = true;
498
    return 0;
499
}
500

501
static bool kbd_outport_needed(void *opaque)
502
{
503
    KBDState *s = opaque;
504
    return s->outport != kbd_outport_default(s);
505
}
506

507
static const VMStateDescription vmstate_kbd_outport = {
508
    .name = "pckbd_outport",
509
    .version_id = 1,
510
    .minimum_version_id = 1,
511
    .post_load = kbd_outport_post_load,
512
    .needed = kbd_outport_needed,
513
    .fields = (const VMStateField[]) {
514
        VMSTATE_UINT8(outport, KBDState),
515
        VMSTATE_END_OF_LIST()
516
    }
517
};
518

519
static int kbd_extended_state_pre_save(void *opaque)
520
{
521
    KBDState *s = opaque;
522

523
    s->migration_flags = 0;
524
    if (s->throttle_timer && timer_pending(s->throttle_timer)) {
525
        s->migration_flags |= KBD_MIGR_TIMER_PENDING;
526
    }
527

528
    return 0;
529
}
530

531
static int kbd_extended_state_post_load(void *opaque, int version_id)
532
{
533
    KBDState *s = opaque;
534

535
    if (s->migration_flags & KBD_MIGR_TIMER_PENDING) {
536
        kbd_throttle_timeout(s);
537
    }
538
    s->extended_state_loaded = true;
539

540
    return 0;
541
}
542

543
static bool kbd_extended_state_needed(void *opaque)
544
{
545
    KBDState *s = opaque;
546

547
    return s->extended_state;
548
}
549

550
static const VMStateDescription vmstate_kbd_extended_state = {
551
    .name = "pckbd/extended_state",
552
    .post_load = kbd_extended_state_post_load,
553
    .pre_save = kbd_extended_state_pre_save,
554
    .needed = kbd_extended_state_needed,
555
    .fields = (const VMStateField[]) {
556
        VMSTATE_UINT32(migration_flags, KBDState),
557
        VMSTATE_UINT32(obsrc, KBDState),
558
        VMSTATE_UINT8(obdata, KBDState),
559
        VMSTATE_UINT8(cbdata, KBDState),
560
        VMSTATE_END_OF_LIST()
561
    }
562
};
563

564
static int kbd_pre_save(void *opaque)
565
{
566
    KBDState *s = opaque;
567

568
    if (s->extended_state) {
569
        s->pending_tmp = s->pending;
570
    } else {
571
        s->pending_tmp = 0;
572
        if (s->pending & KBD_PENDING_KBD) {
573
            s->pending_tmp |= KBD_PENDING_KBD_COMPAT;
574
        }
575
        if (s->pending & KBD_PENDING_AUX) {
576
            s->pending_tmp |= KBD_PENDING_AUX_COMPAT;
577
        }
578
    }
579
    return 0;
580
}
581

582
static int kbd_pre_load(void *opaque)
583
{
584
    KBDState *s = opaque;
585

586
    s->outport_present = false;
587
    s->extended_state_loaded = false;
588
    return 0;
589
}
590

591
static int kbd_post_load(void *opaque, int version_id)
592
{
593
    KBDState *s = opaque;
594
    if (!s->outport_present) {
595
        s->outport = kbd_outport_default(s);
596
    }
597
    s->pending = s->pending_tmp;
598
    if (!s->extended_state_loaded) {
599
        s->obsrc = s->status & KBD_STAT_OBF ?
600
            (s->status & KBD_STAT_MOUSE_OBF ? KBD_OBSRC_MOUSE : KBD_OBSRC_KBD) :
601
            0;
602
        if (s->pending & KBD_PENDING_KBD_COMPAT) {
603
            s->pending |= KBD_PENDING_KBD;
604
        }
605
        if (s->pending & KBD_PENDING_AUX_COMPAT) {
606
            s->pending |= KBD_PENDING_AUX;
607
        }
608
    }
609
    /* clear all unused flags */
610
    s->pending &= KBD_PENDING_CTRL_KBD | KBD_PENDING_CTRL_AUX |
611
                  KBD_PENDING_KBD | KBD_PENDING_AUX;
612
    return 0;
613
}
614

615
static const VMStateDescription vmstate_kbd = {
616
    .name = "pckbd",
617
    .version_id = 3,
618
    .minimum_version_id = 3,
619
    .pre_load = kbd_pre_load,
620
    .post_load = kbd_post_load,
621
    .pre_save = kbd_pre_save,
622
    .fields = (const VMStateField[]) {
623
        VMSTATE_UINT8(write_cmd, KBDState),
624
        VMSTATE_UINT8(status, KBDState),
625
        VMSTATE_UINT8(mode, KBDState),
626
        VMSTATE_UINT8(pending_tmp, KBDState),
627
        VMSTATE_END_OF_LIST()
628
    },
629
    .subsections = (const VMStateDescription * const []) {
630
        &vmstate_kbd_outport,
631
        &vmstate_kbd_extended_state,
632
        NULL
633
    }
634
};
635

636
/* Memory mapped interface */
637
static uint64_t kbd_mm_readfn(void *opaque, hwaddr addr, unsigned size)
638
{
639
    KBDState *s = opaque;
640

641
    if (addr & s->mask) {
642
        return kbd_read_status(s, 0, 1) & 0xff;
643
    } else {
644
        return kbd_read_data(s, 0, 1) & 0xff;
645
    }
646
}
647

648
static void kbd_mm_writefn(void *opaque, hwaddr addr,
649
                           uint64_t value, unsigned size)
650
{
651
    KBDState *s = opaque;
652

653
    if (addr & s->mask) {
654
        kbd_write_command(s, 0, value & 0xff, 1);
655
    } else {
656
        kbd_write_data(s, 0, value & 0xff, 1);
657
    }
658
}
659

660

661
static const MemoryRegionOps i8042_mmio_ops = {
662
    .read = kbd_mm_readfn,
663
    .write = kbd_mm_writefn,
664
    .valid.min_access_size = 1,
665
    .valid.max_access_size = 4,
666
    .endianness = DEVICE_NATIVE_ENDIAN,
667
};
668

669
static void i8042_mmio_set_kbd_irq(void *opaque, int n, int level)
670
{
671
    MMIOKBDState *s = I8042_MMIO(opaque);
672
    KBDState *ks = &s->kbd;
673

674
    kbd_update_kbd_irq(ks, level);
675
}
676

677
static void i8042_mmio_set_mouse_irq(void *opaque, int n, int level)
678
{
679
    MMIOKBDState *s = I8042_MMIO(opaque);
680
    KBDState *ks = &s->kbd;
681

682
    kbd_update_aux_irq(ks, level);
683
}
684

685
static void i8042_mmio_reset(DeviceState *dev)
686
{
687
    MMIOKBDState *s = I8042_MMIO(dev);
688
    KBDState *ks = &s->kbd;
689

690
    kbd_reset(ks);
691
}
692

693
static void i8042_mmio_realize(DeviceState *dev, Error **errp)
694
{
695
    MMIOKBDState *s = I8042_MMIO(dev);
696
    KBDState *ks = &s->kbd;
697

698
    memory_region_init_io(&s->region, OBJECT(dev), &i8042_mmio_ops, ks,
699
                          "i8042", s->size);
700

701
    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &s->region);
702

703
    if (!sysbus_realize(SYS_BUS_DEVICE(&ks->ps2kbd), errp)) {
704
        return;
705
    }
706

707
    if (!sysbus_realize(SYS_BUS_DEVICE(&ks->ps2mouse), errp)) {
708
        return;
709
    }
710

711
    qdev_connect_gpio_out(DEVICE(&ks->ps2kbd), PS2_DEVICE_IRQ,
712
                          qdev_get_gpio_in_named(dev, "ps2-kbd-input-irq",
713
                                                 0));
714

715
    qdev_connect_gpio_out(DEVICE(&ks->ps2mouse), PS2_DEVICE_IRQ,
716
                          qdev_get_gpio_in_named(dev, "ps2-mouse-input-irq",
717
                                                 0));
718
}
719

720
static void i8042_mmio_init(Object *obj)
721
{
722
    MMIOKBDState *s = I8042_MMIO(obj);
723
    KBDState *ks = &s->kbd;
724

725
    ks->extended_state = true;
726

727
    object_initialize_child(obj, "ps2kbd", &ks->ps2kbd, TYPE_PS2_KBD_DEVICE);
728
    object_initialize_child(obj, "ps2mouse", &ks->ps2mouse,
729
                            TYPE_PS2_MOUSE_DEVICE);
730

731
    qdev_init_gpio_out(DEVICE(obj), ks->irqs, 2);
732
    qdev_init_gpio_in_named(DEVICE(obj), i8042_mmio_set_kbd_irq,
733
                            "ps2-kbd-input-irq", 1);
734
    qdev_init_gpio_in_named(DEVICE(obj), i8042_mmio_set_mouse_irq,
735
                            "ps2-mouse-input-irq", 1);
736
}
737

738
static Property i8042_mmio_properties[] = {
739
    DEFINE_PROP_UINT64("mask", MMIOKBDState, kbd.mask, UINT64_MAX),
740
    DEFINE_PROP_UINT32("size", MMIOKBDState, size, -1),
741
    DEFINE_PROP_END_OF_LIST(),
742
};
743

744
static const VMStateDescription vmstate_kbd_mmio = {
745
    .name = "pckbd-mmio",
746
    .version_id = 1,
747
    .minimum_version_id = 1,
748
    .fields = (const VMStateField[]) {
749
        VMSTATE_STRUCT(kbd, MMIOKBDState, 0, vmstate_kbd, KBDState),
750
        VMSTATE_END_OF_LIST()
751
    }
752
};
753

754
static void i8042_mmio_class_init(ObjectClass *klass, void *data)
755
{
756
    DeviceClass *dc = DEVICE_CLASS(klass);
757

758
    dc->realize = i8042_mmio_realize;
759
    dc->reset = i8042_mmio_reset;
760
    dc->vmsd = &vmstate_kbd_mmio;
761
    device_class_set_props(dc, i8042_mmio_properties);
762
    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
763
}
764

765
static const TypeInfo i8042_mmio_info = {
766
    .name          = TYPE_I8042_MMIO,
767
    .parent        = TYPE_SYS_BUS_DEVICE,
768
    .instance_init = i8042_mmio_init,
769
    .instance_size = sizeof(MMIOKBDState),
770
    .class_init    = i8042_mmio_class_init
771
};
772

773
void i8042_isa_mouse_fake_event(ISAKBDState *isa)
774
{
775
    KBDState *s = &isa->kbd;
776

777
    ps2_mouse_fake_event(&s->ps2mouse);
778
}
779

780
static const VMStateDescription vmstate_kbd_isa = {
781
    .name = "pckbd",
782
    .version_id = 3,
783
    .minimum_version_id = 3,
784
    .fields = (const VMStateField[]) {
785
        VMSTATE_STRUCT(kbd, ISAKBDState, 0, vmstate_kbd, KBDState),
786
        VMSTATE_END_OF_LIST()
787
    }
788
};
789

790
static const MemoryRegionOps i8042_data_ops = {
791
    .read = kbd_read_data,
792
    .write = kbd_write_data,
793
    .impl = {
794
        .min_access_size = 1,
795
        .max_access_size = 1,
796
    },
797
    .endianness = DEVICE_LITTLE_ENDIAN,
798
};
799

800
static const MemoryRegionOps i8042_cmd_ops = {
801
    .read = kbd_read_status,
802
    .write = kbd_write_command,
803
    .impl = {
804
        .min_access_size = 1,
805
        .max_access_size = 1,
806
    },
807
    .endianness = DEVICE_LITTLE_ENDIAN,
808
};
809

810
static void i8042_set_kbd_irq(void *opaque, int n, int level)
811
{
812
    ISAKBDState *s = I8042(opaque);
813
    KBDState *ks = &s->kbd;
814

815
    kbd_update_kbd_irq(ks, level);
816
}
817

818
static void i8042_set_mouse_irq(void *opaque, int n, int level)
819
{
820
    ISAKBDState *s = I8042(opaque);
821
    KBDState *ks = &s->kbd;
822

823
    kbd_update_aux_irq(ks, level);
824
}
825

826

827
static void i8042_reset(DeviceState *dev)
828
{
829
    ISAKBDState *s = I8042(dev);
830
    KBDState *ks = &s->kbd;
831

832
    kbd_reset(ks);
833
}
834

835
static void i8042_initfn(Object *obj)
836
{
837
    ISAKBDState *isa_s = I8042(obj);
838
    KBDState *s = &isa_s->kbd;
839

840
    memory_region_init_io(isa_s->io + 0, obj, &i8042_data_ops, s,
841
                          "i8042-data", 1);
842
    memory_region_init_io(isa_s->io + 1, obj, &i8042_cmd_ops, s,
843
                          "i8042-cmd", 1);
844

845
    object_initialize_child(obj, "ps2kbd", &s->ps2kbd, TYPE_PS2_KBD_DEVICE);
846
    object_initialize_child(obj, "ps2mouse", &s->ps2mouse,
847
                            TYPE_PS2_MOUSE_DEVICE);
848

849
    qdev_init_gpio_out_named(DEVICE(obj), &s->a20_out, I8042_A20_LINE, 1);
850

851
    qdev_init_gpio_out(DEVICE(obj), s->irqs, 2);
852
    qdev_init_gpio_in_named(DEVICE(obj), i8042_set_kbd_irq,
853
                            "ps2-kbd-input-irq", 1);
854
    qdev_init_gpio_in_named(DEVICE(obj), i8042_set_mouse_irq,
855
                            "ps2-mouse-input-irq", 1);
856
}
857

858
static void i8042_realizefn(DeviceState *dev, Error **errp)
859
{
860
    ISADevice *isadev = ISA_DEVICE(dev);
861
    ISAKBDState *isa_s = I8042(dev);
862
    KBDState *s = &isa_s->kbd;
863

864
    if (isa_s->kbd_irq >= ISA_NUM_IRQS) {
865
        error_setg(errp, "Maximum value for \"kbd-irq\" is: %u",
866
                   ISA_NUM_IRQS - 1);
867
        return;
868
    }
869

870
    if (isa_s->mouse_irq >= ISA_NUM_IRQS) {
871
        error_setg(errp, "Maximum value for \"mouse-irq\" is: %u",
872
                   ISA_NUM_IRQS - 1);
873
        return;
874
    }
875

876
    isa_connect_gpio_out(isadev, I8042_KBD_IRQ, isa_s->kbd_irq);
877
    isa_connect_gpio_out(isadev, I8042_MOUSE_IRQ, isa_s->mouse_irq);
878

879
    isa_register_ioport(isadev, isa_s->io + 0, 0x60);
880
    isa_register_ioport(isadev, isa_s->io + 1, 0x64);
881

882
    if (!sysbus_realize(SYS_BUS_DEVICE(&s->ps2kbd), errp)) {
883
        return;
884
    }
885

886
    qdev_connect_gpio_out(DEVICE(&s->ps2kbd), PS2_DEVICE_IRQ,
887
                          qdev_get_gpio_in_named(dev, "ps2-kbd-input-irq",
888
                                                 0));
889

890
    if (!sysbus_realize(SYS_BUS_DEVICE(&s->ps2mouse), errp)) {
891
        return;
892
    }
893

894
    qdev_connect_gpio_out(DEVICE(&s->ps2mouse), PS2_DEVICE_IRQ,
895
                          qdev_get_gpio_in_named(dev, "ps2-mouse-input-irq",
896
                                                 0));
897

898
    if (isa_s->kbd_throttle && !isa_s->kbd.extended_state) {
899
        warn_report(TYPE_I8042 ": can't enable kbd-throttle without"
900
                    " extended-state, disabling kbd-throttle");
901
    } else if (isa_s->kbd_throttle) {
902
        s->throttle_timer = timer_new_us(QEMU_CLOCK_VIRTUAL,
903
                                         kbd_throttle_timeout, s);
904
    }
905
}
906

907
static void i8042_build_aml(AcpiDevAmlIf *adev, Aml *scope)
908
{
909
    ISAKBDState *isa_s = I8042(adev);
910
    Aml *kbd;
911
    Aml *mou;
912
    Aml *crs;
913

914
    crs = aml_resource_template();
915
    aml_append(crs, aml_io(AML_DECODE16, 0x0060, 0x0060, 0x01, 0x01));
916
    aml_append(crs, aml_io(AML_DECODE16, 0x0064, 0x0064, 0x01, 0x01));
917
    aml_append(crs, aml_irq_no_flags(isa_s->kbd_irq));
918

919
    kbd = aml_device("KBD");
920
    aml_append(kbd, aml_name_decl("_HID", aml_eisaid("PNP0303")));
921
    aml_append(kbd, aml_name_decl("_STA", aml_int(0xf)));
922
    aml_append(kbd, aml_name_decl("_CRS", crs));
923

924
    crs = aml_resource_template();
925
    aml_append(crs, aml_irq_no_flags(isa_s->mouse_irq));
926

927
    mou = aml_device("MOU");
928
    aml_append(mou, aml_name_decl("_HID", aml_eisaid("PNP0F13")));
929
    aml_append(mou, aml_name_decl("_STA", aml_int(0xf)));
930
    aml_append(mou, aml_name_decl("_CRS", crs));
931

932
    aml_append(scope, kbd);
933
    aml_append(scope, mou);
934
}
935

936
static Property i8042_properties[] = {
937
    DEFINE_PROP_BOOL("extended-state", ISAKBDState, kbd.extended_state, true),
938
    DEFINE_PROP_BOOL("kbd-throttle", ISAKBDState, kbd_throttle, false),
939
    DEFINE_PROP_UINT8("kbd-irq", ISAKBDState, kbd_irq, 1),
940
    DEFINE_PROP_UINT8("mouse-irq", ISAKBDState, mouse_irq, 12),
941
    DEFINE_PROP_END_OF_LIST(),
942
};
943

944
static void i8042_class_initfn(ObjectClass *klass, void *data)
945
{
946
    DeviceClass *dc = DEVICE_CLASS(klass);
947
    AcpiDevAmlIfClass *adevc = ACPI_DEV_AML_IF_CLASS(klass);
948

949
    device_class_set_props(dc, i8042_properties);
950
    dc->reset = i8042_reset;
951
    dc->realize = i8042_realizefn;
952
    dc->vmsd = &vmstate_kbd_isa;
953
    adevc->build_dev_aml = i8042_build_aml;
954
    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
955
}
956

957
static const TypeInfo i8042_info = {
958
    .name          = TYPE_I8042,
959
    .parent        = TYPE_ISA_DEVICE,
960
    .instance_size = sizeof(ISAKBDState),
961
    .instance_init = i8042_initfn,
962
    .class_init    = i8042_class_initfn,
963
    .interfaces = (InterfaceInfo[]) {
964
        { TYPE_ACPI_DEV_AML_IF },
965
        { },
966
    },
967
};
968

969
static void i8042_register_types(void)
970
{
971
    type_register_static(&i8042_info);
972
    type_register_static(&i8042_mmio_info);
973
}
974

975
type_init(i8042_register_types)
976

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.