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 STATEP->init_count = 0; 560 vuid_set_timeout(qp, PS2_INIT_TMOUT_RESET); 561 break; 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