Merge remote-tracking branch 'origin/master'
[unleashed/lotheac.git] / usr / src / uts / common / io / usb / clients / usbms / usbms.c
blob25c710174d1f2103705152aabdbd836eb1b19e15
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
22 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/usb/usba/usbai_version.h>
27 #include <sys/usb/usba.h>
28 #include <sys/usb/clients/hid/hid.h>
29 #include <sys/usb/clients/hidparser/hidparser.h>
31 #include <sys/stropts.h>
32 #include <sys/strsun.h>
33 #include <sys/vuid_event.h>
34 #include <sys/vuid_wheel.h>
35 #include <sys/termios.h>
36 #include <sys/termio.h>
37 #include <sys/strtty.h>
38 #include <sys/msreg.h>
39 #include <sys/msio.h>
41 #include <sys/usb/clients/usbms/usbms.h>
43 /* debugging information */
44 uint_t usbms_errmask = (uint_t)PRINT_MASK_ALL;
45 uint_t usbms_errlevel = USB_LOG_L2;
46 static usb_log_handle_t usbms_log_handle;
48 static struct streamtab usbms_streamtab;
50 static struct fmodsw fsw = {
51 "usbms",
52 &usbms_streamtab,
53 D_MP | D_MTPERMOD
57 * Module linkage information for the kernel.
59 static struct modlstrmod modlstrmod = {
60 &mod_strmodops,
61 "USB mouse streams",
62 &fsw
65 static struct modlinkage modlinkage = {
66 MODREV_1,
67 (void *)&modlstrmod,
68 NULL
72 int
73 _init(void)
75 int rval = mod_install(&modlinkage);
77 if (rval == 0) {
78 usbms_log_handle = usb_alloc_log_hdl(NULL, "usbms",
79 &usbms_errlevel, &usbms_errmask, NULL, 0);
82 return (rval);
85 int
86 _fini(void)
88 int rval = mod_remove(&modlinkage);
90 if (rval == 0) {
91 usb_free_log_hdl(usbms_log_handle);
94 return (rval);
98 int
99 _info(struct modinfo *modinfop)
102 return (mod_info(&modlinkage, modinfop));
106 /* Function prototypes */
107 static void usbms_reioctl(void *);
108 static void usbms_ioctl(queue_t *, mblk_t *);
109 static int usbms_open();
110 static int usbms_close();
111 static int usbms_wput();
112 static void usbms_rput();
113 static void usbms_mctl_receive(
114 register queue_t *q,
115 register mblk_t *mp);
117 static void usbms_rserv(queue_t *q);
118 static void usbms_miocdata(
119 register queue_t *q,
120 register mblk_t *mp);
122 static void usbms_resched(void *);
124 static int usbms_getparms(
125 register Ms_parms *data,
126 usbms_state_t *usbmsp);
128 static int usbms_setparms(
129 register Ms_parms *data,
130 usbms_state_t *usbmsp);
132 static int usbms_get_screen_parms(
133 register queue_t *q,
134 register mblk_t *datap);
136 static void usbms_flush(usbms_state_t *usbmsp);
138 static void usbms_incr(void *);
139 static void usbms_input(
140 usbms_state_t *usbmsp,
141 mblk_t *mp);
142 static void usbms_rserv_vuid_button(
143 queue_t *q,
144 struct usbmouseinfo *mi,
145 mblk_t **bpaddr);
147 static void usbms_rserv_vuid_event_y(
148 queue_t *q,
149 struct usbmouseinfo *mi,
150 mblk_t **bpaddr);
151 static void usbms_rserv_vuid_event_x(
152 queue_t *q,
153 struct usbmouseinfo *mi,
154 mblk_t **bpaddr);
155 static void usbms_rserv_vuid_event_wheel(
156 queue_t *,
157 struct usbmouseinfo *,
158 mblk_t **,
159 ushort_t id);
160 static int usbms_check_for_wheels(usbms_state_t *);
161 static int usbms_make_copyreq(
162 mblk_t *,
163 uint_t pvtsize,
164 uint_t state,
165 uint_t reqsize,
166 uint_t contsize,
167 uint_t copytype);
168 static int usbms_service_wheel_info(
169 queue_t *,
170 mblk_t *);
171 static int usbms_service_wheel_state(
172 queue_t *,
173 mblk_t *,
174 uint_t cmd);
175 static void usbms_ack_ioctl(mblk_t *);
176 static int usbms_read_input_data_format(usbms_state_t *);
177 static mblk_t *usbms_setup_abs_mouse_event();
178 static int usbms_get_coordinate(
179 uint_t pos,
180 uint_t len,
181 mblk_t *mp);
182 extern void uniqtime32();
185 * Device driver qinit functions
187 static struct module_info usbms_mod_info = {
188 0x0ffff, /* module id number */
189 "usbms", /* module name */
190 0, /* min packet size accepted */
191 INFPSZ, /* max packet size accepted */
192 512, /* hi-water mark */
193 128 /* lo-water mark */
196 /* read side queue information structure */
197 static struct qinit rinit = {
198 (int (*)())usbms_rput, /* put procedure not needed */
199 (int (*)())usbms_rserv, /* service procedure */
200 usbms_open, /* called on startup */
201 usbms_close, /* called on finish */
202 NULL, /* for future use */
203 &usbms_mod_info, /* module information structure */
204 NULL /* module statistics structure */
207 /* write side queue information structure */
208 static struct qinit winit = {
209 usbms_wput, /* put procedure */
210 NULL, /* no service proecedure needed */
211 NULL, /* open not used on write side */
212 NULL, /* close not used on write side */
213 NULL, /* for future use */
214 &usbms_mod_info, /* module information structure */
215 NULL /* module statistics structure */
218 static struct streamtab usbms_streamtab = {
219 &rinit,
220 &winit,
221 NULL, /* not a MUX */
222 NULL /* not a MUX */
226 * Message when overrun circular buffer
228 static int overrun_msg;
230 /* Increment when overrun circular buffer */
231 static int overrun_cnt;
233 extern int hz;
236 * Mouse buffer size in bytes. Place here as variable so that one could
237 * massage it using adb if it turns out to be too small.
239 static uint16_t usbms_buf_bytes = USBMS_BUF_BYTES;
243 * Regular STREAMS Entry points
247 * usbms_open() :
248 * open() entry point for the USB mouse module.
250 /*ARGSUSED*/
251 static int
252 usbms_open(queue_t *q,
253 dev_t *devp,
254 int flag,
255 int sflag,
256 cred_t *credp)
258 register struct usbmousebuf *mousebufp;
259 register struct ms_softc *msd_soft;
260 usbms_state_t *usbmsp;
261 struct iocblk mctlmsg;
262 mblk_t *mctl_ptr;
265 /* Clone opens are not allowed */
266 if (sflag != MODOPEN)
267 return (EINVAL);
269 /* If the module is already open, just return */
270 if (q->q_ptr) {
271 return (0);
274 /* allocate usbms state structure */
275 usbmsp = kmem_zalloc(sizeof (usbms_state_t), KM_SLEEP);
277 q->q_ptr = usbmsp;
278 WR(q)->q_ptr = usbmsp;
280 usbmsp->usbms_rq_ptr = q;
281 usbmsp->usbms_wq_ptr = WR(q);
283 qprocson(q);
286 * Set up private data.
288 usbmsp->usbms_state = USBMS_WAIT_BUTN;
289 usbmsp->usbms_iocpending = NULL;
290 usbmsp->usbms_jitter_thresh = USBMS_JITTER_THRESH;
291 usbmsp->usbms_speedlimit = USBMS_SPEEDLIMIT;
292 usbmsp->usbms_speedlaw = USBMS_SPEEDLAW;
293 usbmsp->usbms_speed_count = USBMS_SPEED_COUNT;
295 msd_soft = &usbmsp->usbms_softc;
298 * Initially set the format to MS_VUID_FORMAT
300 msd_soft->ms_readformat = MS_VUID_FORMAT;
303 * Allocate buffer and initialize data.
305 msd_soft->ms_bufbytes = usbms_buf_bytes;
306 mousebufp = kmem_zalloc((uint_t)msd_soft->ms_bufbytes, KM_SLEEP);
308 /* Truncation will happen */
309 mousebufp->mb_size = (uint16_t)((msd_soft->ms_bufbytes -
310 sizeof (struct usbmousebuf)) / sizeof (struct usbmouseinfo));
311 mousebufp->mb_info = (struct usbmouseinfo *)((char *)mousebufp +
312 sizeof (struct usbmousebuf));
313 usbmsp->usbms_buf = mousebufp;
314 msd_soft->ms_vuidaddr = VKEY_FIRST;
315 usbmsp->usbms_jittertimeout = JITTER_TIMEOUT;
317 /* request hid report descriptor from HID */
318 mctlmsg.ioc_cmd = HID_GET_PARSER_HANDLE;
319 mctlmsg.ioc_count = 0;
321 mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0);
322 if (mctl_ptr == NULL) {
323 qprocsoff(q);
324 kmem_free(usbmsp->usbms_buf, msd_soft->ms_bufbytes);
325 kmem_free(usbmsp, sizeof (usbms_state_t));
327 return (ENOMEM);
330 usbmsp->usbms_flags |= USBMS_QWAIT;
331 putnext(usbmsp->usbms_wq_ptr, mctl_ptr);
334 * Now that signal has been sent, wait for report descriptor. Cleanup
335 * if user signals in the mean time (as when this gets opened in an
336 * inappropriate context and the user types a ^C).
338 while (usbmsp->usbms_flags & USBMS_QWAIT) {
340 if (qwait_sig(q) == 0) {
341 qprocsoff(q);
342 kmem_free(usbmsp->usbms_buf, msd_soft->ms_bufbytes);
343 kmem_free(usbmsp, sizeof (usbms_state_t));
345 return (EINTR);
349 if (usbmsp->usbms_report_descr_handle != NULL) {
350 if (hidparser_get_usage_attribute(
351 usbmsp->usbms_report_descr_handle,
353 HIDPARSER_ITEM_INPUT,
354 USBMS_USAGE_PAGE_BUTTON,
356 HIDPARSER_ITEM_REPORT_COUNT,
357 (int32_t *)&usbmsp->usbms_num_buttons) ==
358 HIDPARSER_SUCCESS) {
359 if (usbmsp->usbms_num_buttons > USB_MS_MAX_BUTTON_NO)
360 usbmsp->usbms_num_buttons =
361 USB_MS_MAX_BUTTON_NO;
362 USB_DPRINTF_L2(PRINT_MASK_ALL,
363 usbms_log_handle, "Num of buttons is : %d",
364 usbmsp->usbms_num_buttons);
365 } else {
366 USB_DPRINTF_L3(PRINT_MASK_OPEN,
367 usbms_log_handle,
368 "hidparser_get_usage_attribute failed : "
369 "Set to default number of buttons(3).");
371 usbmsp->usbms_num_buttons = USB_MS_DEFAULT_BUTTON_NO;
373 } else {
374 USB_DPRINTF_L1(PRINT_MASK_ALL,
375 usbms_log_handle, "Invalid HID "
376 "Descriptor Tree. Set to default value(3 buttons).");
377 usbmsp->usbms_num_buttons = USB_MS_DEFAULT_BUTTON_NO;
380 /* check if this mouse has wheel */
381 if (usbms_check_for_wheels(usbmsp) == USB_FAILURE) {
382 USB_DPRINTF_L2(PRINT_MASK_ALL, usbms_log_handle,
383 "No wheels detected");
384 } else {
385 USB_DPRINTF_L2(PRINT_MASK_ALL, usbms_log_handle,
386 "Wheel detected");
389 usbms_flush(usbmsp);
391 /* get the data format from the hid descriptor */
392 if (usbms_read_input_data_format(usbmsp) != USB_SUCCESS) {
394 qprocsoff(q);
395 kmem_free(usbmsp->usbms_buf, msd_soft->ms_bufbytes);
396 kmem_free(usbmsp, sizeof (usbms_state_t));
398 return (EINVAL);
401 usbmsp->usbms_flags |= USBMS_OPEN;
403 USB_DPRINTF_L3(PRINT_MASK_OPEN, usbms_log_handle,
404 "usbms_open exiting");
406 return (0);
411 * usbms_close() :
412 * close() entry point for the USB mouse module.
414 /*ARGSUSED*/
415 static int
416 usbms_close(queue_t *q,
417 int flag,
418 cred_t *credp)
420 usbms_state_t *usbmsp = q->q_ptr;
421 register struct ms_softc *ms = &usbmsp->usbms_softc;
423 USB_DPRINTF_L3(PRINT_MASK_CLOSE, usbms_log_handle,
424 "usbms_close entering");
426 qprocsoff(q);
428 if (usbmsp->usbms_jitter) {
429 (void) quntimeout(q,
430 (timeout_id_t)(long)usbmsp->usbms_timeout_id);
431 usbmsp->usbms_jitter = 0;
433 if (usbmsp->usbms_reioctl_id) {
434 qunbufcall(q, (bufcall_id_t)(long)usbmsp->usbms_reioctl_id);
435 usbmsp->usbms_reioctl_id = 0;
437 if (usbmsp->usbms_resched_id) {
438 qunbufcall(q, (bufcall_id_t)usbmsp->usbms_resched_id);
439 usbmsp->usbms_resched_id = 0;
441 if (usbmsp->usbms_iocpending != NULL) {
443 * We were holding an "ioctl" response pending the
444 * availability of an "mblk" to hold data to be passed up;
445 * another "ioctl" came through, which means that "ioctl"
446 * must have timed out or been aborted.
448 freemsg(usbmsp->usbms_iocpending);
449 usbmsp->usbms_iocpending = NULL;
453 /* Free mouse buffer */
454 if (usbmsp->usbms_buf != NULL) {
455 kmem_free(usbmsp->usbms_buf, ms->ms_bufbytes);
458 kmem_free(usbmsp, sizeof (usbms_state_t));
460 q->q_ptr = NULL;
461 WR(q)->q_ptr = NULL;
464 USB_DPRINTF_L3(PRINT_MASK_CLOSE, usbms_log_handle,
465 "usbms_close exiting");
467 return (0);
472 * usbms_rserv() :
473 * Read queue service routine.
474 * Turn buffered mouse events into stream messages.
476 static void
477 usbms_rserv(queue_t *q)
479 usbms_state_t *usbmsp = q->q_ptr;
480 struct ms_softc *ms;
481 struct usbmousebuf *b;
482 struct usbmouseinfo *mi;
483 mblk_t *bp;
484 ushort_t i, loop;
485 uchar_t nbutt = (uchar_t)usbmsp->usbms_num_buttons;
487 ms = &usbmsp->usbms_softc;
488 b = usbmsp->usbms_buf;
490 USB_DPRINTF_L3(PRINT_MASK_SERV, usbms_log_handle,
491 "usbms_rserv entering");
493 while (canputnext(q) && ms->ms_oldoff != b->mb_off) {
494 mi = &b->mb_info[ms->ms_oldoff];
495 switch (ms->ms_readformat) {
497 case MS_3BYTE_FORMAT: {
498 register char *cp;
500 if ((usbmsp->usbms_idf).xlen != 1) {
501 USB_DPRINTF_L3(PRINT_MASK_SERV,
502 usbms_log_handle,
503 "Can't set to 3 byte format. Length != 1");
505 return;
507 if ((bp = allocb(3, BPRI_HI)) != NULL) {
508 cp = (char *)bp->b_wptr;
510 *cp++ = 0x80 | (mi->mi_buttons & 0xFF);
511 /* Update read buttons */
512 ms->ms_prevbuttons = mi->mi_buttons;
514 *cp++ = (mi->mi_x & 0xFF);
515 *cp++ = ((-mi->mi_y) & 0xFF);
516 /* lower pri to avoid mouse droppings */
517 bp->b_wptr = (uchar_t *)cp;
518 putnext(q, bp);
519 } else {
520 if (usbmsp->usbms_resched_id) {
521 qunbufcall(q,
522 (bufcall_id_t)usbmsp->
523 usbms_resched_id);
525 usbmsp->usbms_resched_id = qbufcall(q,
526 (size_t)3,
527 (uint_t)BPRI_HI,
528 (void (*)())usbms_resched,
529 (void *) usbmsp);
530 if (usbmsp->usbms_resched_id == 0)
532 return; /* try again later */
533 /* bufcall failed; just pitch this event */
534 /* or maybe flush queue? */
536 ms->ms_oldoff++; /* next event */
538 /* circular buffer wraparound */
539 if (ms->ms_oldoff >= b->mb_size) {
540 ms->ms_oldoff = 0;
542 break;
545 case MS_VUID_FORMAT:
546 default: {
548 do {
549 bp = NULL;
551 switch (ms->ms_eventstate) {
553 case EVENT_WHEEL:
554 loop = (usbmsp->usbms_num_wheels ?
555 1 : 0);
557 if (usbmsp->usbms_num_wheels) {
558 for (i = 0; i < loop; i++) {
559 usbms_rserv_vuid_event_wheel
560 (q, mi, &bp, i);
564 break;
565 case EVENT_BUT8:
566 case EVENT_BUT7:
567 case EVENT_BUT6:
568 case EVENT_BUT5:
569 case EVENT_BUT4:
570 case EVENT_BUT3: /* Send right button */
571 case EVENT_BUT2: /* Send middle button */
572 case EVENT_BUT1: /* Send left button */
573 usbms_rserv_vuid_button(q, mi, &bp);
575 break;
576 case EVENT_Y:
577 usbms_rserv_vuid_event_y(q, mi, &bp);
579 break;
580 case EVENT_X:
581 usbms_rserv_vuid_event_x(q, mi, &bp);
583 break;
584 default:
585 /* start again */
586 ms->ms_eventstate = EVENT_WHEEL;
588 break;
590 if (bp != NULL) {
591 /* lower pri to avoid mouse droppings */
592 bp->b_wptr += sizeof (Firm_event);
593 putnext(q, bp);
595 if (ms->ms_eventstate == EVENT_X) {
596 ms->ms_eventstate = EVENT_WHEEL;
597 } else if (ms->ms_eventstate == EVENT_WHEEL) {
598 ms->ms_oldoff++; /* next event */
599 /* circular buffer wraparound */
600 if (ms->ms_oldoff >= b->mb_size) {
601 ms->ms_oldoff = 0;
603 ms->ms_eventstate = EVENT_BUT(nbutt);
604 } else
605 ms->ms_eventstate--;
606 } while (ms->ms_eventstate != EVENT_BUT(nbutt));
610 USB_DPRINTF_L3(PRINT_MASK_SERV, usbms_log_handle,
611 "usbms_rserv exiting");
616 * usbms_rserv_vuid_event_wheel
617 * convert wheel data to firm events
619 static void
620 usbms_rserv_vuid_event_wheel(queue_t *q,
621 struct usbmouseinfo *mi,
622 mblk_t **bpaddr,
623 ushort_t id)
625 Firm_event *fep;
626 mblk_t *tmp;
627 struct ms_softc *ms;
628 usbms_state_t *usbmsp = (usbms_state_t *)q->q_ptr;
630 if (!(usbmsp->usbms_wheel_state_bf & (1 << id))) {
632 return;
634 ms = &usbmsp->usbms_softc;
635 if (mi->mi_z) {
636 if ((tmp = allocb(sizeof (Firm_event), BPRI_HI)) != NULL) {
637 fep = (Firm_event *)tmp->b_wptr;
638 fep->id = vuid_id_addr(vuid_first(VUID_WHEEL)) |
639 vuid_id_offset(id);
640 fep->pair_type = FE_PAIR_NONE;
641 fep->pair = 0;
642 fep->value = mi->mi_z;
643 fep->time = mi->mi_time;
644 *bpaddr = tmp;
645 } else {
646 if (usbmsp->usbms_resched_id) {
647 qunbufcall(q,
648 (bufcall_id_t)usbmsp->usbms_resched_id);
650 usbmsp->usbms_resched_id =
651 qbufcall(q, sizeof (Firm_event), BPRI_HI,
652 (void (*)())usbms_resched, (void *) usbmsp);
653 if (usbmsp->usbms_resched_id == 0) {
654 /* try again later */
656 return;
659 /* flush the queue */
660 ms->ms_eventstate = EVENT_WHEEL;
667 * usbms_rserv_vuid_button() :
668 * Process a VUID button event
670 static void
671 usbms_rserv_vuid_button(queue_t *q,
672 struct usbmouseinfo *mi,
673 mblk_t **bpaddr)
675 usbms_state_t *usbmsp = q->q_ptr;
676 struct ms_softc *ms;
677 int button_number;
678 uchar_t hwbit = 0x0;
679 Firm_event *fep;
680 mblk_t *bp;
681 uchar_t nbutt;
683 ms = &usbmsp->usbms_softc;
685 /* Test button. Send an event if it changed. */
686 nbutt = (uchar_t)usbmsp->usbms_num_buttons;
687 button_number = nbutt - (EVENT_BUT(nbutt) - ms->ms_eventstate) - 1;
688 switch (button_number) {
689 case 2:
690 /* Right button */
691 hwbit = 0x01;
693 break;
694 case 1:
696 * On two-button mice, the second button is the "right"
697 * button. There is no "middle". The vuidps2.c file has
698 * a bmap[] array in sendButtonEvent(). We do something
699 * equivalent here ONLY in the case of two-button mice.
701 if (nbutt == 2) {
702 hwbit = 0x01;
704 * Trick the vuid message into thinking it's a
705 * right-button click also.
707 button_number = 2;
708 } else {
709 /* ... otherwise, it's just the middle button */
710 hwbit = 0x02;
712 break;
713 case 0:
714 /* Left button */
715 hwbit = 0x04;
717 break;
718 default :
719 /* Any other button */
720 hwbit = USBMS_BUT(nbutt) >> (EVENT_BUT(nbutt) -
721 ms->ms_eventstate);
723 break;
726 if ((ms->ms_prevbuttons & hwbit) !=
727 (mi->mi_buttons & hwbit)) {
728 if ((bp = allocb(sizeof (Firm_event),
729 BPRI_HI)) != NULL) {
730 *bpaddr = bp;
731 fep = (Firm_event *)bp->b_wptr;
732 fep->id = vuid_id_addr(
733 ms->ms_vuidaddr) |
734 vuid_id_offset(BUT(1)
735 + button_number);
736 fep->pair_type = FE_PAIR_NONE;
737 fep->pair = 0;
740 * Update read buttons and set
741 * value
743 if (mi->mi_buttons & hwbit) {
744 fep->value = 0;
745 ms->ms_prevbuttons |=
746 hwbit;
747 } else {
748 fep->value = 1;
749 ms->ms_prevbuttons &=
750 ~hwbit;
752 fep->time = mi->mi_time;
753 } else {
754 if (usbmsp->usbms_resched_id) {
755 qunbufcall(q,
756 (bufcall_id_t)usbmsp->usbms_resched_id);
758 usbmsp->usbms_resched_id =
759 qbufcall(q,
760 sizeof (Firm_event),
761 BPRI_HI,
762 (void (*)())usbms_resched,
763 (void *) usbmsp);
764 if (usbmsp->usbms_resched_id == 0)
765 /* try again later */
766 return;
768 * bufcall failed; just pitch
769 * this event
771 /* or maybe flush queue? */
772 ms->ms_eventstate = EVENT_WHEEL;
778 * usbms_rserv_vuid_event_y() :
779 * Process a VUID y-event
781 static void
782 usbms_rserv_vuid_event_y(register queue_t *q,
783 register struct usbmouseinfo *mi,
784 mblk_t **bpaddr)
786 usbms_state_t *usbmsp = q->q_ptr;
787 register struct ms_softc *ms;
788 register Firm_event *fep;
789 mblk_t *bp;
791 ms = &usbmsp->usbms_softc;
794 * The (max, 0) message and (0, max) message are always sent before
795 * the button click message is sent on the IBM Bladecenter. Stop
796 * their sending may prevent the coordinate from moving to the
797 * (max, max).
799 if (!(((usbmsp->usbms_idf).yattr) & HID_MAIN_ITEM_RELATIVE)) {
800 if ((mi->mi_x == 0) &&
801 (mi->mi_y == usbmsp->usbms_logical_Ymax)) {
803 return;
807 /* Send y if changed. */
808 if (mi->mi_y != 0) {
809 if ((bp = allocb(sizeof (Firm_event),
810 BPRI_HI)) != NULL) {
811 *bpaddr = bp;
812 fep = (Firm_event *)bp->b_wptr;
813 if (((usbmsp->usbms_idf).yattr) &
814 HID_MAIN_ITEM_RELATIVE) {
815 fep->id = vuid_id_addr(
816 ms->ms_vuidaddr) |
817 vuid_id_offset(
818 LOC_Y_DELTA);
819 fep->pair_type =
820 FE_PAIR_ABSOLUTE;
821 fep->pair =
822 (uchar_t)LOC_Y_ABSOLUTE;
823 fep->value = -(mi->mi_y);
824 } else {
825 fep->id = vuid_id_addr(
826 ms->ms_vuidaddr) |
827 vuid_id_offset(
828 LOC_Y_ABSOLUTE);
829 fep->pair_type = FE_PAIR_DELTA;
830 fep->pair = (uchar_t)LOC_Y_DELTA;
831 fep->value = (mi->mi_y *
832 ((usbmsp->usbms_resolution).height) /
833 usbmsp->usbms_logical_Ymax);
834 if ((mi->mi_y *
835 ((usbmsp->usbms_resolution).height) %
836 usbmsp->usbms_logical_Ymax) >=
837 (usbmsp->usbms_logical_Ymax / 2)) {
838 fep->value ++;
841 fep->time = mi->mi_time;
842 } else {
843 if (usbmsp->usbms_resched_id) {
844 qunbufcall(q,
845 (bufcall_id_t)usbmsp->usbms_resched_id);
847 usbmsp->usbms_resched_id =
848 qbufcall(q,
849 sizeof (Firm_event),
850 BPRI_HI,
851 (void (*)())usbms_resched,
852 (void *)usbmsp);
853 if (usbmsp->usbms_resched_id == 0) {
854 /* try again later */
855 return;
859 * bufcall failed; just pitch
860 * this event
862 /* or maybe flush queue? */
863 ms->ms_eventstate = EVENT_WHEEL;
869 * usbms_rserv_vuid_event_x() :
870 * Process a VUID x-event
872 static void
873 usbms_rserv_vuid_event_x(register queue_t *q,
874 register struct usbmouseinfo *mi,
875 mblk_t **bpaddr)
877 usbms_state_t *usbmsp = q->q_ptr;
878 register struct ms_softc *ms;
879 register Firm_event *fep;
880 mblk_t *bp;
882 ms = &usbmsp->usbms_softc;
885 * The (max, 0) message and (0, max) message are always sent before
886 * the button click message is sent on the IBM Bladecenter. Stop
887 * their sending may prevent the coordinate from moving to the
888 * (max, max).
890 if (!(((usbmsp->usbms_idf).xattr) & HID_MAIN_ITEM_RELATIVE)) {
891 if ((mi->mi_y == 0) &&
892 (mi->mi_x == usbmsp->usbms_logical_Xmax)) {
894 return;
898 /* Send x if changed. */
899 if (mi->mi_x != 0) {
900 if ((bp = allocb(sizeof (Firm_event),
901 BPRI_HI)) != NULL) {
902 *bpaddr = bp;
903 fep = (Firm_event *)bp->b_wptr;
904 if (((usbmsp->usbms_idf).xattr) &
905 HID_MAIN_ITEM_RELATIVE) {
906 fep->id = vuid_id_addr(
907 ms->ms_vuidaddr) |
908 vuid_id_offset(LOC_X_DELTA);
909 fep->pair_type =
910 FE_PAIR_ABSOLUTE;
911 fep->pair =
912 (uchar_t)LOC_X_ABSOLUTE;
913 fep->value = mi->mi_x;
914 } else {
915 fep->id = vuid_id_addr(ms->ms_vuidaddr) |
916 vuid_id_offset(LOC_X_ABSOLUTE);
917 fep->pair_type = FE_PAIR_DELTA;
918 fep->pair = (uchar_t)LOC_X_DELTA;
919 fep->value = (mi->mi_x *
920 ((usbmsp->usbms_resolution).width) /
921 usbmsp->usbms_logical_Xmax);
922 if ((mi->mi_x *
923 ((usbmsp->usbms_resolution).width) %
924 usbmsp->usbms_logical_Xmax) >=
925 (usbmsp->usbms_logical_Xmax / 2)) {
926 fep->value ++;
929 fep->time = mi->mi_time;
930 } else {
931 if (usbmsp->usbms_resched_id)
932 qunbufcall(q,
933 (bufcall_id_t)usbmsp->usbms_resched_id);
934 usbmsp->usbms_resched_id =
935 qbufcall(q,
936 sizeof (Firm_event),
937 BPRI_HI,
938 (void (*)())usbms_resched,
939 (void *) usbmsp);
940 if (usbmsp->usbms_resched_id == 0)
941 /* try again later */
942 return;
945 * bufcall failed; just
946 * pitch this event
948 /* or maybe flush queue? */
949 ms->ms_eventstate = EVENT_WHEEL;
955 * usbms_resched() :
956 * Callback routine for the qbufcall() in case
957 * of allocb() failure. When buffer becomes
958 * available, this function is called and
959 * enables the queue.
961 static void
962 usbms_resched(void * usbmsp)
964 register queue_t *q;
965 register usbms_state_t *tmp_usbmsp = (usbms_state_t *)usbmsp;
967 tmp_usbmsp->usbms_resched_id = 0;
968 if ((q = tmp_usbmsp->usbms_rq_ptr) != 0)
969 qenable(q); /* run the service procedure */
973 * usbms_wput() :
974 * wput() routine for the mouse module.
975 * Module below : hid, module above : consms
977 static int
978 usbms_wput(queue_t *q,
979 mblk_t *mp)
981 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
982 "usbms_wput entering");
983 switch (mp->b_datap->db_type) {
985 case M_FLUSH: /* Canonical flush handling */
986 if (*mp->b_rptr & FLUSHW) {
987 flushq(q, FLUSHDATA);
990 if (*mp->b_rptr & FLUSHR) {
991 flushq(RD(q), FLUSHDATA);
994 putnext(q, mp); /* pass it down the line. */
995 break;
997 case M_IOCTL:
998 usbms_ioctl(q, mp);
999 break;
1001 case M_IOCDATA:
1002 usbms_miocdata(q, mp);
1004 break;
1005 default:
1006 putnext(q, mp); /* pass it down the line. */
1009 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
1010 "usbms_wput exiting");
1012 return (0);
1017 * usbms_ioctl() :
1018 * Process ioctls we recognize and own. Otherwise, NAK.
1020 static void
1021 usbms_ioctl(register queue_t *q,
1022 register mblk_t *mp)
1024 usbms_state_t *usbmsp = (usbms_state_t *)q->q_ptr;
1025 register struct ms_softc *ms;
1026 register struct iocblk *iocp;
1027 Vuid_addr_probe *addr_probe;
1028 uint_t ioctlrespsize;
1029 int err = 0;
1030 mblk_t *datap;
1031 ushort_t transparent = 0;
1032 boolean_t report_abs = B_FALSE;
1033 mblk_t *mb;
1035 USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbms_log_handle,
1036 "usbms_ioctl entering");
1038 if (usbmsp == NULL) {
1039 miocnak(q, mp, 0, EINVAL);
1041 return;
1043 ms = &usbmsp->usbms_softc;
1045 iocp = (struct iocblk *)mp->b_rptr;
1046 switch (iocp->ioc_cmd) {
1048 case VUIDSFORMAT:
1049 err = miocpullup(mp, sizeof (int));
1050 if (err != 0)
1051 break;
1053 if (*(int *)mp->b_cont->b_rptr == ms->ms_readformat) {
1054 break;
1056 ms->ms_readformat = *(int *)mp->b_cont->b_rptr;
1058 * Flush mouse buffer because the messages upstream of us
1059 * are in the old format.
1062 usbms_flush(usbmsp);
1063 break;
1065 case VUIDGFORMAT:
1066 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
1067 ioctlrespsize = sizeof (int);
1068 goto allocfailure;
1070 *(int *)datap->b_wptr = ms->ms_readformat;
1071 datap->b_wptr += sizeof (int);
1072 freemsg(mp->b_cont);
1073 mp->b_cont = datap;
1074 iocp->ioc_count = sizeof (int);
1075 break;
1077 case VUIDGADDR:
1078 case VUIDSADDR:
1079 err = miocpullup(mp, sizeof (Vuid_addr_probe));
1080 if (err != 0)
1081 break;
1083 addr_probe = (Vuid_addr_probe *)mp->b_cont->b_rptr;
1084 if (addr_probe->base != VKEY_FIRST) {
1085 err = ENODEV;
1086 break;
1088 if (iocp->ioc_cmd == VUIDSADDR)
1089 ms->ms_vuidaddr = addr_probe->data.next;
1090 else
1091 addr_probe->data.current = ms->ms_vuidaddr;
1092 break;
1094 case MSIOGETPARMS:
1095 if ((datap = allocb(sizeof (Ms_parms), BPRI_HI)) == NULL) {
1096 ioctlrespsize = sizeof (Ms_parms);
1097 goto allocfailure;
1099 err = usbms_getparms((Ms_parms *)datap->b_wptr, usbmsp);
1100 datap->b_wptr += sizeof (Ms_parms);
1101 freemsg(mp->b_cont);
1102 mp->b_cont = datap;
1103 iocp->ioc_count = sizeof (Ms_parms);
1104 break;
1106 case MSIOSETPARMS:
1107 err = miocpullup(mp, sizeof (Ms_parms));
1108 if (err != 0)
1109 break;
1110 err = usbms_setparms((Ms_parms *)mp->b_cont->b_rptr, usbmsp);
1111 break;
1113 case MSIOBUTTONS:
1114 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
1115 ioctlrespsize = sizeof (int);
1116 goto allocfailure;
1118 *(int *)datap->b_wptr = (int)usbmsp->usbms_num_buttons;
1119 datap->b_wptr += sizeof (int);
1120 freemsg(mp->b_cont);
1121 mp->b_cont = datap;
1122 iocp->ioc_count = sizeof (int);
1124 break;
1125 case VUIDGWHEELCOUNT:
1127 * New IOCTL support. Since it's explicitly mentioned that
1128 * you can't add more ioctls to stream head's hard coded
1129 * list, we have to do the transparent ioctl processing
1130 * which is heavy.
1133 /* Currently support for only one wheel */
1135 if (iocp->ioc_count == TRANSPARENT) {
1136 transparent = 1;
1137 if (err = usbms_make_copyreq(mp, 0, 0, sizeof (int),
1138 0, M_COPYOUT)) {
1140 break;
1143 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
1144 ioctlrespsize = sizeof (int);
1146 goto allocfailure;
1148 *((int *)datap->b_wptr) = (usbmsp->usbms_num_wheels ? 1 : 0);
1149 datap->b_wptr += sizeof (int);
1150 if (mp->b_cont) {
1151 freemsg(mp->b_cont);
1152 mp->b_cont = NULL;
1154 mp->b_cont = datap;
1155 if (transparent) {
1156 qreply(q, mp);
1158 return;
1161 break;
1162 case VUIDGWHEELINFO:
1163 if (iocp->ioc_count == TRANSPARENT) {
1164 if (err = usbms_make_copyreq(mp,
1165 sizeof (usbms_iocstate_t),
1166 USBMS_GETSTRUCT,
1167 sizeof (wheel_info),
1169 M_COPYIN)) {
1171 break;
1174 * If there is no b_cont the earlier func. will fail.
1175 * Hence there is no need for an explicit check here.
1177 freemsg(mp->b_cont);
1178 mp->b_cont = NULL;
1179 qreply(q, mp);
1181 return;
1183 if (mp->b_cont == NULL || iocp->ioc_count !=
1184 sizeof (wheel_info)) {
1185 err = EINVAL;
1186 break;
1188 datap = mp->b_cont;
1189 err = usbms_service_wheel_info(q, datap);
1191 break;
1192 case VUIDGWHEELSTATE:
1193 if (iocp->ioc_count == TRANSPARENT) {
1194 if (err = usbms_make_copyreq(mp,
1195 sizeof (usbms_iocstate_t),
1196 USBMS_GETSTRUCT,
1197 sizeof (wheel_state),
1199 M_COPYIN)) {
1201 break;
1203 freemsg(mp->b_cont);
1204 mp->b_cont = NULL;
1205 qreply(q, mp);
1207 return;
1209 if ((mp->b_cont == NULL) ||
1210 (iocp->ioc_count != sizeof (wheel_state))) {
1211 err = EINVAL;
1213 break;
1215 datap = mp->b_cont;
1216 err = usbms_service_wheel_state(q, datap, VUIDGWHEELSTATE);
1218 break;
1219 case VUIDSWHEELSTATE:
1220 if (iocp->ioc_count == TRANSPARENT) {
1221 if (err = usbms_make_copyreq(mp,
1222 sizeof (usbms_iocstate_t),
1223 USBMS_GETSTRUCT,
1224 sizeof (wheel_state),
1226 M_COPYIN)) {
1228 break;
1230 freemsg(mp->b_cont);
1231 mp->b_cont = NULL;
1232 qreply(q, mp);
1234 return;
1236 if (mp->b_cont == NULL) {
1237 err = EINVAL;
1239 break;
1241 datap = mp->b_cont;
1242 err = usbms_service_wheel_state(q, datap, VUIDSWHEELSTATE);
1244 break;
1245 case MSIOSRESOLUTION:
1246 if (iocp->ioc_count == TRANSPARENT) {
1247 if (err = usbms_make_copyreq(mp,
1248 sizeof (usbms_iocstate_t),
1249 USBMS_GETSTRUCT,
1250 sizeof (Ms_screen_resolution),
1252 M_COPYIN)) {
1254 break;
1257 freemsg(mp->b_cont);
1258 mp->b_cont = NULL;
1259 qreply(q, mp);
1261 return;
1263 if (mp->b_cont == NULL) {
1264 err = EINVAL;
1266 break;
1268 datap = mp->b_cont;
1269 err = usbms_get_screen_parms(q, datap);
1271 * Create the absolute mouse type event.
1272 * It is used for the hotplug absolute mouse.
1274 if ((!((usbmsp->usbms_idf).xattr & HID_MAIN_ITEM_RELATIVE)) &&
1275 (usbmsp->usbms_rpt_abs == B_FALSE)) {
1276 report_abs = B_TRUE;
1279 break;
1281 default:
1282 putnext(q, mp); /* pass it down the line */
1284 return;
1285 } /* switch */
1287 if (err != 0)
1288 miocnak(q, mp, 0, err);
1289 else {
1290 iocp->ioc_rval = 0;
1291 iocp->ioc_error = 0;
1292 mp->b_datap->db_type = M_IOCACK;
1293 qreply(q, mp);
1295 if (report_abs == B_TRUE) {
1296 /* send the abs mouse type event to the upper level */
1297 if ((mb = usbms_setup_abs_mouse_event()) != NULL) {
1298 usbmsp->usbms_rpt_abs = B_TRUE;
1299 qreply(q, mb);
1304 return;
1306 allocfailure:
1308 * We needed to allocate something to handle this "ioctl", but
1309 * couldn't; save this "ioctl" and arrange to get called back when
1310 * it's more likely that we can get what we need.
1311 * If there's already one being saved, throw it out, since it
1312 * must have timed out.
1314 freemsg(usbmsp->usbms_iocpending);
1315 usbmsp->usbms_iocpending = mp;
1316 if (usbmsp->usbms_reioctl_id) {
1317 qunbufcall(q, (bufcall_id_t)usbmsp->usbms_reioctl_id);
1319 usbmsp->usbms_reioctl_id = qbufcall(q, ioctlrespsize, BPRI_HI,
1320 (void (*)())usbms_reioctl,
1321 (void *)usbmsp);
1326 * M_IOCDATA processing for IOCTL's: VUIDGWHEELCOUNT, VUIDGWHEELINFO,
1327 * VUIDGWHEELSTATE, VUIDSWHEELSTATE & MSIOSRESOLUTION.
1329 static void
1330 usbms_miocdata(register queue_t *q,
1331 register mblk_t *mp)
1333 struct copyresp *copyresp;
1334 struct iocblk *iocbp;
1335 mblk_t *datap;
1336 mblk_t *ioctmp;
1337 usbms_iocstate_t *usbmsioc;
1338 int err = 0;
1340 copyresp = (struct copyresp *)mp->b_rptr;
1341 iocbp = (struct iocblk *)mp->b_rptr;
1342 if (copyresp->cp_rval) {
1343 err = EAGAIN;
1345 goto err;
1347 switch (copyresp->cp_cmd) {
1349 case VUIDGWHEELCOUNT:
1350 usbms_ack_ioctl(mp);
1352 break;
1353 case VUIDGWHEELINFO:
1354 ioctmp = copyresp->cp_private;
1355 usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr;
1356 if (usbmsioc->ioc_state == USBMS_GETSTRUCT) {
1357 if (mp->b_cont == NULL) {
1358 err = EINVAL;
1360 break;
1362 datap = (mblk_t *)mp->b_cont;
1363 if (err = usbms_service_wheel_info(q, datap)) {
1365 goto err;
1367 if (err = usbms_make_copyreq(mp, 0, USBMS_GETRESULT,
1368 sizeof (wheel_info), 0, M_COPYOUT)) {
1370 goto err;
1372 } else if (usbmsioc->ioc_state == USBMS_GETRESULT) {
1373 freemsg(ioctmp);
1374 usbms_ack_ioctl(mp);
1377 break;
1378 case VUIDGWHEELSTATE:
1379 ioctmp = (mblk_t *)copyresp->cp_private;
1380 usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr;
1381 if (usbmsioc->ioc_state == USBMS_GETSTRUCT) {
1382 if (mp->b_cont == NULL) {
1383 err = EINVAL;
1385 break;
1387 if (err = usbms_service_wheel_state(q, mp->b_cont,
1388 VUIDGWHEELSTATE)) {
1389 goto err;
1391 if (err = usbms_make_copyreq(mp, 0, USBMS_GETRESULT,
1392 sizeof (wheel_state), 0, M_COPYOUT)) {
1394 goto err;
1396 } else if (usbmsioc->ioc_state == USBMS_GETRESULT) {
1397 freemsg(ioctmp);
1398 usbms_ack_ioctl(mp);
1401 break;
1402 case VUIDSWHEELSTATE:
1403 ioctmp = (mblk_t *)copyresp->cp_private;
1404 usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr;
1405 if (mp->b_cont == NULL) {
1406 err = EINVAL;
1408 break;
1410 if (err = usbms_service_wheel_state(q, mp->b_cont,
1411 VUIDSWHEELSTATE)) {
1413 goto err;
1415 freemsg(ioctmp);
1416 usbms_ack_ioctl(mp);
1418 break;
1419 case MSIOSRESOLUTION:
1420 ioctmp = (mblk_t *)copyresp->cp_private;
1421 usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr;
1422 if (mp->b_cont == NULL) {
1423 err = EINVAL;
1425 break;
1427 if (err = usbms_get_screen_parms(q, mp->b_cont)) {
1429 goto err;
1431 freemsg(ioctmp);
1432 usbms_ack_ioctl(mp);
1434 break;
1435 default:
1436 err = EINVAL;
1437 break;
1440 err:
1441 if (err) {
1442 mp->b_datap->db_type = M_IOCNAK;
1443 if (mp->b_cont) {
1444 freemsg(mp->b_cont);
1445 mp->b_cont = NULL;
1447 if (copyresp->cp_private) {
1448 freemsg((mblk_t *)copyresp->cp_private);
1449 copyresp->cp_private = NULL;
1451 iocbp->ioc_count = 0;
1452 iocbp->ioc_error = err;
1454 qreply(q, mp);
1459 * usbms_reioctl() :
1460 * This function is set up as call-back function should an ioctl fail.
1461 * It retries the ioctl.
1463 static void
1464 usbms_reioctl(void * usbms_addr)
1466 usbms_state_t *usbmsp = (usbms_state_t *)usbms_addr;
1467 register queue_t *q;
1468 register mblk_t *mp;
1470 q = usbmsp->usbms_wq_ptr;
1471 if ((mp = usbmsp->usbms_iocpending) != NULL) {
1472 usbmsp->usbms_iocpending = NULL; /* not pending any more */
1473 usbms_ioctl(q, mp);
1478 * usbms_getparms() :
1479 * Called from MSIOGETPARMS ioctl to get the
1480 * current jitter_thesh, speed_law and speed_limit
1481 * values.
1483 static int
1484 usbms_getparms(register Ms_parms *data,
1485 usbms_state_t *usbmsp)
1487 data->jitter_thresh = usbmsp->usbms_jitter_thresh;
1488 data->speed_law = usbmsp->usbms_speedlaw;
1489 data->speed_limit = usbmsp->usbms_speedlimit;
1491 return (0);
1496 * usbms_setparms() :
1497 * Called from MSIOSETPARMS ioctl to set the
1498 * current jitter_thesh, speed_law and speed_limit
1499 * values.
1501 static int
1502 usbms_setparms(register Ms_parms *data,
1503 usbms_state_t *usbmsp)
1505 usbmsp->usbms_jitter_thresh = data->jitter_thresh;
1506 usbmsp->usbms_speedlaw = data->speed_law;
1507 usbmsp->usbms_speedlimit = data->speed_limit;
1509 return (0);
1513 * usbms_flush() :
1514 * Resets the ms_softc structure to default values
1515 * and sends M_FLUSH above.
1517 static void
1518 usbms_flush(usbms_state_t *usbmsp)
1520 register struct ms_softc *ms = &usbmsp->usbms_softc;
1521 register queue_t *q;
1523 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
1524 "usbms_flush entering");
1526 ms->ms_oldoff = 0;
1527 ms->ms_eventstate = EVENT_BUT(usbmsp->usbms_num_buttons);
1528 usbmsp->usbms_buf->mb_off = 0;
1529 ms->ms_prevbuttons = (char)USB_NO_BUT_PRESSED;
1530 usbmsp->usbms_oldbutt = ms->ms_prevbuttons;
1531 if ((q = usbmsp->usbms_rq_ptr) != NULL && q->q_next != NULL) {
1532 (void) putnextctl1(q, M_FLUSH, FLUSHR);
1535 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
1536 "usbms_flush exiting");
1541 * usbms_rput() :
1542 * Put procedure for input from driver end of stream (read queue).
1544 static void
1545 usbms_rput(queue_t *q,
1546 mblk_t *mp)
1548 usbms_state_t *usbmsp = q->q_ptr;
1549 mblk_t *tmp_mp;
1550 ushort_t limit = (usbmsp->usbms_idf).tlen;
1552 /* Maintain the original mp */
1553 tmp_mp = mp;
1555 if (usbmsp == 0) {
1556 freemsg(mp); /* nobody's listening */
1558 return;
1561 switch (mp->b_datap->db_type) {
1563 case M_FLUSH:
1564 if (*mp->b_rptr & FLUSHW)
1565 flushq(WR(q), FLUSHDATA);
1566 if (*mp->b_rptr & FLUSHR)
1567 flushq(q, FLUSHDATA);
1568 freemsg(mp);
1570 return;
1572 case M_BREAK:
1574 * We don't have to handle this
1575 * because nothing is sent from the downstream
1578 freemsg(mp);
1580 return;
1582 case M_DATA:
1583 if (!(usbmsp->usbms_flags & USBMS_OPEN)) {
1584 freemsg(mp); /* not ready to listen */
1586 return;
1588 break;
1590 case M_CTL:
1591 usbms_mctl_receive(q, mp);
1593 return;
1595 case M_ERROR:
1596 usbmsp->usbms_protoerr = 1;
1597 usbmsp->usbms_flags &= ~USBMS_QWAIT;
1598 if (*mp->b_rptr == ENODEV) {
1599 putnext(q, mp);
1600 } else {
1601 freemsg(mp);
1604 return;
1605 default:
1606 putnext(q, mp);
1608 return;
1612 * A data message, consisting of bytes from the mouse.
1613 * Make sure there are atleast "limit" number of bytes.
1615 if ((MBLKL(tmp_mp) < limit) || ((MBLKL(tmp_mp) == limit) &&
1616 (usbmsp->usbms_rptid != HID_REPORT_ID_UNDEFINED))) {
1617 freemsg(mp);
1618 return;
1620 do {
1621 if (usbmsp->usbms_rptid != HID_REPORT_ID_UNDEFINED) {
1622 if (*(tmp_mp->b_rptr) != usbmsp->usbms_rptid) {
1623 freemsg(mp);
1625 return;
1626 } else {
1627 /* We skip the report id prefix. */
1628 tmp_mp->b_rptr++;
1632 usbms_input(usbmsp, tmp_mp);
1633 } while ((tmp_mp = tmp_mp->b_cont) != NULL); /* next block, if any */
1635 freemsg(mp);
1640 * usbms_mctl_receive() :
1641 * Handle M_CTL messages from hid. If
1642 * we don't understand the command, free message.
1644 static void
1645 usbms_mctl_receive(register queue_t *q,
1646 register mblk_t *mp)
1648 usbms_state_t *usbmsd = (usbms_state_t *)q->q_ptr;
1649 struct iocblk *iocp;
1650 caddr_t data;
1653 iocp = (struct iocblk *)mp->b_rptr;
1654 if (mp->b_cont != NULL)
1655 data = (caddr_t)mp->b_cont->b_rptr;
1657 switch (iocp->ioc_cmd) {
1659 case HID_GET_PARSER_HANDLE:
1660 if ((data != NULL) &&
1661 (iocp->ioc_count == sizeof (hidparser_handle_t)) &&
1662 (MBLKL(mp->b_cont) == iocp->ioc_count)) {
1663 usbmsd->usbms_report_descr_handle =
1664 *(hidparser_handle_t *)data;
1665 } else {
1666 usbmsd->usbms_report_descr_handle = NULL;
1668 freemsg(mp);
1669 usbmsd->usbms_flags &= ~USBMS_QWAIT;
1670 break;
1671 case HID_SET_PROTOCOL:
1672 usbmsd->usbms_flags &= ~USBMS_QWAIT;
1674 /* FALLTHRU */
1675 default:
1676 freemsg(mp);
1677 break;
1683 * usbms_input() :
1685 * Mouse input routine; process a byte received from a mouse and
1686 * assemble into a mouseinfo message for the window system.
1688 * The USB mouse send a three-byte packet organized as
1689 * button, dx, dy
1690 * where dx and dy can be any signed byte value. The mouseinfo message
1691 * is organized as
1692 * dx, dy, button, timestamp
1693 * Our strategy is to collect but, dx & dy three-byte packet, then
1694 * send the mouseinfo message up.
1696 * Basic algorithm: throw away bytes until we get a [potential]
1697 * button byte. Collect button; Collect dx; Collect dy; Send button,
1698 * dx, dy, timestamp.
1700 * Watch out for overflow!
1702 static void
1703 usbms_input(usbms_state_t *usbmsp,
1704 mblk_t *mp)
1706 register struct usbmousebuf *b;
1707 register struct usbmouseinfo *mi;
1708 register int jitter_radius;
1709 register int32_t nbutt;
1710 ushort_t i;
1711 char c;
1713 nbutt = usbmsp->usbms_num_buttons;
1714 b = usbmsp->usbms_buf;
1716 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1717 "usbms_input entering");
1719 if (b == NULL) {
1721 return;
1724 mi = &b->mb_info[b->mb_off];
1727 * Lower 3 bits are middle, right, left.
1729 c = mp->b_rptr[(usbmsp->usbms_idf).bpos];
1730 mi->mi_buttons = (char)USB_NO_BUT_PRESSED;
1731 if (c & USBMS_BUT(1)) { /* left button is pressed */
1732 mi->mi_buttons = mi->mi_buttons & USB_LEFT_BUT_PRESSED;
1733 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR,
1734 usbms_log_handle,
1735 "left button pressed");
1737 if (c & USBMS_BUT(2)) { /* right button is pressed */
1738 mi->mi_buttons = mi->mi_buttons & USB_RIGHT_BUT_PRESSED;
1739 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR,
1740 usbms_log_handle,
1741 "right button pressed");
1743 if (c & USBMS_BUT(3)) { /* middle button is pressed */
1744 mi->mi_buttons = mi->mi_buttons &
1745 USB_MIDDLE_BUT_PRESSED;
1746 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR,
1747 usbms_log_handle,
1748 "middle button pressed");
1751 if (nbutt > 3) {
1752 for (i = 4; i < (nbutt + 1); i++) {
1753 if (c & USBMS_BUT(i)) {
1754 mi->mi_buttons = mi->mi_buttons &
1755 USB_BUT_PRESSED(i);
1756 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR,
1757 usbms_log_handle,
1758 "%d button pressed", i);
1763 /* get the delta X and Y from the sample */
1764 mi->mi_x += usbms_get_coordinate((usbmsp->usbms_idf).xpos,
1765 (usbmsp->usbms_idf).xlen, mp);
1767 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR,
1768 usbms_log_handle, "x = %d", (int)mi->mi_x);
1770 uniqtime32(&mi->mi_time); /* record time when sample arrived */
1772 mi->mi_y += usbms_get_coordinate((usbmsp->usbms_idf).ypos,
1773 (usbmsp->usbms_idf).ylen, mp);
1775 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1776 "y = %d", (int)mi->mi_y);
1779 * Check the wheel data in the current event.
1780 * If it exists, the wheel data is got from the sample.
1783 if (usbmsp->usbms_num_wheels) {
1784 mi->mi_z += usbms_get_coordinate((usbmsp->usbms_idf).zpos,
1785 (usbmsp->usbms_idf).zlen, mp);
1787 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1788 "z = %d", (int)mi->mi_z);
1791 if (usbmsp->usbms_jitter) {
1792 (void) quntimeout(usbmsp->usbms_rq_ptr,
1793 (timeout_id_t)usbmsp->usbms_timeout_id);
1794 usbmsp->usbms_jitter = 0;
1797 if (!usbmsp->usbms_num_wheels) {
1798 mi->mi_z = 0;
1802 * If there is a wheel movement or a change in the button state,
1803 * send the data up immediately.
1805 if (!(mi->mi_z) && (mi->mi_buttons == usbmsp->usbms_oldbutt)) {
1807 * Buttons did not change; did position?
1809 if (mi->mi_x == 0 && mi->mi_y == 0) {
1810 /* no, position did not change */
1812 return;
1816 * Did the mouse move more than the jitter threshhold?
1818 jitter_radius = usbmsp->usbms_jitter_thresh;
1819 if (USB_ABS((int)mi->mi_x) <= jitter_radius &&
1820 USB_ABS((int)mi->mi_y) <= jitter_radius) {
1822 * Mouse moved less than the jitter threshhold.
1823 * Don't indicate an event; keep accumulating motions.
1824 * After "jittertimeout" ticks expire, treat
1825 * the accumulated delta as the real delta.
1827 usbmsp->usbms_jitter = 1;
1828 usbmsp->usbms_timeout_id =
1829 qtimeout(usbmsp->usbms_rq_ptr,
1830 (void (*)())usbms_incr,
1831 (void *)usbmsp,
1832 (clock_t)usbmsp->usbms_jittertimeout);
1834 return;
1837 usbmsp->usbms_oldbutt = mi->mi_buttons;
1838 usbms_incr(usbmsp);
1840 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1841 "usbms_input exiting");
1846 * usbms_get_coordinate():
1847 * get the X, Y, WHEEL coordinate values
1849 static int
1850 usbms_get_coordinate(uint_t pos, uint_t len, mblk_t *mp)
1852 uint_t utmp, bitval, val;
1853 int i, xyz;
1855 /* get the unsigned int value from the bit stream */
1856 utmp = 0;
1857 for (i = (pos + len - 1); i >= (int)pos; i--) {
1858 bitval = (mp->b_rptr[i/8] & (1 << (i%8))) >> (i%8);
1859 utmp = utmp * 2 + bitval;
1862 /* convert the unsigned int value into int value */
1863 val = 1 << (len - 1);
1864 xyz = (int)(utmp - val);
1865 if (xyz < 0)
1866 xyz += val;
1867 else if (xyz == 0)
1868 xyz = -(val - 1);
1869 else
1870 xyz -= val;
1872 return (xyz);
1877 * usbms_incr() :
1878 * Increment the mouse sample pointer.
1879 * Called either immediately after a sample or after a jitter timeout.
1881 static void
1882 usbms_incr(void *arg)
1884 usbms_state_t *usbmsp = arg;
1885 register struct ms_softc *ms = &usbmsp->usbms_softc;
1886 register struct usbmousebuf *b;
1887 register struct usbmouseinfo *mi;
1888 register int xc, yc, zc;
1889 register int wake;
1890 register int speedl = usbmsp->usbms_speedlimit;
1891 register int xabs, yabs;
1894 * No longer waiting for jitter timeout
1896 usbmsp->usbms_jitter = 0;
1898 b = usbmsp->usbms_buf;
1900 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1901 "usbms_incr entering");
1903 if (b == NULL) {
1905 return;
1907 mi = &b->mb_info[b->mb_off];
1908 if (usbmsp->usbms_speedlaw) {
1909 xabs = USB_ABS((int)mi->mi_x);
1910 yabs = USB_ABS((int)mi->mi_y);
1911 if (xabs > speedl || yabs > speedl) {
1912 usbmsp->usbms_speed_count++;
1914 if (xabs > speedl) {
1915 mi->mi_x = 0;
1917 if (yabs > speedl) {
1918 mi->mi_y = 0;
1923 xc = yc = zc = 0;
1925 /* See if we need to wake up anyone waiting for input */
1926 wake = b->mb_off == ms->ms_oldoff;
1928 /* Adjust circular buffer pointer */
1929 if (++b->mb_off >= b->mb_size) {
1930 b->mb_off = 0;
1931 mi = b->mb_info;
1932 } else {
1933 mi++;
1937 * If over-took read index then flush buffer so that mouse state
1938 * is consistent.
1940 if (b->mb_off == ms->ms_oldoff) {
1941 if (overrun_msg) {
1942 USB_DPRINTF_L1(PRINT_MASK_ALL, usbms_log_handle,
1943 "Mouse buffer flushed when overrun.");
1945 usbms_flush(usbmsp);
1946 overrun_cnt++;
1947 mi = b->mb_info;
1950 /* Remember current buttons and fractional part of x & y */
1951 mi->mi_buttons = (char)USB_NO_BUT_PRESSED;
1952 mi->mi_x = xc;
1953 mi->mi_y = yc;
1954 mi->mi_z = zc;
1956 if (wake) {
1957 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1958 "usbms_incr run service");
1959 qenable(usbmsp->usbms_rq_ptr); /* run the service proc */
1961 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1962 "usbms_incr exiting");
1967 * usbms_check_for_wheels
1968 * return SUCCESS if wheel is found, else return FAILURE
1970 static int
1971 usbms_check_for_wheels(usbms_state_t *usbmsp)
1973 int rval, report_id;
1976 if (usbmsp->usbms_report_descr_handle) {
1977 /* Get the report id that has mouse data */
1978 if (hidparser_get_usage_attribute(
1979 usbmsp->usbms_report_descr_handle,
1980 0, /* Doesn't matter */
1981 HIDPARSER_ITEM_INPUT,
1982 HID_GENERIC_DESKTOP,
1983 HID_GD_X,
1984 HIDPARSER_ITEM_REPORT_ID,
1985 &usbmsp->usbms_rptid) == HIDPARSER_NOT_FOUND) {
1986 usbmsp->usbms_rptid = HID_REPORT_ID_UNDEFINED;
1987 report_id = 0;
1988 } else {
1989 report_id = usbmsp->usbms_rptid;
1992 /* find no. of wheels in this report */
1993 rval = hidparser_get_usage_attribute(
1994 usbmsp->usbms_report_descr_handle,
1995 report_id,
1996 HIDPARSER_ITEM_INPUT,
1997 HID_GENERIC_DESKTOP,
1998 HID_GD_WHEEL,
1999 HIDPARSER_ITEM_REPORT_COUNT,
2000 &usbmsp->usbms_num_wheels);
2001 if (rval == HIDPARSER_SUCCESS) {
2003 * Found wheel. By default enable the wheel.
2004 * Currently only enable only the first wheel.
2006 usbmsp->usbms_wheel_state_bf |=
2007 VUID_WHEEL_STATE_ENABLED;
2009 return (USB_SUCCESS);
2012 usbmsp->usbms_num_wheels = 0;
2014 return (USB_FAILURE);
2019 * usbms_make_copyreq
2020 * helper function for usbms ioctls
2022 static int
2023 usbms_make_copyreq(mblk_t *mp,
2024 uint_t pvtsize,
2025 uint_t state,
2026 uint_t reqsize,
2027 uint_t contsize,
2028 uint_t copytype)
2031 struct copyreq *cq;
2032 struct copyresp *cr;
2033 mblk_t *ioctmp;
2034 mblk_t *conttmp;
2035 usbms_iocstate_t *usbmsioc;
2037 if ((!pvtsize) && state) {
2038 cr = (struct copyresp *)mp->b_rptr;
2039 ioctmp = cr->cp_private;
2041 cq = (struct copyreq *)mp->b_rptr;
2042 if (mp->b_cont == NULL) {
2044 return (EINVAL);
2046 cq->cq_addr = *((caddr_t *)mp->b_cont->b_rptr);
2047 cq->cq_size = reqsize;
2048 cq->cq_flag = 0;
2049 if (pvtsize) {
2050 ioctmp = (mblk_t *)allocb(pvtsize, BPRI_MED);
2051 if (ioctmp == NULL) {
2053 return (EAGAIN);
2055 cq->cq_private = ioctmp;
2056 ioctmp = cq->cq_private;
2057 } else {
2059 * Here we need to set cq_private even if there's
2060 * no private data, otherwise its value will be
2061 * TRANSPARENT (-1) on 64bit systems because it
2062 * overlaps iocp->ioc_count. If user address (cq_addr)
2063 * is invalid, it would cause panic later in
2064 * usbms_miocdata:
2065 * freemsg((mblk_t *)copyresp->cp_private);
2067 cq->cq_private = NULL;
2069 if (state) {
2070 usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr;
2071 usbmsioc->ioc_state = state;
2072 if (pvtsize) { /* M_COPYIN */
2073 usbmsioc->u_addr = cq->cq_addr;
2074 } else {
2075 cq->cq_addr = usbmsioc->u_addr;
2076 cq->cq_private = ioctmp;
2078 ioctmp->b_wptr = ioctmp->b_rptr + sizeof (usbms_iocstate_t);
2080 if (contsize) {
2081 conttmp = (mblk_t *)allocb(contsize, BPRI_MED);
2082 if (conttmp == NULL) {
2084 return (EAGAIN);
2086 if (mp->b_cont) {
2087 freemsg(mp->b_cont);
2088 mp->b_cont = conttmp;
2091 mp->b_datap->db_type = (unsigned char)copytype;
2092 mp->b_wptr = mp->b_rptr + sizeof (struct copyreq);
2094 return (USB_SUCCESS);
2098 static int
2099 usbms_service_wheel_info(register queue_t *q, register mblk_t *datap)
2102 wheel_info *wi;
2103 usbms_state_t *usbmsp = (usbms_state_t *)q->q_ptr;
2104 uint_t err;
2106 wi = (wheel_info *)datap->b_rptr;
2107 if (wi->vers != VUID_WHEEL_INFO_VERS) {
2108 err = EINVAL;
2110 return (err);
2112 if (wi->id > (usbmsp->usbms_num_wheels - 1)) {
2113 err = EINVAL;
2115 return (err);
2117 wi->format = (usbmsp->usbms_wheel_orient_bf & (1 << wi->id)) ?
2118 VUID_WHEEL_FORMAT_HORIZONTAL : VUID_WHEEL_FORMAT_VERTICAL;
2120 return (USB_SUCCESS);
2124 static int
2125 usbms_service_wheel_state(register queue_t *q,
2126 register mblk_t *datap,
2127 register uint_t cmd)
2130 wheel_state *ws;
2131 uint_t err;
2132 usbms_state_t *usbmsp = (usbms_state_t *)q->q_ptr;
2134 ws = (wheel_state *)datap->b_rptr;
2135 if (ws->vers != VUID_WHEEL_STATE_VERS) {
2136 err = EINVAL;
2138 return (err);
2140 if (ws->id > (usbmsp->usbms_num_wheels - 1)) {
2141 err = EINVAL;
2143 return (err);
2146 switch (cmd) {
2147 case VUIDGWHEELSTATE:
2148 ws->stateflags = (usbmsp->usbms_wheel_state_bf >> ws->id) &
2149 VUID_WHEEL_STATE_ENABLED;
2151 break;
2152 case VUIDSWHEELSTATE:
2153 usbmsp->usbms_wheel_state_bf = (ws->stateflags << ws->id) |
2154 (~(1 << ws->id) & usbmsp->usbms_wheel_state_bf);
2156 break;
2157 default:
2158 err = EINVAL;
2160 return (err);
2163 return (USB_SUCCESS);
2168 * usbms_get_screen_parms() :
2169 * Called from MSIOSRESOLUTION ioctl to get the
2170 * current screen height/width params from X.
2172 static int
2173 usbms_get_screen_parms(register queue_t *q,
2174 register mblk_t *datap)
2177 usbms_state_t *usbmsp = (usbms_state_t *)q->q_ptr;
2178 Ms_screen_resolution *res = &(usbmsp->usbms_resolution);
2179 Ms_screen_resolution *data;
2181 data = (Ms_screen_resolution *)datap->b_rptr;
2182 res->height = data->height;
2183 res->width = data->width;
2185 return (USB_SUCCESS);
2189 static void
2190 usbms_ack_ioctl(mblk_t *mp)
2193 struct iocblk *iocbp = (struct iocblk *)mp->b_rptr;
2195 mp->b_datap->db_type = M_IOCACK;
2196 mp->b_wptr = mp->b_rptr + sizeof (struct iocblk);
2197 iocbp->ioc_error = 0;
2198 iocbp->ioc_count = 0;
2199 iocbp->ioc_rval = 0;
2200 if (mp->b_cont != NULL) {
2201 freemsg(mp->b_cont);
2202 mp->b_cont = NULL;
2208 * usbms_setup_abs_mouse_event() :
2209 * Called from MSIOSRESOLUTION ioctl to create
2210 * the absolute mouse type firm event.
2212 static mblk_t *
2213 usbms_setup_abs_mouse_event()
2215 mblk_t *mb;
2216 Firm_event *fep;
2218 if ((mb = allocb(sizeof (Firm_event), BPRI_HI)) != NULL) {
2219 fep = (Firm_event *)mb->b_wptr;
2220 fep->id = MOUSE_TYPE_ABSOLUTE;
2221 fep->pair_type = FE_PAIR_NONE;
2222 fep->pair = 0;
2223 fep->value = 0;
2224 mb->b_wptr += sizeof (Firm_event);
2225 } else {
2226 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
2227 "No resource to report ABS mouse event");
2230 return (mb);
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.
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.
2244 usbms_read_input_data_format(usbms_state_t *usbmsp)
2247 hidparser_rpt_t *ms_rpt;
2248 uint_t i, button_page;
2249 uint_t limit = 0;
2250 uint32_t rptcnt, rptsz;
2251 usbms_idf *idf = &(usbmsp->usbms_idf);
2252 Ms_screen_resolution *res = &(usbmsp->usbms_resolution);
2253 mblk_t *mb;
2254 register queue_t *q;
2255 int rval;
2257 usbmsp->usbms_rpt_abs = B_FALSE;
2259 /* allocate hidparser report structure */
2260 ms_rpt = kmem_zalloc(sizeof (hidparser_rpt_t), KM_SLEEP);
2263 * Check what is the total length of the mouse packet
2264 * and get the usages and their lengths in order
2267 rval = hidparser_get_usage_list_in_order(
2268 usbmsp->usbms_report_descr_handle,
2269 usbmsp->usbms_rptid,
2270 HIDPARSER_ITEM_INPUT,
2271 ms_rpt);
2273 if (rval != HIDPARSER_SUCCESS) {
2275 kmem_free(ms_rpt, sizeof (hidparser_rpt_t));
2276 return (USB_FAILURE);
2279 button_page = 0;
2280 for (i = 0; i < ms_rpt->no_of_usages; i++) {
2281 rptcnt = ms_rpt->usage_descr[i].rptcnt;
2282 rptsz = ms_rpt->usage_descr[i].rptsz;
2283 if ((ms_rpt->usage_descr[i].usage_page ==
2284 HID_BUTTON_PAGE) && (!button_page)) {
2285 idf->bpos = limit;
2286 limit += (rptcnt * rptsz);
2287 button_page = 1;
2288 continue;
2291 switch (ms_rpt->usage_descr[i].usage_id) {
2293 case HID_GD_X:
2294 idf->xpos = limit;
2295 idf->xlen = rptsz;
2296 limit += rptsz;
2297 break;
2298 case HID_GD_Y:
2299 idf->ypos = limit;
2300 idf->ylen = rptsz;
2301 limit += rptsz;
2302 break;
2303 case HID_GD_Z:
2305 * z-axis not yet supported, just skip it.
2307 * It would be ideal if the HID_GD_Z data would be
2308 * reported as horizontal wheel, and HID_GD_WHEEL
2309 * as vertical wheel.
2311 * We can not use the default case, because
2312 * that skips rptcnt*rptsz, but for an
2313 * "Apple Might Mouse" rptsz must be used.
2315 limit += rptsz;
2316 break;
2317 case HID_GD_WHEEL:
2318 idf->zpos = limit;
2319 idf->zlen = rptsz;
2320 limit += rptsz;
2321 break;
2322 default:
2323 limit += rptcnt * rptsz;
2324 break;
2328 kmem_free(ms_rpt, sizeof (hidparser_rpt_t));
2330 /* get the length of sending data */
2331 idf->tlen = limit / 8;
2333 /* Check whether X and Y are relative or absolute */
2334 rval = hidparser_get_main_item_data_descr(
2335 usbmsp->usbms_report_descr_handle,
2336 usbmsp->usbms_rptid,
2337 HIDPARSER_ITEM_INPUT,
2338 HID_GENERIC_DESKTOP,
2339 HID_GD_X,
2340 &idf->xattr);
2342 if (rval != HIDPARSER_SUCCESS) {
2344 return (USB_FAILURE);
2347 /* For the time being assume that Y also has the same attr */
2348 idf->yattr = idf->xattr;
2350 /* get the logical_maximum for X and Y respectively */
2351 if (!(idf->xattr & HID_MAIN_ITEM_RELATIVE)) {
2353 /* the data format can't be parsed correctly */
2354 if (limit % 8) {
2355 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
2356 "Wrong data packet include %d bits", limit);
2358 return (USB_FAILURE);
2360 if (hidparser_get_usage_attribute(
2361 usbmsp->usbms_report_descr_handle,
2362 usbmsp->usbms_rptid,
2363 HIDPARSER_ITEM_INPUT,
2364 HID_GENERIC_DESKTOP,
2365 HID_GD_X,
2366 HIDPARSER_ITEM_LOGICAL_MAXIMUM,
2367 &usbmsp->usbms_logical_Xmax) != HIDPARSER_SUCCESS) {
2369 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
2370 "fail to get X logical max.");
2372 return (USB_FAILURE);
2374 if (hidparser_get_usage_attribute(
2375 usbmsp->usbms_report_descr_handle,
2376 usbmsp->usbms_rptid,
2377 HIDPARSER_ITEM_INPUT,
2378 HID_GENERIC_DESKTOP,
2379 HID_GD_Y,
2380 HIDPARSER_ITEM_LOGICAL_MAXIMUM,
2381 &usbmsp->usbms_logical_Ymax) != HIDPARSER_SUCCESS) {
2383 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
2384 "fail to get Y logical max.");
2386 return (USB_FAILURE);
2389 if (usbmsp->usbms_logical_Xmax == 0) {
2390 USB_DPRINTF_L3(PRINT_MASK_ALL,
2391 usbms_log_handle,
2392 "X logical max value is zero");
2394 return (USB_FAILURE);
2397 if (usbmsp->usbms_logical_Ymax == 0) {
2398 USB_DPRINTF_L3(PRINT_MASK_ALL,
2399 usbms_log_handle,
2400 "Y logical max value is zero");
2402 return (USB_FAILURE);
2405 res->height = USBMS_DEFAULT_RES_HEIGHT;
2406 res->width = USBMS_DEFAULT_RES_WIDTH;
2408 /* The wheel is not supported in current remote kvms. */
2409 usbmsp->usbms_num_wheels = 0;
2410 q = usbmsp->usbms_rq_ptr;
2411 if ((mb = usbms_setup_abs_mouse_event()) != NULL) {
2412 putnext(q, mb);
2413 } else {
2415 return (USB_NO_RESOURCES);
2419 return (USB_SUCCESS);