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