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