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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */ 22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */ 23 /* All Rights Reserved */ 24 25 /* 26 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 27 * Use is subject to license terms. 28 */ 29 30 31 /* 32 * PS/2 type Mouse Module - Streams 33 */ 34 35 #include <sys/param.h> 36 #include <sys/types.h> 37 #include <sys/kmem.h> 38 #include <sys/signal.h> 39 #include <sys/errno.h> 40 #include <sys/file.h> 41 #include <sys/termio.h> 42 #include <sys/stream.h> 43 #include <sys/stropts.h> 44 #include <sys/strtty.h> 45 #include <sys/strsun.h> 46 #include <sys/debug.h> 47 #include <sys/ddi.h> 48 #include <sys/stat.h> 49 #include <sys/cmn_err.h> 50 #include <sys/sunddi.h> 51 52 #include <sys/promif.h> 53 #include <sys/cred.h> 54 55 #include <sys/i8042.h> 56 #include <sys/note.h> 57 #include <sys/mouse.h> 58 59 #define DRIVER_NAME(dip) ddi_driver_name(dip) 60 61 #define MOUSE8042_INTERNAL_OPEN(minor) (((minor) & 0x1) == 1) 62 #define MOUSE8042_MINOR_TO_INSTANCE(minor) ((minor) / 2) 63 #define MOUSE8042_INTERNAL_MINOR(minor) ((minor) + 1) 64 65 #define MOUSE8042_RESET_TIMEOUT_USECS 500000 /* 500 ms */ 66 67 extern int ddi_create_internal_pathname(dev_info_t *, char *, int, minor_t); 68 extern void consconfig_link(major_t major, minor_t minor); 69 extern int consconfig_unlink(major_t major, minor_t minor); 70 71 72 /* 73 * 74 * Local Static Data 75 * 76 */ 77 78 /* 79 * We only support one instance. Yes, it's theoretically possible to 80 * plug in more than one, but it's not worth the implementation cost. 81 * 82 * The introduction of USB keyboards might make it worth reassessing 83 * this decision, as they might free up the keyboard port for a second 84 * PS/2 style mouse. 85 */ 86 static dev_info_t *mouse8042_dip; 87 88 /* 89 * RESET states 90 */ 91 typedef enum { 92 MSE_RESET_IDLE, /* No reset in progress */ 93 MSE_RESET_PRE, /* Send reset, waiting for ACK */ 94 MSE_RESET_ACK, /* Got ACK, waiting for 0xAA */ 95 MSE_RESET_AA, /* Got 0xAA, waiting for 0x00 */ 96 MSE_RESET_FAILED 97 } mouse8042_reset_state_e; 98 99 struct mouse_state { 100 queue_t *ms_rqp; 101 queue_t *ms_wqp; 102 ddi_iblock_cookie_t ms_iblock_cookie; 103 ddi_acc_handle_t ms_handle; 104 uint8_t *ms_addr; 105 kmutex_t ms_mutex; 106 107 minor_t ms_minor; 108 boolean_t ms_opened; 109 kmutex_t reset_mutex; 110 mouse8042_reset_state_e reset_state; 111 timeout_id_t reset_tid; 112 int ready; 113 mblk_t *reply_mp; 114 bufcall_id_t bc_id; 115 }; 116 117 static uint_t mouse8042_intr(caddr_t arg); 118 static int mouse8042_open(queue_t *q, dev_t *devp, int flag, int sflag, 119 cred_t *cred_p); 120 static int mouse8042_close(queue_t *q, int flag, cred_t *cred_p); 121 static int mouse8042_wsrv(queue_t *qp); 122 123 static int mouse8042_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd, 124 void *arg, void **result); 125 static int mouse8042_attach(dev_info_t *dev, ddi_attach_cmd_t cmd); 126 static int mouse8042_detach(dev_info_t *dev, ddi_detach_cmd_t cmd); 127 128 129 /* 130 * Streams module info. 131 */ 132 #define MODULE_NAME "mouse8042" 133 134 static struct module_info mouse8042_minfo = { 135 23, /* Module ID number */ 136 MODULE_NAME, 137 0, INFPSZ, /* minimum & maximum packet sizes */ 138 256, 128 /* hi and low water marks */ 139 }; 140 141 static struct qinit mouse8042_rinit = { 142 NULL, /* put */ 143 NULL, /* service */ 144 mouse8042_open, 145 mouse8042_close, 146 NULL, /* admin */ 147 &mouse8042_minfo, 148 NULL /* statistics */ 149 }; 150 151 static struct qinit mouse8042_winit = { 152 putq, /* put */ 153 mouse8042_wsrv, /* service */ 154 NULL, /* open */ 155 NULL, /* close */ 156 NULL, /* admin */ 157 &mouse8042_minfo, 158 NULL /* statistics */ 159 }; 160 161 static struct streamtab mouse8042_strinfo = { 162 &mouse8042_rinit, 163 &mouse8042_winit, 164 NULL, /* muxrinit */ 165 NULL, /* muxwinit */ 166 }; 167 168 /* 169 * Local Function Declarations 170 */ 171 172 static struct cb_ops mouse8042_cb_ops = { 173 nodev, /* open */ 174 nodev, /* close */ 175 nodev, /* strategy */ 176 nodev, /* print */ 177 nodev, /* dump */ 178 nodev, /* read */ 179 nodev, /* write */ 180 nodev, /* ioctl */ 181 nodev, /* devmap */ 182 nodev, /* mmap */ 183 nodev, /* segmap */ 184 nochpoll, /* poll */ 185 ddi_prop_op, /* cb_prop_op */ 186 &mouse8042_strinfo, /* streamtab */ 187 D_MP | D_NEW 188 }; 189 190 191 static struct dev_ops mouse8042_ops = { 192 DEVO_REV, /* devo_rev, */ 193 0, /* refcnt */ 194 mouse8042_getinfo, /* getinfo */ 195 nulldev, /* identify */ 196 nulldev, /* probe */ 197 mouse8042_attach, /* attach */ 198 mouse8042_detach, /* detach */ 199 nodev, /* reset */ 200 &mouse8042_cb_ops, /* driver operations */ 201 (struct bus_ops *)0, /* bus operations */ 202 NULL, /* power */ 203 ddi_quiesce_not_needed, /* quiesce */ 204 }; 205 206 /* 207 * This is the loadable module wrapper. 208 */ 209 #include <sys/modctl.h> 210 211 extern struct mod_ops mod_driverops; 212 213 /* 214 * Module linkage information for the kernel. 215 */ 216 217 static struct modldrv modldrv = { 218 &mod_driverops, /* Type of module. This one is a driver */ 219 "PS/2 Mouse", 220 &mouse8042_ops, /* driver ops */ 221 }; 222 223 static struct modlinkage modlinkage = { 224 MODREV_1, 225 (void *)&modldrv, 226 NULL 227 }; 228 229 /* 230 * This is the driver initialization routine. 231 */ 232 int 233 _init() 234 { 235 int rv; 236 237 rv = mod_install(&modlinkage); 238 return (rv); 239 } 240 241 242 int 243 _fini(void) 244 { 245 return (mod_remove(&modlinkage)); 246 } 247 248 249 int 250 _info(struct modinfo *modinfop) 251 { 252 return (mod_info(&modlinkage, modinfop)); 253 } 254 255 static int 256 mouse8042_attach(dev_info_t *dip, ddi_attach_cmd_t cmd) 257 { 258 struct mouse_state *state; 259 mblk_t *mp; 260 int instance = ddi_get_instance(dip); 261 static ddi_device_acc_attr_t attr = { 262 DDI_DEVICE_ATTR_V0, 263 DDI_NEVERSWAP_ACC, 264 DDI_STRICTORDER_ACC, 265 }; 266 int rc; 267 268 269 if (cmd == DDI_RESUME) { 270 state = (struct mouse_state *)ddi_get_driver_private(dip); 271 272 /* Ready to handle inbound data from mouse8042_intr */ 273 state->ready = 1; 274 275 /* 276 * Send a 0xaa 0x00 upstream. 277 * This causes the vuid module to reset the mouse. 278 */ 279 if (state->ms_rqp != NULL) { 280 if (mp = allocb(1, BPRI_MED)) { 281 *mp->b_wptr++ = 0xaa; 282 putnext(state->ms_rqp, mp); 283 } 284 if (mp = allocb(1, BPRI_MED)) { 285 *mp->b_wptr++ = 0x0; 286 putnext(state->ms_rqp, mp); 287 } 288 } 289 return (DDI_SUCCESS); 290 } 291 292 if (cmd != DDI_ATTACH) 293 return (DDI_FAILURE); 294 295 if (mouse8042_dip != NULL) 296 return (DDI_FAILURE); 297 298 /* allocate and initialize state structure */ 299 state = kmem_zalloc(sizeof (struct mouse_state), KM_SLEEP); 300 state->ms_opened = B_FALSE; 301 state->reset_state = MSE_RESET_IDLE; 302 state->reset_tid = 0; 303 state->bc_id = 0; 304 ddi_set_driver_private(dip, state); 305 306 /* 307 * In order to support virtual keyboard/mouse, we should distinguish 308 * between internal virtual open and external physical open. 309 * 310 * When the physical devices are opened by application, they will 311 * be unlinked from the virtual device and their data stream will 312 * not be sent to the virtual device. When the opened physical 313 * devices are closed, they will be relinked to the virtual devices. 314 * 315 * All these automatic switch between virtual and physical are 316 * transparent. 317 * 318 * So we change minor node numbering scheme to be: 319 * external node minor num == instance * 2 320 * internal node minor num == instance * 2 + 1 321 */ 322 rc = ddi_create_minor_node(dip, "mouse", S_IFCHR, instance * 2, 323 DDI_NT_MOUSE, NULL); 324 if (rc != DDI_SUCCESS) { 325 goto fail_1; 326 } 327 328 if (ddi_create_internal_pathname(dip, "internal_mouse", S_IFCHR, 329 instance * 2 + 1) != DDI_SUCCESS) { 330 goto fail_2; 331 } 332 333 rc = ddi_regs_map_setup(dip, 0, (caddr_t *)&state->ms_addr, 334 (offset_t)0, (offset_t)0, &attr, &state->ms_handle); 335 if (rc != DDI_SUCCESS) { 336 goto fail_2; 337 } 338 339 rc = ddi_get_iblock_cookie(dip, 0, &state->ms_iblock_cookie); 340 if (rc != DDI_SUCCESS) { 341 goto fail_3; 342 } 343 344 mutex_init(&state->ms_mutex, NULL, MUTEX_DRIVER, 345 state->ms_iblock_cookie); 346 mutex_init(&state->reset_mutex, NULL, MUTEX_DRIVER, 347 state->ms_iblock_cookie); 348 349 rc = ddi_add_intr(dip, 0, 350 (ddi_iblock_cookie_t *)NULL, (ddi_idevice_cookie_t *)NULL, 351 mouse8042_intr, (caddr_t)state); 352 if (rc != DDI_SUCCESS) { 353 goto fail_3; 354 } 355 356 mouse8042_dip = dip; 357 358 /* Ready to handle inbound data from mouse8042_intr */ 359 state->ready = 1; 360 361 /* Now that we're attached, announce our presence to the world. */ 362 ddi_report_dev(dip); 363 return (DDI_SUCCESS); 364 365 fail_3: 366 ddi_regs_map_free(&state->ms_handle); 367 368 fail_2: 369 ddi_remove_minor_node(dip, NULL); 370 371 fail_1: 372 kmem_free(state, sizeof (struct mouse_state)); 373 return (rc); 374 } 375 376 /*ARGSUSED*/ 377 static int 378 mouse8042_detach(dev_info_t *dip, ddi_detach_cmd_t cmd) 379 { 380 struct mouse_state *state; 381 382 state = ddi_get_driver_private(dip); 383 384 switch (cmd) { 385 case DDI_SUSPEND: 386 /* Ignore all data from mouse8042_intr until we fully resume */ 387 state->ready = 0; 388 return (DDI_SUCCESS); 389 390 case DDI_DETACH: 391 ddi_remove_intr(dip, 0, state->ms_iblock_cookie); 392 mouse8042_dip = NULL; 393 mutex_destroy(&state->reset_mutex); 394 mutex_destroy(&state->ms_mutex); 395 ddi_prop_remove_all(dip); 396 ddi_regs_map_free(&state->ms_handle); 397 ddi_remove_minor_node(dip, NULL); 398 kmem_free(state, sizeof (struct mouse_state)); 399 return (DDI_SUCCESS); 400 401 default: 402 return (DDI_FAILURE); 403 } 404 } 405 406 407 /* ARGSUSED */ 408 static int 409 mouse8042_getinfo( 410 dev_info_t *dip, 411 ddi_info_cmd_t infocmd, 412 void *arg, 413 void **result) 414 { 415 dev_t dev = (dev_t)arg; 416 minor_t minor = getminor(dev); 417 int instance = MOUSE8042_MINOR_TO_INSTANCE(minor); 418 419 switch (infocmd) { 420 case DDI_INFO_DEVT2DEVINFO: 421 if (mouse8042_dip == NULL) 422 return (DDI_FAILURE); 423 424 *result = (void *)mouse8042_dip; 425 break; 426 case DDI_INFO_DEVT2INSTANCE: 427 *result = (void *)(uintptr_t)instance; 428 break; 429 default: 430 return (DDI_FAILURE); 431 } 432 return (DDI_SUCCESS); 433 } 434 435 /*ARGSUSED*/ 436 static int 437 mouse8042_open( 438 queue_t *q, 439 dev_t *devp, 440 int flag, 441 int sflag, 442 cred_t *cred_p) 443 { 444 struct mouse_state *state; 445 minor_t minor = getminor(*devp); 446 int rval; 447 448 if (mouse8042_dip == NULL) 449 return (ENXIO); 450 451 state = ddi_get_driver_private(mouse8042_dip); 452 453 mutex_enter(&state->ms_mutex); 454 455 if (state->ms_opened) { 456 /* 457 * Exit if the same minor node is already open 458 */ 459 if (state->ms_minor == minor) { 460 mutex_exit(&state->ms_mutex); 461 return (0); 462 } 463 464 /* 465 * Check whether it is switch between physical and virtual 466 * 467 * Opening from virtual while the device is being physically 468 * opened by an application should not happen. So we ASSERT 469 * this in DEBUG version, and return error in the non-DEBUG 470 * case. 471 */ 472 ASSERT(!MOUSE8042_INTERNAL_OPEN(minor)); 473 474 if (MOUSE8042_INTERNAL_OPEN(minor)) { 475 mutex_exit(&state->ms_mutex); 476 return (EINVAL); 477 } 478 479 /* 480 * Opening the physical one while it is being underneath 481 * the virtual one. 482 * 483 * consconfig_unlink is called to unlink this device from 484 * the virtual one, thus the old stream serving for this 485 * device under the virtual one is closed, and then the 486 * lower driver's close routine (here is mouse8042_close) 487 * is also called to accomplish the whole stream close. 488 * Here we have to drop the lock because mouse8042_close 489 * also needs the lock. 490 * 491 * For mouse, the old stream is: 492 * consms->["pushmod"->]"mouse_vp driver" 493 * 494 * After the consconfig_unlink returns, the old stream is closed 495 * and we grab the lock again to reopen this device as normal. 496 */ 497 mutex_exit(&state->ms_mutex); 498 499 /* 500 * If unlink fails, fail the physical open. 501 */ 502 if ((rval = consconfig_unlink(ddi_driver_major(mouse8042_dip), 503 MOUSE8042_INTERNAL_MINOR(minor))) != 0) { 504 return (rval); 505 } 506 507 mutex_enter(&state->ms_mutex); 508 } 509 510 511 q->q_ptr = (caddr_t)state; 512 WR(q)->q_ptr = (caddr_t)state; 513 state->ms_rqp = q; 514 state->ms_wqp = WR(q); 515 516 qprocson(q); 517 518 state->ms_minor = minor; 519 state->ms_opened = B_TRUE; 520 521 mutex_exit(&state->ms_mutex); 522 523 return (0); 524 } 525 526 527 /*ARGSUSED*/ 528 static int 529 mouse8042_close(queue_t *q, int flag, cred_t *cred_p) 530 { 531 struct mouse_state *state; 532 minor_t minor; 533 534 state = (struct mouse_state *)q->q_ptr; 535 536 mutex_enter(&state->ms_mutex); 537 538 qprocsoff(q); 539 540 if (state->reset_tid != 0) { 541 (void) quntimeout(q, state->reset_tid); 542 state->reset_tid = 0; 543 } 544 if (state->bc_id != 0) { 545 (void) qunbufcall(q, state->bc_id); 546 state->bc_id = 0; 547 } 548 if (state->reply_mp != NULL) { 549 freemsg(state->reply_mp); 550 state->reply_mp = NULL; 551 } 552 553 q->q_ptr = NULL; 554 WR(q)->q_ptr = NULL; 555 state->ms_rqp = NULL; 556 state->ms_wqp = NULL; 557 558 state->ms_opened = B_FALSE; 559 560 minor = state->ms_minor; 561 562 mutex_exit(&state->ms_mutex); 563 564 if (!MOUSE8042_INTERNAL_OPEN(minor)) { 565 /* 566 * Closing physical PS/2 mouse 567 * 568 * Link it back to virtual mouse, and 569 * mouse8042_open will be called as a result 570 * of the consconfig_link call. Do NOT try 571 * this if the mouse is about to be detached! 572 * 573 * If linking back fails, this specific mouse 574 * will not be available underneath the virtual 575 * mouse, and can only be accessed via physical 576 * open. 577 */ 578 consconfig_link(ddi_driver_major(mouse8042_dip), 579 MOUSE8042_INTERNAL_MINOR(minor)); 580 } 581 582 return (0); 583 } 584 585 static void 586 mouse8042_iocnack( 587 queue_t *qp, 588 mblk_t *mp, 589 struct iocblk *iocp, 590 int error, 591 int rval) 592 { 593 mp->b_datap->db_type = M_IOCNAK; 594 iocp->ioc_rval = rval; 595 iocp->ioc_error = error; 596 qreply(qp, mp); 597 } 598 599 static void 600 mouse8042_reset_timeout(void *argp) 601 { 602 struct mouse_state *state = (struct mouse_state *)argp; 603 mblk_t *mp; 604 605 mutex_enter(&state->reset_mutex); 606 607 /* 608 * If the interrupt handler hasn't completed the reset handling 609 * (reset_state would be IDLE or FAILED in that case), then 610 * drop the 8042 lock, and send a faked retry reply upstream, 611 * then enable the queue for further message processing. 612 */ 613 if (state->reset_state != MSE_RESET_IDLE && 614 state->reset_state != MSE_RESET_FAILED) { 615 616 state->reset_tid = 0; 617 state->reset_state = MSE_RESET_IDLE; 618 619 (void) ddi_get8(state->ms_handle, state->ms_addr + 620 I8042_UNLOCK); 621 622 mp = state->reply_mp; 623 *mp->b_wptr++ = MSERESEND; 624 state->reply_mp = NULL; 625 626 if (state->ms_rqp != NULL) 627 putnext(state->ms_rqp, mp); 628 else 629 freemsg(mp); 630 631 ASSERT(state->ms_wqp != NULL); 632 633 enableok(state->ms_wqp); 634 qenable(state->ms_wqp); 635 } 636 637 mutex_exit(&state->reset_mutex); 638 } 639 640 /* 641 * Returns 1 if the caller should put the message (bp) back on the queue 642 */ 643 static int 644 mouse8042_process_reset(queue_t *q, mblk_t *mp, struct mouse_state *state) 645 { 646 mutex_enter(&state->reset_mutex); 647 /* 648 * If we're in the middle of a reset, put the message back on the queue 649 * for processing later. 650 */ 651 if (state->reset_state != MSE_RESET_IDLE) { 652 /* 653 * We noenable the queue again here in case it was backenabled 654 * by an upper-level module. 655 */ 656 noenable(q); 657 658 mutex_exit(&state->reset_mutex); 659 return (1); 660 } 661 662 /* 663 * Drop the reset state lock before allocating the response message and 664 * grabbing the 8042 exclusive-access lock (since those operations 665 * may take an extended period of time to complete). 666 */ 667 mutex_exit(&state->reset_mutex); 668 669 state->reply_mp = allocb(3, BPRI_MED); 670 if (state->reply_mp == NULL) { 671 /* 672 * Allocation failed -- set up a bufcall to enable the queue 673 * whenever there is enough memory to allocate the response 674 * message. 675 */ 676 state->bc_id = qbufcall(q, 3, BPRI_MED, 677 (void (*)(void *))qenable, q); 678 679 if (state->bc_id == 0) { 680 /* 681 * If the qbufcall failed, we cannot proceed, so use the 682 * message we were sent to respond with an error. 683 */ 684 *mp->b_rptr = MSEERROR; 685 mp->b_wptr = mp->b_rptr + 1; 686 qreply(q, mp); 687 return (0); 688 } 689 690 return (1); 691 } 692 693 /* 694 * Gain exclusive access to the 8042 for the duration of the reset. 695 * The unlock will occur when the reset has either completed or timed 696 * out. 697 */ 698 (void) ddi_get8(state->ms_handle, 699 state->ms_addr + I8042_LOCK); 700 701 mutex_enter(&state->reset_mutex); 702 703 state->reset_state = MSE_RESET_PRE; 704 noenable(q); 705 706 state->reset_tid = qtimeout(q, 707 mouse8042_reset_timeout, 708 state, 709 drv_usectohz( 710 MOUSE8042_RESET_TIMEOUT_USECS)); 711 712 ddi_put8(state->ms_handle, 713 state->ms_addr + 714 I8042_INT_OUTPUT_DATA, MSERESET); 715 716 mp->b_rptr++; 717 718 mutex_exit(&state->reset_mutex); 719 return (1); 720 } 721 722 /* 723 * Returns 1 if the caller should stop processing messages 724 */ 725 static int 726 mouse8042_process_data_msg(queue_t *q, mblk_t *mp, struct mouse_state *state) 727 { 728 mblk_t *bp; 729 mblk_t *next; 730 731 bp = mp; 732 do { 733 while (bp->b_rptr < bp->b_wptr) { 734 /* 735 * Detect an attempt to reset the mouse. Lock out any 736 * further mouse writes until the reset has completed. 737 */ 738 if (*bp->b_rptr == MSERESET) { 739 740 /* 741 * If we couldn't allocate memory and we 742 * we couldn't register a bufcall, 743 * mouse8042_process_reset returns 0 and 744 * has already used the message to send an 745 * error reply back upstream, so there is no 746 * need to deallocate or put this message back 747 * on the queue. 748 */ 749 if (mouse8042_process_reset(q, bp, state) == 0) 750 return (1); 751 752 /* 753 * If there's no data remaining in this block, 754 * free this block and put the following blocks 755 * of this message back on the queue. If putting 756 * the rest of the message back on the queue 757 * fails, free the the message. 758 */ 759 if (MBLKL(bp) == 0) { 760 next = bp->b_cont; 761 freeb(bp); 762 bp = next; 763 } 764 if (bp != NULL) { 765 if (!putbq(q, bp)) 766 freemsg(bp); 767 } 768 769 return (1); 770 771 } 772 ddi_put8(state->ms_handle, 773 state->ms_addr + I8042_INT_OUTPUT_DATA, 774 *bp->b_rptr++); 775 } 776 next = bp->b_cont; 777 freeb(bp); 778 } while ((bp = next) != NULL); 779 780 return (0); 781 } 782 783 static int 784 mouse8042_process_msg(queue_t *q, mblk_t *mp, struct mouse_state *state) 785 { 786 struct iocblk *iocbp; 787 int rv = 0; 788 789 iocbp = (struct iocblk *)mp->b_rptr; 790 791 switch (mp->b_datap->db_type) { 792 case M_FLUSH: 793 if (*mp->b_rptr & FLUSHW) { 794 flushq(q, FLUSHDATA); 795 *mp->b_rptr &= ~FLUSHW; 796 } 797 if (*mp->b_rptr & FLUSHR) { 798 qreply(q, mp); 799 } else 800 freemsg(mp); 801 break; 802 case M_IOCTL: 803 mouse8042_iocnack(q, mp, iocbp, EINVAL, 0); 804 break; 805 case M_IOCDATA: 806 mouse8042_iocnack(q, mp, iocbp, EINVAL, 0); 807 break; 808 case M_DATA: 809 rv = mouse8042_process_data_msg(q, mp, state); 810 break; 811 default: 812 freemsg(mp); 813 break; 814 } 815 816 return (rv); 817 } 818 819 static int 820 mouse8042_wsrv(queue_t *qp) 821 { 822 mblk_t *mp; 823 struct mouse_state *state; 824 state = (struct mouse_state *)qp->q_ptr; 825 826 while ((mp = getq(qp)) != NULL) { 827 if (mouse8042_process_msg(qp, mp, state) != 0) 828 break; 829 } 830 831 return (0); 832 } 833 834 /* 835 * Returns the next reset state, given the current state and the byte 836 * received from the mouse. Error and Resend codes are handled by the 837 * caller. 838 */ 839 static mouse8042_reset_state_e 840 mouse8042_reset_fsm(mouse8042_reset_state_e reset_state, uint8_t mdata) 841 { 842 switch (reset_state) { 843 case MSE_RESET_PRE: /* RESET sent, now we expect an ACK */ 844 if (mdata == MSE_ACK) /* Got the ACK */ 845 return (MSE_RESET_ACK); 846 break; 847 848 case MSE_RESET_ACK: /* ACK received; now we expect 0xAA */ 849 if (mdata == MSE_AA) /* Got the 0xAA */ 850 return (MSE_RESET_AA); 851 break; 852 853 case MSE_RESET_AA: /* 0xAA received; now we expect 0x00 */ 854 if (mdata == MSE_00) 855 return (MSE_RESET_IDLE); 856 break; 857 } 858 859 return (reset_state); 860 } 861 862 static uint_t 863 mouse8042_intr(caddr_t arg) 864 { 865 unsigned char mdata; 866 mblk_t *mp; 867 struct mouse_state *state = (struct mouse_state *)arg; 868 int rc; 869 870 mutex_enter(&state->ms_mutex); 871 872 rc = DDI_INTR_UNCLAIMED; 873 874 for (;;) { 875 876 if (ddi_get8(state->ms_handle, 877 state->ms_addr + I8042_INT_INPUT_AVAIL) == 0) { 878 break; 879 } 880 881 mdata = ddi_get8(state->ms_handle, 882 state->ms_addr + I8042_INT_INPUT_DATA); 883 884 rc = DDI_INTR_CLAIMED; 885 886 /* 887 * If we're not ready for this data, discard it. 888 */ 889 if (!state->ready) 890 continue; 891 892 mutex_enter(&state->reset_mutex); 893 if (state->reset_state != MSE_RESET_IDLE) { 894 895 if (mdata == MSEERROR || mdata == MSERESET) { 896 state->reset_state = MSE_RESET_FAILED; 897 } else { 898 state->reset_state = 899 mouse8042_reset_fsm(state->reset_state, 900 mdata); 901 } 902 903 /* 904 * If we transitioned back to the idle reset state (or 905 * the reset failed), disable the timeout, release the 906 * 8042 exclusive-access lock, then send the response 907 * the the upper-level modules. Finally, enable the 908 * queue and schedule queue service procedures so that 909 * upper-level modules can process the response. 910 * Otherwise, if we're still in the middle of the 911 * reset sequence, do not send the data up (since the 912 * response is sent at the end of the sequence, or 913 * on timeout/error). 914 */ 915 if (state->reset_state == MSE_RESET_IDLE || 916 state->reset_state == MSE_RESET_FAILED) { 917 918 mutex_exit(&state->reset_mutex); 919 (void) quntimeout(state->ms_wqp, 920 state->reset_tid); 921 mutex_enter(&state->reset_mutex); 922 923 (void) ddi_get8(state->ms_handle, 924 state->ms_addr + I8042_UNLOCK); 925 926 state->reset_tid = 0; 927 mp = state->reply_mp; 928 if (state->reset_state == MSE_RESET_FAILED) { 929 *mp->b_wptr++ = mdata; 930 } else { 931 *mp->b_wptr++ = MSE_ACK; 932 *mp->b_wptr++ = MSE_AA; 933 *mp->b_wptr++ = MSE_00; 934 } 935 state->reply_mp = NULL; 936 937 state->reset_state = MSE_RESET_IDLE; 938 939 if (state->ms_rqp != NULL) 940 putnext(state->ms_rqp, mp); 941 else 942 freemsg(mp); 943 944 enableok(state->ms_wqp); 945 qenable(state->ms_wqp); 946 } 947 948 mutex_exit(&state->reset_mutex); 949 mutex_exit(&state->ms_mutex); 950 return (rc); 951 } 952 mutex_exit(&state->reset_mutex); 953 954 if (state->ms_rqp != NULL && (mp = allocb(1, BPRI_MED))) { 955 *mp->b_wptr++ = mdata; 956 putnext(state->ms_rqp, mp); 957 } 958 } 959 mutex_exit(&state->ms_mutex); 960 961 return (rc); 962 } 963