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