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