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