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