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