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