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
106struct kbd_dev {
107	bool	irq_active;
108	int	irq;
109
110	uint8_t	buffer[FIFOSZ];
111	int	brd, bwr;
112	int	bcnt;
113};
114
115struct aux_dev {
116	bool	irq_active;
117	int	irq;
118};
119
120struct 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
139static struct atkbdc_softc *atkbdc_sc = NULL;
140#endif
141
142static void
143atkbdc_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
151static void
152atkbdc_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
160static int
161atkbdc_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
178static void
179atkbdc_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
245static void
246atkbdc_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
255static void
256atkbdc_kbd_poll(struct atkbdc_softc *sc)
257{
258	assert(pthread_mutex_isowned_np(&sc->mtx));
259
260	atkbdc_kbd_read(sc);
261}
262
263static void
264atkbdc_poll(struct atkbdc_softc *sc)
265{
266	atkbdc_aux_poll(sc);
267	atkbdc_kbd_poll(sc);
268}
269
270static void
271atkbdc_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
306static int
307atkbdc_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
392static int
393atkbdc_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
499void
500atkbdc_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
511void
512atkbdc_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
561int
562atkbdc_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
591done:
592	return (ret);
593}
594#endif
595
596static void
597atkbdc_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}
628LPC_DSDT(atkbdc_dsdt);
629
630