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