1264916Stychon/*- 2264916Stychon * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 3302332Sgrehan * Copyright (c) 2015 Nahanni Systems Inc. 4264916Stychon * All rights reserved. 5264916Stychon * 6264916Stychon * Redistribution and use in source and binary forms, with or without 7264916Stychon * modification, are permitted provided that the following conditions 8264916Stychon * are met: 9264916Stychon * 1. Redistributions of source code must retain the above copyright 10264916Stychon * notice, this list of conditions and the following disclaimer. 11264916Stychon * 2. Redistributions in binary form must reproduce the above copyright 12264916Stychon * notice, this list of conditions and the following disclaimer in the 13264916Stychon * documentation and/or other materials provided with the distribution. 14264916Stychon * 15264916Stychon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 16264916Stychon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17264916Stychon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18264916Stychon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19264916Stychon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20264916Stychon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21264916Stychon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22264916Stychon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23264916Stychon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24264916Stychon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25264916Stychon * SUCH DAMAGE. 26264916Stychon */ 27264916Stychon 28264916Stychon#include <sys/cdefs.h> 29264916Stychon__FBSDID("$FreeBSD: releng/11.0/usr.sbin/bhyve/atkbdc.c 302332 2016-07-04 03:19:06Z grehan $"); 30264916Stychon 31264916Stychon#include <sys/types.h> 32264916Stychon 33264916Stychon#include <machine/vmm.h> 34264916Stychon 35269094Sneel#include <vmmapi.h> 36269094Sneel 37269094Sneel#include <assert.h> 38269094Sneel#include <errno.h> 39302332Sgrehan#include <stdbool.h> 40302332Sgrehan#include <stdlib.h> 41264916Stychon#include <stdio.h> 42302332Sgrehan#include <string.h> 43302332Sgrehan#include <unistd.h> 44302332Sgrehan#include <pthread.h> 45302332Sgrehan#include <pthread_np.h> 46264916Stychon 47302332Sgrehan#include "acpi.h" 48264916Stychon#include "inout.h" 49302332Sgrehan#include "pci_emul.h" 50302332Sgrehan#include "pci_irq.h" 51264916Stychon#include "pci_lpc.h" 52302332Sgrehan#include "ps2kbd.h" 53302332Sgrehan#include "ps2mouse.h" 54264916Stychon 55264916Stychon#define KBD_DATA_PORT 0x60 56264916Stychon 57264916Stychon#define KBD_STS_CTL_PORT 0x64 58264916Stychon 59264916Stychon#define KBDC_RESET 0xfe 60264916Stychon 61302332Sgrehan#define KBD_DEV_IRQ 1 62302332Sgrehan#define AUX_DEV_IRQ 12 63302332Sgrehan 64302332Sgrehan/* controller commands */ 65302332Sgrehan#define KBDC_SET_COMMAND_BYTE 0x60 66302332Sgrehan#define KBDC_GET_COMMAND_BYTE 0x20 67302332Sgrehan#define KBDC_DISABLE_AUX_PORT 0xa7 68302332Sgrehan#define KBDC_ENABLE_AUX_PORT 0xa8 69302332Sgrehan#define KBDC_TEST_AUX_PORT 0xa9 70302332Sgrehan#define KBDC_TEST_CTRL 0xaa 71302332Sgrehan#define KBDC_TEST_KBD_PORT 0xab 72302332Sgrehan#define KBDC_DISABLE_KBD_PORT 0xad 73302332Sgrehan#define KBDC_ENABLE_KBD_PORT 0xae 74302332Sgrehan#define KBDC_READ_INPORT 0xc0 75302332Sgrehan#define KBDC_READ_OUTPORT 0xd0 76302332Sgrehan#define KBDC_WRITE_OUTPORT 0xd1 77302332Sgrehan#define KBDC_WRITE_KBD_OUTBUF 0xd2 78302332Sgrehan#define KBDC_WRITE_AUX_OUTBUF 0xd3 79302332Sgrehan#define KBDC_WRITE_TO_AUX 0xd4 80302332Sgrehan 81302332Sgrehan/* controller command byte (set by KBDC_SET_COMMAND_BYTE) */ 82302332Sgrehan#define KBD_TRANSLATION 0x40 83302332Sgrehan#define KBD_SYS_FLAG_BIT 0x04 84302332Sgrehan#define KBD_DISABLE_KBD_PORT 0x10 85302332Sgrehan#define KBD_DISABLE_AUX_PORT 0x20 86302332Sgrehan#define KBD_ENABLE_AUX_INT 0x02 87302332Sgrehan#define KBD_ENABLE_KBD_INT 0x01 88302332Sgrehan#define KBD_KBD_CONTROL_BITS (KBD_DISABLE_KBD_PORT | KBD_ENABLE_KBD_INT) 89302332Sgrehan#define KBD_AUX_CONTROL_BITS (KBD_DISABLE_AUX_PORT | KBD_ENABLE_AUX_INT) 90302332Sgrehan 91302332Sgrehan/* controller status bits */ 92302332Sgrehan#define KBDS_KBD_BUFFER_FULL 0x01 93302332Sgrehan#define KBDS_SYS_FLAG 0x04 94302332Sgrehan#define KBDS_CTRL_FLAG 0x08 95302332Sgrehan#define KBDS_AUX_BUFFER_FULL 0x20 96302332Sgrehan 97302332Sgrehan/* controller output port */ 98302332Sgrehan#define KBDO_KBD_OUTFULL 0x10 99302332Sgrehan#define KBDO_AUX_OUTFULL 0x20 100302332Sgrehan 101302332Sgrehan#define RAMSZ 32 102302332Sgrehan#define FIFOSZ 15 103302332Sgrehan#define CTRL_CMD_FLAG 0x8000 104302332Sgrehan 105302332Sgrehanstruct kbd_dev { 106302332Sgrehan bool irq_active; 107302332Sgrehan int irq; 108302332Sgrehan 109302332Sgrehan uint8_t buffer[FIFOSZ]; 110302332Sgrehan int brd, bwr; 111302332Sgrehan int bcnt; 112302332Sgrehan}; 113302332Sgrehan 114302332Sgrehanstruct aux_dev { 115302332Sgrehan bool irq_active; 116302332Sgrehan int irq; 117302332Sgrehan}; 118302332Sgrehan 119302332Sgrehanstruct atkbdc_softc { 120302332Sgrehan struct vmctx *ctx; 121302332Sgrehan pthread_mutex_t mtx; 122302332Sgrehan 123302332Sgrehan struct ps2kbd_softc *ps2kbd_sc; 124302332Sgrehan struct ps2mouse_softc *ps2mouse_sc; 125302332Sgrehan 126302332Sgrehan uint8_t status; /* status register */ 127302332Sgrehan uint8_t outport; /* controller output port */ 128302332Sgrehan uint8_t ram[RAMSZ]; /* byte0 = controller config */ 129302332Sgrehan 130302332Sgrehan uint32_t curcmd; /* current command for next byte */ 131302332Sgrehan uint32_t ctrlbyte; 132302332Sgrehan 133302332Sgrehan struct kbd_dev kbd; 134302332Sgrehan struct aux_dev aux; 135302332Sgrehan}; 136302332Sgrehan 137302332Sgrehanstatic void 138302332Sgrehanatkbdc_assert_kbd_intr(struct atkbdc_softc *sc) 139302332Sgrehan{ 140302332Sgrehan if ((sc->ram[0] & KBD_ENABLE_KBD_INT) != 0) { 141302332Sgrehan sc->kbd.irq_active = true; 142302332Sgrehan vm_isa_pulse_irq(sc->ctx, sc->kbd.irq, sc->kbd.irq); 143302332Sgrehan } 144302332Sgrehan} 145302332Sgrehan 146302332Sgrehanstatic void 147302332Sgrehanatkbdc_assert_aux_intr(struct atkbdc_softc *sc) 148302332Sgrehan{ 149302332Sgrehan if ((sc->ram[0] & KBD_ENABLE_AUX_INT) != 0) { 150302332Sgrehan sc->aux.irq_active = true; 151302332Sgrehan vm_isa_pulse_irq(sc->ctx, sc->aux.irq, sc->aux.irq); 152302332Sgrehan } 153302332Sgrehan} 154302332Sgrehan 155264916Stychonstatic int 156302332Sgrehanatkbdc_kbd_queue_data(struct atkbdc_softc *sc, uint8_t val) 157302332Sgrehan{ 158302332Sgrehan assert(pthread_mutex_isowned_np(&sc->mtx)); 159302332Sgrehan 160302332Sgrehan if (sc->kbd.bcnt < FIFOSZ) { 161302332Sgrehan sc->kbd.buffer[sc->kbd.bwr] = val; 162302332Sgrehan sc->kbd.bwr = (sc->kbd.bwr + 1) % FIFOSZ; 163302332Sgrehan sc->kbd.bcnt++; 164302332Sgrehan sc->status |= KBDS_KBD_BUFFER_FULL; 165302332Sgrehan sc->outport |= KBDO_KBD_OUTFULL; 166302332Sgrehan } else { 167302332Sgrehan printf("atkbd data buffer full\n"); 168302332Sgrehan } 169302332Sgrehan 170302332Sgrehan return (sc->kbd.bcnt < FIFOSZ); 171302332Sgrehan} 172302332Sgrehan 173302332Sgrehanstatic void 174302332Sgrehanatkbdc_kbd_read(struct atkbdc_softc *sc) 175302332Sgrehan{ 176302332Sgrehan const uint8_t translation[256] = { 177302332Sgrehan 0xff, 0x43, 0x41, 0x3f, 0x3d, 0x3b, 0x3c, 0x58, 178302332Sgrehan 0x64, 0x44, 0x42, 0x40, 0x3e, 0x0f, 0x29, 0x59, 179302332Sgrehan 0x65, 0x38, 0x2a, 0x70, 0x1d, 0x10, 0x02, 0x5a, 180302332Sgrehan 0x66, 0x71, 0x2c, 0x1f, 0x1e, 0x11, 0x03, 0x5b, 181302332Sgrehan 0x67, 0x2e, 0x2d, 0x20, 0x12, 0x05, 0x04, 0x5c, 182302332Sgrehan 0x68, 0x39, 0x2f, 0x21, 0x14, 0x13, 0x06, 0x5d, 183302332Sgrehan 0x69, 0x31, 0x30, 0x23, 0x22, 0x15, 0x07, 0x5e, 184302332Sgrehan 0x6a, 0x72, 0x32, 0x24, 0x16, 0x08, 0x09, 0x5f, 185302332Sgrehan 0x6b, 0x33, 0x25, 0x17, 0x18, 0x0b, 0x0a, 0x60, 186302332Sgrehan 0x6c, 0x34, 0x35, 0x26, 0x27, 0x19, 0x0c, 0x61, 187302332Sgrehan 0x6d, 0x73, 0x28, 0x74, 0x1a, 0x0d, 0x62, 0x6e, 188302332Sgrehan 0x3a, 0x36, 0x1c, 0x1b, 0x75, 0x2b, 0x63, 0x76, 189302332Sgrehan 0x55, 0x56, 0x77, 0x78, 0x79, 0x7a, 0x0e, 0x7b, 190302332Sgrehan 0x7c, 0x4f, 0x7d, 0x4b, 0x47, 0x7e, 0x7f, 0x6f, 191302332Sgrehan 0x52, 0x53, 0x50, 0x4c, 0x4d, 0x48, 0x01, 0x45, 192302332Sgrehan 0x57, 0x4e, 0x51, 0x4a, 0x37, 0x49, 0x46, 0x54, 193302332Sgrehan 0x80, 0x81, 0x82, 0x41, 0x54, 0x85, 0x86, 0x87, 194302332Sgrehan 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 195302332Sgrehan 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 196302332Sgrehan 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 197302332Sgrehan 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 198302332Sgrehan 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 199302332Sgrehan 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 200302332Sgrehan 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 201302332Sgrehan 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 202302332Sgrehan 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 203302332Sgrehan 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 204302332Sgrehan 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 205302332Sgrehan 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 206302332Sgrehan 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 207302332Sgrehan 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 208302332Sgrehan 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff 209302332Sgrehan }; 210302332Sgrehan uint8_t val; 211302332Sgrehan uint8_t release = 0; 212302332Sgrehan 213302332Sgrehan assert(pthread_mutex_isowned_np(&sc->mtx)); 214302332Sgrehan 215302332Sgrehan if (sc->ram[0] & KBD_TRANSLATION) { 216302332Sgrehan while (ps2kbd_read(sc->ps2kbd_sc, &val) != -1) { 217302332Sgrehan if (val == 0xf0) { 218302332Sgrehan release = 0x80; 219302332Sgrehan continue; 220302332Sgrehan } else { 221302332Sgrehan val = translation[val] | release; 222302332Sgrehan } 223302332Sgrehan atkbdc_kbd_queue_data(sc, val); 224302332Sgrehan break; 225302332Sgrehan } 226302332Sgrehan } else { 227302332Sgrehan while (sc->kbd.bcnt < FIFOSZ) { 228302332Sgrehan if (ps2kbd_read(sc->ps2kbd_sc, &val) != -1) 229302332Sgrehan atkbdc_kbd_queue_data(sc, val); 230302332Sgrehan else 231302332Sgrehan break; 232302332Sgrehan } 233302332Sgrehan } 234302332Sgrehan 235302332Sgrehan if (((sc->ram[0] & KBD_DISABLE_AUX_PORT) || 236302332Sgrehan ps2mouse_fifocnt(sc->ps2mouse_sc) == 0) && sc->kbd.bcnt > 0) 237302332Sgrehan atkbdc_assert_kbd_intr(sc); 238302332Sgrehan} 239302332Sgrehan 240302332Sgrehanstatic void 241302332Sgrehanatkbdc_aux_poll(struct atkbdc_softc *sc) 242302332Sgrehan{ 243302332Sgrehan if (ps2mouse_fifocnt(sc->ps2mouse_sc) > 0) { 244302332Sgrehan sc->status |= KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL; 245302332Sgrehan sc->outport |= KBDO_AUX_OUTFULL; 246302332Sgrehan atkbdc_assert_aux_intr(sc); 247302332Sgrehan } 248302332Sgrehan} 249302332Sgrehan 250302332Sgrehanstatic void 251302332Sgrehanatkbdc_kbd_poll(struct atkbdc_softc *sc) 252302332Sgrehan{ 253302332Sgrehan assert(pthread_mutex_isowned_np(&sc->mtx)); 254302332Sgrehan 255302332Sgrehan atkbdc_kbd_read(sc); 256302332Sgrehan} 257302332Sgrehan 258302332Sgrehanstatic void 259302332Sgrehanatkbdc_poll(struct atkbdc_softc *sc) 260302332Sgrehan{ 261302332Sgrehan atkbdc_aux_poll(sc); 262302332Sgrehan atkbdc_kbd_poll(sc); 263302332Sgrehan} 264302332Sgrehan 265302332Sgrehanstatic void 266302332Sgrehanatkbdc_dequeue_data(struct atkbdc_softc *sc, uint8_t *buf) 267302332Sgrehan{ 268302332Sgrehan assert(pthread_mutex_isowned_np(&sc->mtx)); 269302332Sgrehan 270302332Sgrehan if (ps2mouse_read(sc->ps2mouse_sc, buf) == 0) { 271302332Sgrehan if (ps2mouse_fifocnt(sc->ps2mouse_sc) == 0) { 272302332Sgrehan if (sc->kbd.bcnt == 0) 273302332Sgrehan sc->status &= ~(KBDS_AUX_BUFFER_FULL | 274302332Sgrehan KBDS_KBD_BUFFER_FULL); 275302332Sgrehan else 276302332Sgrehan sc->status &= ~(KBDS_AUX_BUFFER_FULL); 277302332Sgrehan sc->outport &= ~KBDO_AUX_OUTFULL; 278302332Sgrehan } 279302332Sgrehan 280302332Sgrehan atkbdc_poll(sc); 281302332Sgrehan return; 282302332Sgrehan } 283302332Sgrehan 284302332Sgrehan if (sc->kbd.bcnt > 0) { 285302332Sgrehan *buf = sc->kbd.buffer[sc->kbd.brd]; 286302332Sgrehan sc->kbd.brd = (sc->kbd.brd + 1) % FIFOSZ; 287302332Sgrehan sc->kbd.bcnt--; 288302332Sgrehan if (sc->kbd.bcnt == 0) { 289302332Sgrehan sc->status &= ~KBDS_KBD_BUFFER_FULL; 290302332Sgrehan sc->outport &= ~KBDO_KBD_OUTFULL; 291302332Sgrehan } 292302332Sgrehan 293302332Sgrehan atkbdc_poll(sc); 294302332Sgrehan } 295302332Sgrehan 296302332Sgrehan if (ps2mouse_fifocnt(sc->ps2mouse_sc) == 0 && sc->kbd.bcnt == 0) { 297302332Sgrehan sc->status &= ~(KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL); 298302332Sgrehan } 299302332Sgrehan} 300302332Sgrehan 301302332Sgrehanstatic int 302264916Stychonatkbdc_data_handler(struct vmctx *ctx, int vcpu, int in, int port, int bytes, 303264916Stychon uint32_t *eax, void *arg) 304264916Stychon{ 305302332Sgrehan struct atkbdc_softc *sc; 306302332Sgrehan uint8_t buf; 307302332Sgrehan int retval; 308302332Sgrehan 309264916Stychon if (bytes != 1) 310269094Sneel return (-1); 311302332Sgrehan sc = arg; 312302332Sgrehan retval = 0; 313264916Stychon 314302332Sgrehan pthread_mutex_lock(&sc->mtx); 315302332Sgrehan if (in) { 316302332Sgrehan sc->curcmd = 0; 317302332Sgrehan if (sc->ctrlbyte != 0) { 318302332Sgrehan *eax = sc->ctrlbyte & 0xff; 319302332Sgrehan sc->ctrlbyte = 0; 320302332Sgrehan } else { 321302332Sgrehan /* read device buffer; includes kbd cmd responses */ 322302332Sgrehan atkbdc_dequeue_data(sc, &buf); 323302332Sgrehan *eax = buf; 324302332Sgrehan } 325264916Stychon 326302332Sgrehan sc->status &= ~KBDS_CTRL_FLAG; 327302332Sgrehan pthread_mutex_unlock(&sc->mtx); 328302332Sgrehan return (retval); 329302332Sgrehan } 330302332Sgrehan 331302332Sgrehan if (sc->status & KBDS_CTRL_FLAG) { 332302332Sgrehan /* 333302332Sgrehan * Command byte for the controller. 334302332Sgrehan */ 335302332Sgrehan switch (sc->curcmd) { 336302332Sgrehan case KBDC_SET_COMMAND_BYTE: 337302332Sgrehan sc->ram[0] = *eax; 338302332Sgrehan if (sc->ram[0] & KBD_SYS_FLAG_BIT) 339302332Sgrehan sc->status |= KBDS_SYS_FLAG; 340302332Sgrehan else 341302332Sgrehan sc->status &= ~KBDS_SYS_FLAG; 342302332Sgrehan break; 343302332Sgrehan case KBDC_WRITE_OUTPORT: 344302332Sgrehan sc->outport = *eax; 345302332Sgrehan break; 346302332Sgrehan case KBDC_WRITE_TO_AUX: 347302332Sgrehan ps2mouse_write(sc->ps2mouse_sc, *eax, 0); 348302332Sgrehan atkbdc_poll(sc); 349302332Sgrehan break; 350302332Sgrehan case KBDC_WRITE_KBD_OUTBUF: 351302332Sgrehan atkbdc_kbd_queue_data(sc, *eax); 352302332Sgrehan break; 353302332Sgrehan case KBDC_WRITE_AUX_OUTBUF: 354302332Sgrehan ps2mouse_write(sc->ps2mouse_sc, *eax, 1); 355302332Sgrehan sc->status |= (KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL); 356302332Sgrehan atkbdc_aux_poll(sc); 357302332Sgrehan break; 358302332Sgrehan default: 359302332Sgrehan /* write to particular RAM byte */ 360302332Sgrehan if (sc->curcmd >= 0x61 && sc->curcmd <= 0x7f) { 361302332Sgrehan int byten; 362302332Sgrehan 363302332Sgrehan byten = (sc->curcmd - 0x60) & 0x1f; 364302332Sgrehan sc->ram[byten] = *eax & 0xff; 365302332Sgrehan } 366302332Sgrehan break; 367302332Sgrehan } 368302332Sgrehan 369302332Sgrehan sc->curcmd = 0; 370302332Sgrehan sc->status &= ~KBDS_CTRL_FLAG; 371302332Sgrehan 372302332Sgrehan pthread_mutex_unlock(&sc->mtx); 373302332Sgrehan return (retval); 374302332Sgrehan } 375302332Sgrehan 376302332Sgrehan /* 377302332Sgrehan * Data byte for the device. 378302332Sgrehan */ 379302332Sgrehan ps2kbd_write(sc->ps2kbd_sc, *eax); 380302332Sgrehan atkbdc_poll(sc); 381302332Sgrehan 382302332Sgrehan pthread_mutex_unlock(&sc->mtx); 383302332Sgrehan 384302332Sgrehan return (retval); 385264916Stychon} 386264916Stychon 387264916Stychonstatic int 388264916Stychonatkbdc_sts_ctl_handler(struct vmctx *ctx, int vcpu, int in, int port, 389264916Stychon int bytes, uint32_t *eax, void *arg) 390264916Stychon{ 391302332Sgrehan struct atkbdc_softc *sc; 392302332Sgrehan int error, retval; 393264916Stychon 394264916Stychon if (bytes != 1) 395269094Sneel return (-1); 396264916Stychon 397302332Sgrehan sc = arg; 398269094Sneel retval = 0; 399302332Sgrehan 400302332Sgrehan pthread_mutex_lock(&sc->mtx); 401302332Sgrehan 402264916Stychon if (in) { 403302332Sgrehan /* read status register */ 404302332Sgrehan *eax = sc->status; 405302332Sgrehan pthread_mutex_unlock(&sc->mtx); 406302332Sgrehan return (retval); 407302332Sgrehan } 408302332Sgrehan 409302332Sgrehan 410302332Sgrehan sc->curcmd = 0; 411302332Sgrehan sc->status |= KBDS_CTRL_FLAG; 412302332Sgrehan sc->ctrlbyte = 0; 413302332Sgrehan 414302332Sgrehan switch (*eax) { 415302332Sgrehan case KBDC_GET_COMMAND_BYTE: 416302332Sgrehan sc->ctrlbyte = CTRL_CMD_FLAG | sc->ram[0]; 417302332Sgrehan break; 418302332Sgrehan case KBDC_TEST_CTRL: 419302332Sgrehan sc->ctrlbyte = CTRL_CMD_FLAG | 0x55; 420302332Sgrehan break; 421302332Sgrehan case KBDC_TEST_AUX_PORT: 422302332Sgrehan case KBDC_TEST_KBD_PORT: 423302332Sgrehan sc->ctrlbyte = CTRL_CMD_FLAG | 0; 424302332Sgrehan break; 425302332Sgrehan case KBDC_READ_INPORT: 426302332Sgrehan sc->ctrlbyte = CTRL_CMD_FLAG | 0; 427302332Sgrehan break; 428302332Sgrehan case KBDC_READ_OUTPORT: 429302332Sgrehan sc->ctrlbyte = CTRL_CMD_FLAG | sc->outport; 430302332Sgrehan break; 431302332Sgrehan case KBDC_SET_COMMAND_BYTE: 432302332Sgrehan case KBDC_WRITE_OUTPORT: 433302332Sgrehan case KBDC_WRITE_KBD_OUTBUF: 434302332Sgrehan case KBDC_WRITE_AUX_OUTBUF: 435302332Sgrehan sc->curcmd = *eax; 436302332Sgrehan break; 437302332Sgrehan case KBDC_DISABLE_KBD_PORT: 438302332Sgrehan sc->ram[0] |= KBD_DISABLE_KBD_PORT; 439302332Sgrehan break; 440302332Sgrehan case KBDC_ENABLE_KBD_PORT: 441302332Sgrehan sc->ram[0] &= ~KBD_DISABLE_KBD_PORT; 442302332Sgrehan if (sc->kbd.bcnt > 0) 443302332Sgrehan sc->status |= KBDS_KBD_BUFFER_FULL; 444302332Sgrehan atkbdc_poll(sc); 445302332Sgrehan break; 446302332Sgrehan case KBDC_WRITE_TO_AUX: 447302332Sgrehan sc->curcmd = *eax; 448302332Sgrehan break; 449302332Sgrehan case KBDC_DISABLE_AUX_PORT: 450302332Sgrehan sc->ram[0] |= KBD_DISABLE_AUX_PORT; 451302332Sgrehan ps2mouse_toggle(sc->ps2mouse_sc, 0); 452302332Sgrehan sc->status &= ~(KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL); 453302332Sgrehan sc->outport &= ~KBDS_AUX_BUFFER_FULL; 454302332Sgrehan break; 455302332Sgrehan case KBDC_ENABLE_AUX_PORT: 456302332Sgrehan sc->ram[0] &= ~KBD_DISABLE_AUX_PORT; 457302332Sgrehan ps2mouse_toggle(sc->ps2mouse_sc, 1); 458302332Sgrehan if (ps2mouse_fifocnt(sc->ps2mouse_sc) > 0) 459302332Sgrehan sc->status |= KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL; 460302332Sgrehan break; 461302332Sgrehan case KBDC_RESET: /* Pulse "reset" line */ 462302332Sgrehan error = vm_suspend(ctx, VM_SUSPEND_RESET); 463302332Sgrehan assert(error == 0 || errno == EALREADY); 464302332Sgrehan break; 465302332Sgrehan default: 466302332Sgrehan if (*eax >= 0x21 && *eax <= 0x3f) { 467302332Sgrehan /* read "byte N" from RAM */ 468302332Sgrehan int byten; 469302332Sgrehan 470302332Sgrehan byten = (*eax - 0x20) & 0x1f; 471302332Sgrehan sc->ctrlbyte = CTRL_CMD_FLAG | sc->ram[byten]; 472264916Stychon } 473302332Sgrehan break; 474264916Stychon } 475264916Stychon 476302332Sgrehan pthread_mutex_unlock(&sc->mtx); 477302332Sgrehan 478302332Sgrehan if (sc->ctrlbyte != 0) { 479302332Sgrehan sc->status |= KBDS_KBD_BUFFER_FULL; 480302332Sgrehan sc->status &= ~KBDS_AUX_BUFFER_FULL; 481302332Sgrehan atkbdc_assert_kbd_intr(sc); 482302332Sgrehan } else if (ps2mouse_fifocnt(sc->ps2mouse_sc) > 0 && 483302332Sgrehan (sc->ram[0] & KBD_DISABLE_AUX_PORT) == 0) { 484302332Sgrehan sc->status |= KBDS_AUX_BUFFER_FULL | KBDS_KBD_BUFFER_FULL; 485302332Sgrehan atkbdc_assert_aux_intr(sc); 486302332Sgrehan } else if (sc->kbd.bcnt > 0 && (sc->ram[0] & KBD_DISABLE_KBD_PORT) == 0) { 487302332Sgrehan sc->status |= KBDS_KBD_BUFFER_FULL; 488302332Sgrehan atkbdc_assert_kbd_intr(sc); 489302332Sgrehan } 490302332Sgrehan 491264916Stychon return (retval); 492264916Stychon} 493264916Stychon 494302332Sgrehanvoid 495302332Sgrehanatkbdc_event(struct atkbdc_softc *sc, int iskbd) 496302332Sgrehan{ 497302332Sgrehan pthread_mutex_lock(&sc->mtx); 498302332Sgrehan 499302332Sgrehan if (iskbd) 500302332Sgrehan atkbdc_kbd_poll(sc); 501302332Sgrehan else 502302332Sgrehan atkbdc_aux_poll(sc); 503302332Sgrehan pthread_mutex_unlock(&sc->mtx); 504302332Sgrehan} 505302332Sgrehan 506302332Sgrehanvoid 507302332Sgrehanatkbdc_init(struct vmctx *ctx) 508302332Sgrehan{ 509302332Sgrehan struct inout_port iop; 510302332Sgrehan struct atkbdc_softc *sc; 511302332Sgrehan int error; 512302332Sgrehan 513302332Sgrehan sc = calloc(1, sizeof(struct atkbdc_softc)); 514302332Sgrehan sc->ctx = ctx; 515302332Sgrehan 516302332Sgrehan pthread_mutex_init(&sc->mtx, NULL); 517302332Sgrehan 518302332Sgrehan bzero(&iop, sizeof(struct inout_port)); 519302332Sgrehan iop.name = "atkdbc"; 520302332Sgrehan iop.port = KBD_STS_CTL_PORT; 521302332Sgrehan iop.size = 1; 522302332Sgrehan iop.flags = IOPORT_F_INOUT; 523302332Sgrehan iop.handler = atkbdc_sts_ctl_handler; 524302332Sgrehan iop.arg = sc; 525302332Sgrehan 526302332Sgrehan error = register_inout(&iop); 527302332Sgrehan assert(error == 0); 528302332Sgrehan 529302332Sgrehan bzero(&iop, sizeof(struct inout_port)); 530302332Sgrehan iop.name = "atkdbc"; 531302332Sgrehan iop.port = KBD_DATA_PORT; 532302332Sgrehan iop.size = 1; 533302332Sgrehan iop.flags = IOPORT_F_INOUT; 534302332Sgrehan iop.handler = atkbdc_data_handler; 535302332Sgrehan iop.arg = sc; 536302332Sgrehan 537302332Sgrehan error = register_inout(&iop); 538302332Sgrehan assert(error == 0); 539302332Sgrehan 540302332Sgrehan pci_irq_reserve(KBD_DEV_IRQ); 541302332Sgrehan sc->kbd.irq = KBD_DEV_IRQ; 542302332Sgrehan 543302332Sgrehan pci_irq_reserve(AUX_DEV_IRQ); 544302332Sgrehan sc->aux.irq = AUX_DEV_IRQ; 545302332Sgrehan 546302332Sgrehan sc->ps2kbd_sc = ps2kbd_init(sc); 547302332Sgrehan sc->ps2mouse_sc = ps2mouse_init(sc); 548302332Sgrehan} 549302332Sgrehan 550302332Sgrehanstatic void 551302332Sgrehanatkbdc_dsdt(void) 552302332Sgrehan{ 553302332Sgrehan 554302332Sgrehan dsdt_line(""); 555302332Sgrehan dsdt_line("Device (KBD)"); 556302332Sgrehan dsdt_line("{"); 557302332Sgrehan dsdt_line(" Name (_HID, EisaId (\"PNP0303\"))"); 558302332Sgrehan dsdt_line(" Name (_CRS, ResourceTemplate ()"); 559302332Sgrehan dsdt_line(" {"); 560302332Sgrehan dsdt_indent(2); 561302332Sgrehan dsdt_fixed_ioport(KBD_DATA_PORT, 1); 562302332Sgrehan dsdt_fixed_ioport(KBD_STS_CTL_PORT, 1); 563302332Sgrehan dsdt_fixed_irq(1); 564302332Sgrehan dsdt_unindent(2); 565302332Sgrehan dsdt_line(" })"); 566302332Sgrehan dsdt_line("}"); 567302332Sgrehan 568302332Sgrehan dsdt_line(""); 569302332Sgrehan dsdt_line("Device (MOU)"); 570302332Sgrehan dsdt_line("{"); 571302332Sgrehan dsdt_line(" Name (_HID, EisaId (\"PNP0F13\"))"); 572302332Sgrehan dsdt_line(" Name (_CRS, ResourceTemplate ()"); 573302332Sgrehan dsdt_line(" {"); 574302332Sgrehan dsdt_indent(2); 575302332Sgrehan dsdt_fixed_ioport(KBD_DATA_PORT, 1); 576302332Sgrehan dsdt_fixed_ioport(KBD_STS_CTL_PORT, 1); 577302332Sgrehan dsdt_fixed_irq(12); 578302332Sgrehan dsdt_unindent(2); 579302332Sgrehan dsdt_line(" })"); 580302332Sgrehan dsdt_line("}"); 581302332Sgrehan} 582302332SgrehanLPC_DSDT(atkbdc_dsdt); 583302332Sgrehan 584