xref: /illumos-gate/usr/src/cmd/bhyve/atkbdc.c (revision 32640292)
1bf21cd93STycho Nightingale /*-
2*32640292SAndy Fiddaman  * SPDX-License-Identifier: BSD-2-Clause
34c87aefeSPatrick Mooney  *
4bf21cd93STycho Nightingale  * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
5bf21cd93STycho Nightingale  * Copyright (c) 2015 Nahanni Systems Inc.
6bf21cd93STycho Nightingale  * All rights reserved.
7bf21cd93STycho Nightingale  *
8bf21cd93STycho Nightingale  * Redistribution and use in source and binary forms, with or without
9bf21cd93STycho Nightingale  * modification, are permitted provided that the following conditions
10bf21cd93STycho Nightingale  * are met:
11bf21cd93STycho Nightingale  * 1. Redistributions of source code must retain the above copyright
12bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer.
13bf21cd93STycho Nightingale  * 2. Redistributions in binary form must reproduce the above copyright
14bf21cd93STycho Nightingale  *    notice, this list of conditions and the following disclaimer in the
15bf21cd93STycho Nightingale  *    documentation and/or other materials provided with the distribution.
16bf21cd93STycho Nightingale  *
17bf21cd93STycho Nightingale  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
18bf21cd93STycho Nightingale  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19bf21cd93STycho Nightingale  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20bf21cd93STycho Nightingale  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21bf21cd93STycho Nightingale  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22bf21cd93STycho Nightingale  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23bf21cd93STycho Nightingale  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24bf21cd93STycho Nightingale  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25bf21cd93STycho Nightingale  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26bf21cd93STycho Nightingale  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27bf21cd93STycho Nightingale  * SUCH DAMAGE.
28bf21cd93STycho Nightingale  */
29bf21cd93STycho Nightingale 
30bf21cd93STycho Nightingale #include <sys/cdefs.h>
31bf21cd93STycho Nightingale 
32bf21cd93STycho Nightingale #include <sys/types.h>
33bf21cd93STycho Nightingale 
34bf21cd93STycho Nightingale #include <machine/vmm.h>
35bf21cd93STycho Nightingale 
36bf21cd93STycho Nightingale #include <vmmapi.h>
37bf21cd93STycho Nightingale 
38bf21cd93STycho Nightingale #include <assert.h>
39bf21cd93STycho Nightingale #include <errno.h>
40bf21cd93STycho Nightingale #include <stdbool.h>
41bf21cd93STycho Nightingale #include <stdlib.h>
42bf21cd93STycho Nightingale #include <stdio.h>
43bf21cd93STycho Nightingale #include <string.h>
44bf21cd93STycho Nightingale #include <unistd.h>
45bf21cd93STycho Nightingale #include <pthread.h>
46bf21cd93STycho Nightingale #include <pthread_np.h>
47bf21cd93STycho Nightingale 
48bf21cd93STycho Nightingale #include "acpi.h"
494c87aefeSPatrick Mooney #include "atkbdc.h"
50bf21cd93STycho Nightingale #include "inout.h"
51bf21cd93STycho Nightingale #include "pci_emul.h"
52bf21cd93STycho Nightingale #include "pci_irq.h"
53bf21cd93STycho Nightingale #include "pci_lpc.h"
54bf21cd93STycho Nightingale #include "ps2kbd.h"
55bf21cd93STycho Nightingale #include "ps2mouse.h"
56bf21cd93STycho Nightingale 
57bf21cd93STycho Nightingale #define	KBD_DATA_PORT		0x60
58bf21cd93STycho Nightingale 
59bf21cd93STycho Nightingale #define	KBD_STS_CTL_PORT	0x64
60bf21cd93STycho Nightingale 
61bf21cd93STycho Nightingale #define	KBDC_RESET		0xfe
62bf21cd93STycho Nightingale 
63bf21cd93STycho Nightingale #define	KBD_DEV_IRQ		1
64bf21cd93STycho Nightingale #define	AUX_DEV_IRQ		12
65bf21cd93STycho Nightingale 
66bf21cd93STycho Nightingale /* controller commands */
67bf21cd93STycho Nightingale #define	KBDC_SET_COMMAND_BYTE	0x60
68bf21cd93STycho Nightingale #define	KBDC_GET_COMMAND_BYTE	0x20
69bf21cd93STycho Nightingale #define	KBDC_DISABLE_AUX_PORT	0xa7
70bf21cd93STycho Nightingale #define	KBDC_ENABLE_AUX_PORT	0xa8
71bf21cd93STycho Nightingale #define	KBDC_TEST_AUX_PORT	0xa9
72bf21cd93STycho Nightingale #define	KBDC_TEST_CTRL		0xaa
73bf21cd93STycho Nightingale #define	KBDC_TEST_KBD_PORT	0xab
74bf21cd93STycho Nightingale #define	KBDC_DISABLE_KBD_PORT	0xad
75bf21cd93STycho Nightingale #define	KBDC_ENABLE_KBD_PORT	0xae
76bf21cd93STycho Nightingale #define	KBDC_READ_INPORT	0xc0
77bf21cd93STycho Nightingale #define	KBDC_READ_OUTPORT	0xd0
78bf21cd93STycho Nightingale #define	KBDC_WRITE_OUTPORT	0xd1
79bf21cd93STycho Nightingale #define	KBDC_WRITE_KBD_OUTBUF	0xd2
80bf21cd93STycho Nightingale #define	KBDC_WRITE_AUX_OUTBUF	0xd3
81bf21cd93STycho Nightingale #define	KBDC_WRITE_TO_AUX	0xd4
82bf21cd93STycho Nightingale 
83bf21cd93STycho Nightingale /* controller command byte (set by KBDC_SET_COMMAND_BYTE) */
84bf21cd93STycho Nightingale #define	KBD_TRANSLATION		0x40
85bf21cd93STycho Nightingale #define	KBD_SYS_FLAG_BIT	0x04
86bf21cd93STycho Nightingale #define	KBD_DISABLE_KBD_PORT	0x10
87bf21cd93STycho Nightingale #define	KBD_DISABLE_AUX_PORT	0x20
88bf21cd93STycho Nightingale #define	KBD_ENABLE_AUX_INT	0x02
89bf21cd93STycho Nightingale #define	KBD_ENABLE_KBD_INT	0x01
90bf21cd93STycho Nightingale #define	KBD_KBD_CONTROL_BITS	(KBD_DISABLE_KBD_PORT | KBD_ENABLE_KBD_INT)
91bf21cd93STycho Nightingale #define	KBD_AUX_CONTROL_BITS	(KBD_DISABLE_AUX_PORT | KBD_ENABLE_AUX_INT)
92bf21cd93STycho Nightingale 
93bf21cd93STycho Nightingale /* controller status bits */
94bf21cd93STycho Nightingale #define	KBDS_KBD_BUFFER_FULL	0x01
95bf21cd93STycho Nightingale #define KBDS_SYS_FLAG		0x04
96bf21cd93STycho Nightingale #define KBDS_CTRL_FLAG		0x08
97bf21cd93STycho Nightingale #define	KBDS_AUX_BUFFER_FULL	0x20
98bf21cd93STycho Nightingale 
99bf21cd93STycho Nightingale /* controller output port */
100bf21cd93STycho Nightingale #define	KBDO_KBD_OUTFULL	0x10
101bf21cd93STycho Nightingale #define	KBDO_AUX_OUTFULL	0x20
102bf21cd93STycho Nightingale 
103bf21cd93STycho Nightingale #define	RAMSZ			32
1044c87aefeSPatrick Mooney #define	FIFOSZ			15
1054c87aefeSPatrick Mooney #define	CTRL_CMD_FLAG		0x8000
106bf21cd93STycho Nightingale 
107bf21cd93STycho Nightingale struct kbd_dev {
108bf21cd93STycho Nightingale 	bool	irq_active;
109bf21cd93STycho Nightingale 	int	irq;
110bf21cd93STycho Nightingale 
1114c87aefeSPatrick Mooney 	uint8_t	buffer[FIFOSZ];
1124c87aefeSPatrick Mooney 	int	brd, bwr;
1134c87aefeSPatrick Mooney 	int	bcnt;
114bf21cd93STycho Nightingale };
115bf21cd93STycho Nightingale 
116bf21cd93STycho Nightingale struct aux_dev {
117bf21cd93STycho Nightingale 	bool	irq_active;
118bf21cd93STycho Nightingale 	int	irq;
119bf21cd93STycho Nightingale };
120bf21cd93STycho Nightingale 
121bf21cd93STycho Nightingale struct atkbdc_softc {
122bf21cd93STycho Nightingale 	struct vmctx *ctx;
123bf21cd93STycho Nightingale 	pthread_mutex_t mtx;
124bf21cd93STycho Nightingale 
125bf21cd93STycho Nightingale 	struct ps2kbd_softc	*ps2kbd_sc;
126bf21cd93STycho Nightingale 	struct ps2mouse_softc	*ps2mouse_sc;
127bf21cd93STycho Nightingale 
128bf21cd93STycho Nightingale 	uint8_t	status;		/* status register */
129bf21cd93STycho Nightingale 	uint8_t	outport;	/* controller output port */
130bf21cd93STycho Nightingale 	uint8_t	ram[RAMSZ];	/* byte0 = controller config */
131bf21cd93STycho Nightingale 
132bf21cd93STycho Nightingale 	uint32_t curcmd;	/* current command for next byte */
1334c87aefeSPatrick Mooney 	uint32_t  ctrlbyte;
134bf21cd93STycho Nightingale 
135bf21cd93STycho Nightingale 	struct kbd_dev kbd;
136bf21cd93STycho Nightingale 	struct aux_dev aux;
137bf21cd93STycho Nightingale };
138bf21cd93STycho Nightingale 
139bf21cd93STycho Nightingale static void
atkbdc_assert_kbd_intr(struct atkbdc_softc * sc)140bf21cd93STycho Nightingale atkbdc_assert_kbd_intr(struct atkbdc_softc *sc)
141bf21cd93STycho Nightingale {
1424c87aefeSPatrick Mooney 	if ((sc->ram[0] & KBD_ENABLE_KBD_INT) != 0) {
143bf21cd93STycho Nightingale 		sc->kbd.irq_active = true;
1444c87aefeSPatrick Mooney 		vm_isa_pulse_irq(sc->ctx, sc->kbd.irq, sc->kbd.irq);
145bf21cd93STycho Nightingale 	}
146bf21cd93STycho Nightingale }
147bf21cd93STycho Nightingale 
148bf21cd93STycho Nightingale static void
atkbdc_assert_aux_intr(struct atkbdc_softc * sc)149bf21cd93STycho Nightingale atkbdc_assert_aux_intr(struct atkbdc_softc *sc)
150bf21cd93STycho Nightingale {
1514c87aefeSPatrick Mooney 	if ((sc->ram[0] & KBD_ENABLE_AUX_INT) != 0) {
152bf21cd93STycho Nightingale 		sc->aux.irq_active = true;
1534c87aefeSPatrick Mooney 		vm_isa_pulse_irq(sc->ctx, sc->aux.irq, sc->aux.irq);
154bf21cd93STycho Nightingale 	}
155bf21cd93STycho Nightingale }
156bf21cd93STycho Nightingale 
1574c87aefeSPatrick Mooney static int
atkbdc_kbd_queue_data(struct atkbdc_softc * sc,uint8_t val)158bf21cd93STycho Nightingale atkbdc_kbd_queue_data(struct atkbdc_softc *sc, uint8_t val)
159bf21cd93STycho Nightingale {
160bf21cd93STycho Nightingale 	assert(pthread_mutex_isowned_np(&sc->mtx));
161bf21cd93STycho Nightingale 
1624c87aefeSPatrick Mooney 	if (sc->kbd.bcnt < FIFOSZ) {
1634c87aefeSPatrick Mooney 		sc->kbd.buffer[sc->kbd.bwr] = val;
1644c87aefeSPatrick Mooney 		sc->kbd.bwr = (sc->kbd.bwr + 1) % FIFOSZ;
1654c87aefeSPatrick Mooney 		sc->kbd.bcnt++;
1664c87aefeSPatrick Mooney 		sc->status |= KBDS_KBD_BUFFER_FULL;
1674c87aefeSPatrick Mooney 		sc->outport |= KBDO_KBD_OUTFULL;
1684c87aefeSPatrick Mooney 	} else {
1694c87aefeSPatrick Mooney 		printf("atkbd data buffer full\n");
1704c87aefeSPatrick Mooney 	}
171bf21cd93STycho Nightingale 
1724c87aefeSPatrick Mooney 	return (sc->kbd.bcnt < FIFOSZ);
173bf21cd93STycho Nightingale }
174bf21cd93STycho Nightingale 
175bf21cd93STycho Nightingale static void
atkbdc_kbd_read(struct atkbdc_softc * sc)176bf21cd93STycho Nightingale atkbdc_kbd_read(struct atkbdc_softc *sc)
177bf21cd93STycho Nightingale {
178bf21cd93STycho Nightingale 	const uint8_t translation[256] = {
179bf21cd93STycho Nightingale 		0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58,
180bf21cd93STycho Nightingale 		0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59,
181bf21cd93STycho Nightingale 		0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a,
182bf21cd93STycho Nightingale 		0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b,
183bf21cd93STycho Nightingale 		0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c,
184bf21cd93STycho Nightingale 		0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d,
185bf21cd93STycho Nightingale 		0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e,
186bf21cd93STycho Nightingale 		0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f,
187bf21cd93STycho Nightingale 		0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60,
188bf21cd93STycho Nightingale 		0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61,
189bf21cd93STycho Nightingale 		0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e,
190bf21cd93STycho Nightingale 		0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76,
191bf21cd93STycho Nightingale 		0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b,
192bf21cd93STycho Nightingale 		0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f,
193bf21cd93STycho Nightingale 		0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45,
194bf21cd93STycho Nightingale 		0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54,
195bf21cd93STycho Nightingale 		0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87,
196bf21cd93STycho Nightingale 		0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
197bf21cd93STycho Nightingale 		0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
198bf21cd93STycho Nightingale 		0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
199bf21cd93STycho Nightingale 		0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
200bf21cd93STycho Nightingale 		0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
201bf21cd93STycho Nightingale 		0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
202bf21cd93STycho Nightingale 		0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
203bf21cd93STycho Nightingale 		0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
204bf21cd93STycho Nightingale 		0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
205bf21cd93STycho Nightingale 		0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
206bf21cd93STycho Nightingale 		0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
207bf21cd93STycho Nightingale 		0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
208bf21cd93STycho Nightingale 		0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
209bf21cd93STycho Nightingale 		0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
210bf21cd93STycho Nightingale 		0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
211bf21cd93STycho Nightingale 	};
212bf21cd93STycho Nightingale 	uint8_t val;
213bf21cd93STycho Nightingale 	uint8_t release = 0;
214bf21cd93STycho Nightingale 
215bf21cd93STycho Nightingale 	assert(pthread_mutex_isowned_np(&sc->mtx));
216bf21cd93STycho Nightingale 
217bf21cd93STycho Nightingale 	if (sc->ram[0] & KBD_TRANSLATION) {
218bf21cd93STycho Nightingale 		while (ps2kbd_read(sc->ps2kbd_sc, &val) != -1) {
219bf21cd93STycho Nightingale 			if (val == 0xf0) {
220bf21cd93STycho Nightingale 				release = 0x80;
221bf21cd93STycho Nightingale 				continue;
222bf21cd93STycho Nightingale 			} else {
223bf21cd93STycho Nightingale 				val = translation[val] | release;
224bf21cd93STycho Nightingale 			}
225bf21cd93STycho Nightingale 			atkbdc_kbd_queue_data(sc, val);
226bf21cd93STycho Nightingale 			break;
227bf21cd93STycho Nightingale 		}
228bf21cd93STycho Nightingale 	} else {
2294c87aefeSPatrick Mooney 		while (sc->kbd.bcnt < FIFOSZ) {
2304c87aefeSPatrick Mooney 			if (ps2kbd_read(sc->ps2kbd_sc, &val) != -1)
2314c87aefeSPatrick Mooney 				atkbdc_kbd_queue_data(sc, val);
2324c87aefeSPatrick Mooney 			else
2334c87aefeSPatrick Mooney 				break;
2344c87aefeSPatrick Mooney 		}
235bf21cd93STycho Nightingale 	}
2364c87aefeSPatrick Mooney 
2374c87aefeSPatrick Mooney 	if (((sc->ram[0] & KBD_DISABLE_AUX_PORT) ||
2384c87aefeSPatrick Mooney 	    ps2mouse_fifocnt(sc->ps2mouse_sc) == 0) && sc->kbd.bcnt > 0)
2394c87aefeSPatrick Mooney 		atkbdc_assert_kbd_intr(sc);
240bf21cd93STycho Nightingale }
241bf21cd93STycho Nightingale 
242bf21cd93STycho Nightingale static void
atkbdc_aux_poll(struct atkbdc_softc * sc)243bf21cd93STycho Nightingale atkbdc_aux_poll(struct atkbdc_softc *sc)
244bf21cd93STycho Nightingale {
2454c87aefeSPatrick Mooney 	if (ps2mouse_fifocnt(sc->ps2mouse_sc) > 0) {
2464c87aefeSPatrick Mooney 		sc->status |= KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL;
2474c87aefeSPatrick Mooney 		sc->outport |= KBDO_AUX_OUTFULL;
2484c87aefeSPatrick Mooney 		atkbdc_assert_aux_intr(sc);
2494c87aefeSPatrick Mooney 	}
250bf21cd93STycho Nightingale }
251bf21cd93STycho Nightingale 
252bf21cd93STycho Nightingale static void
atkbdc_kbd_poll(struct atkbdc_softc * sc)253bf21cd93STycho Nightingale atkbdc_kbd_poll(struct atkbdc_softc *sc)
254bf21cd93STycho Nightingale {
255bf21cd93STycho Nightingale 	assert(pthread_mutex_isowned_np(&sc->mtx));
256bf21cd93STycho Nightingale 
2574c87aefeSPatrick Mooney 	atkbdc_kbd_read(sc);
258bf21cd93STycho Nightingale }
259bf21cd93STycho Nightingale 
260bf21cd93STycho Nightingale static void
atkbdc_poll(struct atkbdc_softc * sc)261bf21cd93STycho Nightingale atkbdc_poll(struct atkbdc_softc *sc)
262bf21cd93STycho Nightingale {
263bf21cd93STycho Nightingale 	atkbdc_aux_poll(sc);
264bf21cd93STycho Nightingale 	atkbdc_kbd_poll(sc);
265bf21cd93STycho Nightingale }
266bf21cd93STycho Nightingale 
267bf21cd93STycho Nightingale static void
atkbdc_dequeue_data(struct atkbdc_softc * sc,uint8_t * buf)268bf21cd93STycho Nightingale atkbdc_dequeue_data(struct atkbdc_softc *sc, uint8_t *buf)
269bf21cd93STycho Nightingale {
270bf21cd93STycho Nightingale 	assert(pthread_mutex_isowned_np(&sc->mtx));
271bf21cd93STycho Nightingale 
2724c87aefeSPatrick Mooney 	if (ps2mouse_read(sc->ps2mouse_sc, buf) == 0) {
2734c87aefeSPatrick Mooney 		if (ps2mouse_fifocnt(sc->ps2mouse_sc) == 0) {
2744c87aefeSPatrick Mooney 			if (sc->kbd.bcnt == 0)
2754c87aefeSPatrick Mooney 				sc->status &= ~(KBDS_AUX_BUFFER_FULL |
2764c87aefeSPatrick Mooney 				                KBDS_KBD_BUFFER_FULL);
2774c87aefeSPatrick Mooney 			else
2784c87aefeSPatrick Mooney 				sc->status &= ~(KBDS_AUX_BUFFER_FULL);
2794c87aefeSPatrick Mooney 			sc->outport &= ~KBDO_AUX_OUTFULL;
2804c87aefeSPatrick Mooney 		}
281bf21cd93STycho Nightingale 
282bf21cd93STycho Nightingale 		atkbdc_poll(sc);
283bf21cd93STycho Nightingale 		return;
284bf21cd93STycho Nightingale 	}
285bf21cd93STycho Nightingale 
2864c87aefeSPatrick Mooney 	if (sc->kbd.bcnt > 0) {
2874c87aefeSPatrick Mooney 		*buf = sc->kbd.buffer[sc->kbd.brd];
2884c87aefeSPatrick Mooney 		sc->kbd.brd = (sc->kbd.brd + 1) % FIFOSZ;
2894c87aefeSPatrick Mooney 		sc->kbd.bcnt--;
2904c87aefeSPatrick Mooney 		if (sc->kbd.bcnt == 0) {
2914c87aefeSPatrick Mooney 			sc->status &= ~KBDS_KBD_BUFFER_FULL;
2924c87aefeSPatrick Mooney 			sc->outport &= ~KBDO_KBD_OUTFULL;
2934c87aefeSPatrick Mooney 		}
294bf21cd93STycho Nightingale 
2954c87aefeSPatrick Mooney 		atkbdc_poll(sc);
2964c87aefeSPatrick Mooney 	}
2974c87aefeSPatrick Mooney 
2984c87aefeSPatrick Mooney 	if (ps2mouse_fifocnt(sc->ps2mouse_sc) == 0 && sc->kbd.bcnt == 0) {
2994c87aefeSPatrick Mooney 		sc->status &= ~(KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL);
3004c87aefeSPatrick Mooney 	}
301bf21cd93STycho Nightingale }
302bf21cd93STycho Nightingale 
303bf21cd93STycho Nightingale static int
atkbdc_data_handler(struct vmctx * ctx __unused,int in,int port __unused,int bytes,uint32_t * eax,void * arg)30459d65d31SAndy Fiddaman atkbdc_data_handler(struct vmctx *ctx __unused, int in,
30559d65d31SAndy Fiddaman     int port __unused, int bytes, uint32_t *eax, void *arg)
306bf21cd93STycho Nightingale {
307bf21cd93STycho Nightingale 	struct atkbdc_softc *sc;
308bf21cd93STycho Nightingale 	uint8_t buf;
309bf21cd93STycho Nightingale 	int retval;
310bf21cd93STycho Nightingale 
311bf21cd93STycho Nightingale 	if (bytes != 1)
312bf21cd93STycho Nightingale 		return (-1);
313bf21cd93STycho Nightingale 	sc = arg;
314bf21cd93STycho Nightingale 	retval = 0;
315bf21cd93STycho Nightingale 
316bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->mtx);
317bf21cd93STycho Nightingale 	if (in) {
318bf21cd93STycho Nightingale 		sc->curcmd = 0;
3194c87aefeSPatrick Mooney 		if (sc->ctrlbyte != 0) {
3204c87aefeSPatrick Mooney 			*eax = sc->ctrlbyte & 0xff;
3214c87aefeSPatrick Mooney 			sc->ctrlbyte = 0;
3224c87aefeSPatrick Mooney 		} else {
3234c87aefeSPatrick Mooney 			/* read device buffer; includes kbd cmd responses */
3244c87aefeSPatrick Mooney 			atkbdc_dequeue_data(sc, &buf);
3254c87aefeSPatrick Mooney 			*eax = buf;
3264c87aefeSPatrick Mooney 		}
327bf21cd93STycho Nightingale 
3284c87aefeSPatrick Mooney 		sc->status &= ~KBDS_CTRL_FLAG;
329bf21cd93STycho Nightingale 		pthread_mutex_unlock(&sc->mtx);
330bf21cd93STycho Nightingale 		return (retval);
331bf21cd93STycho Nightingale 	}
332bf21cd93STycho Nightingale 
333bf21cd93STycho Nightingale 	if (sc->status & KBDS_CTRL_FLAG) {
334bf21cd93STycho Nightingale 		/*
335bf21cd93STycho Nightingale 		 * Command byte for the controller.
336bf21cd93STycho Nightingale 		 */
337bf21cd93STycho Nightingale 		switch (sc->curcmd) {
338bf21cd93STycho Nightingale 		case KBDC_SET_COMMAND_BYTE:
339bf21cd93STycho Nightingale 			sc->ram[0] = *eax;
340bf21cd93STycho Nightingale 			if (sc->ram[0] & KBD_SYS_FLAG_BIT)
341bf21cd93STycho Nightingale 				sc->status |= KBDS_SYS_FLAG;
342bf21cd93STycho Nightingale 			else
3434c87aefeSPatrick Mooney 				sc->status &= ~KBDS_SYS_FLAG;
344bf21cd93STycho Nightingale 			break;
345bf21cd93STycho Nightingale 		case KBDC_WRITE_OUTPORT:
346bf21cd93STycho Nightingale 			sc->outport = *eax;
347bf21cd93STycho Nightingale 			break;
348bf21cd93STycho Nightingale 		case KBDC_WRITE_TO_AUX:
3494c87aefeSPatrick Mooney 			ps2mouse_write(sc->ps2mouse_sc, *eax, 0);
350bf21cd93STycho Nightingale 			atkbdc_poll(sc);
351bf21cd93STycho Nightingale 			break;
352bf21cd93STycho Nightingale 		case KBDC_WRITE_KBD_OUTBUF:
353bf21cd93STycho Nightingale 			atkbdc_kbd_queue_data(sc, *eax);
354bf21cd93STycho Nightingale 			break;
355bf21cd93STycho Nightingale 		case KBDC_WRITE_AUX_OUTBUF:
3564c87aefeSPatrick Mooney 			ps2mouse_write(sc->ps2mouse_sc, *eax, 1);
3574c87aefeSPatrick Mooney 			sc->status |= (KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL);
3584c87aefeSPatrick Mooney 			atkbdc_aux_poll(sc);
359bf21cd93STycho Nightingale 			break;
360bf21cd93STycho Nightingale 		default:
361bf21cd93STycho Nightingale 			/* write to particular RAM byte */
362bf21cd93STycho Nightingale 			if (sc->curcmd >= 0x61 && sc->curcmd <= 0x7f) {
363bf21cd93STycho Nightingale 				int byten;
364bf21cd93STycho Nightingale 
365bf21cd93STycho Nightingale 				byten = (sc->curcmd - 0x60) & 0x1f;
366bf21cd93STycho Nightingale 				sc->ram[byten] = *eax & 0xff;
367bf21cd93STycho Nightingale 			}
368bf21cd93STycho Nightingale 			break;
369bf21cd93STycho Nightingale 		}
370bf21cd93STycho Nightingale 
371bf21cd93STycho Nightingale 		sc->curcmd = 0;
372bf21cd93STycho Nightingale 		sc->status &= ~KBDS_CTRL_FLAG;
373bf21cd93STycho Nightingale 
374bf21cd93STycho Nightingale 		pthread_mutex_unlock(&sc->mtx);
375bf21cd93STycho Nightingale 		return (retval);
376bf21cd93STycho Nightingale 	}
377bf21cd93STycho Nightingale 
378bf21cd93STycho Nightingale 	/*
379bf21cd93STycho Nightingale 	 * Data byte for the device.
380bf21cd93STycho Nightingale 	 */
381bf21cd93STycho Nightingale 	ps2kbd_write(sc->ps2kbd_sc, *eax);
382bf21cd93STycho Nightingale 	atkbdc_poll(sc);
383bf21cd93STycho Nightingale 
384bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->mtx);
385bf21cd93STycho Nightingale 
386bf21cd93STycho Nightingale 	return (retval);
387bf21cd93STycho Nightingale }
388bf21cd93STycho Nightingale 
389bf21cd93STycho Nightingale static int
atkbdc_sts_ctl_handler(struct vmctx * ctx,int in,int port __unused,int bytes,uint32_t * eax,void * arg)39059d65d31SAndy Fiddaman atkbdc_sts_ctl_handler(struct vmctx *ctx, int in,
39159d65d31SAndy Fiddaman     int port __unused, int bytes, uint32_t *eax, void *arg)
392bf21cd93STycho Nightingale {
393bf21cd93STycho Nightingale 	struct atkbdc_softc *sc;
394bf21cd93STycho Nightingale 	int	error, retval;
395bf21cd93STycho Nightingale 
396bf21cd93STycho Nightingale 	if (bytes != 1)
397bf21cd93STycho Nightingale 		return (-1);
398bf21cd93STycho Nightingale 
399bf21cd93STycho Nightingale 	sc = arg;
400bf21cd93STycho Nightingale 	retval = 0;
401bf21cd93STycho Nightingale 
402bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->mtx);
403bf21cd93STycho Nightingale 
404bf21cd93STycho Nightingale 	if (in) {
405bf21cd93STycho Nightingale 		/* read status register */
406bf21cd93STycho Nightingale 		*eax = sc->status;
407bf21cd93STycho Nightingale 		pthread_mutex_unlock(&sc->mtx);
408bf21cd93STycho Nightingale 		return (retval);
409bf21cd93STycho Nightingale 	}
410bf21cd93STycho Nightingale 
4114c87aefeSPatrick Mooney 
412bf21cd93STycho Nightingale 	sc->curcmd = 0;
413bf21cd93STycho Nightingale 	sc->status |= KBDS_CTRL_FLAG;
4144c87aefeSPatrick Mooney 	sc->ctrlbyte = 0;
415bf21cd93STycho Nightingale 
416bf21cd93STycho Nightingale 	switch (*eax) {
417bf21cd93STycho Nightingale 	case KBDC_GET_COMMAND_BYTE:
4184c87aefeSPatrick Mooney 		sc->ctrlbyte = CTRL_CMD_FLAG | sc->ram[0];
419bf21cd93STycho Nightingale 		break;
420bf21cd93STycho Nightingale 	case KBDC_TEST_CTRL:
4214c87aefeSPatrick Mooney 		sc->ctrlbyte = CTRL_CMD_FLAG | 0x55;
422bf21cd93STycho Nightingale 		break;
423bf21cd93STycho Nightingale 	case KBDC_TEST_AUX_PORT:
424bf21cd93STycho Nightingale 	case KBDC_TEST_KBD_PORT:
4254c87aefeSPatrick Mooney 		sc->ctrlbyte = CTRL_CMD_FLAG | 0;
426bf21cd93STycho Nightingale 		break;
427bf21cd93STycho Nightingale 	case KBDC_READ_INPORT:
4284c87aefeSPatrick Mooney 		sc->ctrlbyte = CTRL_CMD_FLAG | 0;
429bf21cd93STycho Nightingale 		break;
430bf21cd93STycho Nightingale 	case KBDC_READ_OUTPORT:
4314c87aefeSPatrick Mooney 		sc->ctrlbyte = CTRL_CMD_FLAG | sc->outport;
432bf21cd93STycho Nightingale 		break;
433bf21cd93STycho Nightingale 	case KBDC_SET_COMMAND_BYTE:
434bf21cd93STycho Nightingale 	case KBDC_WRITE_OUTPORT:
435bf21cd93STycho Nightingale 	case KBDC_WRITE_KBD_OUTBUF:
436bf21cd93STycho Nightingale 	case KBDC_WRITE_AUX_OUTBUF:
437bf21cd93STycho Nightingale 		sc->curcmd = *eax;
438bf21cd93STycho Nightingale 		break;
439bf21cd93STycho Nightingale 	case KBDC_DISABLE_KBD_PORT:
440bf21cd93STycho Nightingale 		sc->ram[0] |= KBD_DISABLE_KBD_PORT;
441bf21cd93STycho Nightingale 		break;
442bf21cd93STycho Nightingale 	case KBDC_ENABLE_KBD_PORT:
443bf21cd93STycho Nightingale 		sc->ram[0] &= ~KBD_DISABLE_KBD_PORT;
4444c87aefeSPatrick Mooney 		if (sc->kbd.bcnt > 0)
4454c87aefeSPatrick Mooney 			sc->status |= KBDS_KBD_BUFFER_FULL;
446bf21cd93STycho Nightingale 		atkbdc_poll(sc);
447bf21cd93STycho Nightingale 		break;
448bf21cd93STycho Nightingale 	case KBDC_WRITE_TO_AUX:
449bf21cd93STycho Nightingale 		sc->curcmd = *eax;
450bf21cd93STycho Nightingale 		break;
451bf21cd93STycho Nightingale 	case KBDC_DISABLE_AUX_PORT:
452bf21cd93STycho Nightingale 		sc->ram[0] |= KBD_DISABLE_AUX_PORT;
4534c87aefeSPatrick Mooney 		ps2mouse_toggle(sc->ps2mouse_sc, 0);
4544c87aefeSPatrick Mooney 		sc->status &= ~(KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL);
4554c87aefeSPatrick Mooney 		sc->outport &= ~KBDS_AUX_BUFFER_FULL;
456bf21cd93STycho Nightingale 		break;
457bf21cd93STycho Nightingale 	case KBDC_ENABLE_AUX_PORT:
458bf21cd93STycho Nightingale 		sc->ram[0] &= ~KBD_DISABLE_AUX_PORT;
4594c87aefeSPatrick Mooney 		ps2mouse_toggle(sc->ps2mouse_sc, 1);
4604c87aefeSPatrick Mooney 		if (ps2mouse_fifocnt(sc->ps2mouse_sc) > 0)
4614c87aefeSPatrick Mooney 			sc->status |= KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL;
462bf21cd93STycho Nightingale 		break;
463bf21cd93STycho Nightingale 	case KBDC_RESET:		/* Pulse "reset" line */
464bf21cd93STycho Nightingale 		error = vm_suspend(ctx, VM_SUSPEND_RESET);
465bf21cd93STycho Nightingale 		assert(error == 0 || errno == EALREADY);
466bf21cd93STycho Nightingale 		break;
467bf21cd93STycho Nightingale 	default:
468bf21cd93STycho Nightingale 		if (*eax >= 0x21 && *eax <= 0x3f) {
469bf21cd93STycho Nightingale 			/* read "byte N" from RAM */
470bf21cd93STycho Nightingale 			int	byten;
471bf21cd93STycho Nightingale 
472bf21cd93STycho Nightingale 			byten = (*eax - 0x20) & 0x1f;
4734c87aefeSPatrick Mooney 			sc->ctrlbyte = CTRL_CMD_FLAG | sc->ram[byten];
474bf21cd93STycho Nightingale 		}
475bf21cd93STycho Nightingale 		break;
476bf21cd93STycho Nightingale 	}
477bf21cd93STycho Nightingale 
478bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->mtx);
479bf21cd93STycho Nightingale 
4804c87aefeSPatrick Mooney 	if (sc->ctrlbyte != 0) {
4814c87aefeSPatrick Mooney 		sc->status |= KBDS_KBD_BUFFER_FULL;
4824c87aefeSPatrick Mooney 		sc->status &= ~KBDS_AUX_BUFFER_FULL;
4834c87aefeSPatrick Mooney 		atkbdc_assert_kbd_intr(sc);
4844c87aefeSPatrick Mooney 	} else if (ps2mouse_fifocnt(sc->ps2mouse_sc) > 0 &&
4854c87aefeSPatrick Mooney 	           (sc->ram[0] & KBD_DISABLE_AUX_PORT) == 0) {
4864c87aefeSPatrick Mooney 		sc->status |= KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL;
4874c87aefeSPatrick Mooney 		atkbdc_assert_aux_intr(sc);
4884c87aefeSPatrick Mooney 	} else if (sc->kbd.bcnt > 0 && (sc->ram[0] & KBD_DISABLE_KBD_PORT) == 0) {
4894c87aefeSPatrick Mooney 		sc->status |= KBDS_KBD_BUFFER_FULL;
4904c87aefeSPatrick Mooney 		atkbdc_assert_kbd_intr(sc);
4914c87aefeSPatrick Mooney 	}
4924c87aefeSPatrick Mooney 
493bf21cd93STycho Nightingale 	return (retval);
494bf21cd93STycho Nightingale }
495bf21cd93STycho Nightingale 
496bf21cd93STycho Nightingale void
atkbdc_event(struct atkbdc_softc * sc,int iskbd)4974c87aefeSPatrick Mooney atkbdc_event(struct atkbdc_softc *sc, int iskbd)
498bf21cd93STycho Nightingale {
499bf21cd93STycho Nightingale 	pthread_mutex_lock(&sc->mtx);
5004c87aefeSPatrick Mooney 
5014c87aefeSPatrick Mooney 	if (iskbd)
5024c87aefeSPatrick Mooney 		atkbdc_kbd_poll(sc);
5034c87aefeSPatrick Mooney 	else
5044c87aefeSPatrick Mooney 		atkbdc_aux_poll(sc);
505bf21cd93STycho Nightingale 	pthread_mutex_unlock(&sc->mtx);
506bf21cd93STycho Nightingale }
507bf21cd93STycho Nightingale 
508bf21cd93STycho Nightingale void
atkbdc_init(struct vmctx * ctx)509bf21cd93STycho Nightingale atkbdc_init(struct vmctx *ctx)
510bf21cd93STycho Nightingale {
511bf21cd93STycho Nightingale 	struct inout_port iop;
512bf21cd93STycho Nightingale 	struct atkbdc_softc *sc;
513bf21cd93STycho Nightingale 	int error;
514bf21cd93STycho Nightingale 
515bf21cd93STycho Nightingale 	sc = calloc(1, sizeof(struct atkbdc_softc));
516bf21cd93STycho Nightingale 	sc->ctx = ctx;
517bf21cd93STycho Nightingale 
518bf21cd93STycho Nightingale 	pthread_mutex_init(&sc->mtx, NULL);
519bf21cd93STycho Nightingale 
520bf21cd93STycho Nightingale 	bzero(&iop, sizeof(struct inout_port));
521bf21cd93STycho Nightingale 	iop.name = "atkdbc";
522bf21cd93STycho Nightingale 	iop.port = KBD_STS_CTL_PORT;
523bf21cd93STycho Nightingale 	iop.size = 1;
524bf21cd93STycho Nightingale 	iop.flags = IOPORT_F_INOUT;
525bf21cd93STycho Nightingale 	iop.handler = atkbdc_sts_ctl_handler;
526bf21cd93STycho Nightingale 	iop.arg = sc;
527bf21cd93STycho Nightingale 
528bf21cd93STycho Nightingale 	error = register_inout(&iop);
529bf21cd93STycho Nightingale 	assert(error == 0);
530bf21cd93STycho Nightingale 
531bf21cd93STycho Nightingale 	bzero(&iop, sizeof(struct inout_port));
532bf21cd93STycho Nightingale 	iop.name = "atkdbc";
533bf21cd93STycho Nightingale 	iop.port = KBD_DATA_PORT;
534bf21cd93STycho Nightingale 	iop.size = 1;
535bf21cd93STycho Nightingale 	iop.flags = IOPORT_F_INOUT;
536bf21cd93STycho Nightingale 	iop.handler = atkbdc_data_handler;
537bf21cd93STycho Nightingale 	iop.arg = sc;
538bf21cd93STycho Nightingale 
539bf21cd93STycho Nightingale 	error = register_inout(&iop);
540bf21cd93STycho Nightingale 	assert(error == 0);
541bf21cd93STycho Nightingale 
542bf21cd93STycho Nightingale 	pci_irq_reserve(KBD_DEV_IRQ);
543bf21cd93STycho Nightingale 	sc->kbd.irq = KBD_DEV_IRQ;
544bf21cd93STycho Nightingale 
545bf21cd93STycho Nightingale 	pci_irq_reserve(AUX_DEV_IRQ);
546bf21cd93STycho Nightingale 	sc->aux.irq = AUX_DEV_IRQ;
547bf21cd93STycho Nightingale 
548bf21cd93STycho Nightingale 	sc->ps2kbd_sc = ps2kbd_init(sc);
549bf21cd93STycho Nightingale 	sc->ps2mouse_sc = ps2mouse_init(sc);
550bf21cd93STycho Nightingale }
551bf21cd93STycho Nightingale 
552bf21cd93STycho Nightingale static void
atkbdc_dsdt(void)553bf21cd93STycho Nightingale atkbdc_dsdt(void)
554bf21cd93STycho Nightingale {
555bf21cd93STycho Nightingale 
556bf21cd93STycho Nightingale 	dsdt_line("");
557bf21cd93STycho Nightingale 	dsdt_line("Device (KBD)");
558bf21cd93STycho Nightingale 	dsdt_line("{");
559bf21cd93STycho Nightingale 	dsdt_line("  Name (_HID, EisaId (\"PNP0303\"))");
560bf21cd93STycho Nightingale 	dsdt_line("  Name (_CRS, ResourceTemplate ()");
561bf21cd93STycho Nightingale 	dsdt_line("  {");
562bf21cd93STycho Nightingale 	dsdt_indent(2);
563bf21cd93STycho Nightingale 	dsdt_fixed_ioport(KBD_DATA_PORT, 1);
564bf21cd93STycho Nightingale 	dsdt_fixed_ioport(KBD_STS_CTL_PORT, 1);
565bf21cd93STycho Nightingale 	dsdt_fixed_irq(1);
566bf21cd93STycho Nightingale 	dsdt_unindent(2);
567bf21cd93STycho Nightingale 	dsdt_line("  })");
568bf21cd93STycho Nightingale 	dsdt_line("}");
569bf21cd93STycho Nightingale 
570bf21cd93STycho Nightingale 	dsdt_line("");
571bf21cd93STycho Nightingale 	dsdt_line("Device (MOU)");
572bf21cd93STycho Nightingale 	dsdt_line("{");
573bf21cd93STycho Nightingale 	dsdt_line("  Name (_HID, EisaId (\"PNP0F13\"))");
574bf21cd93STycho Nightingale 	dsdt_line("  Name (_CRS, ResourceTemplate ()");
575bf21cd93STycho Nightingale 	dsdt_line("  {");
576bf21cd93STycho Nightingale 	dsdt_indent(2);
577bf21cd93STycho Nightingale 	dsdt_fixed_ioport(KBD_DATA_PORT, 1);
578bf21cd93STycho Nightingale 	dsdt_fixed_ioport(KBD_STS_CTL_PORT, 1);
579bf21cd93STycho Nightingale 	dsdt_fixed_irq(12);
580bf21cd93STycho Nightingale 	dsdt_unindent(2);
581bf21cd93STycho Nightingale 	dsdt_line("  })");
582bf21cd93STycho Nightingale 	dsdt_line("}");
583bf21cd93STycho Nightingale }
584bf21cd93STycho Nightingale LPC_DSDT(atkbdc_dsdt);
5854c87aefeSPatrick Mooney 
586