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