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