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