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 if ((STATEP->state == PS2_WAIT_WHEEL_SMPL1_RATE_ACK) || 262 (STATEP->state == PS2_WAIT_WHEEL_SMPL2_RATE_ACK) || 263 (STATEP->state == PS2_WAIT_WHEEL_SMPL3_RATE_ACK)) { 264 /* 265 * We overload 'inited' to mark the PS/2 mouse 266 * as one which doesn't respond to extended commands. 267 */ 268 269 STATEP->inited |= PS2_FLAG_NO_EXTN; 270 } 271 272 if (++STATEP->init_count >= PS2_MAX_INIT_COUNT) { 273 STATEP->inited |= PS2_FLAG_INIT_TIMEOUT; 274 return; 275 } 276 277 278 STATEP->state = PS2_WAIT_RESET_ACK; 279 280 /* try again */ 281 put1(WR(qp), MSERESET); 282 283 vuid_set_timeout(qp, PS2_INIT_TMOUT_RESET); 284 } 285 286 void 287 VUID_QUEUE(queue_t *const qp, mblk_t *mp) 288 { 289 int code; 290 clock_t now; 291 clock_t elapsed; 292 clock_t mouse_timeout; 293 294 mouse_timeout = drv_usectohz(250000); 295 now = ddi_get_lbolt(); 296 elapsed = now - STATEP->last_event_lbolt; 297 STATEP->last_event_lbolt = now; 298 299 while (mp->b_rptr < mp->b_wptr) { 300 code = *mp->b_rptr++; 301 302 switch (STATEP->state) { 303 304 /* 305 * Start state. We stay here if the start code is not 306 * received thus forcing us back into sync. When we get a 307 * start code the button mask comes with it forcing us to 308 * to the next state. 309 */ 310 restart: 311 case PS2_START: 312 313 /* 314 * 3-byte packet format 315 * 316 * Bit 7 6 5 4 3 2 1 0 317 * Byte ---- ---- ----- ----- -- ------ ------ ------ 318 * 1 Y_Ov X_Ov Y_Sgn X_Sgn 1 MdlBtn RgtBtn LftBtn 319 * 2 |<--------------X Movement----------------->| 320 * 3 |<--------------Y Movement----------------->| 321 * 322 * 4-byte wheel 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 * 4 |<--------------Z Movement----------------->| 330 * 331 * 4-byte wheel+5 packet format 332 * 333 * Bit 7 6 5 4 3 2 1 0 334 * Byte ---- ---- ----- ----- -- ------ ------ ------ 335 * 1 Y_Ov X_Ov Y_Sgn X_Sgn 1 MdlBtn RgtBtn LftBtn 336 * 2 |<--------------X Movement----------------->| 337 * 3 |<--------------Y Movement----------------->| 338 * 4 0 0 5_Btn 4_Btn Z3 Z2 Z1 Z0 339 */ 340 341 if (!(STATEP->inited & PS2_FLAG_INIT_DONE)) { 342 STATEP->sync_byte = code & 0x8; 343 STATEP->inited |= PS2_FLAG_INIT_DONE; 344 } 345 /* 346 * the PS/2 mouse data format doesn't have any sort of sync 347 * data to make sure we are in sync with the packet stream, 348 * but the Technical Reference manual states that bits 2 & 3 349 * of the first byte are reserved. Logitech uses bit 2 for 350 * the middle button. We HOPE that noone uses bit 3 though, 351 * and decide we're out of sync if bit 3 is not set here. 352 */ 353 354 if ((code ^ STATEP->sync_byte) & 0x08) { 355 /* bit 3 not set */ 356 STATEP->state = PS2_START; 357 break; /* toss the code */ 358 } 359 360 /* get the button values */ 361 STATEP->buttons = code & PS2_BUTTONMASK; 362 if (STATEP->buttons != STATEP->oldbuttons) { 363 sendButtonEvent(qp); 364 STATEP->oldbuttons = STATEP->buttons; 365 } 366 367 /* bit 5 indicates Y value is negative (the sign bit) */ 368 if (code & PS2_DATA_YSIGN) 369 STATEP->deltay = -1 & ~0xff; 370 else 371 STATEP->deltay = 0; 372 373 /* bit 4 is X sign bit */ 374 if (code & PS2_DATA_XSIGN) 375 STATEP->deltax = -1 & ~0xff; 376 else 377 STATEP->deltax = 0; 378 379 if (code == MSE_AA) 380 STATEP->state = PS2_MAYBE_REATTACH; 381 else 382 STATEP->state = PS2_BUTTON; 383 384 break; 385 386 case PS2_MAYBE_REATTACH: 387 if (code == MSE_00) { 388 put1(WR(qp), MSERESET); 389 STATEP->state = PS2_WAIT_RESET_ACK; 390 vuid_set_timeout(qp, PS2_INIT_TMOUT_RESET); 391 break; 392 } 393 /*FALLTHROUGH*/ 394 395 case PS2_BUTTON: 396 /* 397 * Now for the 7 bits of delta x. "Or" in 398 * the sign bit and continue. This is ac- 399 * tually a signed 9 bit number, but I just 400 * truncate it to a signed char in order to 401 * avoid changing and retesting all of the 402 * mouse-related modules for this patch. 403 */ 404 if (elapsed > mouse_timeout) 405 goto restart; 406 STATEP->deltax |= code & 0xff; 407 STATEP->state = PS2_DELTA_Y; 408 break; 409 410 case PS2_DELTA_Y: 411 /* 412 * This byte is delta Y. If this is a plain mouse, 413 * we're done. Wheel mice have two different flavors 414 * of fourth byte. 415 */ 416 417 if (elapsed > mouse_timeout) { 418 goto restart; 419 } 420 STATEP->deltay |= code & 0xff; 421 422 if (STATEP->vuid_mouse_mode == MOUSE_MODE_WHEEL) { 423 STATEP->state = PS2_WHEEL_DELTA_Z; 424 break; 425 } else if (STATEP->vuid_mouse_mode == 426 MOUSE_MODE_WHEEL5) { 427 STATEP->state = PS2_WHEEL5_DELTA_Z; 428 break; 429 } 430 goto packet_complete; 431 432 case PS2_WHEEL5_DELTA_Z: 433 if (code & 0x10) { 434 /* fourth physical button */ 435 VUID_PUTNEXT(qp, (uchar_t)BUT(4), 436 FE_PAIR_NONE, 0, 1); 437 VUID_PUTNEXT(qp, (uchar_t)BUT(4), 438 FE_PAIR_NONE, 0, 0); 439 } else if (code & 0x20) { 440 /* fifth physical button */ 441 VUID_PUTNEXT(qp, (uchar_t)BUT(5), 442 FE_PAIR_NONE, 0, 1); 443 VUID_PUTNEXT(qp, (uchar_t)BUT(5), 444 FE_PAIR_NONE, 0, 0); 445 } 446 /*FALLTHROUGH*/ 447 448 case PS2_WHEEL_DELTA_Z: 449 /* 450 * Check whether reporting vertical wheel 451 * movements is enabled 452 */ 453 code &= 0xf; 454 455 if (STATEP->wheel_state_bf & (1 << 456 VUIDMICE_VERTICAL_WHEEL_ID)) { 457 /* 458 * PS/2 mouse reports -ve values 459 * when the wheel is scrolled up. So 460 * we need to convert it into +ve as 461 * X interprets a +ve value as wheel up event. 462 * Same is true for the horizontal wheel also. 463 * The mouse reports 0xf when scrolled up 464 * and 0x1 when scrolled down. This observation 465 * is based on Logitech, HCL, 466 * Microsoft and Black Cat mouse only 467 */ 468 if (code == 0xf) { 469 /* negative Z - wheel up */ 470 code |= 0xfffffff0; 471 vuidmice_send_wheel_event(qp, 0, 472 FE_PAIR_NONE, 0, -code); 473 } else if (code == 0x01) { 474 /* positive Z - wheel down */ 475 vuidmice_send_wheel_event(qp, 0, 476 FE_PAIR_NONE, 0, -code); 477 } 478 } 479 480 /* 481 * Check whether reporting horizontal wheel 482 * movements is enabled 483 */ 484 if (STATEP->wheel_state_bf & 485 (1 << VUIDMICE_HORIZONTAL_WHEEL_ID)) { 486 487 /* 488 * The mouse return -7 and +7 when it 489 * is scrolled horizontally 490 */ 491 if (code == 0x09) { 492 /* negative Z - wheel left */ 493 vuidmice_send_wheel_event(qp, 1, 494 FE_PAIR_NONE, 0, 1); 495 } else if (code == 0x07) { 496 /* positive Z - wheel right */ 497 vuidmice_send_wheel_event(qp, 1, 498 FE_PAIR_NONE, 0, -1); 499 } 500 } 501 502 packet_complete: 503 STATEP->state = PS2_START; 504 /* 505 * If we can peek at the next mouse character, and 506 * its not the start of the next packet, don't use 507 * this packet. 508 */ 509 if ((mp->b_wptr - mp->b_rptr) > 0 && 510 ((mp->b_rptr[0] ^ STATEP->sync_byte) & 0x08)) { 511 /* 512 * bit 3 not set 513 */ 514 break; 515 } 516 517 /* 518 * send the info to the next level -- 519 * need to send multiple events if we have both 520 * a delta *AND* button event(s) 521 */ 522 523 /* motion has occurred ... */ 524 if (STATEP->deltax) 525 VUID_PUTNEXT(qp, (uchar_t)LOC_X_DELTA, 526 FE_PAIR_ABSOLUTE, (uchar_t)LOC_X_ABSOLUTE, 527 STATEP->deltax); 528 529 if (STATEP->deltay) 530 VUID_PUTNEXT(qp, (uchar_t)LOC_Y_DELTA, 531 FE_PAIR_ABSOLUTE, (uchar_t)LOC_Y_ABSOLUTE, 532 STATEP->deltay); 533 534 STATEP->deltax = STATEP->deltay = 0; 535 break; 536 537 case PS2_WAIT_RESET_ACK: 538 if (code != MSE_ACK) { 539 break; 540 } 541 STATEP->state = PS2_WAIT_RESET_AA; 542 break; 543 544 case PS2_WAIT_RESET_AA: 545 if (code != MSE_AA) { 546 break; 547 } 548 STATEP->state = PS2_WAIT_RESET_00; 549 break; 550 551 case PS2_WAIT_RESET_00: 552 if (code != MSE_00) { 553 break; 554 } 555 556 /* Reset has been ok */ 557 vuid_cancel_timeout(qp); 558 559 put1(WR(qp), MSESETRES); 560 STATEP->state = PS2_WAIT_SETRES0_ACK1; 561 562 /* Set timeout for set res */ 563 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 564 565 break; 566 567 case PS2_WAIT_SETRES0_ACK1: 568 if (code != MSE_ACK) { 569 break; 570 } 571 put1(WR(qp), 0); 572 STATEP->state = PS2_WAIT_SETRES0_ACK2; 573 break; 574 575 case PS2_WAIT_SETRES0_ACK2: 576 case PS2_WAIT_SCALE1_1_ACK: 577 case PS2_WAIT_SCALE1_2_ACK: 578 if (code != MSE_ACK) { 579 break; 580 } 581 put1(WR(qp), MSESCALE1); 582 STATEP->state++; 583 break; 584 585 case PS2_WAIT_SCALE1_3_ACK: 586 if (code != MSE_ACK) { 587 break; 588 } 589 590 /* Set res and scale have been ok */ 591 vuid_cancel_timeout(qp); 592 593 put1(WR(qp), MSESTATREQ); 594 STATEP->state = PS2_WAIT_STATREQ_ACK; 595 596 /* Set timeout for status request */ 597 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 598 599 break; 600 601 case PS2_WAIT_STATREQ_ACK: 602 if (code != MSE_ACK) { 603 break; 604 } 605 STATEP->state = PS2_WAIT_STATUS_1; 606 break; 607 608 case PS2_WAIT_STATUS_1: 609 STATEP->state = PS2_WAIT_STATUS_BUTTONS; 610 break; 611 612 case PS2_WAIT_STATUS_BUTTONS: 613 if (code != 0) { 614 STATEP->nbuttons = (uchar_t)code; 615 STATEP->state = (uchar_t)PS2_WAIT_STATUS_REV; 616 } else { 617 #if defined(VUID3PS2) 618 /* 619 * It seems that there are some 3-button mice 620 * that don't play the Logitech autodetect 621 * game. One is a Mouse Systems mouse OEM'ed 622 * by Intergraph. 623 * 624 * Until we find out how to autodetect these 625 * mice, we'll assume that if we're being 626 * compiled as vuid3ps2 and the mouse doesn't 627 * play the autodetect game, it's a 3-button 628 * mouse. This effectively disables 629 * autodetect for mice using vuid3ps2, but 630 * since vuid3ps2 is used only on x86 where 631 * we currently assume manual configuration, 632 * this shouldn't be a problem. At some point 633 * in the future when we *do* start using 634 * autodetect on x86, we should probably define 635 * VUIDPS2 instead of VUID3PS2. Even then, 636 * we could leave this code so that *some* 637 * mice could use autodetect and others not. 638 */ 639 STATEP->nbuttons = 3; 640 #else 641 STATEP->nbuttons = 2; 642 #endif 643 STATEP->state = PS2_WAIT_STATUS_3; 644 } 645 break; 646 647 case PS2_WAIT_STATUS_REV: 648 /*FALLTHROUGH*/ 649 650 case PS2_WAIT_STATUS_3: 651 652 /* Status request has been ok */ 653 vuid_cancel_timeout(qp); 654 655 /* 656 * Start the wheel-mouse detection code. First, we look 657 * for standard wheel mice. If we set the sample rate 658 * to 200, 100, and then 80 and finally request the 659 * device ID, a wheel mouse will return an ID of 0x03. 660 * After that, we'll try for the wheel+5 variety. The 661 * incantation in this case is 200, 200, and 80. We'll 662 * get 0x04 back in that case. 663 */ 664 if (STATEP->inited & PS2_FLAG_NO_EXTN) { 665 STATEP->state = PS2_WAIT_SETRES3_ACK1; 666 put1(WR(qp), MSESETRES); 667 } else { 668 put1(WR(qp), MSECHGMOD); 669 STATEP->state = PS2_WAIT_WHEEL_SMPL1_CMD_ACK; 670 } 671 672 /* Set timeout for set res or sample rate */ 673 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 674 675 break; 676 case PS2_WAIT_WHEEL_SMPL1_CMD_ACK: 677 if (code != MSE_ACK) { 678 break; 679 } 680 put1(WR(qp), 200); 681 STATEP->state = PS2_WAIT_WHEEL_SMPL1_RATE_ACK; 682 break; 683 case PS2_WAIT_WHEEL_SMPL1_RATE_ACK: 684 if (code != MSE_ACK) { 685 break; 686 } 687 put1(WR(qp), MSECHGMOD); 688 STATEP->state = PS2_WAIT_WHEEL_SMPL2_CMD_ACK; 689 break; 690 691 case PS2_WAIT_WHEEL_SMPL2_CMD_ACK: 692 if (code != MSE_ACK) { 693 break; 694 } 695 put1(WR(qp), 100); 696 STATEP->state = PS2_WAIT_WHEEL_SMPL2_RATE_ACK; 697 break; 698 699 case PS2_WAIT_WHEEL_SMPL2_RATE_ACK: 700 if (code != MSE_ACK) { 701 break; 702 } 703 put1(WR(qp), MSECHGMOD); 704 STATEP->state = PS2_WAIT_WHEEL_SMPL3_CMD_ACK; 705 break; 706 707 case PS2_WAIT_WHEEL_SMPL3_CMD_ACK: 708 if (code != MSE_ACK) { 709 break; 710 } 711 put1(WR(qp), 80); 712 STATEP->state = PS2_WAIT_WHEEL_SMPL3_RATE_ACK; 713 break; 714 715 case PS2_WAIT_WHEEL_SMPL3_RATE_ACK: 716 if (code != MSE_ACK) { 717 break; 718 } 719 720 /* Set sample rate has been ok */ 721 vuid_cancel_timeout(qp); 722 723 put1(WR(qp), MSEGETDEV); 724 STATEP->state = PS2_WAIT_WHEEL_DEV_CMD; 725 726 /* Set timeout for get dev */ 727 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 728 729 break; 730 731 case PS2_WAIT_WHEEL_DEV_CMD: 732 if (code != MSE_ACK) { 733 break; 734 } 735 STATEP->state = PS2_WAIT_WHEEL_DEV_ACK; 736 break; 737 738 case PS2_WAIT_WHEEL_DEV_ACK: 739 740 /* Get dev has been ok */ 741 vuid_cancel_timeout(qp); 742 743 if (code != 0x03) { 744 put1(WR(qp), MSESETRES); 745 STATEP->state = PS2_WAIT_SETRES3_ACK1; 746 747 /* Set timeout for set res */ 748 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 749 750 break; 751 } 752 753 STATEP->vuid_mouse_mode = MOUSE_MODE_WHEEL; 754 755 /* 756 * Found wheel. By default enable the wheel. 757 */ 758 STATEP->wheel_state_bf |= VUID_WHEEL_STATE_ENABLED; 759 760 /* We're on a roll - try for wheel+5 */ 761 put1(WR(qp), MSECHGMOD); 762 STATEP->state = PS2_WAIT_WHEEL5_SMPL1_CMD_ACK; 763 764 /* Set timeout for set sample rate */ 765 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 766 767 break; 768 769 case PS2_WAIT_WHEEL5_SMPL1_CMD_ACK: 770 if (code != MSE_ACK) { 771 break; 772 } 773 put1(WR(qp), 200); 774 STATEP->state = PS2_WAIT_WHEEL5_SMPL1_RATE_ACK; 775 break; 776 777 case PS2_WAIT_WHEEL5_SMPL1_RATE_ACK: 778 if (code != MSE_ACK) { 779 break; 780 } 781 put1(WR(qp), MSECHGMOD); 782 STATEP->state = PS2_WAIT_WHEEL5_SMPL2_CMD_ACK; 783 break; 784 785 case PS2_WAIT_WHEEL5_SMPL2_CMD_ACK: 786 if (code != MSE_ACK) { 787 break; 788 } 789 put1(WR(qp), 200); 790 STATEP->state = PS2_WAIT_WHEEL5_SMPL2_RATE_ACK; 791 break; 792 793 case PS2_WAIT_WHEEL5_SMPL2_RATE_ACK: 794 if (code != MSE_ACK) { 795 break; 796 } 797 put1(WR(qp), MSECHGMOD); 798 STATEP->state = PS2_WAIT_WHEEL5_SMPL3_CMD_ACK; 799 break; 800 801 case PS2_WAIT_WHEEL5_SMPL3_CMD_ACK: 802 if (code != MSE_ACK) { 803 break; 804 } 805 put1(WR(qp), 80); 806 STATEP->state = PS2_WAIT_WHEEL5_SMPL3_RATE_ACK; 807 break; 808 809 case PS2_WAIT_WHEEL5_SMPL3_RATE_ACK: 810 if (code != MSE_ACK) { 811 break; 812 } 813 814 /* Set sample rate has been ok */ 815 vuid_cancel_timeout(qp); 816 817 put1(WR(qp), MSEGETDEV); 818 STATEP->state = PS2_WAIT_WHEEL5_DEV_CMD; 819 820 /* Set timeout for wheel5 get dev */ 821 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 822 823 break; 824 825 case PS2_WAIT_WHEEL5_DEV_CMD: 826 if (code != MSE_ACK) { 827 break; 828 } 829 STATEP->state = PS2_WAIT_WHEEL5_DEV_ACK; 830 break; 831 832 case PS2_WAIT_WHEEL5_DEV_ACK: 833 if (code == 0x04) { 834 STATEP->vuid_mouse_mode = MOUSE_MODE_WHEEL5; 835 STATEP->nbuttons = 5; 836 837 /* 838 * Found wheel. By default enable the wheel. 839 */ 840 STATEP->wheel_state_bf |= 841 VUID_WHEEL_STATE_ENABLED << 842 MOUSE_MODE_WHEEL; 843 } 844 845 /* Wheel5 get dev has been ok */ 846 vuid_cancel_timeout(qp); 847 848 /* FALLTHROUGH */ 849 850 case PS2_WAIT_SETRES3_CMD: 851 put1(WR(qp), MSESETRES); 852 STATEP->state = PS2_WAIT_SETRES3_ACK1; 853 854 /* Set timeout for set res */ 855 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 856 857 break; 858 859 case PS2_WAIT_SETRES3_ACK1: 860 if (code != MSE_ACK) { 861 break; 862 } 863 put1(WR(qp), 3); 864 STATEP->state = PS2_WAIT_SETRES3_ACK2; 865 break; 866 867 case PS2_WAIT_SETRES3_ACK2: 868 if (code != MSE_ACK) { 869 break; 870 } 871 872 /* Set res has been ok */ 873 vuid_cancel_timeout(qp); 874 875 put1(WR(qp), MSESTREAM); 876 STATEP->state = PS2_WAIT_STREAM_ACK; 877 878 /* Set timeout for enable */ 879 vuid_set_timeout(qp, PS2_INIT_TMOUT_PER_CMD); 880 881 break; 882 883 case PS2_WAIT_STREAM_ACK: 884 if (code != MSE_ACK) { 885 break; 886 } 887 put1(WR(qp), MSEON); 888 STATEP->state = PS2_WAIT_ON_ACK; 889 break; 890 891 case PS2_WAIT_ON_ACK: 892 if (code != MSE_ACK) { 893 break; 894 } 895 896 /* Enable has been ok */ 897 vuid_cancel_timeout(qp); 898 899 STATEP->state = PS2_START; 900 break; 901 } 902 } 903 freemsg(mp); 904 } 905