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 /* 22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* 27 * 2/3/5 Button PS/2 Mouse Protocol 28 * 29 * This module dynamically determines the number of buttons on the mouse. 30 */ 31 32 #include <sys/param.h> 33 #include <sys/stream.h> 34 #include <sys/vuid_event.h> 35 #include "vuidmice.h" 36 #include <sys/vuid_wheel.h> 37 #include <sys/mouse.h> 38 #include <sys/strsun.h> 39 #include <sys/ddi.h> 40 #include <sys/sunddi.h> 41 42 /* 43 * BUT(1) LEFT BUTTON 44 * BUT(2) MIDDLE BUTTON (if present) 45 * BUT(3) RIGHT BUTTON 46 */ 47 48 #define PS2_BUTTONMASK 7 /* mask byte zero with this */ 49 50 #define PS2_BUTTON_L (uchar_t)0x01 /* Left button pressed */ 51 #define PS2_BUTTON_R (uchar_t)0x02 /* Right button pressed */ 52 #define PS2_BUTTON_M (uchar_t)0x04 /* Middle button pressed */ 53 #define PS2_DATA_XSIGN (uchar_t)0x10 /* X data sign bit */ 54 #define PS2_DATA_YSIGN (uchar_t)0x20 /* Y data sign bit */ 55 56 #define PS2_START 0 /* Beginning of packet */ 57 #define PS2_BUTTON 1 /* Got button status */ 58 #define PS2_MAYBE_REATTACH 2 /* Got button status */ 59 #define PS2_DELTA_Y 3 /* Got delta X */ 60 #define PS2_WHEEL_DELTA_Z 4 61 #define PS2_WHEEL5_DELTA_Z 5 62 #define PS2_WAIT_RESET_COMPLETE 6 63 #define PS2_WAIT_FOR_AA 7 64 #define PS2_WAIT_FOR_00 8 65 #define PS2_WAIT_SETRES0_ACK1 9 66 #define PS2_WAIT_SETRES0_ACK2 10 /* -+ must be consecutive */ 67 #define PS2_WAIT_SCALE1_1_ACK 11 /* | */ 68 #define PS2_WAIT_SCALE1_2_ACK 12 /* | */ 69 #define PS2_WAIT_SCALE1_3_ACK 13 /* -+ */ 70 #define PS2_WAIT_STATREQ_ACK 14 /* -+ */ 71 #define PS2_WAIT_STATUS_1 15 /* | */ 72 #define PS2_WAIT_STATUS_BUTTONS 16 /* | must stay in this order */ 73 #define PS2_WAIT_STATUS_REV 17 /* -+ */ 74 #define PS2_WAIT_STATUS_3 18 75 #define PS2_WAIT_WHEEL_SMPL1_CMD_ACK 19 /* Set the sample rate to 200 */ 76 #define PS2_WAIT_WHEEL_SMPL1_RATE_ACK 20 77 #define PS2_WAIT_WHEEL_SMPL2_CMD_ACK 21 /* Set the sample rate to 200 */ 78 #define PS2_WAIT_WHEEL_SMPL2_RATE_ACK 22 79 #define PS2_WAIT_WHEEL_SMPL3_CMD_ACK 23 /* Set the sample rate to 80 */ 80 #define PS2_WAIT_WHEEL_SMPL3_RATE_ACK 24 81 #define PS2_WAIT_WHEEL_DEV_CMD 25 82 #define PS2_WAIT_WHEEL_DEV_ACK 26 /* Detected wheel mouse */ 83 #define PS2_WAIT_WHEEL5_SMPL1_CMD_ACK 27 /* Set the sample rate to 200 */ 84 #define PS2_WAIT_WHEEL5_SMPL1_RATE_ACK 28 85 #define PS2_WAIT_WHEEL5_SMPL2_CMD_ACK 29 /* Set the sample rate to 200 */ 86 #define PS2_WAIT_WHEEL5_SMPL2_RATE_ACK 30 87 #define PS2_WAIT_WHEEL5_SMPL3_CMD_ACK 31 /* Set the sample rate to 100 */ 88 #define PS2_WAIT_WHEEL5_SMPL3_RATE_ACK 32 89 #define PS2_WAIT_WHEEL5_DEV_CMD 33 90 #define PS2_WAIT_WHEEL5_DEV_ACK 34 /* Detected 5 button mouse */ 91 #define PS2_WAIT_SETRES3_CMD 35 92 #define PS2_WAIT_SETRES3_ACK1 36 93 #define PS2_WAIT_SETRES3_ACK2 37 94 #define PS2_WAIT_STREAM_ACK 38 95 #define PS2_WAIT_ON_ACK 39 96 97 #define MOUSE_MODE_PLAIN 0 /* Normal PS/2 mouse - 3 byte msgs */ 98 #define MOUSE_MODE_WHEEL 1 /* Wheel mouse - 4 byte msgs */ 99 #define MOUSE_MODE_WHEEL5 2 /* Wheel + 5 btn mouse - 4 byte msgs */ 100 101 #define PS2_FLAG_NO_EXTN 0x08 /* Mouse doesn't obey extended cmds */ 102 #define PS2_FLAG_INIT_DONE 0x01 /* Mouse has been inited successfully */ 103 #define PS2_FLAG_INIT_TIMEOUT 0x02 /* Mouse init timeout */ 104 105 /* 106 * The RESET command takes more time 107 * before the PS/2 mouse is ready 108 */ 109 #define PS2_INIT_TMOUT_RESET 500000 /* 500ms for RESET command */ 110 #define PS2_INIT_TMOUT_PER_CMD 200000 /* 200ms for each command-response */ 111 #define PS2_INIT_TMOUT_PER_GROUP 500000 /* 500ms for group commands */ 112 113 #define PS2_MAX_INIT_COUNT 5 114 115 static void vuidmice_send_wheel_event(queue_t *const, uchar_t, 116 uchar_t, uchar_t, int); 117 extern void VUID_PUTNEXT(queue_t *const, uchar_t, uchar_t, uchar_t, int); 118 extern void uniqtime32(struct timeval32 *); 119 static void VUID_INIT_TIMEOUT(void *q); 120 121 /* 122 * We apply timeout to nearly each command-response 123 * during initialization: 124 * 125 * Set timeout for SET RESOLUTION 126 * Set timeout for SET SCALE 127 * Set timeout for SET SAMPLE RATE 128 * Set timeout for STATUS REQUEST 129 * Set timeout for GET DEV 130 * Set timeout for SET STREAM MODE and ENABLE. 131 * 132 * But for simplicity, sometimes we just apply the timeout 133 * to a function with group commands (e.g. wheel-mouse detection). 134 * 135 */ 136 static void 137 vuid_set_timeout(queue_t *const qp, clock_t time) 138 { 139 if (STATEP->init_tid != 0) 140 (void) quntimeout(qp, STATEP->init_tid); 141 STATEP->init_tid = qtimeout(qp, VUID_INIT_TIMEOUT, 142 qp, drv_usectohz(time)); 143 } 144 145 static void 146 vuid_cancel_timeout(queue_t *const qp) 147 { 148 (void) quntimeout(qp, STATEP->init_tid); 149 STATEP->init_tid = 0; 150 } 151 152 /* 153 * vuidmice_send_wheel_event 154 * Convert wheel data to firm_events 155 */ 156 static void 157 vuidmice_send_wheel_event(queue_t *const qp, uchar_t event_id, 158 uchar_t event_pair_type, uchar_t event_pair, int event_value) 159 { 160 mblk_t *bp; 161 Firm_event *fep; 162 163 if ((bp = allocb((int)sizeof (Firm_event), BPRI_HI)) == NULL) { 164 165 return; 166 } 167 168 fep = (void *)bp->b_wptr; 169 fep->id = vuid_id_addr(vuid_first(VUID_WHEEL)) | 170 vuid_id_offset(event_id); 171 fep->pair_type = event_pair_type; 172 fep->pair = event_pair; 173 fep->value = event_value; 174 uniqtime32(&fep->time); 175 bp->b_wptr += sizeof (Firm_event); 176 177 if (canput(qp->q_next)) { 178 putnext(qp, bp); 179 } else { 180 (void) putbq(qp, bp); /* read side is blocked */ 181 } 182 } 183 184 185 static void 186 sendButtonEvent(queue_t *const qp) 187 { 188 static int bmap[3] = {1, 3, 2}; 189 uint_t b; 190 191 /* for each button, see if it has changed */ 192 for (b = 0; b < STATEP->nbuttons; b++) { 193 uchar_t mask = 0x1 << b; 194 195 if ((STATEP->buttons & mask) != (STATEP->oldbuttons & mask)) 196 VUID_PUTNEXT(qp, (uchar_t)BUT(bmap[b]), FE_PAIR_NONE, 0, 197 (STATEP->buttons & mask ? 1 : 0)); 198 } 199 } 200 201 void 202 put1(queue_t *const qp, int c) 203 { 204 mblk_t *bp; 205 206 if (bp = allocb(1, BPRI_MED)) { 207 *bp->b_wptr++ = (char)c; 208 putnext(qp, bp); 209 } 210 } 211 212 static void 213 vuidmice_start_wdc_or_setres(queue_t *qp) 214 { 215 /* Set timeout for set res or sample rate */ 216 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP); 217 218 /* 219 * Start the wheel-mouse detection code. First, we look 220 * for standard wheel mice. If we set the sample rate 221 * to 200, 100, and then 80 and finally request the 222 * device ID, a wheel mouse will return an ID of 0x03. 223 * After that, we'll try for the wheel+5 variety. The 224 * incantation in this case is 200, 200, and 80. We'll 225 * get 0x04 back in that case. 226 */ 227 if (STATEP->inited & PS2_FLAG_NO_EXTN) { 228 STATEP->state = PS2_WAIT_SETRES3_ACK1; 229 put1(WR(qp), MSESETRES); 230 } else { 231 STATEP->state = PS2_WAIT_WHEEL_SMPL1_CMD_ACK; 232 put1(WR(qp), MSECHGMOD); 233 } 234 } 235 236 int 237 VUID_OPEN(queue_t *const qp) 238 { 239 STATEP->format = VUID_FIRM_EVENT; 240 STATEP->vuid_mouse_mode = MOUSE_MODE_PLAIN; 241 STATEP->inited = 0; 242 STATEP->nbuttons = 3; 243 244 STATEP->state = PS2_WAIT_RESET_COMPLETE; 245 246 put1(WR(qp), MSERESET); 247 248 while ((STATEP->state != PS2_START) && 249 !(STATEP->inited & PS2_FLAG_INIT_TIMEOUT)) { 250 if (qwait_sig(qp) == 0) 251 break; 252 } 253 254 /* 255 * Later the PS/2 mouse maybe re-attach, so here 256 * clear the init_count. 257 */ 258 STATEP->init_count = 0; 259 260 return (0); 261 } 262 263 void 264 VUID_CLOSE(queue_t *const qp) 265 { 266 if (STATEP->init_tid != 0) 267 vuid_cancel_timeout(qp); 268 } 269 270 static void 271 VUID_INIT_TIMEOUT(void *q) 272 { 273 queue_t *qp = q; 274 275 STATEP->init_tid = 0; 276 277 /* 278 * Some mice do not even send an error in response to 279 * the wheel mouse sample commands, so if we're in any of 280 * the PS2_WAIT_WHEEL_SMPL* states, and there has been 281 * a timeout, assume the mouse cannot handle the extended 282 * (wheel mouse) commands. 283 */ 284 if ((STATEP->state == PS2_WAIT_WHEEL_SMPL1_CMD_ACK) || 285 (STATEP->state == PS2_WAIT_WHEEL_SMPL1_RATE_ACK) || 286 (STATEP->state == PS2_WAIT_WHEEL_SMPL2_RATE_ACK) || 287 (STATEP->state == PS2_WAIT_WHEEL_SMPL3_RATE_ACK)) { 288 /* 289 * We overload 'inited' to mark the PS/2 mouse 290 * as one which doesn't respond to extended commands. 291 */ 292 293 STATEP->inited |= PS2_FLAG_NO_EXTN; 294 } 295 296 297 /* 298 * If the Logitech button detection sequence timed out at some point 299 * in the sequence, ignore it and skip to the next step in 300 * initialization. Do NOT count this as a timeout, so do NOT 301 * increment init_count. 302 */ 303 if (STATEP->state >= PS2_WAIT_STATREQ_ACK && 304 STATEP->state <= PS2_WAIT_STATUS_REV) { 305 306 /* See the comment under the PS2_WAIT_STATUS_BUTTONS case */ 307 #if defined(VUID3PS2) 308 STATEP->nbuttons = 3; 309 #else 310 STATEP->nbuttons = 2; 311 #endif 312 vuidmice_start_wdc_or_setres(qp); 313 return; 314 } 315 316 /* 317 * If the initialization process has timed out too many times, even if 318 * a subset of the process was successful, stop trying and put the 319 * mouse in the only state from which it can recover -- waiting for an 320 * 0xAA 0x00 response (i.e. like one we get on resume from mouse8042 321 * or from a replug). 322 */ 323 if (++STATEP->init_count >= PS2_MAX_INIT_COUNT) { 324 STATEP->inited |= PS2_FLAG_INIT_TIMEOUT; 325 STATEP->state = PS2_WAIT_FOR_AA; 326 } else { 327 328 STATEP->state = PS2_WAIT_RESET_COMPLETE; 329 330 /* Try to reset the mouse again */ 331 put1(WR(qp), MSERESET); 332 } 333 } 334 335 void 336 VUID_QUEUE(queue_t *const qp, mblk_t *mp) 337 { 338 int code, length; 339 clock_t now; 340 clock_t elapsed; 341 clock_t mouse_timeout; 342 343 mouse_timeout = drv_usectohz(250000); 344 now = ddi_get_lbolt(); 345 elapsed = now - STATEP->last_event_lbolt; 346 STATEP->last_event_lbolt = now; 347 348 while (mp->b_rptr < mp->b_wptr) { 349 length = MBLKL(mp); 350 code = *mp->b_rptr++; 351 352 switch (STATEP->state) { 353 354 /* 355 * Start state. We stay here if the start code is not 356 * received thus forcing us back into sync. When we get a 357 * start code the button mask comes with it forcing us to 358 * to the next state. 359 */ 360 restart: 361 case PS2_START: 362 363 /* 364 * 3-byte packet format 365 * 366 * Bit 7 6 5 4 3 2 1 0 367 * Byte ---- ---- ----- ----- -- ------ ------ ------ 368 * 1 Y_Ov X_Ov Y_Sgn X_Sgn 1 MdlBtn RgtBtn LftBtn 369 * 2 |<--------------X Movement----------------->| 370 * 3 |<--------------Y Movement----------------->| 371 * 372 * 4-byte wheel packet format 373 * 374 * Bit 7 6 5 4 3 2 1 0 375 * Byte ---- ---- ----- ----- -- ------ ------ ------ 376 * 1 Y_Ov X_Ov Y_Sgn X_Sgn 1 MdlBtn RgtBtn LftBtn 377 * 2 |<--------------X Movement----------------->| 378 * 3 |<--------------Y Movement----------------->| 379 * 4 |<--------------Z Movement----------------->| 380 * 381 * 4-byte wheel+5 packet format 382 * 383 * Bit 7 6 5 4 3 2 1 0 384 * Byte ---- ---- ----- ----- -- ------ ------ ------ 385 * 1 Y_Ov X_Ov Y_Sgn X_Sgn 1 MdlBtn RgtBtn LftBtn 386 * 2 |<--------------X Movement----------------->| 387 * 3 |<--------------Y Movement----------------->| 388 * 4 0 0 5_Btn 4_Btn Z3 Z2 Z1 Z0 389 */ 390 391 if (!(STATEP->inited & PS2_FLAG_INIT_DONE)) { 392 STATEP->sync_byte = code & 0x8; 393 STATEP->inited |= PS2_FLAG_INIT_DONE; 394 } 395 /* 396 * the PS/2 mouse data format doesn't have any sort of sync 397 * data to make sure we are in sync with the packet stream, 398 * but the Technical Reference manual states that bits 2 & 3 399 * of the first byte are reserved. Logitech uses bit 2 for 400 * the middle button. We HOPE that noone uses bit 3 though, 401 * and decide we're out of sync if bit 3 is not set here. 402 */ 403 404 if ((code ^ STATEP->sync_byte) & 0x08) { 405 /* bit 3 not set */ 406 STATEP->state = PS2_START; 407 break; /* toss the code */ 408 } 409 410 /* get the button values */ 411 STATEP->buttons = code & PS2_BUTTONMASK; 412 if (STATEP->buttons != STATEP->oldbuttons) { 413 sendButtonEvent(qp); 414 STATEP->oldbuttons = STATEP->buttons; 415 } 416 417 /* bit 5 indicates Y value is negative (the sign bit) */ 418 if (code & PS2_DATA_YSIGN) 419 STATEP->deltay = -1 & ~0xff; 420 else 421 STATEP->deltay = 0; 422 423 /* bit 4 is X sign bit */ 424 if (code & PS2_DATA_XSIGN) 425 STATEP->deltax = -1 & ~0xff; 426 else 427 STATEP->deltax = 0; 428 429 if (code == MSE_AA) 430 STATEP->state = PS2_MAYBE_REATTACH; 431 else 432 STATEP->state = PS2_BUTTON; 433 434 break; 435 436 case PS2_WAIT_FOR_AA: 437 /* 438 * On Dell latitude D800, the initial MSE_ACK is 439 * received after the initialization sequence 440 * times out, so restart it here. 441 */ 442 if (code == MSE_ACK) { 443 STATEP->inited &= ~PS2_FLAG_INIT_TIMEOUT; 444 STATEP->init_count = 0; 445 STATEP->state = PS2_WAIT_RESET_COMPLETE; 446 put1(WR(qp), MSERESET); 447 break; 448 } 449 450 if (code != MSE_AA) 451 break; 452 453 STATEP->state = PS2_WAIT_FOR_00; 454 break; 455 456 case PS2_WAIT_FOR_00: 457 if (code != MSE_00) 458 break; 459 460 STATEP->inited &= ~PS2_FLAG_INIT_TIMEOUT; 461 STATEP->init_count = 0; 462 STATEP->state = PS2_WAIT_RESET_COMPLETE; 463 put1(WR(qp), MSERESET); 464 break; 465 466 case PS2_MAYBE_REATTACH: 467 if (code == MSE_00) { 468 STATEP->state = PS2_WAIT_RESET_COMPLETE; 469 put1(WR(qp), MSERESET); 470 break; 471 } 472 /*FALLTHROUGH*/ 473 474 case PS2_BUTTON: 475 /* 476 * Now for the 7 bits of delta x. "Or" in 477 * the sign bit and continue. This is ac- 478 * tually a signed 9 bit number, but I just 479 * truncate it to a signed char in order to 480 * avoid changing and retesting all of the 481 * mouse-related modules for this patch. 482 */ 483 if (elapsed > mouse_timeout) 484 goto restart; 485 STATEP->deltax |= code & 0xff; 486 STATEP->state = PS2_DELTA_Y; 487 break; 488 489 case PS2_DELTA_Y: 490 /* 491 * This byte is delta Y. If this is a plain mouse, 492 * we're done. Wheel mice have two different flavors 493 * of fourth byte. 494 */ 495 496 if (elapsed > mouse_timeout) { 497 goto restart; 498 } 499 STATEP->deltay |= code & 0xff; 500 501 if (STATEP->vuid_mouse_mode == MOUSE_MODE_WHEEL) { 502 STATEP->state = PS2_WHEEL_DELTA_Z; 503 break; 504 } else if (STATEP->vuid_mouse_mode == 505 MOUSE_MODE_WHEEL5) { 506 STATEP->state = PS2_WHEEL5_DELTA_Z; 507 break; 508 } 509 goto packet_complete; 510 511 case PS2_WHEEL5_DELTA_Z: 512 if (code & 0x10) { 513 /* fourth physical button */ 514 VUID_PUTNEXT(qp, (uchar_t)BUT(4), 515 FE_PAIR_NONE, 0, 1); 516 VUID_PUTNEXT(qp, (uchar_t)BUT(4), 517 FE_PAIR_NONE, 0, 0); 518 } else if (code & 0x20) { 519 /* fifth physical button */ 520 VUID_PUTNEXT(qp, (uchar_t)BUT(5), 521 FE_PAIR_NONE, 0, 1); 522 VUID_PUTNEXT(qp, (uchar_t)BUT(5), 523 FE_PAIR_NONE, 0, 0); 524 } 525 /*FALLTHROUGH*/ 526 527 case PS2_WHEEL_DELTA_Z: 528 /* 529 * Check whether reporting vertical wheel 530 * movements is enabled 531 */ 532 code &= 0xf; 533 534 if (STATEP->wheel_state_bf & (1 << 535 VUIDMICE_VERTICAL_WHEEL_ID)) { 536 /* 537 * PS/2 mouse reports -ve values 538 * when the wheel is scrolled up. So 539 * we need to convert it into +ve as 540 * X interprets a +ve value as wheel up event. 541 * Same is true for the horizontal wheel also. 542 * The mouse reports 0xf when scrolled up 543 * and 0x1 when scrolled down. This observation 544 * is based on Logitech, HCL, 545 * Microsoft and Black Cat mouse only 546 */ 547 if (code == 0xf) { 548 /* negative Z - wheel up */ 549 code |= 0xfffffff0; 550 vuidmice_send_wheel_event(qp, 0, 551 FE_PAIR_NONE, 0, -code); 552 } else if (code == 0x01) { 553 /* positive Z - wheel down */ 554 vuidmice_send_wheel_event(qp, 0, 555 FE_PAIR_NONE, 0, -code); 556 } 557 } 558 559 /* 560 * Check whether reporting horizontal wheel 561 * movements is enabled 562 */ 563 if (STATEP->wheel_state_bf & 564 (1 << VUIDMICE_HORIZONTAL_WHEEL_ID)) { 565 566 /* 567 * The mouse return -7 and +7 when it 568 * is scrolled horizontally 569 */ 570 if (code == 0x09) { 571 /* negative Z - wheel left */ 572 vuidmice_send_wheel_event(qp, 1, 573 FE_PAIR_NONE, 0, 1); 574 } else if (code == 0x07) { 575 /* positive Z - wheel right */ 576 vuidmice_send_wheel_event(qp, 1, 577 FE_PAIR_NONE, 0, -1); 578 } 579 } 580 581 packet_complete: 582 STATEP->state = PS2_START; 583 /* 584 * If we can peek at the next mouse character, and 585 * its not the start of the next packet, don't use 586 * this packet. 587 */ 588 if (mp->b_wptr > mp->b_rptr && 589 ((mp->b_rptr[0] ^ STATEP->sync_byte) & 0x08)) { 590 /* 591 * bit 3 not set 592 */ 593 break; 594 } 595 596 /* 597 * send the info to the next level -- 598 * need to send multiple events if we have both 599 * a delta *AND* button event(s) 600 */ 601 602 /* motion has occurred ... */ 603 if (STATEP->deltax) 604 VUID_PUTNEXT(qp, (uchar_t)LOC_X_DELTA, 605 FE_PAIR_ABSOLUTE, (uchar_t)LOC_X_ABSOLUTE, 606 STATEP->deltax); 607 608 if (STATEP->deltay) 609 VUID_PUTNEXT(qp, (uchar_t)LOC_Y_DELTA, 610 FE_PAIR_ABSOLUTE, (uchar_t)LOC_Y_ABSOLUTE, 611 STATEP->deltay); 612 613 STATEP->deltax = STATEP->deltay = 0; 614 break; 615 616 case PS2_WAIT_RESET_COMPLETE: 617 618 /* 619 * If length is 1, code holds the data from the message. 620 * for lengths > 1, we look at *(mp->b_rptr + offset) 621 * for the rest of the data. 622 */ 623 if (length == 1) { 624 /* 625 * A response with length 1 from the mouse 626 * driver can be either an ACK (the first part 627 * of the reset reply) or either MSEERROR or 628 * MSERESEND. Issue another reset if either 629 * of the latter are received. For mice that 630 * are not connected, MSERESEND is received 631 * quickly. 632 */ 633 634 if (code == MSE_ACK) 635 break; 636 637 if (++STATEP->init_count >= 638 PS2_MAX_INIT_COUNT) { 639 STATEP->inited |= PS2_FLAG_INIT_TIMEOUT; 640 STATEP->state = PS2_WAIT_FOR_AA; 641 } else { 642 put1(WR(qp), MSERESET); 643 } 644 645 break; 646 647 } else if (length != 2) { 648 break; 649 } 650 651 /* 652 * The only possible 2-byte reply from mouse8042 is 653 * 0xAA 0x00. If the mouse doesn't send that, mouse8042 654 * will send a 1-byte error message, handled above by 655 * resetting the mouse. 656 */ 657 658 /* Skip past the 0x00 (since `code' contains 0xAA) */ 659 mp->b_rptr += 1; 660 661 /* Reset completed successfully */ 662 663 STATEP->state = PS2_WAIT_SETRES0_ACK1; 664 665 /* Set timeout for set res */ 666 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP); 667 668 /* Begin Logitech autodetect sequence */ 669 put1(WR(qp), MSESETRES); 670 break; 671 672 case PS2_WAIT_SETRES0_ACK1: 673 if (code != MSE_ACK) { 674 break; 675 } 676 STATEP->state = PS2_WAIT_SETRES0_ACK2; 677 put1(WR(qp), 0); 678 break; 679 680 case PS2_WAIT_SETRES0_ACK2: 681 case PS2_WAIT_SCALE1_1_ACK: 682 case PS2_WAIT_SCALE1_2_ACK: 683 if (code != MSE_ACK) { 684 break; 685 } 686 STATEP->state++; 687 put1(WR(qp), MSESCALE1); 688 break; 689 690 case PS2_WAIT_SCALE1_3_ACK: 691 if (code != MSE_ACK) { 692 break; 693 } 694 695 /* Set res and scale have been ok */ 696 vuid_cancel_timeout(qp); 697 698 STATEP->state = PS2_WAIT_STATREQ_ACK; 699 700 /* Set timeout for status request */ 701 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP); 702 703 put1(WR(qp), MSESTATREQ); 704 705 break; 706 707 case PS2_WAIT_STATREQ_ACK: 708 if (code != MSE_ACK) { 709 break; 710 } 711 STATEP->state = PS2_WAIT_STATUS_1; 712 break; 713 714 case PS2_WAIT_STATUS_1: 715 STATEP->state = PS2_WAIT_STATUS_BUTTONS; 716 break; 717 718 case PS2_WAIT_STATUS_BUTTONS: 719 if (code != 0) { 720 STATEP->nbuttons = (uchar_t)code; 721 STATEP->state = (uchar_t)PS2_WAIT_STATUS_REV; 722 } else { 723 #if defined(VUID3PS2) 724 /* 725 * It seems that there are some 3-button mice 726 * that don't play the Logitech autodetect 727 * game. One is a Mouse Systems mouse OEM'ed 728 * by Intergraph. 729 * 730 * Until we find out how to autodetect these 731 * mice, we'll assume that if we're being 732 * compiled as vuid3ps2 and the mouse doesn't 733 * play the autodetect game, it's a 3-button 734 * mouse. This effectively disables 735 * autodetect for mice using vuid3ps2, but 736 * since vuid3ps2 is used only on x86 where 737 * we currently assume manual configuration, 738 * this shouldn't be a problem. At some point 739 * in the future when we *do* start using 740 * autodetect on x86, we should probably define 741 * VUIDPS2 instead of VUID3PS2. Even then, 742 * we could leave this code so that *some* 743 * mice could use autodetect and others not. 744 */ 745 STATEP->nbuttons = 3; 746 #else 747 STATEP->nbuttons = 2; 748 #endif 749 STATEP->state = PS2_WAIT_STATUS_3; 750 } 751 break; 752 753 case PS2_WAIT_STATUS_REV: 754 /*FALLTHROUGH*/ 755 756 case PS2_WAIT_STATUS_3: 757 758 /* Status request completed successfully */ 759 vuid_cancel_timeout(qp); 760 761 vuidmice_start_wdc_or_setres(qp); 762 break; 763 764 case PS2_WAIT_WHEEL_SMPL1_CMD_ACK: 765 if (code != MSE_ACK) { 766 break; 767 } 768 STATEP->state = PS2_WAIT_WHEEL_SMPL1_RATE_ACK; 769 put1(WR(qp), 200); 770 break; 771 case PS2_WAIT_WHEEL_SMPL1_RATE_ACK: 772 if (code != MSE_ACK) { 773 break; 774 } 775 STATEP->state = PS2_WAIT_WHEEL_SMPL2_CMD_ACK; 776 put1(WR(qp), MSECHGMOD); 777 break; 778 779 case PS2_WAIT_WHEEL_SMPL2_CMD_ACK: 780 if (code != MSE_ACK) { 781 break; 782 } 783 STATEP->state = PS2_WAIT_WHEEL_SMPL2_RATE_ACK; 784 put1(WR(qp), 100); 785 break; 786 787 case PS2_WAIT_WHEEL_SMPL2_RATE_ACK: 788 if (code != MSE_ACK) { 789 break; 790 } 791 STATEP->state = PS2_WAIT_WHEEL_SMPL3_CMD_ACK; 792 put1(WR(qp), MSECHGMOD); 793 break; 794 795 case PS2_WAIT_WHEEL_SMPL3_CMD_ACK: 796 if (code != MSE_ACK) { 797 break; 798 } 799 STATEP->state = PS2_WAIT_WHEEL_SMPL3_RATE_ACK; 800 put1(WR(qp), 80); 801 break; 802 803 case PS2_WAIT_WHEEL_SMPL3_RATE_ACK: 804 if (code != MSE_ACK) { 805 break; 806 } 807 808 /* Set sample rate completed successfully */ 809 vuid_cancel_timeout(qp); 810 811 STATEP->state = PS2_WAIT_WHEEL_DEV_CMD; 812 813 /* Set timeout for get dev */ 814 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 815 816 put1(WR(qp), MSEGETDEV); 817 break; 818 819 case PS2_WAIT_WHEEL_DEV_CMD: 820 if (code != MSE_ACK) { 821 break; 822 } 823 STATEP->state = PS2_WAIT_WHEEL_DEV_ACK; 824 break; 825 826 case PS2_WAIT_WHEEL_DEV_ACK: 827 828 /* Get dev completed successfully */ 829 vuid_cancel_timeout(qp); 830 831 if (code != 0x03) { 832 STATEP->state = PS2_WAIT_SETRES3_ACK1; 833 834 /* Set timeout for set res */ 835 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 836 837 put1(WR(qp), MSESETRES); 838 839 break; 840 } 841 842 STATEP->vuid_mouse_mode = MOUSE_MODE_WHEEL; 843 844 /* 845 * Found wheel. By default enable the wheel. 846 */ 847 STATEP->wheel_state_bf |= VUID_WHEEL_STATE_ENABLED; 848 849 STATEP->state = PS2_WAIT_WHEEL5_SMPL1_CMD_ACK; 850 851 /* Set timeout for set sample rate */ 852 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_GROUP); 853 854 /* We're on a roll - try for wheel+5 */ 855 put1(WR(qp), MSECHGMOD); 856 857 break; 858 859 case PS2_WAIT_WHEEL5_SMPL1_CMD_ACK: 860 if (code != MSE_ACK) { 861 break; 862 } 863 STATEP->state = PS2_WAIT_WHEEL5_SMPL1_RATE_ACK; 864 put1(WR(qp), 200); 865 break; 866 867 case PS2_WAIT_WHEEL5_SMPL1_RATE_ACK: 868 if (code != MSE_ACK) { 869 break; 870 } 871 STATEP->state = PS2_WAIT_WHEEL5_SMPL2_CMD_ACK; 872 put1(WR(qp), MSECHGMOD); 873 break; 874 875 case PS2_WAIT_WHEEL5_SMPL2_CMD_ACK: 876 if (code != MSE_ACK) { 877 break; 878 } 879 STATEP->state = PS2_WAIT_WHEEL5_SMPL2_RATE_ACK; 880 put1(WR(qp), 200); 881 break; 882 883 case PS2_WAIT_WHEEL5_SMPL2_RATE_ACK: 884 if (code != MSE_ACK) { 885 break; 886 } 887 STATEP->state = PS2_WAIT_WHEEL5_SMPL3_CMD_ACK; 888 put1(WR(qp), MSECHGMOD); 889 break; 890 891 case PS2_WAIT_WHEEL5_SMPL3_CMD_ACK: 892 if (code != MSE_ACK) { 893 break; 894 } 895 STATEP->state = PS2_WAIT_WHEEL5_SMPL3_RATE_ACK; 896 put1(WR(qp), 80); 897 break; 898 899 case PS2_WAIT_WHEEL5_SMPL3_RATE_ACK: 900 if (code != MSE_ACK) { 901 break; 902 } 903 904 /* Set sample rate completed successfully */ 905 vuid_cancel_timeout(qp); 906 907 STATEP->state = PS2_WAIT_WHEEL5_DEV_CMD; 908 909 /* Set timeout for wheel5 get dev */ 910 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 911 912 put1(WR(qp), MSEGETDEV); 913 914 break; 915 916 case PS2_WAIT_WHEEL5_DEV_CMD: 917 if (code != MSE_ACK) { 918 break; 919 } 920 STATEP->state = PS2_WAIT_WHEEL5_DEV_ACK; 921 break; 922 923 case PS2_WAIT_WHEEL5_DEV_ACK: 924 if (code == 0x04) { 925 STATEP->vuid_mouse_mode = MOUSE_MODE_WHEEL5; 926 STATEP->nbuttons = 5; 927 928 /* 929 * Found wheel. By default enable the wheel. 930 */ 931 STATEP->wheel_state_bf |= 932 VUID_WHEEL_STATE_ENABLED << 933 MOUSE_MODE_WHEEL; 934 } 935 936 /* Wheel5 get dev completed successfully */ 937 vuid_cancel_timeout(qp); 938 939 /* FALLTHROUGH */ 940 941 case PS2_WAIT_SETRES3_CMD: 942 STATEP->state = PS2_WAIT_SETRES3_ACK1; 943 944 /* Set timeout for set res */ 945 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 946 947 put1(WR(qp), MSESETRES); 948 949 break; 950 951 case PS2_WAIT_SETRES3_ACK1: 952 if (code != MSE_ACK) { 953 break; 954 } 955 STATEP->state = PS2_WAIT_SETRES3_ACK2; 956 put1(WR(qp), 3); 957 break; 958 959 case PS2_WAIT_SETRES3_ACK2: 960 if (code != MSE_ACK) { 961 break; 962 } 963 964 /* Set res completed successfully */ 965 vuid_cancel_timeout(qp); 966 967 STATEP->state = PS2_WAIT_STREAM_ACK; 968 969 /* Set timeout for enable */ 970 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 971 972 put1(WR(qp), MSESTREAM); 973 974 break; 975 976 case PS2_WAIT_STREAM_ACK: 977 if (code != MSE_ACK) { 978 break; 979 } 980 STATEP->state = PS2_WAIT_ON_ACK; 981 put1(WR(qp), MSEON); 982 break; 983 984 case PS2_WAIT_ON_ACK: 985 if (code != MSE_ACK) { 986 break; 987 } 988 989 /* Enable completed successfully */ 990 991 /* 992 * The entire initialization sequence 993 * is complete. Now, we can clear the 994 * init_count retry counter. 995 */ 996 STATEP->init_count = 0; 997 vuid_cancel_timeout(qp); 998 999 1000 STATEP->state = PS2_START; 1001 break; 1002 } 1003 } 1004 freemsg(mp); 1005 } 1006