xref: /freebsd/usr.sbin/bhyve/amd64/atkbdc.c (revision 2008043f386721d58158e37e0d7e50df8095942d)
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
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
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
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
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
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
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
265 atkbdc_poll(struct atkbdc_softc *sc)
266 {
267 	atkbdc_aux_poll(sc);
268 	atkbdc_kbd_poll(sc);
269 }
270 
271 static void
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
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
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
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
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
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
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