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