1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 #include <sys/types.h> 30 #include <sys/inline.h> 31 #include <sys/conf.h> 32 #include <sys/sunddi.h> 33 #include <sys/sunndi.h> 34 #include <sys/i8042.h> 35 #include <sys/kmem.h> 36 #include <sys/promif.h> /* for prom_printf */ 37 #include <sys/note.h> 38 39 /* 40 * Note: this driver is only used to attach a keyboard when 41 * booting with ACPI enumeration turned off (acpi-enum=off). 42 */ 43 44 /* 45 * Unfortunately, soft interrupts are implemented poorly. Each additional 46 * soft interrupt user impacts the performance of all existing soft interrupt 47 * users. 48 */ 49 #undef USE_SOFT_INTRS 50 51 #define BUFSIZ 64 52 53 enum i8042_ports { 54 MAIN_PORT = 0, 55 AUX_PORT 56 }; 57 58 #define NUM_PORTS 2 59 60 /* 61 * One of these for each port - main (keyboard) and aux (mouse). 62 */ 63 struct i8042_port { 64 boolean_t initialized; 65 dev_info_t *dip; 66 int inumber; 67 enum i8042_ports which; /* main or aux port */ 68 #if defined(USE_SOFT_INTRS) 69 ddi_softint_handle_t soft_hdl; 70 boolean_t soft_intr_enabled; 71 #else 72 uint_t (*intr_func)(caddr_t arg1, caddr_t arg2); 73 caddr_t intr_arg1; 74 caddr_t intr_arg2; 75 kmutex_t intr_mutex; 76 #endif 77 struct i8042 *i8042_global; 78 /* 79 * wptr is next byte to write 80 */ 81 int wptr; 82 /* 83 * rptr is next byte to read, == wptr means empty 84 * NB: At full, one byte is unused. 85 */ 86 int rptr; 87 int overruns; 88 unsigned char buf[BUFSIZ]; 89 }; 90 91 /* 92 * Describes entire 8042 device. 93 */ 94 struct i8042 { 95 struct i8042_port i8042_ports[NUM_PORTS]; 96 kmutex_t i8042_mutex; 97 kmutex_t i8042_out_mutex; 98 boolean_t initialized; 99 ddi_acc_handle_t io_handle; 100 uint8_t *io_addr; 101 ddi_iblock_cookie_t iblock_cookie_0; 102 ddi_iblock_cookie_t iblock_cookie_1; 103 }; 104 105 /* 106 * i8042 hardware register definitions 107 */ 108 109 /* 110 * These are I/O registers, relative to the device's base (normally 0x60). 111 */ 112 #define I8042_DATA 0x00 /* read/write data here */ 113 #define I8042_STAT 0x04 /* read status here */ 114 #define I8042_CMD 0x04 /* write commands here */ 115 116 /* 117 * These are bits in I8042_STAT. 118 */ 119 #define I8042_STAT_OUTBF 0x01 /* Output (to host) buffer full */ 120 #define I8042_STAT_INBF 0x02 /* Input (from host) buffer full */ 121 #define I8042_STAT_AUXBF 0x20 /* Output buffer data is from aux */ 122 123 /* 124 * These are commands to the i8042 itself (as distinct from the devices 125 * attached to it). 126 */ 127 #define I8042_CMD_RCB 0x20 /* Read command byte (we don't use) */ 128 #define I8042_CMD_WCB 0x60 /* Write command byte */ 129 #define I8042_CMD_WRITE_AUX 0xD4 /* Send next data byte to aux port */ 130 131 /* 132 * function prototypes for bus ops routines: 133 */ 134 static int i8042_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp, 135 off_t offset, off_t len, caddr_t *addrp); 136 static int i8042_ctlops(dev_info_t *dip, dev_info_t *rdip, 137 ddi_ctl_enum_t op, void *arg, void *result); 138 139 /* 140 * function prototypes for dev ops routines: 141 */ 142 static int i8042_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 143 static int i8042_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 144 static int i8042_intr_ops(dev_info_t *dip, dev_info_t *rdip, 145 ddi_intr_op_t intr_op, ddi_intr_handle_impl_t *hdlp, void *result); 146 static int i8042_bus_config(dev_info_t *, uint_t, ddi_bus_config_op_t, 147 void *, dev_info_t **); 148 static int i8042_bus_unconfig(dev_info_t *, uint_t, 149 ddi_bus_config_op_t, void *); 150 151 /* 152 * bus ops and dev ops structures: 153 */ 154 static struct bus_ops i8042_bus_ops = { 155 BUSO_REV, 156 i8042_map, 157 NULL, 158 NULL, 159 NULL, 160 NULL, /* ddi_map_fault */ 161 NULL, /* ddi_dma_map */ 162 NULL, /* ddi_dma_allochdl */ 163 NULL, /* ddi_dma_freehdl */ 164 NULL, /* ddi_dma_bindhdl */ 165 NULL, /* ddi_dma_unbindhdl */ 166 NULL, /* ddi_dma_flush */ 167 NULL, /* ddi_dma_win */ 168 NULL, /* ddi_dma_mctl */ 169 i8042_ctlops, 170 ddi_bus_prop_op, 171 NULL, /* (*bus_get_eventcookie)(); */ 172 NULL, /* (*bus_add_eventcall)(); */ 173 NULL, /* (*bus_remove_eventcall)(); */ 174 NULL, /* (*bus_post_event)(); */ 175 NULL, /* bus_intr_ctl */ 176 i8042_bus_config, /* bus_config */ 177 i8042_bus_unconfig, /* bus_unconfig */ 178 NULL, /* bus_fm_init */ 179 NULL, /* bus_fm_fini */ 180 NULL, /* bus_fm_access_enter */ 181 NULL, /* bus_fm_access_exit */ 182 NULL, /* bus_power */ 183 i8042_intr_ops /* bus_intr_op */ 184 }; 185 186 static struct dev_ops i8042_ops = { 187 DEVO_REV, 188 0, 189 ddi_no_info, 190 nulldev, 191 0, 192 i8042_attach, 193 i8042_detach, 194 nodev, 195 (struct cb_ops *)0, 196 &i8042_bus_ops 197 }; 198 199 200 /* 201 * module definitions: 202 */ 203 #include <sys/modctl.h> 204 extern struct mod_ops mod_driverops; 205 206 static struct modldrv modldrv = { 207 &mod_driverops, /* Type of module. This one is a driver */ 208 "i8042 nexus driver %I%", /* Name of module. */ 209 &i8042_ops, /* driver ops */ 210 }; 211 212 static struct modlinkage modlinkage = { 213 MODREV_1, (void *)&modldrv, NULL 214 }; 215 216 int 217 _init(void) 218 { 219 int e; 220 221 /* 222 * Install the module. 223 */ 224 e = mod_install(&modlinkage); 225 return (e); 226 } 227 228 int 229 _fini(void) 230 { 231 int e; 232 233 /* 234 * Remove the module. 235 */ 236 e = mod_remove(&modlinkage); 237 if (e != 0) 238 return (e); 239 240 return (e); 241 } 242 243 int 244 _info(struct modinfo *modinfop) 245 { 246 return (mod_info(&modlinkage, modinfop)); 247 } 248 249 #define DRIVER_NAME(dip) ddi_driver_name(dip) 250 251 static unsigned int i8042_intr(caddr_t arg); 252 static void i8042_write_command_byte(struct i8042_port *, unsigned char); 253 static uint8_t i8042_get8(ddi_acc_impl_t *handlep, uint8_t *addr); 254 static void i8042_put8(ddi_acc_impl_t *handlep, uint8_t *addr, 255 uint8_t value); 256 static void i8042_send(struct i8042 *global, int reg, unsigned char cmd); 257 258 unsigned int i8042_unclaimed_interrupts = 0; 259 260 static int 261 i8042_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 262 { 263 struct i8042_port *port; 264 enum i8042_ports which_port; 265 int rc; 266 unsigned char stat; 267 static ddi_device_acc_attr_t attr = { 268 DDI_DEVICE_ATTR_V0, 269 DDI_NEVERSWAP_ACC, 270 DDI_STRICTORDER_ACC, 271 }; 272 struct i8042 *global; 273 274 if (cmd != DDI_ATTACH) { 275 /* 276 * We don't support anything but DDI_ATTACH. Eventually 277 * we probably should. 278 */ 279 return (DDI_FAILURE); 280 } 281 282 global = kmem_zalloc(sizeof (*global), KM_SLEEP); 283 ddi_set_driver_private(dip, global); 284 285 /* 286 * We're evil - we never release this. 287 * 288 * Well, we will when we have a detach routine. 289 */ 290 rc = ddi_regs_map_setup(dip, 0, (caddr_t *)&global->io_addr, 291 (offset_t)0, (offset_t)0, &attr, &global->io_handle); 292 if (rc != DDI_SUCCESS) 293 goto fail_1; 294 295 rc = ddi_get_iblock_cookie(dip, 0, &global->iblock_cookie_0); 296 if (rc != DDI_SUCCESS) 297 goto fail_2; 298 299 mutex_init(&global->i8042_mutex, NULL, MUTEX_DRIVER, 300 global->iblock_cookie_0); 301 302 mutex_init(&global->i8042_out_mutex, NULL, MUTEX_DRIVER, NULL); 303 304 for (which_port = 0; which_port < NUM_PORTS; ++which_port) { 305 port = &global->i8042_ports[which_port]; 306 port->initialized = B_FALSE; 307 port->i8042_global = global; 308 port->which = which_port; 309 mutex_init(&port->intr_mutex, NULL, MUTEX_DRIVER, 310 global->iblock_cookie_0); 311 } 312 313 /* 314 * Disable input and interrupts from both the main and aux ports. 315 * 316 * It is difficult if not impossible to read the command byte in 317 * a completely clean way. Reading the command byte may cause 318 * an interrupt, and there is no way to suppress interrupts without 319 * writing the command byte. On a PC we might rely on the fact 320 * that IRQ 1 is disabled and guaranteed not shared, but on 321 * other platforms the interrupt line might be shared and so 322 * causing an interrupt could be bad. 323 * 324 * Since we can't read the command byte and update it, we 325 * just set it to static values: 326 * 327 * 0x80: 0 = Reserved, must be zero. 328 * 0x40: 1 = Translate to XT codes. 329 * 0x20: 1 = Disable aux (mouse) port. 330 * 0x10: 1 = Disable main (keyboard) port. 331 * 0x08: 0 = Reserved, must be zero. 332 * 0x04: 1 = System flag, 1 means passed self-test. 333 * Caution: setting this bit to zero causes some 334 * systems (HP Kayak XA) to fail to reboot without 335 * a hard reset. 336 * 0x02: 0 = Disable aux port interrupts. 337 * 0x01: 0 = Disable main port interrupts. 338 */ 339 i8042_write_command_byte(&global->i8042_ports[0], 0x74); 340 341 global->initialized = B_TRUE; 342 343 rc = ddi_add_intr(dip, 0, 344 (ddi_iblock_cookie_t *)NULL, (ddi_idevice_cookie_t *)NULL, 345 i8042_intr, (caddr_t)global); 346 if (rc != DDI_SUCCESS) 347 goto fail_2; 348 349 /* 350 * Some systems (SPARCengine-6) have both interrupts wired to 351 * a single interrupt line. We should try to detect this case 352 * and not call ddi_add_intr twice. 353 */ 354 rc = ddi_add_intr(dip, 1, 355 &global->iblock_cookie_1, (ddi_idevice_cookie_t *)NULL, 356 i8042_intr, (caddr_t)global); 357 if (rc != DDI_SUCCESS) 358 goto fail_3; 359 360 /* Discard any junk data that may have been left around */ 361 for (;;) { 362 stat = ddi_get8(global->io_handle, 363 global->io_addr + I8042_STAT); 364 if (! (stat & I8042_STAT_OUTBF)) 365 break; 366 (void) ddi_get8(global->io_handle, 367 global->io_addr + I8042_DATA); 368 369 } 370 371 /* 372 * As noted above, we simply set the command byte to the 373 * desired value. For normal operation, that value is: 374 * 375 * 0x80: 0 = Reserved, must be zero. 376 * 0x40: 1 = Translate to XT codes. 377 * 0x20: 0 = Enable aux (mouse) port. 378 * 0x10: 0 = Enable main (keyboard) port. 379 * 0x08: 0 = Reserved, must be zero. 380 * 0x04: 1 = System flag, 1 means passed self-test. 381 * Caution: setting this bit to zero causes some 382 * systems (HP Kayak XA) to fail to reboot without 383 * a hard reset. 384 * 0x02: 1 = Enable aux port interrupts. 385 * 0x01: 1 = Enable main port interrupts. 386 */ 387 i8042_write_command_byte(&global->i8042_ports[0], 0x47); 388 return (rc); 389 390 fail_3: 391 ddi_remove_intr(dip, 0, global->iblock_cookie_0); 392 fail_2: 393 ddi_regs_map_free(&global->io_handle); 394 fail_1: 395 kmem_free(global, sizeof (*global)); 396 ddi_set_driver_private(dip, NULL); 397 return (rc); 398 } 399 400 /*ARGSUSED*/ 401 static int 402 i8042_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 403 { 404 if (cmd != DDI_DETACH) 405 return (DDI_FAILURE); 406 407 /* 408 * We do not support detach. Eventually we probably should, but 409 * (a) detach of nexus drivers is iffy at present, and (b) 410 * realistically, the keyboard never detaches. This assumption 411 * might come into question when USB keyboards are introduced. 412 */ 413 cmn_err(CE_WARN, "i8042_detach: detach not supported"); 414 return (DDI_FAILURE); 415 } 416 417 /* 418 * The primary interface to us from our children is via virtual registers. 419 * This is the entry point that allows our children to "map" these 420 * virtual registers. 421 */ 422 static int 423 i8042_map( 424 dev_info_t *dip, 425 dev_info_t *rdip, 426 ddi_map_req_t *mp, 427 off_t offset, 428 off_t len, 429 caddr_t *addrp) 430 { 431 struct i8042_port *port; 432 struct i8042 *global; 433 enum i8042_ports which_port; 434 int *iprop; 435 unsigned int iprop_len; 436 int rnumber; 437 ddi_acc_hdl_t *handle; 438 ddi_acc_impl_t *ap; 439 440 global = ddi_get_driver_private(dip); 441 442 switch (mp->map_type) { 443 case DDI_MT_REGSPEC: 444 which_port = *(int *)mp->map_obj.rp; 445 break; 446 447 case DDI_MT_RNUMBER: 448 rnumber = mp->map_obj.rnumber; 449 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, rdip, 450 DDI_PROP_DONTPASS, "reg", &iprop, &iprop_len) != 451 DDI_SUCCESS) { 452 #if defined(DEBUG) 453 cmn_err(CE_WARN, "%s #%d: Missing 'reg' on %s@%s", 454 DRIVER_NAME(dip), ddi_get_instance(dip), 455 ddi_node_name(rdip), ddi_get_name_addr(rdip)); 456 #endif 457 return (DDI_FAILURE); 458 } 459 #if defined(DEBUG) 460 if (iprop_len != 1) { 461 cmn_err(CE_WARN, "%s #%d: Malformed 'reg' on %s@%s", 462 DRIVER_NAME(dip), ddi_get_instance(dip), 463 ddi_node_name(rdip), ddi_get_name_addr(rdip)); 464 return (DDI_FAILURE); 465 } 466 if (rnumber < 0 || rnumber >= iprop_len) { 467 cmn_err(CE_WARN, "%s #%d: bad map request for %s@%s", 468 DRIVER_NAME(dip), ddi_get_instance(dip), 469 ddi_node_name(rdip), ddi_get_name_addr(rdip)); 470 return (DDI_FAILURE); 471 } 472 #endif 473 which_port = iprop[rnumber]; 474 ddi_prop_free((void *)iprop); 475 #if defined(DEBUG) 476 if (which_port != MAIN_PORT && which_port != AUX_PORT) { 477 cmn_err(CE_WARN, 478 "%s #%d: bad 'reg' value %d on %s@%s", 479 DRIVER_NAME(dip), ddi_get_instance(dip), 480 which_port, 481 ddi_node_name(rdip), ddi_get_name_addr(rdip)); 482 return (DDI_FAILURE); 483 } 484 #endif 485 break; 486 487 default: 488 #if defined(DEBUG) 489 cmn_err(CE_WARN, "%s #%d: unknown map type %d for %s@%s", 490 DRIVER_NAME(dip), ddi_get_instance(dip), 491 mp->map_type, 492 ddi_node_name(rdip), ddi_get_name_addr(rdip)); 493 #endif 494 return (DDI_FAILURE); 495 } 496 497 #if defined(DEBUG) 498 if (offset != 0 || len != 0) { 499 cmn_err(CE_WARN, 500 "%s #%d: partial mapping attempt for %s@%s ignored", 501 DRIVER_NAME(dip), ddi_get_instance(dip), 502 ddi_node_name(rdip), ddi_get_name_addr(rdip)); 503 } 504 #endif 505 506 port = &global->i8042_ports[which_port]; 507 508 switch (mp->map_op) { 509 case DDI_MO_MAP_LOCKED: 510 #if defined(USE_SOFT_INTRS) 511 port->soft_intr_enabled = B_FALSE; 512 #else 513 port->intr_func = NULL; 514 #endif 515 port->wptr = 0; 516 port->rptr = 0; 517 port->dip = dip; 518 port->inumber = 0; 519 port->initialized = B_TRUE; 520 521 handle = mp->map_handlep; 522 handle->ah_bus_private = port; 523 handle->ah_addr = 0; 524 ap = (ddi_acc_impl_t *)handle->ah_platform_private; 525 /* 526 * Only single get/put 8 is supported on this "bus". 527 */ 528 ap->ahi_put8 = i8042_put8; 529 ap->ahi_get8 = i8042_get8; 530 ap->ahi_put16 = NULL; 531 ap->ahi_get16 = NULL; 532 ap->ahi_put32 = NULL; 533 ap->ahi_get32 = NULL; 534 ap->ahi_put64 = NULL; 535 ap->ahi_get64 = NULL; 536 ap->ahi_rep_put8 = NULL; 537 ap->ahi_rep_get8 = NULL; 538 ap->ahi_rep_put16 = NULL; 539 ap->ahi_rep_get16 = NULL; 540 ap->ahi_rep_put32 = NULL; 541 ap->ahi_rep_get32 = NULL; 542 ap->ahi_rep_put64 = NULL; 543 ap->ahi_rep_get64 = NULL; 544 *addrp = 0; 545 return (DDI_SUCCESS); 546 547 case DDI_MO_UNMAP: 548 port->initialized = B_FALSE; 549 return (DDI_SUCCESS); 550 551 default: 552 cmn_err(CE_WARN, "%s: map operation %d not supported", 553 DRIVER_NAME(dip), mp->map_op); 554 return (DDI_FAILURE); 555 } 556 } 557 558 /* 559 * i8042 hardware interrupt routine. Called for both main and aux port 560 * interrupts. 561 */ 562 static unsigned int 563 i8042_intr(caddr_t arg) 564 { 565 struct i8042 *global = (struct i8042 *)arg; 566 enum i8042_ports which_port; 567 unsigned char stat; 568 unsigned char byte; 569 int new_wptr; 570 struct i8042_port *port; 571 572 mutex_enter(&global->i8042_mutex); 573 574 stat = ddi_get8(global->io_handle, global->io_addr + I8042_STAT); 575 576 if (! (stat & I8042_STAT_OUTBF)) { 577 ++i8042_unclaimed_interrupts; 578 mutex_exit(&global->i8042_mutex); 579 return (DDI_INTR_UNCLAIMED); 580 } 581 582 byte = ddi_get8(global->io_handle, global->io_addr + I8042_DATA); 583 584 which_port = (stat & I8042_STAT_AUXBF) ? AUX_PORT : MAIN_PORT; 585 586 port = &global->i8042_ports[which_port]; 587 588 if (! port->initialized) { 589 mutex_exit(&global->i8042_mutex); 590 return (DDI_INTR_CLAIMED); 591 } 592 593 new_wptr = (port->wptr + 1) % BUFSIZ; 594 if (new_wptr == port->rptr) { 595 port->overruns++; 596 #if defined(DEBUG) 597 if (port->overruns % 50 == 1) { 598 cmn_err(CE_WARN, "i8042/%d: %d overruns\n", 599 which_port, port->overruns); 600 } 601 #endif 602 mutex_exit(&global->i8042_mutex); 603 return (DDI_INTR_CLAIMED); 604 } 605 606 port->buf[port->wptr] = byte; 607 port->wptr = new_wptr; 608 609 #if defined(USE_SOFT_INTRS) 610 if (port->soft_intr_enabled) 611 (void) ddi_intr_trigger_softint(port->soft_hdl, NULL); 612 #endif 613 614 mutex_exit(&global->i8042_mutex); 615 616 #if !defined(USE_SOFT_INTRS) 617 mutex_enter(&port->intr_mutex); 618 if (port->intr_func != NULL) 619 port->intr_func(port->intr_arg1, NULL); 620 mutex_exit(&port->intr_mutex); 621 #endif 622 623 return (DDI_INTR_CLAIMED); 624 } 625 626 static void 627 i8042_write_command_byte(struct i8042_port *port, unsigned char cb) 628 { 629 struct i8042 *global; 630 631 global = port->i8042_global; 632 633 mutex_enter(&global->i8042_mutex); 634 i8042_send(global, I8042_CMD, I8042_CMD_WCB); 635 i8042_send(global, I8042_DATA, cb); 636 mutex_exit(&global->i8042_mutex); 637 } 638 639 /* 640 * Send a byte to either the i8042 command or data register, depending on 641 * the argument. 642 */ 643 static void 644 i8042_send(struct i8042 *global, int reg, unsigned char val) 645 { 646 uint8_t stat; 647 648 /* 649 * First, wait for the i8042 to be ready to accept data. 650 */ 651 do { 652 stat = ddi_get8(global->io_handle, 653 global->io_addr + I8042_STAT); 654 } while (stat & I8042_STAT_INBF); 655 656 /* 657 * ... and then send the data. 658 */ 659 ddi_put8(global->io_handle, global->io_addr+reg, val); 660 } 661 662 /* 663 * Here's the interface to the virtual registers on the device. 664 * 665 * Normal interrupt-driven I/O: 666 * 667 * I8042_INT_INPUT_AVAIL (r/o) 668 * Interrupt mode input bytes available? Zero = No. 669 * I8042_INT_INPUT_DATA (r/o) 670 * Fetch interrupt mode input byte. 671 * I8042_INT_OUTPUT_DATA (w/o) 672 * Interrupt mode output byte. 673 * 674 * Polled I/O, used by (e.g.) kmdb, when normal system services are 675 * unavailable: 676 * 677 * I8042_POLL_INPUT_AVAIL (r/o) 678 * Polled mode input bytes available? Zero = No. 679 * I8042_POLL_INPUT_DATA (r/o) 680 * Polled mode input byte. 681 * I8042_POLL_OUTPUT_DATA (w/o) 682 * Polled mode output byte. 683 * 684 * Note that in polled mode we cannot use cmn_err; only prom_printf is safe. 685 */ 686 static uint8_t 687 i8042_get8(ddi_acc_impl_t *handlep, uint8_t *addr) 688 { 689 struct i8042_port *port; 690 struct i8042 *global; 691 uint8_t ret; 692 ddi_acc_hdl_t *h; 693 uint8_t stat; 694 695 h = (ddi_acc_hdl_t *)handlep; 696 697 port = (struct i8042_port *)h->ah_bus_private; 698 global = port->i8042_global; 699 700 switch ((uintptr_t)addr) { 701 case I8042_INT_INPUT_AVAIL: 702 mutex_enter(&global->i8042_mutex); 703 ret = port->rptr != port->wptr; 704 mutex_exit(&global->i8042_mutex); 705 return (ret); 706 707 case I8042_INT_INPUT_DATA: 708 mutex_enter(&global->i8042_mutex); 709 710 if (port->rptr != port->wptr) { 711 ret = port->buf[port->rptr]; 712 port->rptr = (port->rptr + 1) % BUFSIZ; 713 } else { 714 #if defined(DEBUG) 715 cmn_err(CE_WARN, 716 "i8042: Tried to read from empty buffer"); 717 #endif 718 ret = 0; 719 } 720 721 722 mutex_exit(&global->i8042_mutex); 723 724 break; 725 726 #if defined(DEBUG) 727 case I8042_INT_OUTPUT_DATA: 728 case I8042_POLL_OUTPUT_DATA: 729 cmn_err(CE_WARN, "i8042: read of write-only register 0x%p", 730 (void *)addr); 731 ret = 0; 732 break; 733 #endif 734 735 case I8042_POLL_INPUT_AVAIL: 736 if (port->rptr != port->wptr) 737 return (B_TRUE); 738 for (;;) { 739 stat = ddi_get8(global->io_handle, 740 global->io_addr + I8042_STAT); 741 if ((stat & I8042_STAT_OUTBF) == 0) 742 return (B_FALSE); 743 switch (port->which) { 744 case MAIN_PORT: 745 if ((stat & I8042_STAT_AUXBF) == 0) 746 return (B_TRUE); 747 break; 748 case AUX_PORT: 749 if ((stat & I8042_STAT_AUXBF) != 0) 750 return (B_TRUE); 751 break; 752 } 753 /* 754 * Data for wrong port pending; discard it. 755 */ 756 (void) ddi_get8(global->io_handle, 757 global->io_addr + I8042_DATA); 758 } 759 760 /* NOTREACHED */ 761 762 case I8042_POLL_INPUT_DATA: 763 if (port->rptr != port->wptr) { 764 ret = port->buf[port->rptr]; 765 port->rptr = (port->rptr + 1) % BUFSIZ; 766 return (ret); 767 } 768 769 stat = ddi_get8(global->io_handle, 770 global->io_addr + I8042_STAT); 771 if ((stat & I8042_STAT_OUTBF) == 0) { 772 #if defined(DEBUG) 773 prom_printf("I8042_POLL_INPUT_DATA: no data!\n"); 774 #endif 775 return (0); 776 } 777 ret = ddi_get8(global->io_handle, 778 global->io_addr + I8042_DATA); 779 switch (port->which) { 780 case MAIN_PORT: 781 if ((stat & I8042_STAT_AUXBF) == 0) 782 return (ret); 783 break; 784 case AUX_PORT: 785 if ((stat & I8042_STAT_AUXBF) != 0) 786 return (ret); 787 break; 788 } 789 #if defined(DEBUG) 790 prom_printf("I8042_POLL_INPUT_DATA: data for wrong port!\n"); 791 #endif 792 return (0); 793 794 default: 795 #if defined(DEBUG) 796 cmn_err(CE_WARN, "i8042: read of undefined register 0x%p", 797 (void *)addr); 798 #endif 799 ret = 0; 800 break; 801 } 802 return (ret); 803 } 804 805 static void 806 i8042_put8(ddi_acc_impl_t *handlep, uint8_t *addr, uint8_t value) 807 { 808 struct i8042_port *port; 809 struct i8042 *global; 810 ddi_acc_hdl_t *h; 811 812 h = (ddi_acc_hdl_t *)handlep; 813 814 port = (struct i8042_port *)h->ah_bus_private; 815 global = port->i8042_global; 816 817 switch ((uintptr_t)addr) { 818 case I8042_INT_OUTPUT_DATA: 819 case I8042_POLL_OUTPUT_DATA: 820 821 if ((uintptr_t)addr == I8042_INT_OUTPUT_DATA) 822 mutex_enter(&global->i8042_out_mutex); 823 824 if (port->which == AUX_PORT) 825 i8042_send(global, I8042_CMD, I8042_CMD_WRITE_AUX); 826 827 i8042_send(global, I8042_DATA, value); 828 829 if ((uintptr_t)addr == I8042_INT_OUTPUT_DATA) 830 mutex_exit(&global->i8042_out_mutex); 831 break; 832 833 834 #if defined(DEBUG) 835 case I8042_INT_INPUT_AVAIL: 836 case I8042_INT_INPUT_DATA: 837 case I8042_POLL_INPUT_AVAIL: 838 case I8042_POLL_INPUT_DATA: 839 cmn_err(CE_WARN, "i8042: write of read-only register 0x%p", 840 (void *)addr); 841 break; 842 843 default: 844 cmn_err(CE_WARN, "i8042: read of undefined register 0x%p", 845 (void *)addr); 846 break; 847 #endif 848 } 849 } 850 851 852 /* ARGSUSED */ 853 static int 854 i8042_intr_ops(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 855 ddi_intr_handle_impl_t *hdlp, void *result) 856 { 857 struct i8042_port *port; 858 #if defined(USE_SOFT_INTRS) 859 struct i8042 *global; 860 int ret; 861 #endif 862 863 switch (intr_op) { 864 case DDI_INTROP_SUPPORTED_TYPES: 865 *(int *)result = DDI_INTR_TYPE_FIXED; 866 break; 867 case DDI_INTROP_GETCAP: 868 if (i_ddi_intr_ops(dip, rdip, intr_op, hdlp, result) 869 == DDI_FAILURE) 870 *(int *)result = 0; 871 break; 872 case DDI_INTROP_NINTRS: 873 *(int *)result = 1; 874 break; 875 case DDI_INTROP_ALLOC: 876 *(int *)result = hdlp->ih_scratch1; 877 break; 878 case DDI_INTROP_FREE: 879 break; 880 case DDI_INTROP_GETPRI: 881 /* Hard coding it for x86 */ 882 *(int *)result = 5; 883 break; 884 case DDI_INTROP_ADDISR: 885 port = ddi_get_parent_data(rdip); 886 887 #if defined(USE_SOFT_INTRS) 888 global = port->i8042_global; 889 ret = ddi_intr_add_softint(rdip, &port->soft_hdl, 890 I8042_SOFTINT_PRI, hdlp->ih_cb_func, hdlp->ih_cb_arg1); 891 892 if (ret != DDI_SUCCESS) { 893 #if defined(DEBUG) 894 cmn_err(CE_WARN, "%s #%d: " 895 "Cannot add soft interrupt for %s #%d, ret=%d.", 896 DRIVER_NAME(dip), ddi_get_instance(dip), 897 DRIVER_NAME(rdip), ddi_get_instance(rdip), ret); 898 #endif /* defined(DEBUG) */ 899 return (ret); 900 } 901 902 #else /* defined(USE_SOFT_INTRS) */ 903 mutex_enter(&port->intr_mutex); 904 port->intr_func = hdlp->ih_cb_func; 905 port->intr_arg1 = hdlp->ih_cb_arg1; 906 port->intr_arg2 = hdlp->ih_cb_arg2; 907 mutex_exit(&port->intr_mutex); 908 #endif /* defined(USE_SOFT_INTRS) */ 909 break; 910 case DDI_INTROP_REMISR: 911 port = ddi_get_parent_data(rdip); 912 913 #if defined(USE_SOFT_INTRS) 914 global = port->i8042_global; 915 mutex_enter(&global->i8042_mutex); 916 port->soft_hdl = 0; 917 mutex_exit(&global->i8042_mutex); 918 #else /* defined(USE_SOFT_INTRS) */ 919 mutex_enter(&port->intr_mutex); 920 port->intr_func = NULL; 921 mutex_exit(&port->intr_mutex); 922 #endif /* defined(USE_SOFT_INTRS) */ 923 break; 924 case DDI_INTROP_ENABLE: 925 port = ddi_get_parent_data(rdip); 926 #if defined(USE_SOFT_INTRS) 927 global = port->i8042_global; 928 mutex_enter(&global->i8042_mutex); 929 port->soft_intr_enabled = B_TRUE; 930 if (port->wptr != port->rptr) 931 (void) ddi_intr_trigger_softint(port->soft_hdl, NULL); 932 mutex_exit(&global->i8042_mutex); 933 #else /* defined(USE_SOFT_INTRS) */ 934 mutex_enter(&port->intr_mutex); 935 if (port->wptr != port->rptr) 936 port->intr_func(port->intr_arg1, port->intr_arg2); 937 mutex_exit(&port->intr_mutex); 938 #endif /* defined(USE_SOFT_INTRS) */ 939 break; 940 case DDI_INTROP_DISABLE: 941 #if defined(USE_SOFT_INTRS) 942 port = ddi_get_parent_data(rdip); 943 global = port->i8042_global; 944 mutex_enter(&global->i8042_mutex); 945 port->soft_intr_enabled = B_FALSE; 946 (void) ddi_intr_remove_softint((port->soft_hdl); 947 mutex_exit(&global->i8042_mutex); 948 #endif /* defined(USE_SOFT_INTRS) */ 949 break; 950 case DDI_INTROP_NAVAIL: 951 *(int *)result = 1; 952 break; 953 default: 954 return (DDI_FAILURE); 955 } 956 957 return (DDI_SUCCESS); 958 } 959 960 static int 961 i8042_ctlops(dev_info_t *dip, dev_info_t *rdip, 962 ddi_ctl_enum_t op, void *arg, void *result) 963 { 964 int *iprop; 965 unsigned int iprop_len; 966 int which_port; 967 char name[16]; 968 struct i8042 *global; 969 dev_info_t *child; 970 971 global = ddi_get_driver_private(dip); 972 973 switch (op) { 974 case DDI_CTLOPS_INITCHILD: 975 child = (dev_info_t *)arg; 976 if (ddi_prop_lookup_int_array(DDI_DEV_T_ANY, child, 977 DDI_PROP_DONTPASS, "reg", &iprop, &iprop_len) != 978 DDI_SUCCESS) { 979 #if defined(DEBUG) 980 cmn_err(CE_WARN, "%s #%d: Missing 'reg' on %s@???", 981 DRIVER_NAME(dip), ddi_get_instance(dip), 982 ddi_node_name(child)); 983 #endif 984 return (DDI_FAILURE); 985 } 986 which_port = iprop[0]; 987 ddi_prop_free((void *)iprop); 988 989 (void) sprintf(name, "%d", which_port); 990 ddi_set_name_addr(child, name); 991 ddi_set_parent_data(child, 992 (caddr_t)&global->i8042_ports[which_port]); 993 return (DDI_SUCCESS); 994 995 case DDI_CTLOPS_UNINITCHILD: 996 child = (dev_info_t *)arg; 997 ddi_set_name_addr(child, NULL); 998 ddi_set_parent_data(child, NULL); 999 return (DDI_SUCCESS); 1000 1001 case DDI_CTLOPS_REPORTDEV: 1002 cmn_err(CE_CONT, "?8042 device: %s@%s, %s # %d\n", 1003 ddi_node_name(rdip), ddi_get_name_addr(rdip), 1004 DRIVER_NAME(rdip), ddi_get_instance(rdip)); 1005 return (DDI_SUCCESS); 1006 1007 default: 1008 return (ddi_ctlops(dip, rdip, op, arg, result)); 1009 } 1010 /* NOTREACHED */ 1011 } 1012 1013 static void 1014 alloc_kb_mouse(dev_info_t *i8042_dip) 1015 { 1016 static int alloced = 0; 1017 int circ, acpi_off = 0; 1018 dev_info_t *xdip; 1019 char *acpi_prop; 1020 1021 1022 ndi_devi_enter(i8042_dip, &circ); 1023 if (alloced) { /* just in case we are multi-threaded */ 1024 ndi_devi_exit(i8042_dip, circ); 1025 return; 1026 } 1027 alloced = 1; 1028 1029 /* don't alloc unless acpi is off */ 1030 if (ddi_prop_lookup_string(DDI_DEV_T_ANY, ddi_root_node(), 1031 DDI_PROP_DONTPASS, "acpi-enum", &acpi_prop) == DDI_PROP_SUCCESS) { 1032 if (strcmp("off", acpi_prop) == 0) { 1033 acpi_off = 1; 1034 } 1035 ddi_prop_free(acpi_prop); 1036 } 1037 if (acpi_off == 0) { 1038 ndi_devi_exit(i8042_dip, circ); 1039 return; 1040 } 1041 1042 /* mouse */ 1043 ndi_devi_alloc_sleep(i8042_dip, "mouse", 1044 (dnode_t)DEVI_SID_NODEID, &xdip); 1045 (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, 1046 "reg", 1); 1047 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 1048 "compatible", "pnpPNP,f03"); 1049 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 1050 "device-type", "mouse"); 1051 (void) ndi_devi_bind_driver(xdip, 0); 1052 1053 /* keyboard */ 1054 ndi_devi_alloc_sleep(i8042_dip, "keyboard", 1055 (dnode_t)DEVI_SID_NODEID, &xdip); 1056 (void) ndi_prop_update_int(DDI_DEV_T_NONE, xdip, 1057 "reg", 0); 1058 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 1059 "compatible", "pnpPNP,303"); 1060 (void) ndi_prop_update_string(DDI_DEV_T_NONE, xdip, 1061 "device-type", "keyboard"); 1062 (void) ndi_devi_bind_driver(xdip, 0); 1063 1064 ndi_devi_exit(i8042_dip, circ); 1065 } 1066 1067 static int 1068 i8042_bus_config(dev_info_t *parent, uint_t flags, 1069 ddi_bus_config_op_t op, void *arg, dev_info_t **childp) 1070 { 1071 alloc_kb_mouse(parent); 1072 1073 return (ndi_busop_bus_config(parent, flags, op, arg, childp, 0)); 1074 } 1075 1076 static int 1077 i8042_bus_unconfig(dev_info_t *parent, uint_t flags, 1078 ddi_bus_config_op_t op, void *arg) 1079 { 1080 return (ndi_busop_bus_unconfig(parent, flags, op, arg)); 1081 } 1082