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