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