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 117 #define PS2_MAX_INIT_COUNT 5 118 119 120 static void vuidmice_send_wheel_event(queue_t *const, uchar_t, 121 uchar_t, uchar_t, int); 122 extern void VUID_PUTNEXT(queue_t *const, uchar_t, uchar_t, uchar_t, int); 123 extern void uniqtime32(struct timeval32 *); 124 static void VUID_INIT_TIMEOUT(void *q); 125 126 /* 127 * We apply timeout to nearly each command-response 128 * during initialization: 129 * 130 * Set timeout for RESET 131 * Set timeout for SET RESOLUTION 132 * Set timeout for SET SCALE 133 * Set timeout for SET SAMPLE RATE 134 * Set timeout for STATUS REQUEST 135 * Set timeout for GET DEV 136 * Set timeout for SET STREAM MODE and ENABLE. 137 * 138 * But for simplicity, sometimes we just apply the timeout 139 * to a function (e.g. wheel-mouse detection). 140 * 141 */ 142 static void 143 vuid_set_timeout(queue_t *const qp, clock_t time) 144 { 145 ASSERT(STATEP->init_tid == 0); 146 STATEP->init_tid = qtimeout(qp, VUID_INIT_TIMEOUT, 147 qp, drv_usectohz(time)); 148 } 149 150 static void 151 vuid_cancel_timeout(queue_t *const qp) 152 { 153 ASSERT(STATEP->init_tid != 0); 154 (void) quntimeout(qp, STATEP->init_tid); 155 STATEP->init_tid = 0; 156 } 157 158 /* 159 * vuidmice_send_wheel_event 160 * Convert wheel data to firm_events 161 */ 162 static void 163 vuidmice_send_wheel_event(queue_t *const qp, uchar_t event_id, 164 uchar_t event_pair_type, uchar_t event_pair, int event_value) 165 { 166 mblk_t *bp; 167 Firm_event *fep; 168 169 if ((bp = allocb((int)sizeof (Firm_event), BPRI_HI)) == NULL) { 170 171 return; 172 } 173 174 fep = (Firm_event *)bp->b_wptr; 175 fep->id = vuid_id_addr(vuid_first(VUID_WHEEL)) | 176 vuid_id_offset(event_id); 177 fep->pair_type = event_pair_type; 178 fep->pair = event_pair; 179 fep->value = event_value; 180 uniqtime32(&fep->time); 181 bp->b_wptr += sizeof (Firm_event); 182 183 if (canput(qp->q_next)) { 184 putnext(qp, bp); 185 } else { 186 (void) putbq(qp, bp); /* read side is blocked */ 187 } 188 } 189 190 191 static void 192 sendButtonEvent(queue_t *const qp) 193 { 194 static int bmap[3] = {1, 3, 2}; 195 uint_t b; 196 197 /* for each button, see if it has changed */ 198 for (b = 0; b < STATEP->nbuttons; b++) { 199 uchar_t mask = 0x1 << b; 200 201 if ((STATEP->buttons & mask) != (STATEP->oldbuttons & mask)) 202 VUID_PUTNEXT(qp, (uchar_t)BUT(bmap[b]), FE_PAIR_NONE, 0, 203 (STATEP->buttons & mask ? 1 : 0)); 204 } 205 } 206 207 void 208 put1(queue_t *const qp, int c) 209 { 210 mblk_t *bp; 211 212 if (bp = allocb(1, BPRI_MED)) { 213 *bp->b_wptr++ = (char)c; 214 putnext(qp, bp); 215 } 216 } 217 218 int 219 VUID_OPEN(queue_t *const qp) 220 { 221 STATEP->format = VUID_FIRM_EVENT; 222 STATEP->vuid_mouse_mode = MOUSE_MODE_PLAIN; 223 STATEP->inited = 0; 224 STATEP->nbuttons = 3; 225 226 STATEP->state = PS2_WAIT_RESET_ACK; 227 put1(WR(qp), MSERESET); 228 229 /* Set timeout for reset */ 230 vuid_set_timeout(qp, PS2_INIT_TMOUT_RESET); 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 /* try again */ 289 put1(WR(qp), MSERESET); 290 291 vuid_set_timeout(qp, PS2_INIT_TMOUT_RESET); 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 put1(WR(qp), MSERESET); 397 STATEP->state = PS2_WAIT_RESET_ACK; 398 vuid_set_timeout(qp, PS2_INIT_TMOUT_RESET); 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) > 0 && 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 STATEP->state = PS2_WAIT_RESET_AA; 550 break; 551 552 case PS2_WAIT_RESET_AA: 553 if (code != MSE_AA) { 554 break; 555 } 556 STATEP->state = PS2_WAIT_RESET_00; 557 break; 558 559 case PS2_WAIT_RESET_00: 560 if (code != MSE_00) { 561 break; 562 } 563 564 /* Reset has been ok */ 565 vuid_cancel_timeout(qp); 566 567 put1(WR(qp), MSESETRES); 568 STATEP->state = PS2_WAIT_SETRES0_ACK1; 569 570 /* Set timeout for set res */ 571 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 572 573 break; 574 575 case PS2_WAIT_SETRES0_ACK1: 576 if (code != MSE_ACK) { 577 break; 578 } 579 put1(WR(qp), 0); 580 STATEP->state = PS2_WAIT_SETRES0_ACK2; 581 break; 582 583 case PS2_WAIT_SETRES0_ACK2: 584 case PS2_WAIT_SCALE1_1_ACK: 585 case PS2_WAIT_SCALE1_2_ACK: 586 if (code != MSE_ACK) { 587 break; 588 } 589 put1(WR(qp), MSESCALE1); 590 STATEP->state++; 591 break; 592 593 case PS2_WAIT_SCALE1_3_ACK: 594 if (code != MSE_ACK) { 595 break; 596 } 597 598 /* Set res and scale have been ok */ 599 vuid_cancel_timeout(qp); 600 601 put1(WR(qp), MSESTATREQ); 602 STATEP->state = PS2_WAIT_STATREQ_ACK; 603 604 /* Set timeout for status request */ 605 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 606 607 break; 608 609 case PS2_WAIT_STATREQ_ACK: 610 if (code != MSE_ACK) { 611 break; 612 } 613 STATEP->state = PS2_WAIT_STATUS_1; 614 break; 615 616 case PS2_WAIT_STATUS_1: 617 STATEP->state = PS2_WAIT_STATUS_BUTTONS; 618 break; 619 620 case PS2_WAIT_STATUS_BUTTONS: 621 if (code != 0) { 622 STATEP->nbuttons = (uchar_t)code; 623 STATEP->state = (uchar_t)PS2_WAIT_STATUS_REV; 624 } else { 625 #if defined(VUID3PS2) 626 /* 627 * It seems that there are some 3-button mice 628 * that don't play the Logitech autodetect 629 * game. One is a Mouse Systems mouse OEM'ed 630 * by Intergraph. 631 * 632 * Until we find out how to autodetect these 633 * mice, we'll assume that if we're being 634 * compiled as vuid3ps2 and the mouse doesn't 635 * play the autodetect game, it's a 3-button 636 * mouse. This effectively disables 637 * autodetect for mice using vuid3ps2, but 638 * since vuid3ps2 is used only on x86 where 639 * we currently assume manual configuration, 640 * this shouldn't be a problem. At some point 641 * in the future when we *do* start using 642 * autodetect on x86, we should probably define 643 * VUIDPS2 instead of VUID3PS2. Even then, 644 * we could leave this code so that *some* 645 * mice could use autodetect and others not. 646 */ 647 STATEP->nbuttons = 3; 648 #else 649 STATEP->nbuttons = 2; 650 #endif 651 STATEP->state = PS2_WAIT_STATUS_3; 652 } 653 break; 654 655 case PS2_WAIT_STATUS_REV: 656 /*FALLTHROUGH*/ 657 658 case PS2_WAIT_STATUS_3: 659 660 /* Status request has been ok */ 661 vuid_cancel_timeout(qp); 662 663 /* 664 * Start the wheel-mouse detection code. First, we look 665 * for standard wheel mice. If we set the sample rate 666 * to 200, 100, and then 80 and finally request the 667 * device ID, a wheel mouse will return an ID of 0x03. 668 * After that, we'll try for the wheel+5 variety. The 669 * incantation in this case is 200, 200, and 80. We'll 670 * get 0x04 back in that case. 671 */ 672 if (STATEP->inited & PS2_FLAG_NO_EXTN) { 673 STATEP->state = PS2_WAIT_SETRES3_ACK1; 674 put1(WR(qp), MSESETRES); 675 } else { 676 put1(WR(qp), MSECHGMOD); 677 STATEP->state = PS2_WAIT_WHEEL_SMPL1_CMD_ACK; 678 } 679 680 /* Set timeout for set res or sample rate */ 681 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 682 683 break; 684 case PS2_WAIT_WHEEL_SMPL1_CMD_ACK: 685 if (code != MSE_ACK) { 686 break; 687 } 688 put1(WR(qp), 200); 689 STATEP->state = PS2_WAIT_WHEEL_SMPL1_RATE_ACK; 690 break; 691 case PS2_WAIT_WHEEL_SMPL1_RATE_ACK: 692 if (code != MSE_ACK) { 693 break; 694 } 695 put1(WR(qp), MSECHGMOD); 696 STATEP->state = PS2_WAIT_WHEEL_SMPL2_CMD_ACK; 697 break; 698 699 case PS2_WAIT_WHEEL_SMPL2_CMD_ACK: 700 if (code != MSE_ACK) { 701 break; 702 } 703 put1(WR(qp), 100); 704 STATEP->state = PS2_WAIT_WHEEL_SMPL2_RATE_ACK; 705 break; 706 707 case PS2_WAIT_WHEEL_SMPL2_RATE_ACK: 708 if (code != MSE_ACK) { 709 break; 710 } 711 put1(WR(qp), MSECHGMOD); 712 STATEP->state = PS2_WAIT_WHEEL_SMPL3_CMD_ACK; 713 break; 714 715 case PS2_WAIT_WHEEL_SMPL3_CMD_ACK: 716 if (code != MSE_ACK) { 717 break; 718 } 719 put1(WR(qp), 80); 720 STATEP->state = PS2_WAIT_WHEEL_SMPL3_RATE_ACK; 721 break; 722 723 case PS2_WAIT_WHEEL_SMPL3_RATE_ACK: 724 if (code != MSE_ACK) { 725 break; 726 } 727 728 /* Set sample rate has been ok */ 729 vuid_cancel_timeout(qp); 730 731 put1(WR(qp), MSEGETDEV); 732 STATEP->state = PS2_WAIT_WHEEL_DEV_CMD; 733 734 /* Set timeout for get dev */ 735 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 736 737 break; 738 739 case PS2_WAIT_WHEEL_DEV_CMD: 740 if (code != MSE_ACK) { 741 break; 742 } 743 STATEP->state = PS2_WAIT_WHEEL_DEV_ACK; 744 break; 745 746 case PS2_WAIT_WHEEL_DEV_ACK: 747 748 /* Get dev has been ok */ 749 vuid_cancel_timeout(qp); 750 751 if (code != 0x03) { 752 put1(WR(qp), MSESETRES); 753 STATEP->state = PS2_WAIT_SETRES3_ACK1; 754 755 /* Set timeout for set res */ 756 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 757 758 break; 759 } 760 761 STATEP->vuid_mouse_mode = MOUSE_MODE_WHEEL; 762 763 /* 764 * Found wheel. By default enable the wheel. 765 */ 766 STATEP->wheel_state_bf |= VUID_WHEEL_STATE_ENABLED; 767 768 /* We're on a roll - try for wheel+5 */ 769 put1(WR(qp), MSECHGMOD); 770 STATEP->state = PS2_WAIT_WHEEL5_SMPL1_CMD_ACK; 771 772 /* Set timeout for set sample rate */ 773 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 774 775 break; 776 777 case PS2_WAIT_WHEEL5_SMPL1_CMD_ACK: 778 if (code != MSE_ACK) { 779 break; 780 } 781 put1(WR(qp), 200); 782 STATEP->state = PS2_WAIT_WHEEL5_SMPL1_RATE_ACK; 783 break; 784 785 case PS2_WAIT_WHEEL5_SMPL1_RATE_ACK: 786 if (code != MSE_ACK) { 787 break; 788 } 789 put1(WR(qp), MSECHGMOD); 790 STATEP->state = PS2_WAIT_WHEEL5_SMPL2_CMD_ACK; 791 break; 792 793 case PS2_WAIT_WHEEL5_SMPL2_CMD_ACK: 794 if (code != MSE_ACK) { 795 break; 796 } 797 put1(WR(qp), 200); 798 STATEP->state = PS2_WAIT_WHEEL5_SMPL2_RATE_ACK; 799 break; 800 801 case PS2_WAIT_WHEEL5_SMPL2_RATE_ACK: 802 if (code != MSE_ACK) { 803 break; 804 } 805 put1(WR(qp), MSECHGMOD); 806 STATEP->state = PS2_WAIT_WHEEL5_SMPL3_CMD_ACK; 807 break; 808 809 case PS2_WAIT_WHEEL5_SMPL3_CMD_ACK: 810 if (code != MSE_ACK) { 811 break; 812 } 813 put1(WR(qp), 80); 814 STATEP->state = PS2_WAIT_WHEEL5_SMPL3_RATE_ACK; 815 break; 816 817 case PS2_WAIT_WHEEL5_SMPL3_RATE_ACK: 818 if (code != MSE_ACK) { 819 break; 820 } 821 822 /* Set sample rate has been ok */ 823 vuid_cancel_timeout(qp); 824 825 put1(WR(qp), MSEGETDEV); 826 STATEP->state = PS2_WAIT_WHEEL5_DEV_CMD; 827 828 /* Set timeout for wheel5 get dev */ 829 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 830 831 break; 832 833 case PS2_WAIT_WHEEL5_DEV_CMD: 834 if (code != MSE_ACK) { 835 break; 836 } 837 STATEP->state = PS2_WAIT_WHEEL5_DEV_ACK; 838 break; 839 840 case PS2_WAIT_WHEEL5_DEV_ACK: 841 if (code == 0x04) { 842 STATEP->vuid_mouse_mode = MOUSE_MODE_WHEEL5; 843 STATEP->nbuttons = 5; 844 845 /* 846 * Found wheel. By default enable the wheel. 847 */ 848 STATEP->wheel_state_bf |= 849 VUID_WHEEL_STATE_ENABLED << 850 MOUSE_MODE_WHEEL; 851 } 852 853 /* Wheel5 get dev has been ok */ 854 vuid_cancel_timeout(qp); 855 856 /* FALLTHROUGH */ 857 858 case PS2_WAIT_SETRES3_CMD: 859 put1(WR(qp), MSESETRES); 860 STATEP->state = PS2_WAIT_SETRES3_ACK1; 861 862 /* Set timeout for set res */ 863 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 864 865 break; 866 867 case PS2_WAIT_SETRES3_ACK1: 868 if (code != MSE_ACK) { 869 break; 870 } 871 put1(WR(qp), 3); 872 STATEP->state = PS2_WAIT_SETRES3_ACK2; 873 break; 874 875 case PS2_WAIT_SETRES3_ACK2: 876 if (code != MSE_ACK) { 877 break; 878 } 879 880 /* Set res has been ok */ 881 vuid_cancel_timeout(qp); 882 883 put1(WR(qp), MSESTREAM); 884 STATEP->state = PS2_WAIT_STREAM_ACK; 885 886 /* Set timeout for enable */ 887 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 888 889 break; 890 891 case PS2_WAIT_STREAM_ACK: 892 if (code != MSE_ACK) { 893 break; 894 } 895 put1(WR(qp), MSEON); 896 STATEP->state = PS2_WAIT_ON_ACK; 897 break; 898 899 case PS2_WAIT_ON_ACK: 900 if (code != MSE_ACK) { 901 break; 902 } 903 904 /* Enable has been ok */ 905 vuid_cancel_timeout(qp); 906 907 STATEP->state = PS2_START; 908 break; 909 } 910 } 911 freemsg(mp); 912 } 913