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