xref: /illumos-gate/usr/src/uts/common/io/usb/clients/usbms/usbms.c (revision 66582b606a8194f7f3ba5b3a3a6dca5b0d346361)
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 (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23  */
24 
25 
26 #include <sys/usb/usba/usbai_version.h>
27 #include <sys/usb/usba.h>
28 #include <sys/usb/clients/hid/hid.h>
29 #include <sys/usb/clients/hidparser/hidparser.h>
30 
31 #include <sys/stropts.h>
32 #include <sys/strsun.h>
33 #include <sys/systm.h>
34 #include <sys/vuid_event.h>
35 #include <sys/vuid_wheel.h>
36 #include <sys/termios.h>
37 #include <sys/termio.h>
38 #include <sys/strtty.h>
39 #include <sys/msreg.h>
40 #include <sys/msio.h>
41 
42 #include <sys/usb/clients/usbms/usbms.h>
43 
44 /* debugging information */
45 uint_t	usbms_errmask = (uint_t)PRINT_MASK_ALL;
46 uint_t	usbms_errlevel = USB_LOG_L2;
47 static usb_log_handle_t usbms_log_handle;
48 
49 static struct streamtab		usbms_streamtab;
50 
51 static struct fmodsw fsw = {
52 			"usbms",
53 			&usbms_streamtab,
54 			D_MP | D_MTPERMOD
55 };
56 
57 /*
58  * Module linkage information for the kernel.
59  */
60 static struct modlstrmod modlstrmod = {
61 	&mod_strmodops,
62 	"USB mouse streams",
63 	&fsw
64 };
65 
66 static struct modlinkage modlinkage = {
67 	MODREV_1,
68 	(void *)&modlstrmod,
69 	NULL
70 };
71 
72 
73 int
74 _init(void)
75 {
76 	int rval = mod_install(&modlinkage);
77 
78 	if (rval == 0) {
79 		usbms_log_handle = usb_alloc_log_hdl(NULL, "usbms",
80 		    &usbms_errlevel, &usbms_errmask, NULL, 0);
81 	}
82 
83 	return (rval);
84 }
85 
86 int
87 _fini(void)
88 {
89 	int rval = mod_remove(&modlinkage);
90 
91 	if (rval == 0) {
92 		usb_free_log_hdl(usbms_log_handle);
93 	}
94 
95 	return (rval);
96 }
97 
98 
99 int
100 _info(struct modinfo *modinfop)
101 {
102 
103 	return (mod_info(&modlinkage, modinfop));
104 }
105 
106 
107 /* Function prototypes */
108 static void usbms_reioctl(void *);
109 static void usbms_ioctl(queue_t *, mblk_t *);
110 static int usbms_open(queue_t *, dev_t *, int, int, cred_t *);
111 static int usbms_close(queue_t *, int, cred_t *);
112 static int usbms_wput(queue_t *, mblk_t *);
113 static int usbms_rput(queue_t *, mblk_t *);
114 static void usbms_mctl_receive(queue_t *, mblk_t *);
115 
116 static int usbms_rserv(queue_t *);
117 static void usbms_miocdata(queue_t *, mblk_t *);
118 
119 static void usbms_resched(void *);
120 
121 static int usbms_getparms(Ms_parms *, usbms_state_t *);
122 
123 static int usbms_setparms(Ms_parms *, usbms_state_t *);
124 
125 static int usbms_get_screen_parms(queue_t *q, mblk_t *);
126 
127 static void usbms_flush(usbms_state_t *);
128 
129 static void usbms_incr(void *);
130 static void usbms_input(usbms_state_t *, mblk_t	*);
131 static void usbms_rserv_vuid_button(queue_t *, struct usbmouseinfo *,
132     mblk_t **);
133 
134 static void usbms_rserv_vuid_event_y(queue_t *, struct usbmouseinfo *,
135     mblk_t **);
136 static void usbms_rserv_vuid_event_x(queue_t *, struct usbmouseinfo *,
137     mblk_t **);
138 static void usbms_rserv_vuid_event_wheel(queue_t *, struct usbmouseinfo *,
139     mblk_t **, ushort_t);
140 static int usbms_check_for_wheels(usbms_state_t *);
141 static int usbms_make_copyreq(mblk_t *, uint_t, uint_t, uint_t, uint_t, uint_t);
142 static int usbms_service_wheel_info(queue_t *, mblk_t *);
143 static int usbms_service_wheel_state(queue_t *, mblk_t *, uint_t);
144 static void usbms_ack_ioctl(mblk_t *);
145 static int usbms_read_input_data_format(usbms_state_t *);
146 static mblk_t *usbms_setup_abs_mouse_event(void);
147 static int usbms_get_coordinate(uint_t, uint_t, mblk_t *);
148 
149 /*
150  * Device driver qinit functions
151  */
152 static struct module_info usbms_mod_info = {
153 	0x0ffff,		/* module id number */
154 	"usbms",		/* module name */
155 	0,			/* min packet size accepted */
156 	INFPSZ,			/* max packet size accepted */
157 	512,			/* hi-water mark */
158 	128			/* lo-water mark */
159 };
160 
161 /* read side queue information structure */
162 static struct qinit rinit = {
163 	usbms_rput,		/* put procedure not needed */
164 	usbms_rserv,		/* service procedure */
165 	usbms_open,		/* called on startup */
166 	usbms_close,		/* called on finish */
167 	NULL,			/* for future use */
168 	&usbms_mod_info,	/* module information structure */
169 	NULL			/* module statistics structure */
170 };
171 
172 /* write side queue information structure */
173 static struct qinit winit = {
174 	usbms_wput,		/* put procedure */
175 	NULL,			/* no service proecedure needed */
176 	NULL,			/* open not used on write side */
177 	NULL,			/* close not used on write side */
178 	NULL,			/* for future use */
179 	&usbms_mod_info,	/* module information structure */
180 	NULL			/* module statistics structure */
181 };
182 
183 static struct streamtab usbms_streamtab = {
184 	&rinit,
185 	&winit,
186 	NULL,			/* not a MUX */
187 	NULL			/* not a MUX */
188 };
189 
190 /*
191  * Message when overrun circular buffer
192  */
193 static int			overrun_msg;
194 
195 /* Increment when overrun circular buffer */
196 static int			overrun_cnt;
197 
198 extern int			hz;
199 
200 /*
201  * Mouse buffer size in bytes.	Place here as variable so that one could
202  * massage it using adb if it turns out to be too small.
203  */
204 static uint16_t			usbms_buf_bytes = USBMS_BUF_BYTES;
205 
206 
207 /*
208  * Regular STREAMS Entry points
209  */
210 
211 /*
212  * usbms_open() :
213  *	open() entry point for the USB mouse module.
214  */
215 /*ARGSUSED*/
216 static int
217 usbms_open(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *credp)
218 {
219 	struct usbmousebuf	*mousebufp;
220 	struct ms_softc	*msd_soft;
221 	usbms_state_t			*usbmsp;
222 	struct iocblk			mctlmsg;
223 	mblk_t				*mctl_ptr;
224 
225 
226 	/* Clone opens are not allowed */
227 	if (sflag != MODOPEN)
228 		return (EINVAL);
229 
230 	/* If the module is already open, just return */
231 	if (q->q_ptr) {
232 		return (0);
233 	}
234 
235 	/* allocate usbms state structure */
236 	usbmsp = kmem_zalloc(sizeof (usbms_state_t), KM_SLEEP);
237 
238 	q->q_ptr = usbmsp;
239 	WR(q)->q_ptr = usbmsp;
240 
241 	usbmsp->usbms_rq_ptr = q;
242 	usbmsp->usbms_wq_ptr = WR(q);
243 
244 	qprocson(q);
245 
246 	/*
247 	 * Set up private data.
248 	 */
249 	usbmsp->usbms_state = USBMS_WAIT_BUTN;
250 	usbmsp->usbms_iocpending = NULL;
251 	usbmsp->usbms_jitter_thresh = USBMS_JITTER_THRESH;
252 	usbmsp->usbms_speedlimit = USBMS_SPEEDLIMIT;
253 	usbmsp->usbms_speedlaw = USBMS_SPEEDLAW;
254 	usbmsp->usbms_speed_count = USBMS_SPEED_COUNT;
255 
256 	msd_soft = &usbmsp->usbms_softc;
257 
258 	/*
259 	 * Initially set the format to MS_VUID_FORMAT
260 	 */
261 	msd_soft->ms_readformat = MS_VUID_FORMAT;
262 
263 	/*
264 	 * Allocate buffer and initialize data.
265 	 */
266 	msd_soft->ms_bufbytes = usbms_buf_bytes;
267 	mousebufp = kmem_zalloc(msd_soft->ms_bufbytes, KM_SLEEP);
268 
269 	/* Truncation  will happen */
270 	mousebufp->mb_size = (uint16_t)((msd_soft->ms_bufbytes -
271 	    sizeof (struct usbmousebuf)) / sizeof (struct usbmouseinfo));
272 	mousebufp->mb_info = (struct usbmouseinfo *)((char *)mousebufp +
273 	    sizeof (struct usbmousebuf));
274 	usbmsp->usbms_buf = mousebufp;
275 	msd_soft->ms_vuidaddr = VKEY_FIRST;
276 	usbmsp->usbms_jittertimeout = JITTER_TIMEOUT;
277 
278 	/* request hid report descriptor from HID */
279 	mctlmsg.ioc_cmd = HID_GET_PARSER_HANDLE;
280 	mctlmsg.ioc_count = 0;
281 
282 	mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0);
283 	if (mctl_ptr == NULL) {
284 		qprocsoff(q);
285 		kmem_free(usbmsp->usbms_buf, msd_soft->ms_bufbytes);
286 		kmem_free(usbmsp, sizeof (usbms_state_t));
287 
288 		return (ENOMEM);
289 	}
290 
291 	usbmsp->usbms_flags |= USBMS_QWAIT;
292 	putnext(usbmsp->usbms_wq_ptr, mctl_ptr);
293 
294 	/*
295 	 * Now that signal has been sent, wait for report descriptor.  Cleanup
296 	 * if user signals in the mean time (as when this gets opened in an
297 	 * inappropriate context and the user types a ^C).
298 	 */
299 	while (usbmsp->usbms_flags & USBMS_QWAIT) {
300 
301 		if (qwait_sig(q) == 0) {
302 			qprocsoff(q);
303 			kmem_free(usbmsp->usbms_buf, msd_soft->ms_bufbytes);
304 			kmem_free(usbmsp, sizeof (usbms_state_t));
305 
306 			return (EINTR);
307 		}
308 	}
309 
310 	if (usbmsp->usbms_report_descr_handle != NULL) {
311 		if (hidparser_get_usage_attribute(
312 		    usbmsp->usbms_report_descr_handle,
313 		    0,
314 		    HIDPARSER_ITEM_INPUT,
315 		    USBMS_USAGE_PAGE_BUTTON,
316 		    0,
317 		    HIDPARSER_ITEM_REPORT_COUNT,
318 		    (int32_t *)&usbmsp->usbms_num_buttons) ==
319 		    HIDPARSER_SUCCESS) {
320 			if (usbmsp->usbms_num_buttons > USB_MS_MAX_BUTTON_NO)
321 				usbmsp->usbms_num_buttons =
322 				    USB_MS_MAX_BUTTON_NO;
323 			USB_DPRINTF_L2(PRINT_MASK_ALL,
324 			    usbms_log_handle, "Num of buttons is : %d",
325 			    usbmsp->usbms_num_buttons);
326 		} else {
327 			USB_DPRINTF_L3(PRINT_MASK_OPEN,
328 			    usbms_log_handle,
329 			    "hidparser_get_usage_attribute failed : "
330 			    "Set to default number of buttons(3).");
331 
332 			usbmsp->usbms_num_buttons = USB_MS_DEFAULT_BUTTON_NO;
333 		}
334 	} else {
335 		USB_DPRINTF_L1(PRINT_MASK_ALL,
336 		    usbms_log_handle, "Invalid HID "
337 		    "Descriptor Tree. Set to default value(3 buttons).");
338 		usbmsp->usbms_num_buttons = USB_MS_DEFAULT_BUTTON_NO;
339 	}
340 
341 	/* check if this mouse has wheel */
342 	if (usbms_check_for_wheels(usbmsp) == USB_FAILURE) {
343 		USB_DPRINTF_L2(PRINT_MASK_ALL, usbms_log_handle,
344 		    "No wheels detected");
345 	} else {
346 		USB_DPRINTF_L2(PRINT_MASK_ALL, usbms_log_handle,
347 		    "Wheel detected");
348 	}
349 
350 	usbms_flush(usbmsp);
351 
352 	/* get the data format from the hid descriptor */
353 	if (usbms_read_input_data_format(usbmsp) != USB_SUCCESS) {
354 
355 		qprocsoff(q);
356 		kmem_free(usbmsp->usbms_buf, msd_soft->ms_bufbytes);
357 		kmem_free(usbmsp, sizeof (usbms_state_t));
358 
359 		return (EINVAL);
360 	}
361 
362 	usbmsp->usbms_flags |= USBMS_OPEN;
363 
364 	USB_DPRINTF_L3(PRINT_MASK_OPEN, usbms_log_handle,
365 	    "usbms_open exiting");
366 
367 	return (0);
368 }
369 
370 
371 /*
372  * usbms_close() :
373  *	close() entry point for the USB mouse module.
374  */
375 /*ARGSUSED*/
376 static int
377 usbms_close(queue_t *q, int flag, cred_t *credp)
378 {
379 	usbms_state_t			*usbmsp = q->q_ptr;
380 	struct	ms_softc	*ms = &usbmsp->usbms_softc;
381 
382 	USB_DPRINTF_L3(PRINT_MASK_CLOSE, usbms_log_handle,
383 	    "usbms_close entering");
384 
385 	qprocsoff(q);
386 
387 	if (usbmsp->usbms_jitter) {
388 		(void) quntimeout(q,
389 		    (timeout_id_t)(long)usbmsp->usbms_timeout_id);
390 		usbmsp->usbms_jitter = 0;
391 	}
392 	if (usbmsp->usbms_reioctl_id) {
393 		qunbufcall(q, (bufcall_id_t)(long)usbmsp->usbms_reioctl_id);
394 		usbmsp->usbms_reioctl_id = 0;
395 	}
396 	if (usbmsp->usbms_resched_id) {
397 		qunbufcall(q, (bufcall_id_t)usbmsp->usbms_resched_id);
398 		usbmsp->usbms_resched_id = 0;
399 	}
400 	if (usbmsp->usbms_iocpending != NULL) {
401 		/*
402 		 * We were holding an "ioctl" response pending the
403 		 * availability of an "mblk" to hold data to be passed up;
404 		 * another "ioctl" came through, which means that "ioctl"
405 		 * must have timed out or been aborted.
406 		 */
407 		freemsg(usbmsp->usbms_iocpending);
408 		usbmsp->usbms_iocpending = NULL;
409 	}
410 
411 
412 	/* Free mouse buffer */
413 	if (usbmsp->usbms_buf != NULL) {
414 		kmem_free(usbmsp->usbms_buf, ms->ms_bufbytes);
415 	}
416 
417 	kmem_free(usbmsp, sizeof (usbms_state_t));
418 
419 	q->q_ptr = NULL;
420 	WR(q)->q_ptr = NULL;
421 
422 
423 	USB_DPRINTF_L3(PRINT_MASK_CLOSE, usbms_log_handle,
424 	    "usbms_close exiting");
425 
426 	return (0);
427 }
428 
429 
430 /*
431  * usbms_rserv() :
432  *	Read queue service routine.
433  *	Turn buffered mouse events into stream messages.
434  */
435 static int
436 usbms_rserv(queue_t		*q)
437 {
438 	usbms_state_t		*usbmsp = q->q_ptr;
439 	struct ms_softc		*ms;
440 	struct usbmousebuf	*b;
441 	struct usbmouseinfo	*mi;
442 	mblk_t			*bp;
443 	ushort_t		i, loop;
444 	uchar_t			nbutt = (uchar_t)usbmsp->usbms_num_buttons;
445 
446 	ms = &usbmsp->usbms_softc;
447 	b = usbmsp->usbms_buf;
448 
449 	USB_DPRINTF_L3(PRINT_MASK_SERV, usbms_log_handle,
450 	    "usbms_rserv entering");
451 
452 	while (canputnext(q) && ms->ms_oldoff != b->mb_off) {
453 		mi = &b->mb_info[ms->ms_oldoff];
454 		switch (ms->ms_readformat) {
455 
456 		case MS_3BYTE_FORMAT: {
457 			char	*cp;
458 
459 			if ((usbmsp->usbms_idf).xlen != 1) {
460 				USB_DPRINTF_L3(PRINT_MASK_SERV,
461 				    usbms_log_handle,
462 				    "Can't set to 3 byte format. Length != 1");
463 
464 				return (0);
465 			}
466 			if ((bp = allocb(3, BPRI_HI)) != NULL) {
467 				cp = (char *)bp->b_wptr;
468 
469 				*cp++ = 0x80 | (mi->mi_buttons & 0xFF);
470 				/* Update read buttons */
471 				ms->ms_prevbuttons = mi->mi_buttons;
472 
473 				*cp++ = (mi->mi_x & 0xFF);
474 				*cp++ = ((-mi->mi_y) & 0xFF);
475 				/* lower pri to avoid mouse droppings */
476 				bp->b_wptr = (uchar_t *)cp;
477 				putnext(q, bp);
478 			} else {
479 				if (usbmsp->usbms_resched_id) {
480 					qunbufcall(q,
481 					    (bufcall_id_t)usbmsp->
482 					    usbms_resched_id);
483 				}
484 				usbmsp->usbms_resched_id = qbufcall(q,
485 				    (size_t)3,
486 				    (uint_t)BPRI_HI,
487 				    (void (*)())usbms_resched,
488 				    (void *) usbmsp);
489 				if (usbmsp->usbms_resched_id == 0)
490 
491 					return (0);	/* try again later */
492 				/* bufcall failed; just pitch this event */
493 				/* or maybe flush queue? */
494 			}
495 			ms->ms_oldoff++;	/* next event */
496 
497 			/* circular buffer wraparound */
498 			if (ms->ms_oldoff >= b->mb_size) {
499 				ms->ms_oldoff = 0;
500 			}
501 			break;
502 		}
503 
504 		case MS_VUID_FORMAT:
505 		default: {
506 
507 			do {
508 				bp = NULL;
509 
510 				switch (ms->ms_eventstate) {
511 
512 				case EVENT_WHEEL:
513 					loop = (usbmsp->usbms_num_wheels ?
514 					    1 : 0);
515 
516 					if (usbmsp->usbms_num_wheels) {
517 						for (i = 0; i < loop; i++) {
518 						usbms_rserv_vuid_event_wheel
519 						    (q, mi, &bp, i);
520 						}
521 					}
522 
523 					break;
524 				case EVENT_BUT8:
525 				case EVENT_BUT7:
526 				case EVENT_BUT6:
527 				case EVENT_BUT5:
528 				case EVENT_BUT4:
529 				case EVENT_BUT3:  /* Send right button */
530 				case EVENT_BUT2:  /* Send middle button */
531 				case EVENT_BUT1:  /* Send left button */
532 					usbms_rserv_vuid_button(q, mi, &bp);
533 
534 					break;
535 				case EVENT_Y:
536 					usbms_rserv_vuid_event_y(q, mi, &bp);
537 
538 					break;
539 				case EVENT_X:
540 					usbms_rserv_vuid_event_x(q, mi, &bp);
541 
542 					break;
543 				default:
544 					/* start again */
545 					ms->ms_eventstate = EVENT_WHEEL;
546 
547 					break;
548 				}
549 				if (bp != NULL) {
550 					/* lower pri to avoid mouse droppings */
551 					bp->b_wptr += sizeof (Firm_event);
552 					putnext(q, bp);
553 				}
554 				if (ms->ms_eventstate == EVENT_X) {
555 					ms->ms_eventstate = EVENT_WHEEL;
556 				} else if (ms->ms_eventstate == EVENT_WHEEL) {
557 					ms->ms_oldoff++;	/* next event */
558 					/* circular buffer wraparound */
559 					if (ms->ms_oldoff >= b->mb_size) {
560 						ms->ms_oldoff = 0;
561 					}
562 					ms->ms_eventstate = EVENT_BUT(nbutt);
563 				} else
564 					ms->ms_eventstate--;
565 			} while (ms->ms_eventstate != EVENT_BUT(nbutt));
566 		}
567 		}
568 	}
569 	USB_DPRINTF_L3(PRINT_MASK_SERV, usbms_log_handle,
570 	    "usbms_rserv exiting");
571 	return (0);
572 }
573 
574 
575 /*
576  * usbms_rserv_vuid_event_wheel
577  *	convert wheel data to firm events
578  */
579 static void
580 usbms_rserv_vuid_event_wheel(queue_t *q, struct usbmouseinfo *mi,
581     mblk_t **bpaddr, ushort_t id)
582 {
583 	Firm_event *fep;
584 	mblk_t *tmp;
585 	struct ms_softc *ms;
586 	usbms_state_t *usbmsp = (usbms_state_t *)q->q_ptr;
587 
588 	if (!(usbmsp->usbms_wheel_state_bf & (1 << id))) {
589 
590 		return;
591 	}
592 	ms = &usbmsp->usbms_softc;
593 	if (mi->mi_z) {
594 		if ((tmp = allocb(sizeof (Firm_event), BPRI_HI)) != NULL) {
595 			fep = (Firm_event *)tmp->b_wptr;
596 			fep->id = vuid_id_addr(vuid_first(VUID_WHEEL)) |
597 			    vuid_id_offset(id);
598 			fep->pair_type = FE_PAIR_NONE;
599 			fep->pair = 0;
600 			fep->value = mi->mi_z;
601 			fep->time = mi->mi_time;
602 			*bpaddr = tmp;
603 		} else {
604 			if (usbmsp->usbms_resched_id) {
605 				qunbufcall(q,
606 				    (bufcall_id_t)usbmsp->usbms_resched_id);
607 			}
608 			usbmsp->usbms_resched_id =
609 			    qbufcall(q, sizeof (Firm_event), BPRI_HI,
610 			    (void (*)())usbms_resched, (void *) usbmsp);
611 			if (usbmsp->usbms_resched_id == 0) {
612 				/* try again later */
613 
614 				return;
615 			}
616 
617 			/* flush the queue */
618 			ms->ms_eventstate = EVENT_WHEEL;
619 		}
620 	}
621 }
622 
623 
624 /*
625  * usbms_rserv_vuid_button() :
626  *	Process a VUID button event
627  */
628 static void
629 usbms_rserv_vuid_button(queue_t *q, struct usbmouseinfo	*mi, mblk_t **bpaddr)
630 {
631 	usbms_state_t		*usbmsp = q->q_ptr;
632 	struct ms_softc	*ms;
633 	int			button_number;
634 	uchar_t			hwbit = 0x0;
635 	Firm_event		*fep;
636 	mblk_t			*bp;
637 	uchar_t			nbutt;
638 
639 	ms = &usbmsp->usbms_softc;
640 
641 	/* Test button. Send an event if it changed. */
642 	nbutt = (uchar_t)usbmsp->usbms_num_buttons;
643 	button_number = nbutt - (EVENT_BUT(nbutt) - ms->ms_eventstate) - 1;
644 	switch (button_number) {
645 	case	2:
646 		/* Right button */
647 		hwbit = 0x01;
648 
649 		break;
650 	case	1:
651 		/*
652 		 * On two-button mice, the second button is the "right"
653 		 * button.  There is no "middle".  The vuidps2.c file has
654 		 * a bmap[] array in sendButtonEvent().  We do something
655 		 * equivalent here ONLY in the case of two-button mice.
656 		 */
657 		if (nbutt == 2) {
658 			hwbit = 0x01;
659 			/*
660 			 * Trick the vuid message into thinking it's a
661 			 * right-button click also.
662 			 */
663 			button_number = 2;
664 		} else {
665 			/* ... otherwise, it's just the middle button */
666 			hwbit = 0x02;
667 		}
668 		break;
669 	case	0:
670 		/* Left button */
671 		hwbit = 0x04;
672 
673 		break;
674 	default	:
675 		/* Any other button */
676 		hwbit = USBMS_BUT(nbutt) >> (EVENT_BUT(nbutt) -
677 		    ms->ms_eventstate);
678 
679 		break;
680 	}
681 
682 	if ((ms->ms_prevbuttons & hwbit) !=
683 	    (mi->mi_buttons & hwbit)) {
684 		if ((bp = allocb(sizeof (Firm_event),
685 		    BPRI_HI)) != NULL) {
686 			*bpaddr = bp;
687 			fep = (Firm_event *)bp->b_wptr;
688 			fep->id = vuid_id_addr(
689 			    ms->ms_vuidaddr) |
690 			    vuid_id_offset(BUT(1)
691 			    + button_number);
692 			fep->pair_type = FE_PAIR_NONE;
693 			fep->pair = 0;
694 
695 			/*
696 			 * Update read buttons and set
697 			 * value
698 			 */
699 			if (mi->mi_buttons & hwbit) {
700 				fep->value = 0;
701 				ms->ms_prevbuttons |=
702 				    hwbit;
703 			} else {
704 				fep->value = 1;
705 				ms->ms_prevbuttons &=
706 				    ~hwbit;
707 			}
708 			fep->time = mi->mi_time;
709 		} else {
710 			if (usbmsp->usbms_resched_id) {
711 				qunbufcall(q,
712 				    (bufcall_id_t)usbmsp->usbms_resched_id);
713 			}
714 			usbmsp->usbms_resched_id =
715 			    qbufcall(q,
716 			    sizeof (Firm_event),
717 			    BPRI_HI,
718 			    (void (*)())usbms_resched,
719 			    (void *) usbmsp);
720 			if (usbmsp->usbms_resched_id == 0)
721 				/* try again later */
722 				return;
723 			/*
724 			 * bufcall failed; just pitch
725 			 * this event
726 			 */
727 			/* or maybe flush queue? */
728 			ms->ms_eventstate = EVENT_WHEEL;
729 		}
730 	}
731 }
732 
733 /*
734  * usbms_rserv_vuid_event_y() :
735  *	Process a VUID y-event
736  */
737 static void
738 usbms_rserv_vuid_event_y(queue_t *q, struct usbmouseinfo *mi, mblk_t **bpaddr)
739 {
740 	usbms_state_t			*usbmsp = q->q_ptr;
741 	struct ms_softc	*ms;
742 	Firm_event		*fep;
743 	mblk_t				*bp;
744 
745 	ms = &usbmsp->usbms_softc;
746 
747 	/*
748 	 * The (max, 0) message and (0, max) message are always sent before
749 	 * the button click message is sent on the IBM Bladecenter. Stop
750 	 * their sending may prevent the coordinate from moving to the
751 	 * (max, max).
752 	 */
753 	if (!(((usbmsp->usbms_idf).yattr) & HID_MAIN_ITEM_RELATIVE)) {
754 		if ((mi->mi_x == 0) &&
755 		    (mi->mi_y == usbmsp->usbms_logical_Ymax)) {
756 
757 			return;
758 		}
759 	}
760 
761 	/* Send y if changed. */
762 	if (mi->mi_y != 0) {
763 		if ((bp = allocb(sizeof (Firm_event),
764 		    BPRI_HI)) != NULL) {
765 			*bpaddr = bp;
766 			fep = (Firm_event *)bp->b_wptr;
767 			if (((usbmsp->usbms_idf).yattr) &
768 			    HID_MAIN_ITEM_RELATIVE) {
769 				fep->id = vuid_id_addr(
770 				    ms->ms_vuidaddr) |
771 				    vuid_id_offset(
772 				    LOC_Y_DELTA);
773 				fep->pair_type =
774 				    FE_PAIR_ABSOLUTE;
775 				fep->pair =
776 				    (uchar_t)LOC_Y_ABSOLUTE;
777 				fep->value = -(mi->mi_y);
778 			} else {
779 				fep->id = vuid_id_addr(
780 				    ms->ms_vuidaddr) |
781 				    vuid_id_offset(
782 				    LOC_Y_ABSOLUTE);
783 				fep->pair_type = FE_PAIR_DELTA;
784 				fep->pair = (uchar_t)LOC_Y_DELTA;
785 				fep->value = (mi->mi_y *
786 				    ((usbmsp->usbms_resolution).height) /
787 				    usbmsp->usbms_logical_Ymax);
788 				if ((mi->mi_y *
789 				    ((usbmsp->usbms_resolution).height) %
790 				    usbmsp->usbms_logical_Ymax) >=
791 				    (usbmsp->usbms_logical_Ymax / 2)) {
792 					fep->value ++;
793 				}
794 			}
795 			fep->time = mi->mi_time;
796 		} else {
797 			if (usbmsp->usbms_resched_id) {
798 				qunbufcall(q,
799 				    (bufcall_id_t)usbmsp->usbms_resched_id);
800 			}
801 			usbmsp->usbms_resched_id =
802 			    qbufcall(q,
803 			    sizeof (Firm_event),
804 			    BPRI_HI,
805 			    (void (*)())usbms_resched,
806 			    (void *)usbmsp);
807 			if (usbmsp->usbms_resched_id == 0) {
808 				/* try again later */
809 				return;
810 			}
811 
812 			/*
813 			 * bufcall failed; just pitch
814 			 * this event
815 			 */
816 			/* or maybe flush queue? */
817 			ms->ms_eventstate = EVENT_WHEEL;
818 		}
819 	}
820 }
821 
822 /*
823  * usbms_rserv_vuid_event_x() :
824  *	Process a VUID x-event
825  */
826 static void
827 usbms_rserv_vuid_event_x(queue_t *q, struct usbmouseinfo *mi, mblk_t **bpaddr)
828 {
829 	usbms_state_t			*usbmsp = q->q_ptr;
830 	struct ms_softc	*ms;
831 	Firm_event		*fep;
832 	mblk_t				*bp;
833 
834 	ms = &usbmsp->usbms_softc;
835 
836 	/*
837 	 * The (max, 0) message and (0, max) message are always sent before
838 	 * the button click message is sent on the IBM Bladecenter. Stop
839 	 * their sending may prevent the coordinate from moving to the
840 	 * (max, max).
841 	 */
842 	if (!(((usbmsp->usbms_idf).xattr) & HID_MAIN_ITEM_RELATIVE)) {
843 		if ((mi->mi_y == 0) &&
844 		    (mi->mi_x == usbmsp->usbms_logical_Xmax)) {
845 
846 		return;
847 		}
848 	}
849 
850 	/* Send x if changed. */
851 	if (mi->mi_x != 0) {
852 		if ((bp = allocb(sizeof (Firm_event),
853 		    BPRI_HI)) != NULL) {
854 			*bpaddr = bp;
855 			fep = (Firm_event *)bp->b_wptr;
856 			if (((usbmsp->usbms_idf).xattr) &
857 			    HID_MAIN_ITEM_RELATIVE) {
858 				fep->id = vuid_id_addr(
859 				    ms->ms_vuidaddr) |
860 				    vuid_id_offset(LOC_X_DELTA);
861 				fep->pair_type =
862 				    FE_PAIR_ABSOLUTE;
863 				fep->pair =
864 				    (uchar_t)LOC_X_ABSOLUTE;
865 				fep->value = mi->mi_x;
866 			} else {
867 				fep->id = vuid_id_addr(ms->ms_vuidaddr) |
868 				    vuid_id_offset(LOC_X_ABSOLUTE);
869 				fep->pair_type = FE_PAIR_DELTA;
870 				fep->pair = (uchar_t)LOC_X_DELTA;
871 				fep->value = (mi->mi_x *
872 				    ((usbmsp->usbms_resolution).width) /
873 				    usbmsp->usbms_logical_Xmax);
874 				if ((mi->mi_x *
875 				    ((usbmsp->usbms_resolution).width) %
876 				    usbmsp->usbms_logical_Xmax) >=
877 				    (usbmsp->usbms_logical_Xmax / 2)) {
878 					fep->value ++;
879 				}
880 			}
881 			fep->time = mi->mi_time;
882 		} else {
883 			if (usbmsp->usbms_resched_id)
884 				qunbufcall(q,
885 				    (bufcall_id_t)usbmsp->usbms_resched_id);
886 			usbmsp->usbms_resched_id =
887 			    qbufcall(q,
888 			    sizeof (Firm_event),
889 			    BPRI_HI,
890 			    (void (*)())usbms_resched,
891 			    (void *) usbmsp);
892 			if (usbmsp->usbms_resched_id == 0)
893 				/* try again later */
894 				return;
895 
896 			/*
897 			 * bufcall failed; just
898 			 * pitch this event
899 			 */
900 			/* or maybe flush queue? */
901 			ms->ms_eventstate = EVENT_WHEEL;
902 		}
903 	}
904 }
905 
906 /*
907  * usbms_resched() :
908  *	Callback routine for the qbufcall() in case
909  *	of allocb() failure. When buffer becomes
910  *	available, this function is called and
911  *	enables the queue.
912  */
913 static void
914 usbms_resched(void *usbmsp)
915 {
916 	queue_t	*q;
917 	usbms_state_t	*tmp_usbmsp = (usbms_state_t *)usbmsp;
918 
919 	tmp_usbmsp->usbms_resched_id = 0;
920 	if ((q = tmp_usbmsp->usbms_rq_ptr) != 0)
921 		qenable(q);	/* run the service procedure */
922 }
923 
924 /*
925  * usbms_wput() :
926  *	wput() routine for the mouse module.
927  *	Module below : hid, module above : consms
928  */
929 static int
930 usbms_wput(queue_t *q, mblk_t *mp)
931 {
932 	USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
933 	    "usbms_wput entering");
934 	switch (mp->b_datap->db_type) {
935 
936 	case M_FLUSH:  /* Canonical flush handling */
937 		if (*mp->b_rptr & FLUSHW) {
938 			flushq(q, FLUSHDATA);
939 		}
940 
941 		if (*mp->b_rptr & FLUSHR) {
942 			flushq(RD(q), FLUSHDATA);
943 		}
944 
945 		putnext(q, mp); /* pass it down the line. */
946 		break;
947 
948 	case M_IOCTL:
949 		usbms_ioctl(q, mp);
950 		break;
951 
952 	case M_IOCDATA:
953 		usbms_miocdata(q, mp);
954 
955 		break;
956 	default:
957 		putnext(q, mp); /* pass it down the line. */
958 	}
959 
960 	USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
961 	    "usbms_wput exiting");
962 
963 	return (0);
964 }
965 
966 
967 /*
968  * usbms_ioctl() :
969  *	Process ioctls we recognize and own.  Otherwise, NAK.
970  */
971 static void
972 usbms_ioctl(queue_t *q, mblk_t *mp)
973 {
974 	usbms_state_t *usbmsp = (usbms_state_t *)q->q_ptr;
975 	struct ms_softc		*ms;
976 	struct iocblk		*iocp;
977 	Vuid_addr_probe		*addr_probe;
978 	uint_t			ioctlrespsize;
979 	int			err = 0;
980 	mblk_t			*datap;
981 	ushort_t		transparent = 0;
982 	boolean_t		report_abs = B_FALSE;
983 	mblk_t	*mb;
984 
985 	USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbms_log_handle,
986 	    "usbms_ioctl entering");
987 
988 	if (usbmsp == NULL) {
989 		miocnak(q, mp, 0, EINVAL);
990 
991 		return;
992 	}
993 	ms = &usbmsp->usbms_softc;
994 
995 	iocp = (struct iocblk *)mp->b_rptr;
996 	switch (iocp->ioc_cmd) {
997 
998 	case VUIDSFORMAT:
999 		err = miocpullup(mp, sizeof (int));
1000 		if (err != 0)
1001 			break;
1002 
1003 		if (*(int *)mp->b_cont->b_rptr == ms->ms_readformat) {
1004 			break;
1005 		}
1006 		ms->ms_readformat = *(int *)mp->b_cont->b_rptr;
1007 		/*
1008 		 * Flush mouse buffer because the messages upstream of us
1009 		 * are in the old format.
1010 		 */
1011 
1012 		usbms_flush(usbmsp);
1013 		break;
1014 
1015 	case VUIDGFORMAT:
1016 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
1017 			ioctlrespsize = sizeof (int);
1018 			goto allocfailure;
1019 		}
1020 		*(int *)datap->b_wptr = ms->ms_readformat;
1021 		datap->b_wptr += sizeof (int);
1022 		freemsg(mp->b_cont);
1023 		mp->b_cont = datap;
1024 		iocp->ioc_count = sizeof (int);
1025 		break;
1026 
1027 	case VUIDGADDR:
1028 	case VUIDSADDR:
1029 		err = miocpullup(mp, sizeof (Vuid_addr_probe));
1030 		if (err != 0)
1031 			break;
1032 
1033 		addr_probe = (Vuid_addr_probe *)mp->b_cont->b_rptr;
1034 		if (addr_probe->base != VKEY_FIRST) {
1035 			err = ENODEV;
1036 			break;
1037 		}
1038 		if (iocp->ioc_cmd == VUIDSADDR)
1039 			ms->ms_vuidaddr = addr_probe->data.next;
1040 		else
1041 			addr_probe->data.current = ms->ms_vuidaddr;
1042 		break;
1043 
1044 	case MSIOGETPARMS:
1045 		if ((datap = allocb(sizeof (Ms_parms), BPRI_HI)) == NULL) {
1046 			ioctlrespsize = sizeof (Ms_parms);
1047 			goto allocfailure;
1048 		}
1049 		err = usbms_getparms((Ms_parms *)datap->b_wptr, usbmsp);
1050 		datap->b_wptr += sizeof (Ms_parms);
1051 		freemsg(mp->b_cont);
1052 		mp->b_cont = datap;
1053 		iocp->ioc_count = sizeof (Ms_parms);
1054 		break;
1055 
1056 	case MSIOSETPARMS:
1057 		err = miocpullup(mp, sizeof (Ms_parms));
1058 		if (err != 0)
1059 			break;
1060 		err = usbms_setparms((Ms_parms *)mp->b_cont->b_rptr, usbmsp);
1061 		break;
1062 
1063 	case MSIOBUTTONS:
1064 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
1065 			ioctlrespsize = sizeof (int);
1066 			goto allocfailure;
1067 		}
1068 		*(int *)datap->b_wptr = (int)usbmsp->usbms_num_buttons;
1069 		datap->b_wptr += sizeof (int);
1070 		freemsg(mp->b_cont);
1071 		mp->b_cont = datap;
1072 		iocp->ioc_count = sizeof (int);
1073 
1074 		break;
1075 	case VUIDGWHEELCOUNT:
1076 		/*
1077 		 * New IOCTL support. Since it's explicitly mentioned that
1078 		 * you can't add more ioctls to stream head's hard coded
1079 		 * list, we have to do the transparent ioctl processing
1080 		 * which is heavy.
1081 		 */
1082 
1083 		/* Currently support for only one wheel */
1084 
1085 		if (iocp->ioc_count == TRANSPARENT) {
1086 			transparent = 1;
1087 			if (err = usbms_make_copyreq(mp, 0, 0, sizeof (int),
1088 			    0, M_COPYOUT)) {
1089 
1090 				break;
1091 			}
1092 		}
1093 		if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
1094 			ioctlrespsize = sizeof (int);
1095 
1096 			goto allocfailure;
1097 		}
1098 		*((int *)datap->b_wptr) = (usbmsp->usbms_num_wheels ? 1 : 0);
1099 		datap->b_wptr +=  sizeof (int);
1100 		if (mp->b_cont) {
1101 			freemsg(mp->b_cont);
1102 			mp->b_cont = NULL;
1103 		}
1104 		mp->b_cont = datap;
1105 		if (transparent) {
1106 			qreply(q, mp);
1107 
1108 			return;
1109 		}
1110 
1111 		break;
1112 	case VUIDGWHEELINFO:
1113 		if (iocp->ioc_count == TRANSPARENT) {
1114 			if (err = usbms_make_copyreq(mp,
1115 			    sizeof (usbms_iocstate_t),
1116 			    USBMS_GETSTRUCT,
1117 			    sizeof (wheel_info),
1118 			    0,
1119 			    M_COPYIN)) {
1120 
1121 				break;
1122 			}
1123 			/*
1124 			 * If there is no b_cont the earlier func. will fail.
1125 			 * Hence there is no need for an explicit check here.
1126 			 */
1127 			freemsg(mp->b_cont);
1128 			mp->b_cont = (mblk_t *)NULL;
1129 			qreply(q, mp);
1130 
1131 			return;
1132 		}
1133 		if (mp->b_cont == NULL || iocp->ioc_count !=
1134 		    sizeof (wheel_info)) {
1135 			err = EINVAL;
1136 			break;
1137 		}
1138 		datap = mp->b_cont;
1139 		err = usbms_service_wheel_info(q, datap);
1140 
1141 		break;
1142 	case VUIDGWHEELSTATE:
1143 		if (iocp->ioc_count == TRANSPARENT) {
1144 			if (err = usbms_make_copyreq(mp,
1145 			    sizeof (usbms_iocstate_t),
1146 			    USBMS_GETSTRUCT,
1147 			    sizeof (wheel_state),
1148 			    0,
1149 			    M_COPYIN)) {
1150 
1151 				break;
1152 			}
1153 			freemsg(mp->b_cont);
1154 			mp->b_cont = (mblk_t *)NULL;
1155 			qreply(q, mp);
1156 
1157 			return;
1158 		}
1159 		if ((mp->b_cont == NULL) ||
1160 		    (iocp->ioc_count != sizeof (wheel_state))) {
1161 			err = EINVAL;
1162 
1163 			break;
1164 		}
1165 		datap = mp->b_cont;
1166 		err = usbms_service_wheel_state(q, datap, VUIDGWHEELSTATE);
1167 
1168 		break;
1169 	case VUIDSWHEELSTATE:
1170 		if (iocp->ioc_count == TRANSPARENT) {
1171 			if (err = usbms_make_copyreq(mp,
1172 			    sizeof (usbms_iocstate_t),
1173 			    USBMS_GETSTRUCT,
1174 			    sizeof (wheel_state),
1175 			    0,
1176 			    M_COPYIN)) {
1177 
1178 				break;
1179 			}
1180 			freemsg(mp->b_cont);
1181 			mp->b_cont = (mblk_t *)NULL;
1182 			qreply(q, mp);
1183 
1184 			return;
1185 		}
1186 		if (mp->b_cont == NULL) {
1187 			err = EINVAL;
1188 
1189 			break;
1190 		}
1191 		datap = mp->b_cont;
1192 		err = usbms_service_wheel_state(q, datap, VUIDSWHEELSTATE);
1193 
1194 		break;
1195 	case MSIOSRESOLUTION:
1196 		if (iocp->ioc_count == TRANSPARENT) {
1197 			if (err = usbms_make_copyreq(mp,
1198 			    sizeof (usbms_iocstate_t),
1199 			    USBMS_GETSTRUCT,
1200 			    sizeof (Ms_screen_resolution),
1201 			    0,
1202 			    M_COPYIN)) {
1203 
1204 				break;
1205 			}
1206 
1207 			freemsg(mp->b_cont);
1208 			mp->b_cont = (mblk_t *)NULL;
1209 			qreply(q, mp);
1210 
1211 			return;
1212 		}
1213 		if (mp->b_cont == NULL) {
1214 			err = EINVAL;
1215 
1216 			break;
1217 		}
1218 		datap = mp->b_cont;
1219 		err = usbms_get_screen_parms(q, datap);
1220 		/*
1221 		 * Create the absolute mouse type event.
1222 		 * It is used for the hotplug absolute mouse.
1223 		 */
1224 		if ((!((usbmsp->usbms_idf).xattr & HID_MAIN_ITEM_RELATIVE)) &&
1225 		    (usbmsp->usbms_rpt_abs == B_FALSE)) {
1226 			report_abs = B_TRUE;
1227 		}
1228 
1229 		break;
1230 
1231 	default:
1232 		putnext(q, mp); /* pass it down the line */
1233 
1234 		return;
1235 	} /* switch */
1236 
1237 	if (err != 0)
1238 		miocnak(q, mp, 0, err);
1239 	else {
1240 		iocp->ioc_rval = 0;
1241 		iocp->ioc_error = 0;
1242 		mp->b_datap->db_type = M_IOCACK;
1243 		qreply(q, mp);
1244 
1245 		if (report_abs == B_TRUE) {
1246 			/* send the abs mouse type event to the upper level */
1247 			if ((mb = usbms_setup_abs_mouse_event()) != NULL) {
1248 				usbmsp->usbms_rpt_abs = B_TRUE;
1249 				qreply(q, mb);
1250 			}
1251 		}
1252 	}
1253 
1254 	return;
1255 
1256 allocfailure:
1257 	/*
1258 	 * We needed to allocate something to handle this "ioctl", but
1259 	 * couldn't; save this "ioctl" and arrange to get called back when
1260 	 * it's more likely that we can get what we need.
1261 	 * If there's already one being saved, throw it out, since it
1262 	 * must have timed out.
1263 	 */
1264 	freemsg(usbmsp->usbms_iocpending);
1265 	usbmsp->usbms_iocpending = mp;
1266 	if (usbmsp->usbms_reioctl_id) {
1267 		qunbufcall(q, (bufcall_id_t)usbmsp->usbms_reioctl_id);
1268 	}
1269 	usbmsp->usbms_reioctl_id = qbufcall(q, ioctlrespsize, BPRI_HI,
1270 	    (void (*)())usbms_reioctl,
1271 	    (void *)usbmsp);
1272 }
1273 
1274 
1275 /*
1276  * M_IOCDATA processing for IOCTL's: VUIDGWHEELCOUNT, VUIDGWHEELINFO,
1277  * VUIDGWHEELSTATE, VUIDSWHEELSTATE & MSIOSRESOLUTION.
1278  */
1279 static void
1280 usbms_miocdata(queue_t *q, mblk_t *mp)
1281 {
1282 	struct copyresp *copyresp;
1283 	struct iocblk *iocbp;
1284 	mblk_t *datap;
1285 	mblk_t *ioctmp;
1286 	usbms_iocstate_t *usbmsioc;
1287 	int err = 0;
1288 
1289 	copyresp = (struct copyresp *)mp->b_rptr;
1290 	iocbp = (struct iocblk *)mp->b_rptr;
1291 	if (copyresp->cp_rval) {
1292 		err = EAGAIN;
1293 
1294 		goto err;
1295 	}
1296 	switch (copyresp->cp_cmd) {
1297 
1298 	case VUIDGWHEELCOUNT:
1299 		usbms_ack_ioctl(mp);
1300 
1301 		break;
1302 	case VUIDGWHEELINFO:
1303 		ioctmp = copyresp->cp_private;
1304 		usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr;
1305 		if (usbmsioc->ioc_state == USBMS_GETSTRUCT) {
1306 			if (mp->b_cont == NULL) {
1307 				err = EINVAL;
1308 
1309 				break;
1310 			}
1311 			datap = (mblk_t *)mp->b_cont;
1312 			if (err = usbms_service_wheel_info(q, datap)) {
1313 
1314 				goto err;
1315 			}
1316 			if (err = usbms_make_copyreq(mp, 0, USBMS_GETRESULT,
1317 			    sizeof (wheel_info), 0, M_COPYOUT)) {
1318 
1319 				goto err;
1320 			}
1321 		} else if (usbmsioc->ioc_state == USBMS_GETRESULT) {
1322 			freemsg(ioctmp);
1323 			usbms_ack_ioctl(mp);
1324 		}
1325 
1326 		break;
1327 	case VUIDGWHEELSTATE:
1328 		ioctmp = (mblk_t *)copyresp->cp_private;
1329 		usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr;
1330 		if (usbmsioc->ioc_state == USBMS_GETSTRUCT) {
1331 			if (mp->b_cont == NULL) {
1332 				err = EINVAL;
1333 
1334 				break;
1335 			}
1336 			if (err = usbms_service_wheel_state(q, mp->b_cont,
1337 			    VUIDGWHEELSTATE)) {
1338 				goto err;
1339 			}
1340 			if (err = usbms_make_copyreq(mp, 0, USBMS_GETRESULT,
1341 			    sizeof (wheel_state), 0, M_COPYOUT)) {
1342 
1343 				goto err;
1344 			}
1345 		} else if (usbmsioc->ioc_state == USBMS_GETRESULT) {
1346 			freemsg(ioctmp);
1347 			usbms_ack_ioctl(mp);
1348 		}
1349 
1350 		break;
1351 	case VUIDSWHEELSTATE:
1352 		ioctmp = (mblk_t *)copyresp->cp_private;
1353 		usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr;
1354 		if (mp->b_cont == NULL) {
1355 			err = EINVAL;
1356 
1357 			break;
1358 		}
1359 		if (err = usbms_service_wheel_state(q, mp->b_cont,
1360 		    VUIDSWHEELSTATE)) {
1361 
1362 			goto err;
1363 		}
1364 		freemsg(ioctmp);
1365 		usbms_ack_ioctl(mp);
1366 
1367 		break;
1368 	case MSIOSRESOLUTION:
1369 		ioctmp = (mblk_t *)copyresp->cp_private;
1370 		usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr;
1371 		if (mp->b_cont == NULL) {
1372 			err = EINVAL;
1373 
1374 			break;
1375 		}
1376 		if (err = usbms_get_screen_parms(q, mp->b_cont)) {
1377 
1378 			goto err;
1379 		}
1380 		freemsg(ioctmp);
1381 		usbms_ack_ioctl(mp);
1382 
1383 		break;
1384 	default:
1385 		err = EINVAL;
1386 		break;
1387 	}
1388 
1389 err:
1390 	if (err) {
1391 		mp->b_datap->db_type = M_IOCNAK;
1392 		if (mp->b_cont) {
1393 			freemsg(mp->b_cont);
1394 			mp->b_cont = (mblk_t *)NULL;
1395 		}
1396 		if (copyresp->cp_private) {
1397 			freemsg((mblk_t *)copyresp->cp_private);
1398 			copyresp->cp_private = (mblk_t *)NULL;
1399 		}
1400 		iocbp->ioc_count = 0;
1401 		iocbp->ioc_error = err;
1402 	}
1403 	qreply(q, mp);
1404 }
1405 
1406 
1407 /*
1408  * usbms_reioctl() :
1409  *	This function is set up as call-back function should an ioctl fail.
1410  *	It retries the ioctl.
1411  */
1412 static void
1413 usbms_reioctl(void	* usbms_addr)
1414 {
1415 	usbms_state_t *usbmsp = (usbms_state_t *)usbms_addr;
1416 	queue_t	*q;
1417 	mblk_t	*mp;
1418 
1419 	q = usbmsp->usbms_wq_ptr;
1420 	if ((mp = usbmsp->usbms_iocpending) != NULL) {
1421 		usbmsp->usbms_iocpending = NULL; /* not pending any more */
1422 		usbms_ioctl(q, mp);
1423 	}
1424 }
1425 
1426 /*
1427  * usbms_getparms() :
1428  *	Called from MSIOGETPARMS ioctl to get the
1429  *	current jitter_thesh, speed_law and speed_limit
1430  *	values.
1431  */
1432 static int
1433 usbms_getparms(Ms_parms	*data, usbms_state_t *usbmsp)
1434 {
1435 	data->jitter_thresh = usbmsp->usbms_jitter_thresh;
1436 	data->speed_law = usbmsp->usbms_speedlaw;
1437 	data->speed_limit = usbmsp->usbms_speedlimit;
1438 
1439 	return (0);
1440 }
1441 
1442 
1443 /*
1444  * usbms_setparms() :
1445  *	Called from MSIOSETPARMS ioctl to set the
1446  *	current jitter_thesh, speed_law and speed_limit
1447  *	values.
1448  */
1449 static int
1450 usbms_setparms(Ms_parms	*data, usbms_state_t *usbmsp)
1451 {
1452 	usbmsp->usbms_jitter_thresh = data->jitter_thresh;
1453 	usbmsp->usbms_speedlaw = data->speed_law;
1454 	usbmsp->usbms_speedlimit = data->speed_limit;
1455 
1456 	return (0);
1457 }
1458 
1459 /*
1460  * usbms_flush() :
1461  *	Resets the ms_softc structure to default values
1462  *	and sends M_FLUSH above.
1463  */
1464 static void
1465 usbms_flush(usbms_state_t *usbmsp)
1466 {
1467 	struct ms_softc *ms = &usbmsp->usbms_softc;
1468 	queue_t		*q;
1469 
1470 	USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
1471 	    "usbms_flush entering");
1472 
1473 	ms->ms_oldoff = 0;
1474 	ms->ms_eventstate = EVENT_BUT(usbmsp->usbms_num_buttons);
1475 	usbmsp->usbms_buf->mb_off = 0;
1476 	ms->ms_prevbuttons = (char)USB_NO_BUT_PRESSED;
1477 	usbmsp->usbms_oldbutt = ms->ms_prevbuttons;
1478 	if ((q = usbmsp->usbms_rq_ptr) != NULL && q->q_next != NULL) {
1479 		(void) putnextctl1(q, M_FLUSH, FLUSHR);
1480 	}
1481 
1482 	USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
1483 	    "usbms_flush exiting");
1484 }
1485 
1486 
1487 /*
1488  * usbms_rput() :
1489  *	Put procedure for input from driver end of stream (read queue).
1490  */
1491 static int
1492 usbms_rput(queue_t *q, mblk_t *mp)
1493 {
1494 	usbms_state_t *usbmsp = q->q_ptr;
1495 	mblk_t	*tmp_mp;
1496 	ushort_t limit = (usbmsp->usbms_idf).tlen;
1497 
1498 	/* Maintain the original mp */
1499 	tmp_mp = mp;
1500 
1501 	if (usbmsp == 0) {
1502 		freemsg(mp);	/* nobody's listening */
1503 
1504 		return (0);
1505 	}
1506 
1507 	switch (mp->b_datap->db_type) {
1508 
1509 	case M_FLUSH:
1510 		if (*mp->b_rptr & FLUSHW)
1511 			flushq(WR(q), FLUSHDATA);
1512 		if (*mp->b_rptr & FLUSHR)
1513 			flushq(q, FLUSHDATA);
1514 		freemsg(mp);
1515 
1516 		return (0);
1517 
1518 	case M_BREAK:
1519 		/*
1520 		 * We don't have to handle this
1521 		 * because nothing is sent from the downstream
1522 		 */
1523 
1524 		freemsg(mp);
1525 
1526 		return (0);
1527 
1528 	case M_DATA:
1529 		if (!(usbmsp->usbms_flags & USBMS_OPEN)) {
1530 			freemsg(mp);	/* not ready to listen */
1531 
1532 			return (0);
1533 		}
1534 		break;
1535 
1536 	case M_CTL:
1537 		usbms_mctl_receive(q, mp);
1538 
1539 		return (0);
1540 
1541 	case M_ERROR:
1542 		usbmsp->usbms_protoerr = 1;
1543 		usbmsp->usbms_flags &= ~USBMS_QWAIT;
1544 		if (*mp->b_rptr == ENODEV) {
1545 			putnext(q, mp);
1546 		} else {
1547 			freemsg(mp);
1548 		}
1549 
1550 		return (0);
1551 	default:
1552 		putnext(q, mp);
1553 
1554 		return (0);
1555 	}
1556 
1557 	/*
1558 	 * A data message, consisting of bytes from the mouse.
1559 	 * Make sure there are atleast "limit" number of bytes.
1560 	 */
1561 	if ((MBLKL(tmp_mp) < limit) || ((MBLKL(tmp_mp) == limit) &&
1562 	    (usbmsp->usbms_rptid != HID_REPORT_ID_UNDEFINED))) {
1563 		freemsg(mp);
1564 		return (0);
1565 	}
1566 	do {
1567 		if (usbmsp->usbms_rptid != HID_REPORT_ID_UNDEFINED) {
1568 			if (*(tmp_mp->b_rptr) != usbmsp->usbms_rptid) {
1569 				freemsg(mp);
1570 
1571 				return (0);
1572 			} else {
1573 				/* We skip the report id prefix. */
1574 				tmp_mp->b_rptr++;
1575 			}
1576 		}
1577 
1578 		usbms_input(usbmsp, tmp_mp);
1579 	} while ((tmp_mp = tmp_mp->b_cont) != NULL);   /* next block, if any */
1580 
1581 	freemsg(mp);
1582 	return (0);
1583 }
1584 
1585 
1586 /*
1587  * usbms_mctl_receive() :
1588  *	Handle M_CTL messages from hid.  If
1589  *	we don't understand the command, free message.
1590  */
1591 static void
1592 usbms_mctl_receive(queue_t *q, mblk_t *mp)
1593 {
1594 	usbms_state_t *usbmsd = (usbms_state_t *)q->q_ptr;
1595 	struct iocblk				*iocp;
1596 	caddr_t					data;
1597 
1598 
1599 	iocp = (struct iocblk *)mp->b_rptr;
1600 	if (mp->b_cont != NULL)
1601 		data = (caddr_t)mp->b_cont->b_rptr;
1602 
1603 	switch (iocp->ioc_cmd) {
1604 
1605 	case HID_GET_PARSER_HANDLE:
1606 		if ((data != NULL) &&
1607 		    (iocp->ioc_count == sizeof (hidparser_handle_t)) &&
1608 		    (MBLKL(mp->b_cont) == iocp->ioc_count)) {
1609 			usbmsd->usbms_report_descr_handle =
1610 			    *(hidparser_handle_t *)data;
1611 		} else {
1612 			usbmsd->usbms_report_descr_handle = NULL;
1613 		}
1614 		freemsg(mp);
1615 		usbmsd->usbms_flags &= ~USBMS_QWAIT;
1616 		break;
1617 	case HID_SET_PROTOCOL:
1618 		usbmsd->usbms_flags &= ~USBMS_QWAIT;
1619 
1620 		/* FALLTHRU */
1621 	default:
1622 		freemsg(mp);
1623 		break;
1624 	}
1625 }
1626 
1627 
1628 /*
1629  * usbms_input() :
1630  *
1631  *	Mouse input routine; process a byte received from a mouse and
1632  *	assemble into a mouseinfo message for the window system.
1633  *
1634  *	The USB mouse send a three-byte packet organized as
1635  *		button, dx, dy
1636  *	where dx and dy can be any signed byte value. The mouseinfo message
1637  *	is organized as
1638  *		dx, dy, button, timestamp
1639  *	Our strategy is to collect but, dx & dy three-byte packet, then
1640  *	send the mouseinfo message up.
1641  *
1642  *	Basic algorithm: throw away bytes until we get a [potential]
1643  *	button byte. Collect button; Collect dx; Collect dy; Send button,
1644  *	dx, dy, timestamp.
1645  *
1646  *	Watch out for overflow!
1647  */
1648 static void
1649 usbms_input(usbms_state_t *usbmsp, mblk_t *mp)
1650 {
1651 	struct usbmousebuf	*b;
1652 	struct usbmouseinfo	*mi;
1653 	int			jitter_radius;
1654 	int32_t		nbutt;
1655 	ushort_t			i;
1656 	char				c;
1657 
1658 	nbutt = usbmsp->usbms_num_buttons;
1659 	b = usbmsp->usbms_buf;
1660 
1661 	USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1662 	    "usbms_input entering");
1663 
1664 	if (b == NULL) {
1665 
1666 		return;
1667 	}
1668 
1669 	mi = &b->mb_info[b->mb_off];
1670 
1671 	/*
1672 	 * Lower 3 bits are middle, right, left.
1673 	 */
1674 	c = mp->b_rptr[(usbmsp->usbms_idf).bpos];
1675 	mi->mi_buttons = (char)USB_NO_BUT_PRESSED;
1676 	if (c & USBMS_BUT(1)) {	 /* left button is pressed */
1677 		mi->mi_buttons = mi->mi_buttons & USB_LEFT_BUT_PRESSED;
1678 		USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR,
1679 		    usbms_log_handle,
1680 		    "left button pressed");
1681 	}
1682 	if (c & USBMS_BUT(2)) {	/* right button is pressed */
1683 		mi->mi_buttons = mi->mi_buttons & USB_RIGHT_BUT_PRESSED;
1684 		USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR,
1685 		    usbms_log_handle,
1686 		    "right button pressed");
1687 	}
1688 	if (c & USBMS_BUT(3)) {   /* middle button is pressed */
1689 		mi->mi_buttons = mi->mi_buttons &
1690 		    USB_MIDDLE_BUT_PRESSED;
1691 		USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR,
1692 		    usbms_log_handle,
1693 		    "middle button pressed");
1694 	}
1695 
1696 	if (nbutt > 3) {
1697 		for (i = 4; i < (nbutt + 1); i++) {
1698 			if (c & USBMS_BUT(i)) {
1699 				mi->mi_buttons = mi->mi_buttons &
1700 				    USB_BUT_PRESSED(i);
1701 				USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR,
1702 				    usbms_log_handle,
1703 				    "%d button pressed", i);
1704 			}
1705 		}
1706 	}
1707 
1708 	/* get the delta X and Y from the sample */
1709 	mi->mi_x += usbms_get_coordinate((usbmsp->usbms_idf).xpos,
1710 	    (usbmsp->usbms_idf).xlen, mp);
1711 
1712 	USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR,
1713 	    usbms_log_handle, "x = %d", (int)mi->mi_x);
1714 
1715 	uniqtime32(&mi->mi_time); /* record time when sample arrived */
1716 
1717 	mi->mi_y += usbms_get_coordinate((usbmsp->usbms_idf).ypos,
1718 	    (usbmsp->usbms_idf).ylen, mp);
1719 
1720 	USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1721 	    "y = %d", (int)mi->mi_y);
1722 
1723 	/*
1724 	 * Check the wheel data in the current event.
1725 	 * If it exists, the wheel data is got from the sample.
1726 	 */
1727 
1728 	if (usbmsp->usbms_num_wheels) {
1729 		mi->mi_z += usbms_get_coordinate((usbmsp->usbms_idf).zpos,
1730 		    (usbmsp->usbms_idf).zlen, mp);
1731 
1732 		USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1733 		    "z = %d", (int)mi->mi_z);
1734 	}
1735 
1736 	if (usbmsp->usbms_jitter) {
1737 		(void) quntimeout(usbmsp->usbms_rq_ptr,
1738 		    (timeout_id_t)usbmsp->usbms_timeout_id);
1739 		usbmsp->usbms_jitter = 0;
1740 	}
1741 
1742 	if (!usbmsp->usbms_num_wheels) {
1743 		mi->mi_z = 0;
1744 	}
1745 
1746 	/*
1747 	 * If there is a wheel movement or a change in the button state,
1748 	 * send the data up immediately.
1749 	 */
1750 	if (!(mi->mi_z) && (mi->mi_buttons == usbmsp->usbms_oldbutt)) {
1751 		/*
1752 		 * Buttons did not change; did position?
1753 		 */
1754 		if (mi->mi_x == 0 && mi->mi_y == 0) {
1755 			/* no, position did not change */
1756 
1757 			return;
1758 		}
1759 
1760 		/*
1761 		 * Did the mouse move more than the jitter threshhold?
1762 		 */
1763 		jitter_radius = usbmsp->usbms_jitter_thresh;
1764 		if (USB_ABS((int)mi->mi_x) <= jitter_radius &&
1765 		    USB_ABS((int)mi->mi_y) <= jitter_radius) {
1766 			/*
1767 			 * Mouse moved less than the jitter threshhold.
1768 			 * Don't indicate an event; keep accumulating motions.
1769 			 * After "jittertimeout" ticks expire, treat
1770 			 * the accumulated delta as the real delta.
1771 			 */
1772 			usbmsp->usbms_jitter = 1;
1773 			usbmsp->usbms_timeout_id =
1774 			    qtimeout(usbmsp->usbms_rq_ptr,
1775 			    (void (*)())usbms_incr,
1776 			    (void *)usbmsp,
1777 			    (clock_t)usbmsp->usbms_jittertimeout);
1778 
1779 			return;
1780 		}
1781 	}
1782 	usbmsp->usbms_oldbutt = mi->mi_buttons;
1783 	usbms_incr(usbmsp);
1784 
1785 	USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1786 	    "usbms_input exiting");
1787 }
1788 
1789 
1790 /*
1791  * usbms_get_coordinate():
1792  * get the X, Y, WHEEL coordinate values
1793  */
1794 static int
1795 usbms_get_coordinate(uint_t pos, uint_t len, mblk_t *mp)
1796 {
1797 	uint_t utmp, bitval, val;
1798 	int i, xyz;
1799 
1800 	/* get the unsigned int value from the bit stream */
1801 	utmp = 0;
1802 	for (i = (pos + len - 1); i >= (int)pos; i--) {
1803 		bitval = (mp->b_rptr[i/8] & (1 << (i%8))) >> (i%8);
1804 		utmp = utmp * 2 + bitval;
1805 	}
1806 
1807 	/* convert the unsigned int value into int value */
1808 	val = 1 << (len - 1);
1809 	xyz = (int)(utmp - val);
1810 	if (xyz < 0)
1811 		xyz += val;
1812 	else if (xyz == 0)
1813 		xyz = -(val - 1);
1814 	else
1815 		xyz -= val;
1816 
1817 	return (xyz);
1818 }
1819 
1820 
1821 /*
1822  * usbms_incr() :
1823  *	Increment the mouse sample pointer.
1824  *	Called either immediately after a sample or after a jitter timeout.
1825  */
1826 static void
1827 usbms_incr(void				*arg)
1828 {
1829 	usbms_state_t			*usbmsp = arg;
1830 	struct ms_softc	*ms = &usbmsp->usbms_softc;
1831 	struct usbmousebuf	*b;
1832 	struct usbmouseinfo	*mi;
1833 	int			xc, yc, zc;
1834 	int			wake;
1835 	int			speedl = usbmsp->usbms_speedlimit;
1836 	int			xabs, yabs;
1837 
1838 	/*
1839 	 * No longer waiting for jitter timeout
1840 	 */
1841 	usbmsp->usbms_jitter = 0;
1842 
1843 	b = usbmsp->usbms_buf;
1844 
1845 	USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1846 	    "usbms_incr entering");
1847 
1848 	if (b == NULL) {
1849 
1850 		return;
1851 	}
1852 	mi = &b->mb_info[b->mb_off];
1853 	if (usbmsp->usbms_speedlaw) {
1854 		xabs = USB_ABS((int)mi->mi_x);
1855 		yabs = USB_ABS((int)mi->mi_y);
1856 		if (xabs > speedl || yabs > speedl) {
1857 			usbmsp->usbms_speed_count++;
1858 		}
1859 		if (xabs > speedl) {
1860 			mi->mi_x = 0;
1861 		}
1862 		if (yabs > speedl) {
1863 			mi->mi_y = 0;
1864 		}
1865 	}
1866 
1867 
1868 	xc = yc = zc = 0;
1869 
1870 	/* See if we need to wake up anyone waiting for input */
1871 	wake = b->mb_off == ms->ms_oldoff;
1872 
1873 	/* Adjust circular buffer pointer */
1874 	if (++b->mb_off >= b->mb_size) {
1875 		b->mb_off = 0;
1876 		mi = b->mb_info;
1877 	} else {
1878 		mi++;
1879 	}
1880 
1881 	/*
1882 	 * If over-took read index then flush buffer so that mouse state
1883 	 * is consistent.
1884 	 */
1885 	if (b->mb_off == ms->ms_oldoff) {
1886 		if (overrun_msg) {
1887 			USB_DPRINTF_L1(PRINT_MASK_ALL, usbms_log_handle,
1888 			    "Mouse buffer flushed when overrun.");
1889 		}
1890 		usbms_flush(usbmsp);
1891 		overrun_cnt++;
1892 		mi = b->mb_info;
1893 	}
1894 
1895 	/* Remember current buttons and fractional part of x & y */
1896 	mi->mi_buttons = (char)USB_NO_BUT_PRESSED;
1897 	mi->mi_x = xc;
1898 	mi->mi_y = yc;
1899 	mi->mi_z = zc;
1900 
1901 	if (wake) {
1902 		USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1903 		    "usbms_incr run service");
1904 		qenable(usbmsp->usbms_rq_ptr);	/* run the service proc */
1905 	}
1906 	USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1907 	    "usbms_incr exiting");
1908 }
1909 
1910 
1911 /*
1912  * usbms_check_for_wheels
1913  *	return SUCCESS if wheel is found, else return FAILURE
1914  */
1915 static int
1916 usbms_check_for_wheels(usbms_state_t *usbmsp)
1917 {
1918 	int rval, report_id;
1919 
1920 
1921 	if (usbmsp->usbms_report_descr_handle) {
1922 		/* Get the report id that has mouse data */
1923 		if (hidparser_get_usage_attribute(
1924 		    usbmsp->usbms_report_descr_handle,
1925 		    0, /* Doesn't matter */
1926 		    HIDPARSER_ITEM_INPUT,
1927 		    HID_GENERIC_DESKTOP,
1928 		    HID_GD_X,
1929 		    HIDPARSER_ITEM_REPORT_ID,
1930 		    &usbmsp->usbms_rptid) == HIDPARSER_NOT_FOUND) {
1931 			usbmsp->usbms_rptid = HID_REPORT_ID_UNDEFINED;
1932 			report_id = 0;
1933 		} else {
1934 			report_id = usbmsp->usbms_rptid;
1935 		}
1936 
1937 		/* find no. of wheels in this report */
1938 		rval = hidparser_get_usage_attribute(
1939 		    usbmsp->usbms_report_descr_handle,
1940 		    report_id,
1941 		    HIDPARSER_ITEM_INPUT,
1942 		    HID_GENERIC_DESKTOP,
1943 		    HID_GD_WHEEL,
1944 		    HIDPARSER_ITEM_REPORT_COUNT,
1945 		    &usbmsp->usbms_num_wheels);
1946 		if (rval == HIDPARSER_SUCCESS) {
1947 			/*
1948 			 * Found wheel. By default enable the wheel.
1949 			 * Currently only enable only the first wheel.
1950 			 */
1951 			usbmsp->usbms_wheel_state_bf |=
1952 			    VUID_WHEEL_STATE_ENABLED;
1953 
1954 			return (USB_SUCCESS);
1955 		}
1956 	}
1957 	usbmsp->usbms_num_wheels = 0;
1958 
1959 	return (USB_FAILURE);
1960 }
1961 
1962 
1963 /*
1964  * usbms_make_copyreq
1965  *	helper function for usbms ioctls
1966  */
1967 static int
1968 usbms_make_copyreq(mblk_t *mp, uint_t pvtsize, uint_t state, uint_t reqsize,
1969     uint_t contsize, uint_t copytype)
1970 {
1971 
1972 	struct copyreq		*cq;
1973 	struct copyresp		*cr;
1974 	mblk_t			*ioctmp;
1975 	mblk_t			*conttmp;
1976 	usbms_iocstate_t	*usbmsioc;
1977 
1978 	if ((!pvtsize) && state) {
1979 		cr = (struct copyresp *)mp->b_rptr;
1980 		ioctmp = cr->cp_private;
1981 	}
1982 	cq = (struct copyreq *)mp->b_rptr;
1983 	if (mp->b_cont == NULL) {
1984 
1985 		return (EINVAL);
1986 	}
1987 	cq->cq_addr = *((caddr_t *)mp->b_cont->b_rptr);
1988 	cq->cq_size = reqsize;
1989 	cq->cq_flag = 0;
1990 	if (pvtsize) {
1991 		ioctmp = (mblk_t *)allocb(pvtsize, BPRI_MED);
1992 		if (ioctmp == NULL) {
1993 
1994 			return (EAGAIN);
1995 		}
1996 		cq->cq_private = ioctmp;
1997 		ioctmp = cq->cq_private;
1998 	} else {
1999 		/*
2000 		 * Here we need to set cq_private even if there's
2001 		 * no private data, otherwise its value will be
2002 		 * TRANSPARENT (-1) on 64bit systems because it
2003 		 * overlaps iocp->ioc_count. If user address (cq_addr)
2004 		 * is invalid, it would cause panic later in
2005 		 * usbms_miocdata:
2006 		 *	freemsg((mblk_t *)copyresp->cp_private);
2007 		 */
2008 		cq->cq_private = NULL;
2009 		}
2010 	if (state) {
2011 		usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr;
2012 		usbmsioc->ioc_state = state;
2013 		if (pvtsize) {  /* M_COPYIN */
2014 			usbmsioc->u_addr = cq->cq_addr;
2015 		} else {
2016 			cq->cq_addr = usbmsioc->u_addr;
2017 			cq->cq_private = ioctmp;
2018 		}
2019 		ioctmp->b_wptr = ioctmp->b_rptr + sizeof (usbms_iocstate_t);
2020 	}
2021 	if (contsize) {
2022 		conttmp = (mblk_t *)allocb(contsize, BPRI_MED);
2023 		if (conttmp == NULL) {
2024 
2025 			return (EAGAIN);
2026 		}
2027 		if (mp->b_cont) {
2028 			freemsg(mp->b_cont);
2029 			mp->b_cont = conttmp;
2030 		}
2031 	}
2032 	mp->b_datap->db_type = (unsigned char)copytype;
2033 	mp->b_wptr = mp->b_rptr + sizeof (struct copyreq);
2034 
2035 	return (USB_SUCCESS);
2036 }
2037 
2038 
2039 static int
2040 usbms_service_wheel_info(queue_t *q, mblk_t	*datap)
2041 {
2042 
2043 	wheel_info		*wi;
2044 	usbms_state_t		*usbmsp = (usbms_state_t *)q->q_ptr;
2045 	uint_t			err;
2046 
2047 	wi = (wheel_info *)datap->b_rptr;
2048 	if (wi->vers != VUID_WHEEL_INFO_VERS) {
2049 		err = EINVAL;
2050 
2051 		return (err);
2052 	}
2053 	if (wi->id > (usbmsp->usbms_num_wheels - 1)) {
2054 		err = EINVAL;
2055 
2056 		return (err);
2057 	}
2058 	wi->format = (usbmsp->usbms_wheel_orient_bf & (1 << wi->id)) ?
2059 	    VUID_WHEEL_FORMAT_HORIZONTAL : VUID_WHEEL_FORMAT_VERTICAL;
2060 
2061 	return (USB_SUCCESS);
2062 }
2063 
2064 
2065 static int
2066 usbms_service_wheel_state(queue_t *q, mblk_t *datap, uint_t cmd)
2067 {
2068 
2069 	wheel_state	*ws;
2070 	uint_t		err;
2071 	usbms_state_t	*usbmsp = (usbms_state_t *)q->q_ptr;
2072 
2073 	ws = (wheel_state *)datap->b_rptr;
2074 	if (ws->vers != VUID_WHEEL_STATE_VERS) {
2075 		err = EINVAL;
2076 
2077 		return (err);
2078 	}
2079 	if (ws->id > (usbmsp->usbms_num_wheels - 1)) {
2080 		err = EINVAL;
2081 
2082 		return (err);
2083 	}
2084 
2085 	switch (cmd) {
2086 	case	VUIDGWHEELSTATE:
2087 		ws->stateflags = (usbmsp->usbms_wheel_state_bf >> ws->id) &
2088 		    VUID_WHEEL_STATE_ENABLED;
2089 
2090 		break;
2091 	case	VUIDSWHEELSTATE:
2092 		usbmsp->usbms_wheel_state_bf = (ws->stateflags << ws->id) |
2093 		    (~(1 << ws->id) & usbmsp->usbms_wheel_state_bf);
2094 
2095 		break;
2096 	default:
2097 		err = EINVAL;
2098 
2099 		return (err);
2100 	}
2101 
2102 	return (USB_SUCCESS);
2103 }
2104 
2105 
2106 /*
2107  * usbms_get_screen_parms() :
2108  *	Called from MSIOSRESOLUTION ioctl to get the
2109  *	current screen height/width params from X.
2110  */
2111 static int
2112 usbms_get_screen_parms(queue_t *q, mblk_t *datap)
2113 {
2114 
2115 	usbms_state_t	*usbmsp = (usbms_state_t *)q->q_ptr;
2116 	Ms_screen_resolution	*res = &(usbmsp->usbms_resolution);
2117 	Ms_screen_resolution	*data;
2118 
2119 	data = (Ms_screen_resolution *)datap->b_rptr;
2120 	res->height = data->height;
2121 	res->width = data->width;
2122 
2123 	return (USB_SUCCESS);
2124 }
2125 
2126 
2127 static void
2128 usbms_ack_ioctl(mblk_t *mp)
2129 {
2130 
2131 	struct iocblk	*iocbp = (struct iocblk *)mp->b_rptr;
2132 
2133 	mp->b_datap->db_type = M_IOCACK;
2134 	mp->b_wptr = mp->b_rptr + sizeof (struct iocblk);
2135 	iocbp->ioc_error = 0;
2136 	iocbp->ioc_count = 0;
2137 	iocbp->ioc_rval = 0;
2138 	if (mp->b_cont != NULL) {
2139 		freemsg(mp->b_cont);
2140 		mp->b_cont = NULL;
2141 	}
2142 }
2143 
2144 
2145 /*
2146  * usbms_setup_abs_mouse_event() :
2147  *	Called from MSIOSRESOLUTION ioctl to create
2148  *	the absolute mouse type firm event.
2149  */
2150 static mblk_t *
2151 usbms_setup_abs_mouse_event(void)
2152 {
2153 	mblk_t	*mb;
2154 	Firm_event *fep;
2155 
2156 	if ((mb = allocb(sizeof (Firm_event), BPRI_HI)) != NULL) {
2157 		fep = (Firm_event *)mb->b_wptr;
2158 		fep->id = MOUSE_TYPE_ABSOLUTE;
2159 		fep->pair_type = FE_PAIR_NONE;
2160 		fep->pair = 0;
2161 		fep->value = 0;
2162 		mb->b_wptr += sizeof (Firm_event);
2163 	} else {
2164 		USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
2165 		    "No resource to report ABS mouse event");
2166 	}
2167 
2168 	return (mb);
2169 }
2170 
2171 
2172 /*
2173  * usbms_read_input_data_format() :
2174  *	Get the mouse packet length and usages' length.
2175  *	Check whether X and Y are relative or absolute.
2176  *
2177  *	If they are absolute, the X and Y logical max values
2178  *	will be got. A firm event will be created and sent
2179  *	to the upper level.
2180  */
2181 int
2182 usbms_read_input_data_format(usbms_state_t *usbmsp)
2183 {
2184 
2185 	hidparser_rpt_t *ms_rpt;
2186 	uint_t i, button_page;
2187 	uint_t limit = 0;
2188 	uint32_t	rptcnt, rptsz;
2189 	usbms_idf *idf = &(usbmsp->usbms_idf);
2190 	Ms_screen_resolution *res = &(usbmsp->usbms_resolution);
2191 	mblk_t *mb;
2192 	queue_t	*q;
2193 	int	rval;
2194 
2195 	usbmsp->usbms_rpt_abs = B_FALSE;
2196 
2197 	/* allocate hidparser report structure */
2198 	ms_rpt = kmem_zalloc(sizeof (hidparser_rpt_t), KM_SLEEP);
2199 
2200 	/*
2201 	 * Check what is the total length of the mouse packet
2202 	 * and get the usages and their lengths in order
2203 	 */
2204 
2205 	rval = hidparser_get_usage_list_in_order(
2206 	    usbmsp->usbms_report_descr_handle,
2207 	    usbmsp->usbms_rptid,
2208 	    HIDPARSER_ITEM_INPUT,
2209 	    ms_rpt);
2210 
2211 	if (rval != HIDPARSER_SUCCESS) {
2212 
2213 		kmem_free(ms_rpt, sizeof (hidparser_rpt_t));
2214 		return (USB_FAILURE);
2215 	}
2216 
2217 	button_page = 0;
2218 	for (i = 0; i < ms_rpt->no_of_usages; i++) {
2219 		rptcnt = ms_rpt->usage_descr[i].rptcnt;
2220 		rptsz = ms_rpt->usage_descr[i].rptsz;
2221 		if ((ms_rpt->usage_descr[i].usage_page ==
2222 		    HID_BUTTON_PAGE) && (!button_page)) {
2223 			idf->bpos = limit;
2224 			limit += (rptcnt * rptsz);
2225 			button_page = 1;
2226 			continue;
2227 		}
2228 
2229 		switch (ms_rpt->usage_descr[i].usage_id) {
2230 
2231 		case HID_GD_X:
2232 			idf->xpos = limit;
2233 			idf->xlen = rptsz;
2234 			limit += rptsz;
2235 			break;
2236 		case HID_GD_Y:
2237 			idf->ypos = limit;
2238 			idf->ylen = rptsz;
2239 			limit += rptsz;
2240 			break;
2241 		case HID_GD_Z:
2242 			/*
2243 			 * z-axis not yet supported, just skip it.
2244 			 *
2245 			 * It would be ideal if the HID_GD_Z data would be
2246 			 * reported as horizontal wheel, and HID_GD_WHEEL
2247 			 * as vertical wheel.
2248 			 *
2249 			 * We can not use the default case, because
2250 			 * that skips rptcnt*rptsz, but for an
2251 			 * "Apple Might Mouse" rptsz must be used.
2252 			 */
2253 			limit += rptsz;
2254 			break;
2255 		case HID_GD_WHEEL:
2256 			idf->zpos = limit;
2257 			idf->zlen = rptsz;
2258 			limit += rptsz;
2259 			break;
2260 		default:
2261 			limit += rptcnt * rptsz;
2262 			break;
2263 		}
2264 	}
2265 
2266 	kmem_free(ms_rpt, sizeof (hidparser_rpt_t));
2267 
2268 	/* get the length of sending data */
2269 	idf->tlen = limit / 8;
2270 
2271 	/* Check whether X and Y are relative or absolute */
2272 	rval = hidparser_get_main_item_data_descr(
2273 	    usbmsp->usbms_report_descr_handle,
2274 	    usbmsp->usbms_rptid,
2275 	    HIDPARSER_ITEM_INPUT,
2276 	    HID_GENERIC_DESKTOP,
2277 	    HID_GD_X,
2278 	    &idf->xattr);
2279 
2280 	if (rval != HIDPARSER_SUCCESS) {
2281 
2282 		return (USB_FAILURE);
2283 	}
2284 
2285 	/* For the time being assume that Y also has the same attr */
2286 	idf->yattr = idf->xattr;
2287 
2288 	/* get the logical_maximum for X and Y respectively */
2289 	if (!(idf->xattr & HID_MAIN_ITEM_RELATIVE)) {
2290 
2291 		/* the data format can't be parsed correctly */
2292 		if (limit % 8) {
2293 			USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
2294 			    "Wrong data packet include %d bits", limit);
2295 
2296 			return (USB_FAILURE);
2297 		}
2298 		if (hidparser_get_usage_attribute(
2299 		    usbmsp->usbms_report_descr_handle,
2300 		    usbmsp->usbms_rptid,
2301 		    HIDPARSER_ITEM_INPUT,
2302 		    HID_GENERIC_DESKTOP,
2303 		    HID_GD_X,
2304 		    HIDPARSER_ITEM_LOGICAL_MAXIMUM,
2305 		    &usbmsp->usbms_logical_Xmax) != HIDPARSER_SUCCESS) {
2306 
2307 			USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
2308 			    "fail to get X logical max.");
2309 
2310 			return (USB_FAILURE);
2311 		}
2312 		if (hidparser_get_usage_attribute(
2313 		    usbmsp->usbms_report_descr_handle,
2314 		    usbmsp->usbms_rptid,
2315 		    HIDPARSER_ITEM_INPUT,
2316 		    HID_GENERIC_DESKTOP,
2317 		    HID_GD_Y,
2318 		    HIDPARSER_ITEM_LOGICAL_MAXIMUM,
2319 		    &usbmsp->usbms_logical_Ymax) != HIDPARSER_SUCCESS) {
2320 
2321 			USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
2322 			    "fail to get Y logical max.");
2323 
2324 			return (USB_FAILURE);
2325 		}
2326 
2327 		if (usbmsp->usbms_logical_Xmax == 0) {
2328 			USB_DPRINTF_L3(PRINT_MASK_ALL,
2329 			    usbms_log_handle,
2330 			    "X logical max value is zero");
2331 
2332 			return (USB_FAILURE);
2333 		}
2334 
2335 		if (usbmsp->usbms_logical_Ymax == 0) {
2336 			USB_DPRINTF_L3(PRINT_MASK_ALL,
2337 			    usbms_log_handle,
2338 			    "Y logical max value is zero");
2339 
2340 			return (USB_FAILURE);
2341 		}
2342 
2343 		res->height = USBMS_DEFAULT_RES_HEIGHT;
2344 		res->width = USBMS_DEFAULT_RES_WIDTH;
2345 
2346 		/* The wheel is not supported in current remote kvms. */
2347 		usbmsp->usbms_num_wheels = 0;
2348 		q = usbmsp->usbms_rq_ptr;
2349 		if ((mb = usbms_setup_abs_mouse_event()) != NULL) {
2350 			putnext(q, mb);
2351 		} else {
2352 
2353 			return (USB_NO_RESOURCES);
2354 		}
2355 	}
2356 
2357 	return (USB_SUCCESS);
2358 }
2359