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