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