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 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 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 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 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 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 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 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 = NULL; 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 * 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 = NULL; 2161 fep->value = NULL; 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 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