1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
3 *
4 * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
5 * Copyright (c) 2015 Nahanni Systems Inc.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include <sys/types.h>
31
32 #include <machine/vmm.h>
33 #include <machine/vmm_snapshot.h>
34
35 #include <vmmapi.h>
36
37 #include <assert.h>
38 #include <errno.h>
39 #include <stdbool.h>
40 #include <stdlib.h>
41 #include <stdio.h>
42 #include <string.h>
43 #include <unistd.h>
44 #include <pthread.h>
45 #include <pthread_np.h>
46
47 #include "acpi.h"
48 #include "atkbdc.h"
49 #include "inout.h"
50 #include "pci_emul.h"
51 #include "pci_irq.h"
52 #include "pci_lpc.h"
53 #include "ps2kbd.h"
54 #include "ps2mouse.h"
55
56 #define KBD_DATA_PORT 0x60
57
58 #define KBD_STS_CTL_PORT 0x64
59
60 #define KBDC_RESET 0xfe
61
62 #define KBD_DEV_IRQ 1
63 #define AUX_DEV_IRQ 12
64
65 /* controller commands */
66 #define KBDC_SET_COMMAND_BYTE 0x60
67 #define KBDC_GET_COMMAND_BYTE 0x20
68 #define KBDC_DISABLE_AUX_PORT 0xa7
69 #define KBDC_ENABLE_AUX_PORT 0xa8
70 #define KBDC_TEST_AUX_PORT 0xa9
71 #define KBDC_TEST_CTRL 0xaa
72 #define KBDC_TEST_KBD_PORT 0xab
73 #define KBDC_DISABLE_KBD_PORT 0xad
74 #define KBDC_ENABLE_KBD_PORT 0xae
75 #define KBDC_READ_INPORT 0xc0
76 #define KBDC_READ_OUTPORT 0xd0
77 #define KBDC_WRITE_OUTPORT 0xd1
78 #define KBDC_WRITE_KBD_OUTBUF 0xd2
79 #define KBDC_WRITE_AUX_OUTBUF 0xd3
80 #define KBDC_WRITE_TO_AUX 0xd4
81
82 /* controller command byte (set by KBDC_SET_COMMAND_BYTE) */
83 #define KBD_TRANSLATION 0x40
84 #define KBD_SYS_FLAG_BIT 0x04
85 #define KBD_DISABLE_KBD_PORT 0x10
86 #define KBD_DISABLE_AUX_PORT 0x20
87 #define KBD_ENABLE_AUX_INT 0x02
88 #define KBD_ENABLE_KBD_INT 0x01
89 #define KBD_KBD_CONTROL_BITS (KBD_DISABLE_KBD_PORT | KBD_ENABLE_KBD_INT)
90 #define KBD_AUX_CONTROL_BITS (KBD_DISABLE_AUX_PORT | KBD_ENABLE_AUX_INT)
91
92 /* controller status bits */
93 #define KBDS_KBD_BUFFER_FULL 0x01
94 #define KBDS_SYS_FLAG 0x04
95 #define KBDS_CTRL_FLAG 0x08
96 #define KBDS_AUX_BUFFER_FULL 0x20
97
98 /* controller output port */
99 #define KBDO_KBD_OUTFULL 0x10
100 #define KBDO_AUX_OUTFULL 0x20
101
102 #define RAMSZ 32
103 #define FIFOSZ 15
104 #define CTRL_CMD_FLAG 0x8000
105
106 struct kbd_dev {
107 bool irq_active;
108 int irq;
109
110 uint8_t buffer[FIFOSZ];
111 int brd, bwr;
112 int bcnt;
113 };
114
115 struct aux_dev {
116 bool irq_active;
117 int irq;
118 };
119
120 struct atkbdc_softc {
121 struct vmctx *ctx;
122 pthread_mutex_t mtx;
123
124 struct ps2kbd_softc *ps2kbd_sc;
125 struct ps2mouse_softc *ps2mouse_sc;
126
127 uint8_t status; /* status register */
128 uint8_t outport; /* controller output port */
129 uint8_t ram[RAMSZ]; /* byte0 = controller config */
130
131 uint32_t curcmd; /* current command for next byte */
132 uint32_t ctrlbyte;
133
134 struct kbd_dev kbd;
135 struct aux_dev aux;
136 };
137
138 #ifdef BHYVE_SNAPSHOT
139 static struct atkbdc_softc *atkbdc_sc = NULL;
140 #endif
141
142 static void
atkbdc_assert_kbd_intr(struct atkbdc_softc * sc)143 atkbdc_assert_kbd_intr(struct atkbdc_softc *sc)
144 {
145 if ((sc->ram[0] & KBD_ENABLE_KBD_INT) != 0) {
146 sc->kbd.irq_active = true;
147 vm_isa_pulse_irq(sc->ctx, sc->kbd.irq, sc->kbd.irq);
148 }
149 }
150
151 static void
atkbdc_assert_aux_intr(struct atkbdc_softc * sc)152 atkbdc_assert_aux_intr(struct atkbdc_softc *sc)
153 {
154 if ((sc->ram[0] & KBD_ENABLE_AUX_INT) != 0) {
155 sc->aux.irq_active = true;
156 vm_isa_pulse_irq(sc->ctx, sc->aux.irq, sc->aux.irq);
157 }
158 }
159
160 static int
atkbdc_kbd_queue_data(struct atkbdc_softc * sc,uint8_t val)161 atkbdc_kbd_queue_data(struct atkbdc_softc *sc, uint8_t val)
162 {
163 assert(pthread_mutex_isowned_np(&sc->mtx));
164
165 if (sc->kbd.bcnt < FIFOSZ) {
166 sc->kbd.buffer[sc->kbd.bwr] = val;
167 sc->kbd.bwr = (sc->kbd.bwr + 1) % FIFOSZ;
168 sc->kbd.bcnt++;
169 sc->status |= KBDS_KBD_BUFFER_FULL;
170 sc->outport |= KBDO_KBD_OUTFULL;
171 } else {
172 printf("atkbd data buffer full\n");
173 }
174
175 return (sc->kbd.bcnt < FIFOSZ);
176 }
177
178 static void
atkbdc_kbd_read(struct atkbdc_softc * sc)179 atkbdc_kbd_read(struct atkbdc_softc *sc)
180 {
181 const uint8_t translation[256] = {
182 0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58,
183 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59,
184 0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a,
185 0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b,
186 0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c,
187 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d,
188 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e,
189 0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f,
190 0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60,
191 0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61,
192 0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e,
193 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76,
194 0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b,
195 0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f,
196 0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45,
197 0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54,
198 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87,
199 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
200 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
201 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
202 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
203 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
204 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
205 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
206 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
207 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
208 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
209 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
210 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
211 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
212 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
213 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
214 };
215 uint8_t val;
216 uint8_t release = 0;
217
218 assert(pthread_mutex_isowned_np(&sc->mtx));
219
220 if (sc->ram[0] & KBD_TRANSLATION) {
221 while (ps2kbd_read(sc->ps2kbd_sc, &val) != -1) {
222 if (val == 0xf0) {
223 release = 0x80;
224 continue;
225 } else {
226 val = translation[val] | release;
227 }
228 atkbdc_kbd_queue_data(sc, val);
229 break;
230 }
231 } else {
232 while (sc->kbd.bcnt < FIFOSZ) {
233 if (ps2kbd_read(sc->ps2kbd_sc, &val) != -1)
234 atkbdc_kbd_queue_data(sc, val);
235 else
236 break;
237 }
238 }
239
240 if (((sc->ram[0] & KBD_DISABLE_AUX_PORT) ||
241 ps2mouse_fifocnt(sc->ps2mouse_sc) == 0) && sc->kbd.bcnt > 0)
242 atkbdc_assert_kbd_intr(sc);
243 }
244
245 static void
atkbdc_aux_poll(struct atkbdc_softc * sc)246 atkbdc_aux_poll(struct atkbdc_softc *sc)
247 {
248 if (ps2mouse_fifocnt(sc->ps2mouse_sc) > 0) {
249 sc->status |= KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL;
250 sc->outport |= KBDO_AUX_OUTFULL;
251 atkbdc_assert_aux_intr(sc);
252 }
253 }
254
255 static void
atkbdc_kbd_poll(struct atkbdc_softc * sc)256 atkbdc_kbd_poll(struct atkbdc_softc *sc)
257 {
258 assert(pthread_mutex_isowned_np(&sc->mtx));
259
260 atkbdc_kbd_read(sc);
261 }
262
263 static void
atkbdc_poll(struct atkbdc_softc * sc)264 atkbdc_poll(struct atkbdc_softc *sc)
265 {
266 atkbdc_aux_poll(sc);
267 atkbdc_kbd_poll(sc);
268 }
269
270 static void
atkbdc_dequeue_data(struct atkbdc_softc * sc,uint8_t * buf)271 atkbdc_dequeue_data(struct atkbdc_softc *sc, uint8_t *buf)
272 {
273 assert(pthread_mutex_isowned_np(&sc->mtx));
274
275 if (ps2mouse_read(sc->ps2mouse_sc, buf) == 0) {
276 if (ps2mouse_fifocnt(sc->ps2mouse_sc) == 0) {
277 if (sc->kbd.bcnt == 0)
278 sc->status &= ~(KBDS_AUX_BUFFER_FULL |
279 KBDS_KBD_BUFFER_FULL);
280 else
281 sc->status &= ~(KBDS_AUX_BUFFER_FULL);
282 sc->outport &= ~KBDO_AUX_OUTFULL;
283 }
284
285 atkbdc_poll(sc);
286 return;
287 }
288
289 if (sc->kbd.bcnt > 0) {
290 *buf = sc->kbd.buffer[sc->kbd.brd];
291 sc->kbd.brd = (sc->kbd.brd + 1) % FIFOSZ;
292 sc->kbd.bcnt--;
293 if (sc->kbd.bcnt == 0) {
294 sc->status &= ~KBDS_KBD_BUFFER_FULL;
295 sc->outport &= ~KBDO_KBD_OUTFULL;
296 }
297
298 atkbdc_poll(sc);
299 }
300
301 if (ps2mouse_fifocnt(sc->ps2mouse_sc) == 0 && sc->kbd.bcnt == 0) {
302 sc->status &= ~(KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL);
303 }
304 }
305
306 static int
atkbdc_data_handler(struct vmctx * ctx __unused,int in,int port __unused,int bytes,uint32_t * eax,void * arg)307 atkbdc_data_handler(struct vmctx *ctx __unused, int in,
308 int port __unused, int bytes, uint32_t *eax, void *arg)
309 {
310 struct atkbdc_softc *sc;
311 uint8_t buf;
312 int retval;
313
314 if (bytes != 1)
315 return (-1);
316 sc = arg;
317 retval = 0;
318
319 pthread_mutex_lock(&sc->mtx);
320 if (in) {
321 sc->curcmd = 0;
322 if (sc->ctrlbyte != 0) {
323 *eax = sc->ctrlbyte & 0xff;
324 sc->ctrlbyte = 0;
325 } else {
326 /* read device buffer; includes kbd cmd responses */
327 atkbdc_dequeue_data(sc, &buf);
328 *eax = buf;
329 }
330
331 sc->status &= ~KBDS_CTRL_FLAG;
332 pthread_mutex_unlock(&sc->mtx);
333 return (retval);
334 }
335
336 if (sc->status & KBDS_CTRL_FLAG) {
337 /*
338 * Command byte for the controller.
339 */
340 switch (sc->curcmd) {
341 case KBDC_SET_COMMAND_BYTE:
342 sc->ram[0] = *eax;
343 if (sc->ram[0] & KBD_SYS_FLAG_BIT)
344 sc->status |= KBDS_SYS_FLAG;
345 else
346 sc->status &= ~KBDS_SYS_FLAG;
347 break;
348 case KBDC_WRITE_OUTPORT:
349 sc->outport = *eax;
350 break;
351 case KBDC_WRITE_TO_AUX:
352 ps2mouse_write(sc->ps2mouse_sc, *eax, 0);
353 atkbdc_poll(sc);
354 break;
355 case KBDC_WRITE_KBD_OUTBUF:
356 atkbdc_kbd_queue_data(sc, *eax);
357 break;
358 case KBDC_WRITE_AUX_OUTBUF:
359 ps2mouse_write(sc->ps2mouse_sc, *eax, 1);
360 sc->status |= (KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL);
361 atkbdc_aux_poll(sc);
362 break;
363 default:
364 /* write to particular RAM byte */
365 if (sc->curcmd >= 0x61 && sc->curcmd <= 0x7f) {
366 int byten;
367
368 byten = (sc->curcmd - 0x60) & 0x1f;
369 sc->ram[byten] = *eax & 0xff;
370 }
371 break;
372 }
373
374 sc->curcmd = 0;
375 sc->status &= ~KBDS_CTRL_FLAG;
376
377 pthread_mutex_unlock(&sc->mtx);
378 return (retval);
379 }
380
381 /*
382 * Data byte for the device.
383 */
384 ps2kbd_write(sc->ps2kbd_sc, *eax);
385 atkbdc_poll(sc);
386
387 pthread_mutex_unlock(&sc->mtx);
388
389 return (retval);
390 }
391
392 static int
atkbdc_sts_ctl_handler(struct vmctx * ctx,int in,int port __unused,int bytes,uint32_t * eax,void * arg)393 atkbdc_sts_ctl_handler(struct vmctx *ctx, int in,
394 int port __unused, int bytes, uint32_t *eax, void *arg)
395 {
396 struct atkbdc_softc *sc;
397 int error, retval;
398
399 if (bytes != 1)
400 return (-1);
401
402 sc = arg;
403 retval = 0;
404
405 pthread_mutex_lock(&sc->mtx);
406
407 if (in) {
408 /* read status register */
409 *eax = sc->status;
410 pthread_mutex_unlock(&sc->mtx);
411 return (retval);
412 }
413
414
415 sc->curcmd = 0;
416 sc->status |= KBDS_CTRL_FLAG;
417 sc->ctrlbyte = 0;
418
419 switch (*eax) {
420 case KBDC_GET_COMMAND_BYTE:
421 sc->ctrlbyte = CTRL_CMD_FLAG | sc->ram[0];
422 break;
423 case KBDC_TEST_CTRL:
424 sc->ctrlbyte = CTRL_CMD_FLAG | 0x55;
425 break;
426 case KBDC_TEST_AUX_PORT:
427 case KBDC_TEST_KBD_PORT:
428 sc->ctrlbyte = CTRL_CMD_FLAG | 0;
429 break;
430 case KBDC_READ_INPORT:
431 sc->ctrlbyte = CTRL_CMD_FLAG | 0;
432 break;
433 case KBDC_READ_OUTPORT:
434 sc->ctrlbyte = CTRL_CMD_FLAG | sc->outport;
435 break;
436 case KBDC_SET_COMMAND_BYTE:
437 case KBDC_WRITE_OUTPORT:
438 case KBDC_WRITE_KBD_OUTBUF:
439 case KBDC_WRITE_AUX_OUTBUF:
440 sc->curcmd = *eax;
441 break;
442 case KBDC_DISABLE_KBD_PORT:
443 sc->ram[0] |= KBD_DISABLE_KBD_PORT;
444 break;
445 case KBDC_ENABLE_KBD_PORT:
446 sc->ram[0] &= ~KBD_DISABLE_KBD_PORT;
447 if (sc->kbd.bcnt > 0)
448 sc->status |= KBDS_KBD_BUFFER_FULL;
449 atkbdc_poll(sc);
450 break;
451 case KBDC_WRITE_TO_AUX:
452 sc->curcmd = *eax;
453 break;
454 case KBDC_DISABLE_AUX_PORT:
455 sc->ram[0] |= KBD_DISABLE_AUX_PORT;
456 ps2mouse_toggle(sc->ps2mouse_sc, 0);
457 sc->status &= ~(KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL);
458 sc->outport &= ~KBDS_AUX_BUFFER_FULL;
459 break;
460 case KBDC_ENABLE_AUX_PORT:
461 sc->ram[0] &= ~KBD_DISABLE_AUX_PORT;
462 ps2mouse_toggle(sc->ps2mouse_sc, 1);
463 if (ps2mouse_fifocnt(sc->ps2mouse_sc) > 0)
464 sc->status |= KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL;
465 break;
466 case KBDC_RESET: /* Pulse "reset" line */
467 error = vm_suspend(ctx, VM_SUSPEND_RESET);
468 assert(error == 0 || errno == EALREADY);
469 break;
470 default:
471 if (*eax >= 0x21 && *eax <= 0x3f) {
472 /* read "byte N" from RAM */
473 int byten;
474
475 byten = (*eax - 0x20) & 0x1f;
476 sc->ctrlbyte = CTRL_CMD_FLAG | sc->ram[byten];
477 }
478 break;
479 }
480
481 pthread_mutex_unlock(&sc->mtx);
482
483 if (sc->ctrlbyte != 0) {
484 sc->status |= KBDS_KBD_BUFFER_FULL;
485 sc->status &= ~KBDS_AUX_BUFFER_FULL;
486 atkbdc_assert_kbd_intr(sc);
487 } else if (ps2mouse_fifocnt(sc->ps2mouse_sc) > 0 &&
488 (sc->ram[0] & KBD_DISABLE_AUX_PORT) == 0) {
489 sc->status |= KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL;
490 atkbdc_assert_aux_intr(sc);
491 } else if (sc->kbd.bcnt > 0 && (sc->ram[0] & KBD_DISABLE_KBD_PORT) == 0) {
492 sc->status |= KBDS_KBD_BUFFER_FULL;
493 atkbdc_assert_kbd_intr(sc);
494 }
495
496 return (retval);
497 }
498
499 void
atkbdc_event(struct atkbdc_softc * sc,int iskbd)500 atkbdc_event(struct atkbdc_softc *sc, int iskbd)
501 {
502 pthread_mutex_lock(&sc->mtx);
503
504 if (iskbd)
505 atkbdc_kbd_poll(sc);
506 else
507 atkbdc_aux_poll(sc);
508 pthread_mutex_unlock(&sc->mtx);
509 }
510
511 void
atkbdc_init(struct vmctx * ctx)512 atkbdc_init(struct vmctx *ctx)
513 {
514 struct inout_port iop;
515 struct atkbdc_softc *sc;
516 int error;
517
518 sc = calloc(1, sizeof(struct atkbdc_softc));
519 sc->ctx = ctx;
520
521 pthread_mutex_init(&sc->mtx, NULL);
522
523 bzero(&iop, sizeof(struct inout_port));
524 iop.name = "atkdbc";
525 iop.port = KBD_STS_CTL_PORT;
526 iop.size = 1;
527 iop.flags = IOPORT_F_INOUT;
528 iop.handler = atkbdc_sts_ctl_handler;
529 iop.arg = sc;
530
531 error = register_inout(&iop);
532 assert(error == 0);
533
534 bzero(&iop, sizeof(struct inout_port));
535 iop.name = "atkdbc";
536 iop.port = KBD_DATA_PORT;
537 iop.size = 1;
538 iop.flags = IOPORT_F_INOUT;
539 iop.handler = atkbdc_data_handler;
540 iop.arg = sc;
541
542 error = register_inout(&iop);
543 assert(error == 0);
544
545 pci_irq_reserve(KBD_DEV_IRQ);
546 sc->kbd.irq = KBD_DEV_IRQ;
547
548 pci_irq_reserve(AUX_DEV_IRQ);
549 sc->aux.irq = AUX_DEV_IRQ;
550
551 sc->ps2kbd_sc = ps2kbd_init(sc);
552 sc->ps2mouse_sc = ps2mouse_init(sc);
553
554 #ifdef BHYVE_SNAPSHOT
555 assert(atkbdc_sc == NULL);
556 atkbdc_sc = sc;
557 #endif
558 }
559
560 #ifdef BHYVE_SNAPSHOT
561 int
atkbdc_snapshot(struct vm_snapshot_meta * meta)562 atkbdc_snapshot(struct vm_snapshot_meta *meta)
563 {
564 int ret;
565
566 SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->status, meta, ret, done);
567 SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->outport, meta, ret, done);
568 SNAPSHOT_BUF_OR_LEAVE(atkbdc_sc->ram,
569 sizeof(atkbdc_sc->ram), meta, ret, done);
570 SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->curcmd, meta, ret, done);
571 SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->ctrlbyte, meta, ret, done);
572 SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->kbd, meta, ret, done);
573
574 SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->kbd.irq_active, meta, ret, done);
575 SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->kbd.irq, meta, ret, done);
576 SNAPSHOT_BUF_OR_LEAVE(atkbdc_sc->kbd.buffer,
577 sizeof(atkbdc_sc->kbd.buffer), meta, ret, done);
578 SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->kbd.brd, meta, ret, done);
579 SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->kbd.bwr, meta, ret, done);
580 SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->kbd.bcnt, meta, ret, done);
581
582 SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->aux.irq_active, meta, ret, done);
583 SNAPSHOT_VAR_OR_LEAVE(atkbdc_sc->aux.irq, meta, ret, done);
584
585 ret = ps2kbd_snapshot(atkbdc_sc->ps2kbd_sc, meta);
586 if (ret != 0)
587 goto done;
588
589 ret = ps2mouse_snapshot(atkbdc_sc->ps2mouse_sc, meta);
590
591 done:
592 return (ret);
593 }
594 #endif
595
596 static void
atkbdc_dsdt(void)597 atkbdc_dsdt(void)
598 {
599
600 dsdt_line("");
601 dsdt_line("Device (KBD)");
602 dsdt_line("{");
603 dsdt_line(" Name (_HID, EisaId (\"PNP0303\"))");
604 dsdt_line(" Name (_CRS, ResourceTemplate ()");
605 dsdt_line(" {");
606 dsdt_indent(2);
607 dsdt_fixed_ioport(KBD_DATA_PORT, 1);
608 dsdt_fixed_ioport(KBD_STS_CTL_PORT, 1);
609 dsdt_fixed_irq(1);
610 dsdt_unindent(2);
611 dsdt_line(" })");
612 dsdt_line("}");
613
614 dsdt_line("");
615 dsdt_line("Device (MOU)");
616 dsdt_line("{");
617 dsdt_line(" Name (_HID, EisaId (\"PNP0F13\"))");
618 dsdt_line(" Name (_CRS, ResourceTemplate ()");
619 dsdt_line(" {");
620 dsdt_indent(2);
621 dsdt_fixed_ioport(KBD_DATA_PORT, 1);
622 dsdt_fixed_ioport(KBD_STS_CTL_PORT, 1);
623 dsdt_fixed_irq(12);
624 dsdt_unindent(2);
625 dsdt_line(" })");
626 dsdt_line("}");
627 }
628 LPC_DSDT(atkbdc_dsdt);
629
630