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 (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25
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>
30
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>
40
41 #include <sys/usb/clients/usbms/usbms.h>
42
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;
47
48 static struct streamtab usbms_streamtab;
49
50 static struct fmodsw fsw = {
51 "usbms",
52 &usbms_streamtab,
53 D_MP | D_MTPERMOD
54 };
55
56 /*
57 * Module linkage information for the kernel.
58 */
59 static struct modlstrmod modlstrmod = {
60 &mod_strmodops,
61 "USB mouse streams",
62 &fsw
63 };
64
65 static struct modlinkage modlinkage = {
66 MODREV_1,
67 (void *)&modlstrmod,
68 NULL
69 };
70
71
72 int
_init(void)73 _init(void)
74 {
75 int rval = mod_install(&modlinkage);
76
77 if (rval == 0) {
78 usbms_log_handle = usb_alloc_log_hdl(NULL, "usbms",
79 &usbms_errlevel, &usbms_errmask, NULL, 0);
80 }
81
82 return (rval);
83 }
84
85 int
_fini(void)86 _fini(void)
87 {
88 int rval = mod_remove(&modlinkage);
89
90 if (rval == 0) {
91 usb_free_log_hdl(usbms_log_handle);
92 }
93
94 return (rval);
95 }
96
97
98 int
_info(struct modinfo * modinfop)99 _info(struct modinfo *modinfop)
100 {
101
102 return (mod_info(&modlinkage, modinfop));
103 }
104
105
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);
116
117 static void usbms_rserv(queue_t *q);
118 static void usbms_miocdata(
119 register queue_t *q,
120 register mblk_t *mp);
121
122 static void usbms_resched(void *);
123
124 static int usbms_getparms(
125 register Ms_parms *data,
126 usbms_state_t *usbmsp);
127
128 static int usbms_setparms(
129 register Ms_parms *data,
130 usbms_state_t *usbmsp);
131
132 static int usbms_get_screen_parms(
133 register queue_t *q,
134 register mblk_t *datap);
135
136 static void usbms_flush(usbms_state_t *usbmsp);
137
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);
146
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();
183
184 /*
185 * Device driver qinit functions
186 */
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 */
194 };
195
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 */
205 };
206
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 */
216 };
217
218 static struct streamtab usbms_streamtab = {
219 &rinit,
220 &winit,
221 NULL, /* not a MUX */
222 NULL /* not a MUX */
223 };
224
225 /*
226 * Message when overrun circular buffer
227 */
228 static int overrun_msg;
229
230 /* Increment when overrun circular buffer */
231 static int overrun_cnt;
232
233 extern int hz;
234
235 /*
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.
238 */
239 static uint16_t usbms_buf_bytes = USBMS_BUF_BYTES;
240
241
242 /*
243 * Regular STREAMS Entry points
244 */
245
246 /*
247 * usbms_open() :
248 * open() entry point for the USB mouse module.
249 */
250 /*ARGSUSED*/
251 static int
usbms_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * credp)252 usbms_open(queue_t *q,
253 dev_t *devp,
254 int flag,
255 int sflag,
256 cred_t *credp)
257
258 {
259 register struct usbmousebuf *mousebufp;
260 register struct ms_softc *msd_soft;
261 usbms_state_t *usbmsp;
262 struct iocblk mctlmsg;
263 mblk_t *mctl_ptr;
264
265
266 /* Clone opens are not allowed */
267 if (sflag != MODOPEN)
268 return (EINVAL);
269
270 /* If the module is already open, just return */
271 if (q->q_ptr) {
272 return (0);
273 }
274
275 /* allocate usbms state structure */
276 usbmsp = kmem_zalloc(sizeof (usbms_state_t), KM_SLEEP);
277
278 q->q_ptr = usbmsp;
279 WR(q)->q_ptr = usbmsp;
280
281 usbmsp->usbms_rq_ptr = q;
282 usbmsp->usbms_wq_ptr = WR(q);
283
284 qprocson(q);
285
286 /*
287 * Set up private data.
288 */
289 usbmsp->usbms_state = USBMS_WAIT_BUTN;
290 usbmsp->usbms_iocpending = NULL;
291 usbmsp->usbms_jitter_thresh = USBMS_JITTER_THRESH;
292 usbmsp->usbms_speedlimit = USBMS_SPEEDLIMIT;
293 usbmsp->usbms_speedlaw = USBMS_SPEEDLAW;
294 usbmsp->usbms_speed_count = USBMS_SPEED_COUNT;
295
296 msd_soft = &usbmsp->usbms_softc;
297
298 /*
299 * Initially set the format to MS_VUID_FORMAT
300 */
301 msd_soft->ms_readformat = MS_VUID_FORMAT;
302
303 /*
304 * Allocate buffer and initialize data.
305 */
306 msd_soft->ms_bufbytes = usbms_buf_bytes;
307 mousebufp = kmem_zalloc((uint_t)msd_soft->ms_bufbytes,
308 KM_SLEEP);
309
310 /* Truncation will happen */
311 mousebufp->mb_size = (uint16_t)((msd_soft->ms_bufbytes -
312 sizeof (struct usbmousebuf)) /
313 sizeof (struct usbmouseinfo));
314 mousebufp->mb_info = (struct usbmouseinfo *)((char *)mousebufp +
315 sizeof (struct usbmousebuf));
316 usbmsp->usbms_buf = mousebufp;
317 msd_soft->ms_vuidaddr = VKEY_FIRST;
318 usbmsp->usbms_jittertimeout = JITTER_TIMEOUT;
319
320 /* request hid report descriptor from HID */
321 mctlmsg.ioc_cmd = HID_GET_PARSER_HANDLE;
322 mctlmsg.ioc_count = 0;
323
324 mctl_ptr = usba_mk_mctl(mctlmsg, NULL, 0);
325 if (mctl_ptr == NULL) {
326 qprocsoff(q);
327 kmem_free(usbmsp->usbms_buf, msd_soft->ms_bufbytes);
328 kmem_free(usbmsp, sizeof (usbms_state_t));
329
330 return (ENOMEM);
331 }
332
333 usbmsp->usbms_flags |= USBMS_QWAIT;
334 putnext(usbmsp->usbms_wq_ptr, mctl_ptr);
335
336 /*
337 * Now that signal has been sent, wait for report descriptor. Cleanup
338 * if user signals in the mean time (as when this gets opened in an
339 * inappropriate context and the user types a ^C).
340 */
341 while (usbmsp->usbms_flags & USBMS_QWAIT) {
342
343 if (qwait_sig(q) == 0) {
344 qprocsoff(q);
345 kmem_free(usbmsp->usbms_buf, msd_soft->ms_bufbytes);
346 kmem_free(usbmsp, sizeof (usbms_state_t));
347
348 return (EINTR);
349 }
350 }
351
352 if (usbmsp->usbms_report_descr_handle != NULL) {
353 if (hidparser_get_usage_attribute(
354 usbmsp->usbms_report_descr_handle,
355 0,
356 HIDPARSER_ITEM_INPUT,
357 USBMS_USAGE_PAGE_BUTTON,
358 0,
359 HIDPARSER_ITEM_REPORT_COUNT,
360 (int32_t *)&usbmsp->usbms_num_buttons) ==
361 HIDPARSER_SUCCESS) {
362 if (usbmsp->usbms_num_buttons > USB_MS_MAX_BUTTON_NO)
363 usbmsp->usbms_num_buttons =
364 USB_MS_MAX_BUTTON_NO;
365 USB_DPRINTF_L2(PRINT_MASK_ALL,
366 usbms_log_handle, "Num of buttons is : %d",
367 usbmsp->usbms_num_buttons);
368 } else {
369 USB_DPRINTF_L3(PRINT_MASK_OPEN,
370 usbms_log_handle,
371 "hidparser_get_usage_attribute failed : "
372 "Set to default number of buttons(3).");
373
374 usbmsp->usbms_num_buttons = USB_MS_DEFAULT_BUTTON_NO;
375 }
376 } else {
377 USB_DPRINTF_L1(PRINT_MASK_ALL,
378 usbms_log_handle, "Invalid HID "
379 "Descriptor Tree. Set to default value(3 buttons).");
380 usbmsp->usbms_num_buttons = USB_MS_DEFAULT_BUTTON_NO;
381 }
382
383 /* check if this mouse has wheel */
384 if (usbms_check_for_wheels(usbmsp) == USB_FAILURE) {
385 USB_DPRINTF_L2(PRINT_MASK_ALL, usbms_log_handle,
386 "No wheels detected");
387 } else {
388 USB_DPRINTF_L2(PRINT_MASK_ALL, usbms_log_handle,
389 "Wheel detected");
390 }
391
392 usbms_flush(usbmsp);
393
394 /* get the data format from the hid descriptor */
395 if (usbms_read_input_data_format(usbmsp) != USB_SUCCESS) {
396
397 qprocsoff(q);
398 kmem_free(usbmsp->usbms_buf, msd_soft->ms_bufbytes);
399 kmem_free(usbmsp, sizeof (usbms_state_t));
400
401 return (EINVAL);
402 }
403
404 usbmsp->usbms_flags |= USBMS_OPEN;
405
406 USB_DPRINTF_L3(PRINT_MASK_OPEN, usbms_log_handle,
407 "usbms_open exiting");
408
409 return (0);
410 }
411
412
413 /*
414 * usbms_close() :
415 * close() entry point for the USB mouse module.
416 */
417 /*ARGSUSED*/
418 static int
usbms_close(queue_t * q,int flag,cred_t * credp)419 usbms_close(queue_t *q,
420 int flag,
421 cred_t *credp)
422 {
423 usbms_state_t *usbmsp = q->q_ptr;
424 register struct ms_softc *ms = &usbmsp->usbms_softc;
425
426 USB_DPRINTF_L3(PRINT_MASK_CLOSE, usbms_log_handle,
427 "usbms_close entering");
428
429 qprocsoff(q);
430
431 if (usbmsp->usbms_jitter) {
432 (void) quntimeout(q,
433 (timeout_id_t)(long)usbmsp->usbms_timeout_id);
434 usbmsp->usbms_jitter = 0;
435 }
436 if (usbmsp->usbms_reioctl_id) {
437 qunbufcall(q, (bufcall_id_t)(long)usbmsp->usbms_reioctl_id);
438 usbmsp->usbms_reioctl_id = 0;
439 }
440 if (usbmsp->usbms_resched_id) {
441 qunbufcall(q, (bufcall_id_t)usbmsp->usbms_resched_id);
442 usbmsp->usbms_resched_id = 0;
443 }
444 if (usbmsp->usbms_iocpending != NULL) {
445 /*
446 * We were holding an "ioctl" response pending the
447 * availability of an "mblk" to hold data to be passed up;
448 * another "ioctl" came through, which means that "ioctl"
449 * must have timed out or been aborted.
450 */
451 freemsg(usbmsp->usbms_iocpending);
452 usbmsp->usbms_iocpending = NULL;
453 }
454
455
456 /* Free mouse buffer */
457 if (usbmsp->usbms_buf != NULL) {
458 kmem_free(usbmsp->usbms_buf, ms->ms_bufbytes);
459 }
460
461 kmem_free(usbmsp, sizeof (usbms_state_t));
462
463 q->q_ptr = NULL;
464 WR(q)->q_ptr = NULL;
465
466
467 USB_DPRINTF_L3(PRINT_MASK_CLOSE, usbms_log_handle,
468 "usbms_close exiting");
469
470 return (0);
471 }
472
473
474 /*
475 * usbms_rserv() :
476 * Read queue service routine.
477 * Turn buffered mouse events into stream messages.
478 */
479 static void
usbms_rserv(queue_t * q)480 usbms_rserv(queue_t *q)
481 {
482 usbms_state_t *usbmsp = q->q_ptr;
483 struct ms_softc *ms;
484 struct usbmousebuf *b;
485 struct usbmouseinfo *mi;
486 mblk_t *bp;
487 ushort_t i, loop;
488 uchar_t nbutt = (uchar_t)usbmsp->usbms_num_buttons;
489
490 ms = &usbmsp->usbms_softc;
491 b = usbmsp->usbms_buf;
492
493 USB_DPRINTF_L3(PRINT_MASK_SERV, usbms_log_handle,
494 "usbms_rserv entering");
495
496 while (canputnext(q) && ms->ms_oldoff != b->mb_off) {
497 mi = &b->mb_info[ms->ms_oldoff];
498 switch (ms->ms_readformat) {
499
500 case MS_3BYTE_FORMAT: {
501 register char *cp;
502
503 if ((usbmsp->usbms_idf).xlen != 1) {
504 USB_DPRINTF_L3(PRINT_MASK_SERV,
505 usbms_log_handle,
506 "Can't set to 3 byte format. Length != 1");
507
508 return;
509 }
510 if ((bp = allocb(3, BPRI_HI)) != NULL) {
511 cp = (char *)bp->b_wptr;
512
513 *cp++ = 0x80 | (mi->mi_buttons & 0xFF);
514 /* Update read buttons */
515 ms->ms_prevbuttons = mi->mi_buttons;
516
517 *cp++ = (mi->mi_x & 0xFF);
518 *cp++ = ((-mi->mi_y) & 0xFF);
519 /* lower pri to avoid mouse droppings */
520 bp->b_wptr = (uchar_t *)cp;
521 putnext(q, bp);
522 } else {
523 if (usbmsp->usbms_resched_id) {
524 qunbufcall(q,
525 (bufcall_id_t)usbmsp->
526 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
usbms_rserv_vuid_event_wheel(queue_t * q,struct usbmouseinfo * mi,mblk_t ** bpaddr,ushort_t id)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
usbms_rserv_vuid_button(queue_t * q,struct usbmouseinfo * mi,mblk_t ** bpaddr)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
usbms_rserv_vuid_event_y(register queue_t * q,register struct usbmouseinfo * mi,mblk_t ** bpaddr)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
usbms_rserv_vuid_event_x(register queue_t * q,register struct usbmouseinfo * mi,mblk_t ** bpaddr)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
usbms_resched(void * usbmsp)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
usbms_wput(queue_t * q,mblk_t * mp)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
usbms_ioctl(register queue_t * q,register mblk_t * mp)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 boolean_t report_abs = B_FALSE;
1036 mblk_t *mb;
1037
1038 USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbms_log_handle,
1039 "usbms_ioctl entering");
1040
1041 if (usbmsp == NULL) {
1042 miocnak(q, mp, 0, EINVAL);
1043
1044 return;
1045 }
1046 ms = &usbmsp->usbms_softc;
1047
1048 iocp = (struct iocblk *)mp->b_rptr;
1049 switch (iocp->ioc_cmd) {
1050
1051 case VUIDSFORMAT:
1052 err = miocpullup(mp, sizeof (int));
1053 if (err != 0)
1054 break;
1055
1056 if (*(int *)mp->b_cont->b_rptr == ms->ms_readformat) {
1057 break;
1058 }
1059 ms->ms_readformat = *(int *)mp->b_cont->b_rptr;
1060 /*
1061 * Flush mouse buffer because the messages upstream of us
1062 * are in the old format.
1063 */
1064
1065 usbms_flush(usbmsp);
1066 break;
1067
1068 case VUIDGFORMAT:
1069 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
1070 ioctlrespsize = sizeof (int);
1071 goto allocfailure;
1072 }
1073 *(int *)datap->b_wptr = ms->ms_readformat;
1074 datap->b_wptr += sizeof (int);
1075 freemsg(mp->b_cont);
1076 mp->b_cont = datap;
1077 iocp->ioc_count = sizeof (int);
1078 break;
1079
1080 case VUIDGADDR:
1081 case VUIDSADDR:
1082 err = miocpullup(mp, sizeof (Vuid_addr_probe));
1083 if (err != 0)
1084 break;
1085
1086 addr_probe = (Vuid_addr_probe *)mp->b_cont->b_rptr;
1087 if (addr_probe->base != VKEY_FIRST) {
1088 err = ENODEV;
1089 break;
1090 }
1091 if (iocp->ioc_cmd == VUIDSADDR)
1092 ms->ms_vuidaddr = addr_probe->data.next;
1093 else
1094 addr_probe->data.current = ms->ms_vuidaddr;
1095 break;
1096
1097 case MSIOGETPARMS:
1098 if ((datap = allocb(sizeof (Ms_parms), BPRI_HI)) == NULL) {
1099 ioctlrespsize = sizeof (Ms_parms);
1100 goto allocfailure;
1101 }
1102 err = usbms_getparms((Ms_parms *)datap->b_wptr, usbmsp);
1103 datap->b_wptr += sizeof (Ms_parms);
1104 freemsg(mp->b_cont);
1105 mp->b_cont = datap;
1106 iocp->ioc_count = sizeof (Ms_parms);
1107 break;
1108
1109 case MSIOSETPARMS:
1110 err = miocpullup(mp, sizeof (Ms_parms));
1111 if (err != 0)
1112 break;
1113 err = usbms_setparms((Ms_parms *)mp->b_cont->b_rptr, usbmsp);
1114 break;
1115
1116 case MSIOBUTTONS:
1117 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
1118 ioctlrespsize = sizeof (int);
1119 goto allocfailure;
1120 }
1121 *(int *)datap->b_wptr = (int)usbmsp->usbms_num_buttons;
1122 datap->b_wptr += sizeof (int);
1123 freemsg(mp->b_cont);
1124 mp->b_cont = datap;
1125 iocp->ioc_count = sizeof (int);
1126
1127 break;
1128 case VUIDGWHEELCOUNT:
1129 /*
1130 * New IOCTL support. Since it's explicitly mentioned that
1131 * you can't add more ioctls to stream head's hard coded
1132 * list, we have to do the transparent ioctl processing
1133 * which is heavy.
1134 */
1135
1136 /* Currently support for only one wheel */
1137
1138 if (iocp->ioc_count == TRANSPARENT) {
1139 transparent = 1;
1140 if (err = usbms_make_copyreq(mp, 0, 0, sizeof (int),
1141 0, M_COPYOUT)) {
1142
1143 break;
1144 }
1145 }
1146 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) {
1147 ioctlrespsize = sizeof (int);
1148
1149 goto allocfailure;
1150 }
1151 *((int *)datap->b_wptr) = (usbmsp->usbms_num_wheels ? 1 : 0);
1152 datap->b_wptr += sizeof (int);
1153 if (mp->b_cont) {
1154 freemsg(mp->b_cont);
1155 mp->b_cont = NULL;
1156 }
1157 mp->b_cont = datap;
1158 if (transparent) {
1159 qreply(q, mp);
1160
1161 return;
1162 }
1163
1164 break;
1165 case VUIDGWHEELINFO:
1166 if (iocp->ioc_count == TRANSPARENT) {
1167 if (err = usbms_make_copyreq(mp,
1168 sizeof (usbms_iocstate_t),
1169 USBMS_GETSTRUCT,
1170 sizeof (wheel_info),
1171 0,
1172 M_COPYIN)) {
1173
1174 break;
1175 }
1176 /*
1177 * If there is no b_cont the earlier func. will fail.
1178 * Hence there is no need for an explicit check here.
1179 */
1180 freemsg(mp->b_cont);
1181 mp->b_cont = (mblk_t *)NULL;
1182 qreply(q, mp);
1183
1184 return;
1185 }
1186 if (mp->b_cont == NULL || iocp->ioc_count !=
1187 sizeof (wheel_info)) {
1188 err = EINVAL;
1189 break;
1190 }
1191 datap = mp->b_cont;
1192 err = usbms_service_wheel_info(q, datap);
1193
1194 break;
1195 case VUIDGWHEELSTATE:
1196 if (iocp->ioc_count == TRANSPARENT) {
1197 if (err = usbms_make_copyreq(mp,
1198 sizeof (usbms_iocstate_t),
1199 USBMS_GETSTRUCT,
1200 sizeof (wheel_state),
1201 0,
1202 M_COPYIN)) {
1203
1204 break;
1205 }
1206 freemsg(mp->b_cont);
1207 mp->b_cont = (mblk_t *)NULL;
1208 qreply(q, mp);
1209
1210 return;
1211 }
1212 if ((mp->b_cont == NULL) ||
1213 (iocp->ioc_count != sizeof (wheel_state))) {
1214 err = EINVAL;
1215
1216 break;
1217 }
1218 datap = mp->b_cont;
1219 err = usbms_service_wheel_state(q, datap, VUIDGWHEELSTATE);
1220
1221 break;
1222 case VUIDSWHEELSTATE:
1223 if (iocp->ioc_count == TRANSPARENT) {
1224 if (err = usbms_make_copyreq(mp,
1225 sizeof (usbms_iocstate_t),
1226 USBMS_GETSTRUCT,
1227 sizeof (wheel_state),
1228 0,
1229 M_COPYIN)) {
1230
1231 break;
1232 }
1233 freemsg(mp->b_cont);
1234 mp->b_cont = (mblk_t *)NULL;
1235 qreply(q, mp);
1236
1237 return;
1238 }
1239 if (mp->b_cont == NULL) {
1240 err = EINVAL;
1241
1242 break;
1243 }
1244 datap = mp->b_cont;
1245 err = usbms_service_wheel_state(q, datap, VUIDSWHEELSTATE);
1246
1247 break;
1248 case MSIOSRESOLUTION:
1249 if (iocp->ioc_count == TRANSPARENT) {
1250 if (err = usbms_make_copyreq(mp,
1251 sizeof (usbms_iocstate_t),
1252 USBMS_GETSTRUCT,
1253 sizeof (Ms_screen_resolution),
1254 0,
1255 M_COPYIN)) {
1256
1257 break;
1258 }
1259
1260 freemsg(mp->b_cont);
1261 mp->b_cont = (mblk_t *)NULL;
1262 qreply(q, mp);
1263
1264 return;
1265 }
1266 if (mp->b_cont == NULL) {
1267 err = EINVAL;
1268
1269 break;
1270 }
1271 datap = mp->b_cont;
1272 err = usbms_get_screen_parms(q, datap);
1273 /*
1274 * Create the absolute mouse type event.
1275 * It is used for the hotplug absolute mouse.
1276 */
1277 if ((!((usbmsp->usbms_idf).xattr & HID_MAIN_ITEM_RELATIVE)) &&
1278 (usbmsp->usbms_rpt_abs == B_FALSE)) {
1279 report_abs = B_TRUE;
1280 }
1281
1282 break;
1283
1284 default:
1285 putnext(q, mp); /* pass it down the line */
1286
1287 return;
1288 } /* switch */
1289
1290 if (err != 0)
1291 miocnak(q, mp, 0, err);
1292 else {
1293 iocp->ioc_rval = 0;
1294 iocp->ioc_error = 0;
1295 mp->b_datap->db_type = M_IOCACK;
1296 qreply(q, mp);
1297
1298 if (report_abs == B_TRUE) {
1299 /* send the abs mouse type event to the upper level */
1300 if ((mb = usbms_setup_abs_mouse_event()) != NULL) {
1301 usbmsp->usbms_rpt_abs = B_TRUE;
1302 qreply(q, mb);
1303 }
1304 }
1305 }
1306
1307 return;
1308
1309 allocfailure:
1310 /*
1311 * We needed to allocate something to handle this "ioctl", but
1312 * couldn't; save this "ioctl" and arrange to get called back when
1313 * it's more likely that we can get what we need.
1314 * If there's already one being saved, throw it out, since it
1315 * must have timed out.
1316 */
1317 freemsg(usbmsp->usbms_iocpending);
1318 usbmsp->usbms_iocpending = mp;
1319 if (usbmsp->usbms_reioctl_id) {
1320 qunbufcall(q, (bufcall_id_t)usbmsp->usbms_reioctl_id);
1321 }
1322 usbmsp->usbms_reioctl_id = qbufcall(q, ioctlrespsize, BPRI_HI,
1323 (void (*)())usbms_reioctl,
1324 (void *)usbmsp);
1325 }
1326
1327
1328 /*
1329 * M_IOCDATA processing for IOCTL's: VUIDGWHEELCOUNT, VUIDGWHEELINFO,
1330 * VUIDGWHEELSTATE, VUIDSWHEELSTATE & MSIOSRESOLUTION.
1331 */
1332 static void
usbms_miocdata(register queue_t * q,register mblk_t * mp)1333 usbms_miocdata(register queue_t *q,
1334 register mblk_t *mp)
1335 {
1336 struct copyresp *copyresp;
1337 struct iocblk *iocbp;
1338 mblk_t *datap;
1339 mblk_t *ioctmp;
1340 usbms_iocstate_t *usbmsioc;
1341 int err = 0;
1342
1343 copyresp = (struct copyresp *)mp->b_rptr;
1344 iocbp = (struct iocblk *)mp->b_rptr;
1345 if (copyresp->cp_rval) {
1346 err = EAGAIN;
1347
1348 goto err;
1349 }
1350 switch (copyresp->cp_cmd) {
1351
1352 case VUIDGWHEELCOUNT:
1353 usbms_ack_ioctl(mp);
1354
1355 break;
1356 case VUIDGWHEELINFO:
1357 ioctmp = copyresp->cp_private;
1358 usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr;
1359 if (usbmsioc->ioc_state == USBMS_GETSTRUCT) {
1360 if (mp->b_cont == NULL) {
1361 err = EINVAL;
1362
1363 break;
1364 }
1365 datap = (mblk_t *)mp->b_cont;
1366 if (err = usbms_service_wheel_info(q, datap)) {
1367
1368 goto err;
1369 }
1370 if (err = usbms_make_copyreq(mp, 0, USBMS_GETRESULT,
1371 sizeof (wheel_info), 0, M_COPYOUT)) {
1372
1373 goto err;
1374 }
1375 } else if (usbmsioc->ioc_state == USBMS_GETRESULT) {
1376 freemsg(ioctmp);
1377 usbms_ack_ioctl(mp);
1378 }
1379
1380 break;
1381 case VUIDGWHEELSTATE:
1382 ioctmp = (mblk_t *)copyresp->cp_private;
1383 usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr;
1384 if (usbmsioc->ioc_state == USBMS_GETSTRUCT) {
1385 if (mp->b_cont == NULL) {
1386 err = EINVAL;
1387
1388 break;
1389 }
1390 if (err = usbms_service_wheel_state(q, mp->b_cont,
1391 VUIDGWHEELSTATE)) {
1392 goto err;
1393 }
1394 if (err = usbms_make_copyreq(mp, 0, USBMS_GETRESULT,
1395 sizeof (wheel_state), 0, M_COPYOUT)) {
1396
1397 goto err;
1398 }
1399 } else if (usbmsioc->ioc_state == USBMS_GETRESULT) {
1400 freemsg(ioctmp);
1401 usbms_ack_ioctl(mp);
1402 }
1403
1404 break;
1405 case VUIDSWHEELSTATE:
1406 ioctmp = (mblk_t *)copyresp->cp_private;
1407 usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr;
1408 if (mp->b_cont == NULL) {
1409 err = EINVAL;
1410
1411 break;
1412 }
1413 if (err = usbms_service_wheel_state(q, mp->b_cont,
1414 VUIDSWHEELSTATE)) {
1415
1416 goto err;
1417 }
1418 freemsg(ioctmp);
1419 usbms_ack_ioctl(mp);
1420
1421 break;
1422 case MSIOSRESOLUTION:
1423 ioctmp = (mblk_t *)copyresp->cp_private;
1424 usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr;
1425 if (mp->b_cont == NULL) {
1426 err = EINVAL;
1427
1428 break;
1429 }
1430 if (err = usbms_get_screen_parms(q, mp->b_cont)) {
1431
1432 goto err;
1433 }
1434 freemsg(ioctmp);
1435 usbms_ack_ioctl(mp);
1436
1437 break;
1438 default:
1439 err = EINVAL;
1440 break;
1441 }
1442
1443 err:
1444 if (err) {
1445 mp->b_datap->db_type = M_IOCNAK;
1446 if (mp->b_cont) {
1447 freemsg(mp->b_cont);
1448 mp->b_cont = (mblk_t *)NULL;
1449 }
1450 if (copyresp->cp_private) {
1451 freemsg((mblk_t *)copyresp->cp_private);
1452 copyresp->cp_private = (mblk_t *)NULL;
1453 }
1454 iocbp->ioc_count = 0;
1455 iocbp->ioc_error = err;
1456 }
1457 qreply(q, mp);
1458 }
1459
1460
1461 /*
1462 * usbms_reioctl() :
1463 * This function is set up as call-back function should an ioctl fail.
1464 * It retries the ioctl.
1465 */
1466 static void
usbms_reioctl(void * usbms_addr)1467 usbms_reioctl(void * usbms_addr)
1468 {
1469 usbms_state_t *usbmsp = (usbms_state_t *)usbms_addr;
1470 register queue_t *q;
1471 register mblk_t *mp;
1472
1473 q = usbmsp->usbms_wq_ptr;
1474 if ((mp = usbmsp->usbms_iocpending) != NULL) {
1475 usbmsp->usbms_iocpending = NULL; /* not pending any more */
1476 usbms_ioctl(q, mp);
1477 }
1478 }
1479
1480 /*
1481 * usbms_getparms() :
1482 * Called from MSIOGETPARMS ioctl to get the
1483 * current jitter_thesh, speed_law and speed_limit
1484 * values.
1485 */
1486 static int
usbms_getparms(register Ms_parms * data,usbms_state_t * usbmsp)1487 usbms_getparms(register Ms_parms *data,
1488 usbms_state_t *usbmsp)
1489 {
1490 data->jitter_thresh = usbmsp->usbms_jitter_thresh;
1491 data->speed_law = usbmsp->usbms_speedlaw;
1492 data->speed_limit = usbmsp->usbms_speedlimit;
1493
1494 return (0);
1495 }
1496
1497
1498 /*
1499 * usbms_setparms() :
1500 * Called from MSIOSETPARMS ioctl to set the
1501 * current jitter_thesh, speed_law and speed_limit
1502 * values.
1503 */
1504 static int
usbms_setparms(register Ms_parms * data,usbms_state_t * usbmsp)1505 usbms_setparms(register Ms_parms *data,
1506 usbms_state_t *usbmsp)
1507 {
1508 usbmsp->usbms_jitter_thresh = data->jitter_thresh;
1509 usbmsp->usbms_speedlaw = data->speed_law;
1510 usbmsp->usbms_speedlimit = data->speed_limit;
1511
1512 return (0);
1513 }
1514
1515 /*
1516 * usbms_flush() :
1517 * Resets the ms_softc structure to default values
1518 * and sends M_FLUSH above.
1519 */
1520 static void
usbms_flush(usbms_state_t * usbmsp)1521 usbms_flush(usbms_state_t *usbmsp)
1522 {
1523 register struct ms_softc *ms = &usbmsp->usbms_softc;
1524 register queue_t *q;
1525
1526 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
1527 "usbms_flush entering");
1528
1529 ms->ms_oldoff = 0;
1530 ms->ms_eventstate = EVENT_BUT(usbmsp->usbms_num_buttons);
1531 usbmsp->usbms_buf->mb_off = 0;
1532 ms->ms_prevbuttons = (char)USB_NO_BUT_PRESSED;
1533 usbmsp->usbms_oldbutt = ms->ms_prevbuttons;
1534 if ((q = usbmsp->usbms_rq_ptr) != NULL && q->q_next != NULL) {
1535 (void) putnextctl1(q, M_FLUSH, FLUSHR);
1536 }
1537
1538 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
1539 "usbms_flush exiting");
1540 }
1541
1542
1543 /*
1544 * usbms_rput() :
1545 * Put procedure for input from driver end of stream (read queue).
1546 */
1547 static void
usbms_rput(queue_t * q,mblk_t * mp)1548 usbms_rput(queue_t *q,
1549 mblk_t *mp)
1550 {
1551 usbms_state_t *usbmsp = q->q_ptr;
1552 mblk_t *tmp_mp;
1553 ushort_t limit = (usbmsp->usbms_idf).tlen;
1554
1555 /* Maintain the original mp */
1556 tmp_mp = mp;
1557
1558 if (usbmsp == 0) {
1559 freemsg(mp); /* nobody's listening */
1560
1561 return;
1562 }
1563
1564 switch (mp->b_datap->db_type) {
1565
1566 case M_FLUSH:
1567 if (*mp->b_rptr & FLUSHW)
1568 flushq(WR(q), FLUSHDATA);
1569 if (*mp->b_rptr & FLUSHR)
1570 flushq(q, FLUSHDATA);
1571 freemsg(mp);
1572
1573 return;
1574
1575 case M_BREAK:
1576 /*
1577 * We don't have to handle this
1578 * because nothing is sent from the downstream
1579 */
1580
1581 freemsg(mp);
1582
1583 return;
1584
1585 case M_DATA:
1586 if (!(usbmsp->usbms_flags & USBMS_OPEN)) {
1587 freemsg(mp); /* not ready to listen */
1588
1589 return;
1590 }
1591 break;
1592
1593 case M_CTL:
1594 usbms_mctl_receive(q, mp);
1595
1596 return;
1597
1598 case M_ERROR:
1599 usbmsp->usbms_protoerr = 1;
1600 usbmsp->usbms_flags &= ~USBMS_QWAIT;
1601 if (*mp->b_rptr == ENODEV) {
1602 putnext(q, mp);
1603 } else {
1604 freemsg(mp);
1605 }
1606
1607 return;
1608 default:
1609 putnext(q, mp);
1610
1611 return;
1612 }
1613
1614 /*
1615 * A data message, consisting of bytes from the mouse.
1616 * Make sure there are atleast "limit" number of bytes.
1617 */
1618 if ((MBLKL(tmp_mp) < limit) || ((MBLKL(tmp_mp) == limit) &&
1619 (usbmsp->usbms_rptid != HID_REPORT_ID_UNDEFINED))) {
1620 freemsg(mp);
1621 return;
1622 }
1623 do {
1624 if (usbmsp->usbms_rptid != HID_REPORT_ID_UNDEFINED) {
1625 if (*(tmp_mp->b_rptr) != usbmsp->usbms_rptid) {
1626 freemsg(mp);
1627
1628 return;
1629 } else {
1630 /* We skip the report id prefix. */
1631 tmp_mp->b_rptr++;
1632 }
1633 }
1634
1635 usbms_input(usbmsp, tmp_mp);
1636 } while ((tmp_mp = tmp_mp->b_cont) != NULL); /* next block, if any */
1637
1638 freemsg(mp);
1639 }
1640
1641
1642 /*
1643 * usbms_mctl_receive() :
1644 * Handle M_CTL messages from hid. If
1645 * we don't understand the command, free message.
1646 */
1647 static void
usbms_mctl_receive(register queue_t * q,register mblk_t * mp)1648 usbms_mctl_receive(register queue_t *q,
1649 register mblk_t *mp)
1650 {
1651 usbms_state_t *usbmsd = (usbms_state_t *)q->q_ptr;
1652 struct iocblk *iocp;
1653 caddr_t data;
1654
1655
1656 iocp = (struct iocblk *)mp->b_rptr;
1657 if (mp->b_cont != NULL)
1658 data = (caddr_t)mp->b_cont->b_rptr;
1659
1660 switch (iocp->ioc_cmd) {
1661
1662 case HID_GET_PARSER_HANDLE:
1663 if ((data != NULL) &&
1664 (iocp->ioc_count == sizeof (hidparser_handle_t)) &&
1665 (MBLKL(mp->b_cont) == iocp->ioc_count)) {
1666 usbmsd->usbms_report_descr_handle =
1667 *(hidparser_handle_t *)data;
1668 } else {
1669 usbmsd->usbms_report_descr_handle = NULL;
1670 }
1671 freemsg(mp);
1672 usbmsd->usbms_flags &= ~USBMS_QWAIT;
1673 break;
1674 case HID_SET_PROTOCOL:
1675 usbmsd->usbms_flags &= ~USBMS_QWAIT;
1676
1677 /* FALLTHRU */
1678 default:
1679 freemsg(mp);
1680 break;
1681 }
1682 }
1683
1684
1685 /*
1686 * usbms_input() :
1687 *
1688 * Mouse input routine; process a byte received from a mouse and
1689 * assemble into a mouseinfo message for the window system.
1690 *
1691 * The USB mouse send a three-byte packet organized as
1692 * button, dx, dy
1693 * where dx and dy can be any signed byte value. The mouseinfo message
1694 * is organized as
1695 * dx, dy, button, timestamp
1696 * Our strategy is to collect but, dx & dy three-byte packet, then
1697 * send the mouseinfo message up.
1698 *
1699 * Basic algorithm: throw away bytes until we get a [potential]
1700 * button byte. Collect button; Collect dx; Collect dy; Send button,
1701 * dx, dy, timestamp.
1702 *
1703 * Watch out for overflow!
1704 */
1705 static void
usbms_input(usbms_state_t * usbmsp,mblk_t * mp)1706 usbms_input(usbms_state_t *usbmsp,
1707 mblk_t *mp)
1708 {
1709 register struct usbmousebuf *b;
1710 register struct usbmouseinfo *mi;
1711 register int jitter_radius;
1712 register int32_t nbutt;
1713 ushort_t i;
1714 char c;
1715
1716 nbutt = usbmsp->usbms_num_buttons;
1717 b = usbmsp->usbms_buf;
1718
1719 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1720 "usbms_input entering");
1721
1722 if (b == NULL) {
1723
1724 return;
1725 }
1726
1727 mi = &b->mb_info[b->mb_off];
1728
1729 /*
1730 * Lower 3 bits are middle, right, left.
1731 */
1732 c = mp->b_rptr[(usbmsp->usbms_idf).bpos];
1733 mi->mi_buttons = (char)USB_NO_BUT_PRESSED;
1734 if (c & USBMS_BUT(1)) { /* left button is pressed */
1735 mi->mi_buttons = mi->mi_buttons & USB_LEFT_BUT_PRESSED;
1736 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR,
1737 usbms_log_handle,
1738 "left button pressed");
1739 }
1740 if (c & USBMS_BUT(2)) { /* right button is pressed */
1741 mi->mi_buttons = mi->mi_buttons & USB_RIGHT_BUT_PRESSED;
1742 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR,
1743 usbms_log_handle,
1744 "right button pressed");
1745 }
1746 if (c & USBMS_BUT(3)) { /* middle button is pressed */
1747 mi->mi_buttons = mi->mi_buttons &
1748 USB_MIDDLE_BUT_PRESSED;
1749 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR,
1750 usbms_log_handle,
1751 "middle button pressed");
1752 }
1753
1754 if (nbutt > 3) {
1755 for (i = 4; i < (nbutt + 1); i++) {
1756 if (c & USBMS_BUT(i)) {
1757 mi->mi_buttons = mi->mi_buttons &
1758 USB_BUT_PRESSED(i);
1759 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR,
1760 usbms_log_handle,
1761 "%d button pressed", i);
1762 }
1763 }
1764 }
1765
1766 /* get the delta X and Y from the sample */
1767 mi->mi_x += usbms_get_coordinate((usbmsp->usbms_idf).xpos,
1768 (usbmsp->usbms_idf).xlen, mp);
1769
1770 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR,
1771 usbms_log_handle, "x = %d", (int)mi->mi_x);
1772
1773 uniqtime32(&mi->mi_time); /* record time when sample arrived */
1774
1775 mi->mi_y += usbms_get_coordinate((usbmsp->usbms_idf).ypos,
1776 (usbmsp->usbms_idf).ylen, mp);
1777
1778 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1779 "y = %d", (int)mi->mi_y);
1780
1781 /*
1782 * Check the wheel data in the current event.
1783 * If it exists, the wheel data is got from the sample.
1784 */
1785
1786 if (usbmsp->usbms_num_wheels) {
1787 mi->mi_z += usbms_get_coordinate((usbmsp->usbms_idf).zpos,
1788 (usbmsp->usbms_idf).zlen, mp);
1789
1790 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1791 "z = %d", (int)mi->mi_z);
1792 }
1793
1794 if (usbmsp->usbms_jitter) {
1795 (void) quntimeout(usbmsp->usbms_rq_ptr,
1796 (timeout_id_t)usbmsp->usbms_timeout_id);
1797 usbmsp->usbms_jitter = 0;
1798 }
1799
1800 if (!usbmsp->usbms_num_wheels) {
1801 mi->mi_z = 0;
1802 }
1803
1804 /*
1805 * If there is a wheel movement or a change in the button state,
1806 * send the data up immediately.
1807 */
1808 if (!(mi->mi_z) && (mi->mi_buttons == usbmsp->usbms_oldbutt)) {
1809 /*
1810 * Buttons did not change; did position?
1811 */
1812 if (mi->mi_x == 0 && mi->mi_y == 0) {
1813 /* no, position did not change */
1814
1815 return;
1816 }
1817
1818 /*
1819 * Did the mouse move more than the jitter threshhold?
1820 */
1821 jitter_radius = usbmsp->usbms_jitter_thresh;
1822 if (USB_ABS((int)mi->mi_x) <= jitter_radius &&
1823 USB_ABS((int)mi->mi_y) <= jitter_radius) {
1824 /*
1825 * Mouse moved less than the jitter threshhold.
1826 * Don't indicate an event; keep accumulating motions.
1827 * After "jittertimeout" ticks expire, treat
1828 * the accumulated delta as the real delta.
1829 */
1830 usbmsp->usbms_jitter = 1;
1831 usbmsp->usbms_timeout_id =
1832 qtimeout(usbmsp->usbms_rq_ptr,
1833 (void (*)())usbms_incr,
1834 (void *)usbmsp,
1835 (clock_t)usbmsp->usbms_jittertimeout);
1836
1837 return;
1838 }
1839 }
1840 usbmsp->usbms_oldbutt = mi->mi_buttons;
1841 usbms_incr(usbmsp);
1842
1843 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1844 "usbms_input exiting");
1845 }
1846
1847
1848 /*
1849 * usbms_get_coordinate():
1850 * get the X, Y, WHEEL coordinate values
1851 */
1852 static int
usbms_get_coordinate(uint_t pos,uint_t len,mblk_t * mp)1853 usbms_get_coordinate(uint_t pos, uint_t len, mblk_t *mp)
1854 {
1855 uint_t utmp, bitval, val;
1856 int i, xyz;
1857
1858 /* get the unsigned int value from the bit stream */
1859 utmp = 0;
1860 for (i = (pos + len - 1); i >= (int)pos; i--) {
1861 bitval = (mp->b_rptr[i/8] & (1 << (i%8))) >> (i%8);
1862 utmp = utmp * 2 + bitval;
1863 }
1864
1865 /* convert the unsigned int value into int value */
1866 val = 1 << (len - 1);
1867 xyz = (int)(utmp - val);
1868 if (xyz < 0)
1869 xyz += val;
1870 else if (xyz == 0)
1871 xyz = -(val - 1);
1872 else
1873 xyz -= val;
1874
1875 return (xyz);
1876 }
1877
1878
1879 /*
1880 * usbms_incr() :
1881 * Increment the mouse sample pointer.
1882 * Called either immediately after a sample or after a jitter timeout.
1883 */
1884 static void
usbms_incr(void * arg)1885 usbms_incr(void *arg)
1886 {
1887 usbms_state_t *usbmsp = arg;
1888 register struct ms_softc *ms = &usbmsp->usbms_softc;
1889 register struct usbmousebuf *b;
1890 register struct usbmouseinfo *mi;
1891 register int xc, yc, zc;
1892 register int wake;
1893 register int speedl = usbmsp->usbms_speedlimit;
1894 register int xabs, yabs;
1895
1896 /*
1897 * No longer waiting for jitter timeout
1898 */
1899 usbmsp->usbms_jitter = 0;
1900
1901 b = usbmsp->usbms_buf;
1902
1903 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1904 "usbms_incr entering");
1905
1906 if (b == NULL) {
1907
1908 return;
1909 }
1910 mi = &b->mb_info[b->mb_off];
1911 if (usbmsp->usbms_speedlaw) {
1912 xabs = USB_ABS((int)mi->mi_x);
1913 yabs = USB_ABS((int)mi->mi_y);
1914 if (xabs > speedl || yabs > speedl) {
1915 usbmsp->usbms_speed_count++;
1916 }
1917 if (xabs > speedl) {
1918 mi->mi_x = 0;
1919 }
1920 if (yabs > speedl) {
1921 mi->mi_y = 0;
1922 }
1923 }
1924
1925
1926 xc = yc = zc = 0;
1927
1928 /* See if we need to wake up anyone waiting for input */
1929 wake = b->mb_off == ms->ms_oldoff;
1930
1931 /* Adjust circular buffer pointer */
1932 if (++b->mb_off >= b->mb_size) {
1933 b->mb_off = 0;
1934 mi = b->mb_info;
1935 } else {
1936 mi++;
1937 }
1938
1939 /*
1940 * If over-took read index then flush buffer so that mouse state
1941 * is consistent.
1942 */
1943 if (b->mb_off == ms->ms_oldoff) {
1944 if (overrun_msg) {
1945 USB_DPRINTF_L1(PRINT_MASK_ALL, usbms_log_handle,
1946 "Mouse buffer flushed when overrun.");
1947 }
1948 usbms_flush(usbmsp);
1949 overrun_cnt++;
1950 mi = b->mb_info;
1951 }
1952
1953 /* Remember current buttons and fractional part of x & y */
1954 mi->mi_buttons = (char)USB_NO_BUT_PRESSED;
1955 mi->mi_x = xc;
1956 mi->mi_y = yc;
1957 mi->mi_z = zc;
1958
1959 if (wake) {
1960 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1961 "usbms_incr run service");
1962 qenable(usbmsp->usbms_rq_ptr); /* run the service proc */
1963 }
1964 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle,
1965 "usbms_incr exiting");
1966 }
1967
1968
1969 /*
1970 * usbms_check_for_wheels
1971 * return SUCCESS if wheel is found, else return FAILURE
1972 */
1973 static int
usbms_check_for_wheels(usbms_state_t * usbmsp)1974 usbms_check_for_wheels(usbms_state_t *usbmsp)
1975 {
1976 int rval, report_id;
1977
1978
1979 if (usbmsp->usbms_report_descr_handle) {
1980 /* Get the report id that has mouse data */
1981 if (hidparser_get_usage_attribute(
1982 usbmsp->usbms_report_descr_handle,
1983 0, /* Doesn't matter */
1984 HIDPARSER_ITEM_INPUT,
1985 HID_GENERIC_DESKTOP,
1986 HID_GD_X,
1987 HIDPARSER_ITEM_REPORT_ID,
1988 &usbmsp->usbms_rptid) == HIDPARSER_NOT_FOUND) {
1989 usbmsp->usbms_rptid = HID_REPORT_ID_UNDEFINED;
1990 report_id = 0;
1991 } else {
1992 report_id = usbmsp->usbms_rptid;
1993 }
1994
1995 /* find no. of wheels in this report */
1996 rval = hidparser_get_usage_attribute(
1997 usbmsp->usbms_report_descr_handle,
1998 report_id,
1999 HIDPARSER_ITEM_INPUT,
2000 HID_GENERIC_DESKTOP,
2001 HID_GD_WHEEL,
2002 HIDPARSER_ITEM_REPORT_COUNT,
2003 &usbmsp->usbms_num_wheels);
2004 if (rval == HIDPARSER_SUCCESS) {
2005 /*
2006 * Found wheel. By default enable the wheel.
2007 * Currently only enable only the first wheel.
2008 */
2009 usbmsp->usbms_wheel_state_bf |=
2010 VUID_WHEEL_STATE_ENABLED;
2011
2012 return (USB_SUCCESS);
2013 }
2014 }
2015 usbmsp->usbms_num_wheels = 0;
2016
2017 return (USB_FAILURE);
2018 }
2019
2020
2021 /*
2022 * usbms_make_copyreq
2023 * helper function for usbms ioctls
2024 */
2025 static int
usbms_make_copyreq(mblk_t * mp,uint_t pvtsize,uint_t state,uint_t reqsize,uint_t contsize,uint_t copytype)2026 usbms_make_copyreq(mblk_t *mp,
2027 uint_t pvtsize,
2028 uint_t state,
2029 uint_t reqsize,
2030 uint_t contsize,
2031 uint_t copytype)
2032 {
2033
2034 struct copyreq *cq;
2035 struct copyresp *cr;
2036 mblk_t *ioctmp;
2037 mblk_t *conttmp;
2038 usbms_iocstate_t *usbmsioc;
2039
2040 if ((!pvtsize) && state) {
2041 cr = (struct copyresp *)mp->b_rptr;
2042 ioctmp = cr->cp_private;
2043 }
2044 cq = (struct copyreq *)mp->b_rptr;
2045 if (mp->b_cont == NULL) {
2046
2047 return (EINVAL);
2048 }
2049 cq->cq_addr = *((caddr_t *)mp->b_cont->b_rptr);
2050 cq->cq_size = reqsize;
2051 cq->cq_flag = 0;
2052 if (pvtsize) {
2053 ioctmp = (mblk_t *)allocb(pvtsize, BPRI_MED);
2054 if (ioctmp == NULL) {
2055
2056 return (EAGAIN);
2057 }
2058 cq->cq_private = ioctmp;
2059 ioctmp = cq->cq_private;
2060 } else {
2061 /*
2062 * Here we need to set cq_private even if there's
2063 * no private data, otherwise its value will be
2064 * TRANSPARENT (-1) on 64bit systems because it
2065 * overlaps iocp->ioc_count. If user address (cq_addr)
2066 * is invalid, it would cause panic later in
2067 * usbms_miocdata:
2068 * freemsg((mblk_t *)copyresp->cp_private);
2069 */
2070 cq->cq_private = NULL;
2071 }
2072 if (state) {
2073 usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr;
2074 usbmsioc->ioc_state = state;
2075 if (pvtsize) { /* M_COPYIN */
2076 usbmsioc->u_addr = cq->cq_addr;
2077 } else {
2078 cq->cq_addr = usbmsioc->u_addr;
2079 cq->cq_private = ioctmp;
2080 }
2081 ioctmp->b_wptr = ioctmp->b_rptr + sizeof (usbms_iocstate_t);
2082 }
2083 if (contsize) {
2084 conttmp = (mblk_t *)allocb(contsize, BPRI_MED);
2085 if (conttmp == NULL) {
2086
2087 return (EAGAIN);
2088 }
2089 if (mp->b_cont) {
2090 freemsg(mp->b_cont);
2091 mp->b_cont = conttmp;
2092 }
2093 }
2094 mp->b_datap->db_type = (unsigned char)copytype;
2095 mp->b_wptr = mp->b_rptr + sizeof (struct copyreq);
2096
2097 return (USB_SUCCESS);
2098 }
2099
2100
2101 static int
usbms_service_wheel_info(register queue_t * q,register mblk_t * datap)2102 usbms_service_wheel_info(register queue_t *q, register mblk_t *datap)
2103 {
2104
2105 wheel_info *wi;
2106 usbms_state_t *usbmsp = (usbms_state_t *)q->q_ptr;
2107 uint_t err;
2108
2109 wi = (wheel_info *)datap->b_rptr;
2110 if (wi->vers != VUID_WHEEL_INFO_VERS) {
2111 err = EINVAL;
2112
2113 return (err);
2114 }
2115 if (wi->id > (usbmsp->usbms_num_wheels - 1)) {
2116 err = EINVAL;
2117
2118 return (err);
2119 }
2120 wi->format = (usbmsp->usbms_wheel_orient_bf & (1 << wi->id)) ?
2121 VUID_WHEEL_FORMAT_HORIZONTAL : VUID_WHEEL_FORMAT_VERTICAL;
2122
2123 return (USB_SUCCESS);
2124 }
2125
2126
2127 static int
usbms_service_wheel_state(register queue_t * q,register mblk_t * datap,register uint_t cmd)2128 usbms_service_wheel_state(register queue_t *q,
2129 register mblk_t *datap,
2130 register uint_t cmd)
2131 {
2132
2133 wheel_state *ws;
2134 uint_t err;
2135 usbms_state_t *usbmsp = (usbms_state_t *)q->q_ptr;
2136
2137 ws = (wheel_state *)datap->b_rptr;
2138 if (ws->vers != VUID_WHEEL_STATE_VERS) {
2139 err = EINVAL;
2140
2141 return (err);
2142 }
2143 if (ws->id > (usbmsp->usbms_num_wheels - 1)) {
2144 err = EINVAL;
2145
2146 return (err);
2147 }
2148
2149 switch (cmd) {
2150 case VUIDGWHEELSTATE:
2151 ws->stateflags = (usbmsp->usbms_wheel_state_bf >> ws->id) &
2152 VUID_WHEEL_STATE_ENABLED;
2153
2154 break;
2155 case VUIDSWHEELSTATE:
2156 usbmsp->usbms_wheel_state_bf = (ws->stateflags << ws->id) |
2157 (~(1 << ws->id) & usbmsp->usbms_wheel_state_bf);
2158
2159 break;
2160 default:
2161 err = EINVAL;
2162
2163 return (err);
2164 }
2165
2166 return (USB_SUCCESS);
2167 }
2168
2169
2170 /*
2171 * usbms_get_screen_parms() :
2172 * Called from MSIOSRESOLUTION ioctl to get the
2173 * current screen height/width params from X.
2174 */
2175 static int
usbms_get_screen_parms(register queue_t * q,register mblk_t * datap)2176 usbms_get_screen_parms(register queue_t *q,
2177 register mblk_t *datap)
2178 {
2179
2180 usbms_state_t *usbmsp = (usbms_state_t *)q->q_ptr;
2181 Ms_screen_resolution *res = &(usbmsp->usbms_resolution);
2182 Ms_screen_resolution *data;
2183
2184 data = (Ms_screen_resolution *)datap->b_rptr;
2185 res->height = data->height;
2186 res->width = data->width;
2187
2188 return (USB_SUCCESS);
2189 }
2190
2191
2192 static void
usbms_ack_ioctl(mblk_t * mp)2193 usbms_ack_ioctl(mblk_t *mp)
2194 {
2195
2196 struct iocblk *iocbp = (struct iocblk *)mp->b_rptr;
2197
2198 mp->b_datap->db_type = M_IOCACK;
2199 mp->b_wptr = mp->b_rptr + sizeof (struct iocblk);
2200 iocbp->ioc_error = 0;
2201 iocbp->ioc_count = 0;
2202 iocbp->ioc_rval = 0;
2203 if (mp->b_cont != NULL) {
2204 freemsg(mp->b_cont);
2205 mp->b_cont = NULL;
2206 }
2207 }
2208
2209
2210 /*
2211 * usbms_setup_abs_mouse_event() :
2212 * Called from MSIOSRESOLUTION ioctl to create
2213 * the absolute mouse type firm event.
2214 */
2215 static mblk_t *
usbms_setup_abs_mouse_event()2216 usbms_setup_abs_mouse_event()
2217 {
2218 mblk_t *mb;
2219 Firm_event *fep;
2220
2221 if ((mb = allocb(sizeof (Firm_event), BPRI_HI)) != NULL) {
2222 fep = (Firm_event *)mb->b_wptr;
2223 fep->id = MOUSE_TYPE_ABSOLUTE;
2224 fep->pair_type = FE_PAIR_NONE;
2225 fep->pair = NULL;
2226 fep->value = NULL;
2227 mb->b_wptr += sizeof (Firm_event);
2228 } else {
2229 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
2230 "No resource to report ABS mouse event");
2231 }
2232
2233 return (mb);
2234 }
2235
2236
2237 /*
2238 * usbms_read_input_data_format() :
2239 * Get the mouse packet length and usages' length.
2240 * Check whether X and Y are relative or absolute.
2241 *
2242 * If they are absolute, the X and Y logical max values
2243 * will be got. A firm event will be created and sent
2244 * to the upper level.
2245 */
2246 int
usbms_read_input_data_format(usbms_state_t * usbmsp)2247 usbms_read_input_data_format(usbms_state_t *usbmsp)
2248 {
2249
2250 hidparser_rpt_t *ms_rpt;
2251 uint_t i, button_page;
2252 uint_t limit = 0;
2253 uint32_t rptcnt, rptsz;
2254 usbms_idf *idf = &(usbmsp->usbms_idf);
2255 Ms_screen_resolution *res = &(usbmsp->usbms_resolution);
2256 mblk_t *mb;
2257 register queue_t *q;
2258 int rval;
2259
2260 usbmsp->usbms_rpt_abs = B_FALSE;
2261
2262 /* allocate hidparser report structure */
2263 ms_rpt = kmem_zalloc(sizeof (hidparser_rpt_t), KM_SLEEP);
2264
2265 /*
2266 * Check what is the total length of the mouse packet
2267 * and get the usages and their lengths in order
2268 */
2269
2270 rval = hidparser_get_usage_list_in_order(
2271 usbmsp->usbms_report_descr_handle,
2272 usbmsp->usbms_rptid,
2273 HIDPARSER_ITEM_INPUT,
2274 ms_rpt);
2275
2276 if (rval != HIDPARSER_SUCCESS) {
2277
2278 kmem_free(ms_rpt, sizeof (hidparser_rpt_t));
2279 return (USB_FAILURE);
2280 }
2281
2282 button_page = 0;
2283 for (i = 0; i < ms_rpt->no_of_usages; i++) {
2284 rptcnt = ms_rpt->usage_descr[i].rptcnt;
2285 rptsz = ms_rpt->usage_descr[i].rptsz;
2286 if ((ms_rpt->usage_descr[i].usage_page ==
2287 HID_BUTTON_PAGE) && (!button_page)) {
2288 idf->bpos = limit;
2289 limit += (rptcnt * rptsz);
2290 button_page = 1;
2291 continue;
2292 }
2293
2294 switch (ms_rpt->usage_descr[i].usage_id) {
2295
2296 case HID_GD_X:
2297 idf->xpos = limit;
2298 idf->xlen = rptsz;
2299 limit += rptsz;
2300 break;
2301 case HID_GD_Y:
2302 idf->ypos = limit;
2303 idf->ylen = rptsz;
2304 limit += rptsz;
2305 break;
2306 case HID_GD_Z:
2307 /*
2308 * z-axis not yet supported, just skip it.
2309 *
2310 * It would be ideal if the HID_GD_Z data would be
2311 * reported as horizontal wheel, and HID_GD_WHEEL
2312 * as vertical wheel.
2313 *
2314 * We can not use the default case, because
2315 * that skips rptcnt*rptsz, but for an
2316 * "Apple Might Mouse" rptsz must be used.
2317 */
2318 limit += rptsz;
2319 break;
2320 case HID_GD_WHEEL:
2321 idf->zpos = limit;
2322 idf->zlen = rptsz;
2323 limit += rptsz;
2324 break;
2325 default:
2326 limit += rptcnt * rptsz;
2327 break;
2328 }
2329 }
2330
2331 kmem_free(ms_rpt, sizeof (hidparser_rpt_t));
2332
2333 /* get the length of sending data */
2334 idf->tlen = limit / 8;
2335
2336 /* Check whether X and Y are relative or absolute */
2337 rval = hidparser_get_main_item_data_descr(
2338 usbmsp->usbms_report_descr_handle,
2339 usbmsp->usbms_rptid,
2340 HIDPARSER_ITEM_INPUT,
2341 HID_GENERIC_DESKTOP,
2342 HID_GD_X,
2343 &idf->xattr);
2344
2345 if (rval != HIDPARSER_SUCCESS) {
2346
2347 return (USB_FAILURE);
2348 }
2349
2350 /* For the time being assume that Y also has the same attr */
2351 idf->yattr = idf->xattr;
2352
2353 /* get the logical_maximum for X and Y respectively */
2354 if (!(idf->xattr & HID_MAIN_ITEM_RELATIVE)) {
2355
2356 /* the data format can't be parsed correctly */
2357 if (limit % 8) {
2358 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
2359 "Wrong data packet include %d bits", limit);
2360
2361 return (USB_FAILURE);
2362 }
2363 if (hidparser_get_usage_attribute(
2364 usbmsp->usbms_report_descr_handle,
2365 usbmsp->usbms_rptid,
2366 HIDPARSER_ITEM_INPUT,
2367 HID_GENERIC_DESKTOP,
2368 HID_GD_X,
2369 HIDPARSER_ITEM_LOGICAL_MAXIMUM,
2370 &usbmsp->usbms_logical_Xmax) != HIDPARSER_SUCCESS) {
2371
2372 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
2373 "fail to get X logical max.");
2374
2375 return (USB_FAILURE);
2376 }
2377 if (hidparser_get_usage_attribute(
2378 usbmsp->usbms_report_descr_handle,
2379 usbmsp->usbms_rptid,
2380 HIDPARSER_ITEM_INPUT,
2381 HID_GENERIC_DESKTOP,
2382 HID_GD_Y,
2383 HIDPARSER_ITEM_LOGICAL_MAXIMUM,
2384 &usbmsp->usbms_logical_Ymax) != HIDPARSER_SUCCESS) {
2385
2386 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle,
2387 "fail to get Y logical max.");
2388
2389 return (USB_FAILURE);
2390 }
2391
2392 if (usbmsp->usbms_logical_Xmax == 0) {
2393 USB_DPRINTF_L3(PRINT_MASK_ALL,
2394 usbms_log_handle,
2395 "X logical max value is zero");
2396
2397 return (USB_FAILURE);
2398 }
2399
2400 if (usbmsp->usbms_logical_Ymax == 0) {
2401 USB_DPRINTF_L3(PRINT_MASK_ALL,
2402 usbms_log_handle,
2403 "Y logical max value is zero");
2404
2405 return (USB_FAILURE);
2406 }
2407
2408 res->height = USBMS_DEFAULT_RES_HEIGHT;
2409 res->width = USBMS_DEFAULT_RES_WIDTH;
2410
2411 /* The wheel is not supported in current remote kvms. */
2412 usbmsp->usbms_num_wheels = 0;
2413 q = usbmsp->usbms_rq_ptr;
2414 if ((mb = usbms_setup_abs_mouse_event()) != NULL) {
2415 putnext(q, mb);
2416 } else {
2417
2418 return (USB_NO_RESOURCES);
2419 }
2420 }
2421
2422 return (USB_SUCCESS);
2423 }
2424