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 2006 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 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->usbms_resched_id); 527 } 528 usbmsp->usbms_resched_id = qbufcall(q, 529 (size_t)3, 530 (uint_t)BPRI_HI, 531 (void (*)())usbms_resched, 532 (void *) usbmsp); 533 if (usbmsp->usbms_resched_id == 0) 534 535 return; /* try again later */ 536 /* bufcall failed; just pitch this event */ 537 /* or maybe flush queue? */ 538 } 539 ms->ms_oldoff++; /* next event */ 540 541 /* circular buffer wraparound */ 542 if (ms->ms_oldoff >= b->mb_size) { 543 ms->ms_oldoff = 0; 544 } 545 break; 546 } 547 548 case MS_VUID_FORMAT: 549 default: { 550 551 do { 552 bp = NULL; 553 554 switch (ms->ms_eventstate) { 555 556 case EVENT_WHEEL: 557 loop = (usbmsp->usbms_num_wheels ? 558 1 : 0); 559 560 if (usbmsp->usbms_num_wheels) { 561 for (i = 0; i < loop; i++) { 562 usbms_rserv_vuid_event_wheel 563 (q, mi, &bp, i); 564 } 565 } 566 567 break; 568 case EVENT_BUT8: 569 case EVENT_BUT7: 570 case EVENT_BUT6: 571 case EVENT_BUT5: 572 case EVENT_BUT4: 573 case EVENT_BUT3: /* Send right button */ 574 case EVENT_BUT2: /* Send middle button */ 575 case EVENT_BUT1: /* Send left button */ 576 usbms_rserv_vuid_button(q, mi, &bp); 577 578 break; 579 case EVENT_Y: 580 usbms_rserv_vuid_event_y(q, mi, &bp); 581 582 break; 583 case EVENT_X: 584 usbms_rserv_vuid_event_x(q, mi, &bp); 585 586 break; 587 default: 588 /* start again */ 589 ms->ms_eventstate = EVENT_WHEEL; 590 591 break; 592 } 593 if (bp != NULL) { 594 /* lower pri to avoid mouse droppings */ 595 bp->b_wptr += sizeof (Firm_event); 596 putnext(q, bp); 597 } 598 if (ms->ms_eventstate == EVENT_X) { 599 ms->ms_eventstate = EVENT_WHEEL; 600 } else if (ms->ms_eventstate == EVENT_WHEEL) { 601 ms->ms_oldoff++; /* next event */ 602 /* circular buffer wraparound */ 603 if (ms->ms_oldoff >= b->mb_size) { 604 ms->ms_oldoff = 0; 605 } 606 ms->ms_eventstate = EVENT_BUT(nbutt); 607 } else 608 ms->ms_eventstate--; 609 } while (ms->ms_eventstate != EVENT_BUT(nbutt)); 610 } 611 } 612 } 613 USB_DPRINTF_L3(PRINT_MASK_SERV, usbms_log_handle, 614 "usbms_rserv exiting"); 615 } 616 617 618 /* 619 * usbms_rserv_vuid_event_wheel 620 * convert wheel data to firm events 621 */ 622 static void 623 usbms_rserv_vuid_event_wheel(queue_t *q, 624 struct usbmouseinfo *mi, 625 mblk_t **bpaddr, 626 ushort_t id) 627 { 628 Firm_event *fep; 629 mblk_t *tmp; 630 struct ms_softc *ms; 631 usbms_state_t *usbmsp = (usbms_state_t *)q->q_ptr; 632 633 if (!(usbmsp->usbms_wheel_state_bf & (1 << id))) { 634 635 return; 636 } 637 ms = &usbmsp->usbms_softc; 638 if (mi->mi_z) { 639 if ((tmp = allocb(sizeof (Firm_event), BPRI_HI)) != NULL) { 640 fep = (Firm_event *)tmp->b_wptr; 641 fep->id = vuid_id_addr(vuid_first(VUID_WHEEL)) | 642 vuid_id_offset(id); 643 fep->pair_type = FE_PAIR_NONE; 644 fep->pair = NULL; 645 fep->value = mi->mi_z; 646 fep->time = mi->mi_time; 647 *bpaddr = tmp; 648 } else { 649 if (usbmsp->usbms_resched_id) { 650 qunbufcall(q, 651 (bufcall_id_t)usbmsp->usbms_resched_id); 652 } 653 usbmsp->usbms_resched_id = 654 qbufcall(q, sizeof (Firm_event), BPRI_HI, 655 (void (*)())usbms_resched, (void *) usbmsp); 656 if (usbmsp->usbms_resched_id == 0) { 657 /* try again later */ 658 659 return; 660 } 661 662 /* flush the queue */ 663 ms->ms_eventstate = EVENT_WHEEL; 664 } 665 } 666 } 667 668 669 /* 670 * usbms_rserv_vuid_button() : 671 * Process a VUID button event 672 */ 673 static void 674 usbms_rserv_vuid_button(queue_t *q, 675 struct usbmouseinfo *mi, 676 mblk_t **bpaddr) 677 { 678 usbms_state_t *usbmsp = q->q_ptr; 679 struct ms_softc *ms; 680 int button_number; 681 uchar_t hwbit = 0x0; 682 Firm_event *fep; 683 mblk_t *bp; 684 uchar_t nbutt; 685 686 ms = &usbmsp->usbms_softc; 687 688 /* Test button. Send an event if it changed. */ 689 nbutt = (uchar_t)usbmsp->usbms_num_buttons; 690 button_number = nbutt - (EVENT_BUT(nbutt) - ms->ms_eventstate) - 1; 691 switch (button_number) { 692 case 2: 693 /* Right button */ 694 hwbit = 0x01; 695 696 break; 697 case 1: 698 /* 699 * On two-button mice, the second button is the "right" 700 * button. There is no "middle". The vuidps2.c file has 701 * a bmap[] array in sendButtonEvent(). We do something 702 * equivalent here ONLY in the case of two-button mice. 703 */ 704 if (nbutt == 2) { 705 hwbit = 0x01; 706 /* 707 * Trick the vuid message into thinking it's a 708 * right-button click also. 709 */ 710 button_number = 2; 711 } else { 712 /* ... otherwise, it's just the middle button */ 713 hwbit = 0x02; 714 } 715 break; 716 case 0: 717 /* Left button */ 718 hwbit = 0x04; 719 720 break; 721 default : 722 /* Any other button */ 723 hwbit = USBMS_BUT(nbutt) >> (EVENT_BUT(nbutt) - 724 ms->ms_eventstate); 725 726 break; 727 } 728 729 if ((ms->ms_prevbuttons & hwbit) != 730 (mi->mi_buttons & hwbit)) { 731 if ((bp = allocb(sizeof (Firm_event), 732 BPRI_HI)) != NULL) { 733 *bpaddr = bp; 734 fep = (Firm_event *)bp->b_wptr; 735 fep->id = vuid_id_addr( 736 ms->ms_vuidaddr) | 737 vuid_id_offset(BUT(1) 738 + button_number); 739 fep->pair_type = FE_PAIR_NONE; 740 fep->pair = 0; 741 742 /* 743 * Update read buttons and set 744 * value 745 */ 746 if (mi->mi_buttons & hwbit) { 747 fep->value = 0; 748 ms->ms_prevbuttons |= 749 hwbit; 750 } else { 751 fep->value = 1; 752 ms->ms_prevbuttons &= 753 ~hwbit; 754 } 755 fep->time = mi->mi_time; 756 } else { 757 if (usbmsp->usbms_resched_id) { 758 qunbufcall(q, 759 (bufcall_id_t)usbmsp->usbms_resched_id); 760 } 761 usbmsp->usbms_resched_id = 762 qbufcall(q, 763 sizeof (Firm_event), 764 BPRI_HI, 765 (void (*)())usbms_resched, 766 (void *) usbmsp); 767 if (usbmsp->usbms_resched_id == 0) 768 /* try again later */ 769 return; 770 /* 771 * bufcall failed; just pitch 772 * this event 773 */ 774 /* or maybe flush queue? */ 775 ms->ms_eventstate = EVENT_WHEEL; 776 } 777 } 778 } 779 780 /* 781 * usbms_rserv_vuid_event_y() : 782 * Process a VUID y-event 783 */ 784 static void 785 usbms_rserv_vuid_event_y(register queue_t *q, 786 register struct usbmouseinfo *mi, 787 mblk_t **bpaddr) 788 { 789 usbms_state_t *usbmsp = q->q_ptr; 790 register struct ms_softc *ms; 791 register Firm_event *fep; 792 mblk_t *bp; 793 794 ms = &usbmsp->usbms_softc; 795 796 /* 797 * The (max, 0) message and (0, max) message are always sent before 798 * the button click message is sent on the IBM Bladecenter. Stop 799 * their sending may prevent the coordinate from moving to the 800 * (max, max). 801 */ 802 if (!(((usbmsp->usbms_idf).yattr) & HID_MAIN_ITEM_RELATIVE)) { 803 if ((mi->mi_x == 0) && 804 (mi->mi_y == usbmsp->usbms_logical_Ymax)) { 805 806 return; 807 } 808 } 809 810 /* Send y if changed. */ 811 if (mi->mi_y != 0) { 812 if ((bp = allocb(sizeof (Firm_event), 813 BPRI_HI)) != NULL) { 814 *bpaddr = bp; 815 fep = (Firm_event *)bp->b_wptr; 816 if (((usbmsp->usbms_idf).yattr) & 817 HID_MAIN_ITEM_RELATIVE) { 818 fep->id = vuid_id_addr( 819 ms->ms_vuidaddr) | 820 vuid_id_offset( 821 LOC_Y_DELTA); 822 fep->pair_type = 823 FE_PAIR_ABSOLUTE; 824 fep->pair = 825 (uchar_t)LOC_Y_ABSOLUTE; 826 fep->value = -(mi->mi_y); 827 } else { 828 fep->id = vuid_id_addr( 829 ms->ms_vuidaddr) | 830 vuid_id_offset( 831 LOC_Y_ABSOLUTE); 832 fep->pair_type = FE_PAIR_DELTA; 833 fep->pair = (uchar_t)LOC_Y_DELTA; 834 fep->value = (mi->mi_y * 835 ((usbmsp->usbms_resolution).height) / 836 usbmsp->usbms_logical_Ymax); 837 if ((mi->mi_y * 838 ((usbmsp->usbms_resolution).height) % 839 usbmsp->usbms_logical_Ymax) >= 840 (usbmsp->usbms_logical_Ymax / 2)) { 841 fep->value ++; 842 } 843 } 844 fep->time = mi->mi_time; 845 } else { 846 if (usbmsp->usbms_resched_id) { 847 qunbufcall(q, 848 (bufcall_id_t)usbmsp->usbms_resched_id); 849 } 850 usbmsp->usbms_resched_id = 851 qbufcall(q, 852 sizeof (Firm_event), 853 BPRI_HI, 854 (void (*)())usbms_resched, 855 (void *)usbmsp); 856 if (usbmsp->usbms_resched_id == 0) { 857 /* try again later */ 858 return; 859 } 860 861 /* 862 * bufcall failed; just pitch 863 * this event 864 */ 865 /* or maybe flush queue? */ 866 ms->ms_eventstate = EVENT_WHEEL; 867 } 868 } 869 } 870 871 /* 872 * usbms_rserv_vuid_event_x() : 873 * Process a VUID x-event 874 */ 875 static void 876 usbms_rserv_vuid_event_x(register queue_t *q, 877 register struct usbmouseinfo *mi, 878 mblk_t **bpaddr) 879 { 880 usbms_state_t *usbmsp = q->q_ptr; 881 register struct ms_softc *ms; 882 register Firm_event *fep; 883 mblk_t *bp; 884 885 ms = &usbmsp->usbms_softc; 886 887 /* 888 * The (max, 0) message and (0, max) message are always sent before 889 * the button click message is sent on the IBM Bladecenter. Stop 890 * their sending may prevent the coordinate from moving to the 891 * (max, max). 892 */ 893 if (!(((usbmsp->usbms_idf).xattr) & HID_MAIN_ITEM_RELATIVE)) { 894 if ((mi->mi_y == 0) && 895 (mi->mi_x == usbmsp->usbms_logical_Xmax)) { 896 897 return; 898 } 899 } 900 901 /* Send x if changed. */ 902 if (mi->mi_x != 0) { 903 if ((bp = allocb(sizeof (Firm_event), 904 BPRI_HI)) != NULL) { 905 *bpaddr = bp; 906 fep = (Firm_event *)bp->b_wptr; 907 if (((usbmsp->usbms_idf).xattr) & 908 HID_MAIN_ITEM_RELATIVE) { 909 fep->id = vuid_id_addr( 910 ms->ms_vuidaddr) | 911 vuid_id_offset(LOC_X_DELTA); 912 fep->pair_type = 913 FE_PAIR_ABSOLUTE; 914 fep->pair = 915 (uchar_t)LOC_X_ABSOLUTE; 916 fep->value = mi->mi_x; 917 } else { 918 fep->id = vuid_id_addr(ms->ms_vuidaddr) | 919 vuid_id_offset(LOC_X_ABSOLUTE); 920 fep->pair_type = FE_PAIR_DELTA; 921 fep->pair = (uchar_t)LOC_X_DELTA; 922 fep->value = (mi->mi_x * 923 ((usbmsp->usbms_resolution).width) / 924 usbmsp->usbms_logical_Xmax); 925 if ((mi->mi_x * 926 ((usbmsp->usbms_resolution).width) % 927 usbmsp->usbms_logical_Xmax) >= 928 (usbmsp->usbms_logical_Xmax / 2)) { 929 fep->value ++; 930 } 931 } 932 fep->time = mi->mi_time; 933 } else { 934 if (usbmsp->usbms_resched_id) 935 qunbufcall(q, 936 (bufcall_id_t)usbmsp->usbms_resched_id); 937 usbmsp->usbms_resched_id = 938 qbufcall(q, 939 sizeof (Firm_event), 940 BPRI_HI, 941 (void (*)())usbms_resched, 942 (void *) usbmsp); 943 if (usbmsp->usbms_resched_id == 0) 944 /* try again later */ 945 return; 946 947 /* 948 * bufcall failed; just 949 * pitch this event 950 */ 951 /* or maybe flush queue? */ 952 ms->ms_eventstate = EVENT_WHEEL; 953 } 954 } 955 } 956 957 /* 958 * usbms_resched() : 959 * Callback routine for the qbufcall() in case 960 * of allocb() failure. When buffer becomes 961 * available, this function is called and 962 * enables the queue. 963 */ 964 static void 965 usbms_resched(void * usbmsp) 966 { 967 register queue_t *q; 968 register usbms_state_t *tmp_usbmsp = (usbms_state_t *)usbmsp; 969 970 tmp_usbmsp->usbms_resched_id = 0; 971 if ((q = tmp_usbmsp->usbms_rq_ptr) != 0) 972 qenable(q); /* run the service procedure */ 973 } 974 975 /* 976 * usbms_wput() : 977 * wput() routine for the mouse module. 978 * Module below : hid, module above : consms 979 */ 980 static int 981 usbms_wput(queue_t *q, 982 mblk_t *mp) 983 { 984 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle, 985 "usbms_wput entering"); 986 switch (mp->b_datap->db_type) { 987 988 case M_FLUSH: /* Canonical flush handling */ 989 if (*mp->b_rptr & FLUSHW) { 990 flushq(q, FLUSHDATA); 991 } 992 993 if (*mp->b_rptr & FLUSHR) { 994 flushq(RD(q), FLUSHDATA); 995 } 996 997 putnext(q, mp); /* pass it down the line. */ 998 break; 999 1000 case M_IOCTL: 1001 usbms_ioctl(q, mp); 1002 break; 1003 1004 case M_IOCDATA: 1005 usbms_miocdata(q, mp); 1006 1007 break; 1008 default: 1009 putnext(q, mp); /* pass it down the line. */ 1010 } 1011 1012 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle, 1013 "usbms_wput exiting"); 1014 1015 return (0); 1016 } 1017 1018 1019 /* 1020 * usbms_ioctl() : 1021 * Process ioctls we recognize and own. Otherwise, NAK. 1022 */ 1023 static void 1024 usbms_ioctl(register queue_t *q, 1025 register mblk_t *mp) 1026 { 1027 usbms_state_t *usbmsp = (usbms_state_t *)q->q_ptr; 1028 register struct ms_softc *ms; 1029 register struct iocblk *iocp; 1030 Vuid_addr_probe *addr_probe; 1031 uint_t ioctlrespsize; 1032 int err = 0; 1033 mblk_t *datap; 1034 ushort_t transparent = 0; 1035 1036 USB_DPRINTF_L3(PRINT_MASK_IOCTL, usbms_log_handle, 1037 "usbms_ioctl entering"); 1038 1039 if (usbmsp == NULL) { 1040 miocnak(q, mp, 0, EINVAL); 1041 1042 return; 1043 } 1044 ms = &usbmsp->usbms_softc; 1045 1046 iocp = (struct iocblk *)mp->b_rptr; 1047 switch (iocp->ioc_cmd) { 1048 1049 case VUIDSFORMAT: 1050 err = miocpullup(mp, sizeof (int)); 1051 if (err != 0) 1052 break; 1053 1054 if (*(int *)mp->b_cont->b_rptr == ms->ms_readformat) { 1055 break; 1056 } 1057 ms->ms_readformat = *(int *)mp->b_cont->b_rptr; 1058 /* 1059 * Flush mouse buffer because the messages upstream of us 1060 * are in the old format. 1061 */ 1062 1063 usbms_flush(usbmsp); 1064 break; 1065 1066 case VUIDGFORMAT: 1067 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) { 1068 ioctlrespsize = sizeof (int); 1069 goto allocfailure; 1070 } 1071 *(int *)datap->b_wptr = ms->ms_readformat; 1072 datap->b_wptr += sizeof (int); 1073 freemsg(mp->b_cont); 1074 mp->b_cont = datap; 1075 iocp->ioc_count = sizeof (int); 1076 break; 1077 1078 case VUIDGADDR: 1079 case VUIDSADDR: 1080 err = miocpullup(mp, sizeof (Vuid_addr_probe)); 1081 if (err != 0) 1082 break; 1083 1084 addr_probe = (Vuid_addr_probe *)mp->b_cont->b_rptr; 1085 if (addr_probe->base != VKEY_FIRST) { 1086 err = ENODEV; 1087 break; 1088 } 1089 if (iocp->ioc_cmd == VUIDSADDR) 1090 ms->ms_vuidaddr = addr_probe->data.next; 1091 else 1092 addr_probe->data.current = ms->ms_vuidaddr; 1093 break; 1094 1095 case MSIOGETPARMS: 1096 if ((datap = allocb(sizeof (Ms_parms), BPRI_HI)) == NULL) { 1097 ioctlrespsize = sizeof (Ms_parms); 1098 goto allocfailure; 1099 } 1100 err = usbms_getparms((Ms_parms *)datap->b_wptr, usbmsp); 1101 datap->b_wptr += sizeof (Ms_parms); 1102 freemsg(mp->b_cont); 1103 mp->b_cont = datap; 1104 iocp->ioc_count = sizeof (Ms_parms); 1105 break; 1106 1107 case MSIOSETPARMS: 1108 err = miocpullup(mp, sizeof (Ms_parms)); 1109 if (err != 0) 1110 break; 1111 err = usbms_setparms((Ms_parms *)mp->b_cont->b_rptr, usbmsp); 1112 break; 1113 1114 case MSIOBUTTONS: 1115 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) { 1116 ioctlrespsize = sizeof (int); 1117 goto allocfailure; 1118 } 1119 *(int *)datap->b_wptr = (int)usbmsp->usbms_num_buttons; 1120 datap->b_wptr += sizeof (int); 1121 freemsg(mp->b_cont); 1122 mp->b_cont = datap; 1123 iocp->ioc_count = sizeof (int); 1124 1125 break; 1126 case VUIDGWHEELCOUNT: 1127 /* 1128 * New IOCTL support. Since it's explicitly mentioned that 1129 * you can't add more ioctls to stream head's hard coded 1130 * list, we have to do the transparent ioctl processing 1131 * which is heavy. 1132 */ 1133 1134 /* Currently support for only one wheel */ 1135 1136 if (iocp->ioc_count == TRANSPARENT) { 1137 transparent = 1; 1138 if (err = usbms_make_copyreq(mp, 0, 0, sizeof (int), 1139 0, M_COPYOUT)) { 1140 1141 break; 1142 } 1143 } 1144 if ((datap = allocb(sizeof (int), BPRI_HI)) == NULL) { 1145 ioctlrespsize = sizeof (int); 1146 1147 goto allocfailure; 1148 } 1149 *((int *)datap->b_wptr) = (usbmsp->usbms_num_wheels ? 1 : 0); 1150 datap->b_wptr += sizeof (int); 1151 if (mp->b_cont) { 1152 freemsg(mp->b_cont); 1153 mp->b_cont = NULL; 1154 } 1155 mp->b_cont = datap; 1156 if (transparent) { 1157 qreply(q, mp); 1158 1159 return; 1160 } 1161 1162 break; 1163 case VUIDGWHEELINFO: 1164 if (iocp->ioc_count == TRANSPARENT) { 1165 if (err = usbms_make_copyreq(mp, 1166 sizeof (usbms_iocstate_t), 1167 USBMS_GETSTRUCT, 1168 sizeof (wheel_info), 1169 0, 1170 M_COPYIN)) { 1171 1172 break; 1173 } 1174 /* 1175 * If there is no b_cont the earlier func. will fail. 1176 * Hence there is no need for an explicit check here. 1177 */ 1178 freemsg(mp->b_cont); 1179 mp->b_cont = (mblk_t *)NULL; 1180 qreply(q, mp); 1181 1182 return; 1183 } 1184 if (mp->b_cont == NULL || iocp->ioc_count != 1185 sizeof (wheel_info)) { 1186 err = EINVAL; 1187 break; 1188 } 1189 datap = mp->b_cont; 1190 err = usbms_service_wheel_info(q, datap); 1191 1192 break; 1193 case VUIDGWHEELSTATE: 1194 if (iocp->ioc_count == TRANSPARENT) { 1195 if (err = usbms_make_copyreq(mp, 1196 sizeof (usbms_iocstate_t), 1197 USBMS_GETSTRUCT, 1198 sizeof (wheel_state), 1199 0, 1200 M_COPYIN)) { 1201 1202 break; 1203 } 1204 freemsg(mp->b_cont); 1205 mp->b_cont = (mblk_t *)NULL; 1206 qreply(q, mp); 1207 1208 return; 1209 } 1210 if ((mp->b_cont == NULL) || 1211 (iocp->ioc_count != sizeof (wheel_state))) { 1212 err = EINVAL; 1213 1214 break; 1215 } 1216 datap = mp->b_cont; 1217 err = usbms_service_wheel_state(q, datap, VUIDGWHEELSTATE); 1218 1219 break; 1220 case VUIDSWHEELSTATE: 1221 if (iocp->ioc_count == TRANSPARENT) { 1222 if (err = usbms_make_copyreq(mp, 1223 sizeof (usbms_iocstate_t), 1224 USBMS_GETSTRUCT, 1225 sizeof (wheel_state), 1226 0, 1227 M_COPYIN)) { 1228 1229 break; 1230 } 1231 freemsg(mp->b_cont); 1232 mp->b_cont = (mblk_t *)NULL; 1233 qreply(q, mp); 1234 1235 return; 1236 } 1237 if (mp->b_cont == NULL) { 1238 err = EINVAL; 1239 1240 break; 1241 } 1242 datap = mp->b_cont; 1243 err = usbms_service_wheel_state(q, datap, VUIDSWHEELSTATE); 1244 1245 break; 1246 case MSIOSRESOLUTION: 1247 if (iocp->ioc_count == TRANSPARENT) { 1248 if (err = usbms_make_copyreq(mp, 1249 sizeof (usbms_iocstate_t), 1250 USBMS_GETSTRUCT, 1251 sizeof (Ms_screen_resolution), 1252 0, 1253 M_COPYIN)) { 1254 1255 break; 1256 } 1257 1258 freemsg(mp->b_cont); 1259 mp->b_cont = (mblk_t *)NULL; 1260 qreply(q, mp); 1261 1262 return; 1263 } 1264 if (mp->b_cont == NULL) { 1265 err = EINVAL; 1266 1267 break; 1268 } 1269 datap = mp->b_cont; 1270 err = usbms_get_screen_parms(q, datap); 1271 break; 1272 1273 default: 1274 putnext(q, mp); /* pass it down the line */ 1275 1276 return; 1277 } /* switch */ 1278 1279 if (err != 0) 1280 miocnak(q, mp, 0, err); 1281 else { 1282 iocp->ioc_rval = 0; 1283 iocp->ioc_error = 0; 1284 mp->b_datap->db_type = M_IOCACK; 1285 qreply(q, mp); 1286 } 1287 1288 return; 1289 1290 allocfailure: 1291 /* 1292 * We needed to allocate something to handle this "ioctl", but 1293 * couldn't; save this "ioctl" and arrange to get called back when 1294 * it's more likely that we can get what we need. 1295 * If there's already one being saved, throw it out, since it 1296 * must have timed out. 1297 */ 1298 freemsg(usbmsp->usbms_iocpending); 1299 usbmsp->usbms_iocpending = mp; 1300 if (usbmsp->usbms_reioctl_id) { 1301 qunbufcall(q, (bufcall_id_t)usbmsp->usbms_reioctl_id); 1302 } 1303 usbmsp->usbms_reioctl_id = qbufcall(q, ioctlrespsize, BPRI_HI, 1304 (void (*)())usbms_reioctl, 1305 (void *)usbmsp); 1306 } 1307 1308 1309 /* 1310 * M_IOCDATA processing for IOCTL's: VUIDGWHEELCOUNT, VUIDGWHEELINFO, 1311 * VUIDGWHEELSTATE, VUIDSWHEELSTATE & MSIOSRESOLUTION. 1312 */ 1313 static void 1314 usbms_miocdata(register queue_t *q, 1315 register mblk_t *mp) 1316 { 1317 struct copyresp *copyresp; 1318 struct iocblk *iocbp; 1319 mblk_t *datap; 1320 mblk_t *ioctmp; 1321 usbms_iocstate_t *usbmsioc; 1322 int err = 0; 1323 1324 copyresp = (struct copyresp *)mp->b_rptr; 1325 iocbp = (struct iocblk *)mp->b_rptr; 1326 if (copyresp->cp_rval) { 1327 err = EAGAIN; 1328 1329 goto err; 1330 } 1331 switch (copyresp->cp_cmd) { 1332 1333 case VUIDGWHEELCOUNT: 1334 usbms_ack_ioctl(mp); 1335 1336 break; 1337 case VUIDGWHEELINFO: 1338 ioctmp = copyresp->cp_private; 1339 usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr; 1340 if (usbmsioc->ioc_state == USBMS_GETSTRUCT) { 1341 if (mp->b_cont == NULL) { 1342 err = EINVAL; 1343 1344 break; 1345 } 1346 datap = (mblk_t *)mp->b_cont; 1347 if (err = usbms_service_wheel_info(q, datap)) { 1348 1349 goto err; 1350 } 1351 if (err = usbms_make_copyreq(mp, 0, USBMS_GETRESULT, 1352 sizeof (wheel_info), 0, M_COPYOUT)) { 1353 1354 goto err; 1355 } 1356 } else if (usbmsioc->ioc_state == USBMS_GETRESULT) { 1357 freemsg(ioctmp); 1358 usbms_ack_ioctl(mp); 1359 } 1360 1361 break; 1362 case VUIDGWHEELSTATE: 1363 ioctmp = (mblk_t *)copyresp->cp_private; 1364 usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr; 1365 if (usbmsioc->ioc_state == USBMS_GETSTRUCT) { 1366 if (mp->b_cont == NULL) { 1367 err = EINVAL; 1368 1369 break; 1370 } 1371 if (err = usbms_service_wheel_state(q, mp->b_cont, 1372 VUIDGWHEELSTATE)) { 1373 goto err; 1374 } 1375 if (err = usbms_make_copyreq(mp, 0, USBMS_GETRESULT, 1376 sizeof (wheel_state), 0, M_COPYOUT)) { 1377 1378 goto err; 1379 } 1380 } else if (usbmsioc->ioc_state == USBMS_GETRESULT) { 1381 freemsg(ioctmp); 1382 usbms_ack_ioctl(mp); 1383 } 1384 1385 break; 1386 case VUIDSWHEELSTATE: 1387 ioctmp = (mblk_t *)copyresp->cp_private; 1388 usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr; 1389 if (mp->b_cont == NULL) { 1390 err = EINVAL; 1391 1392 break; 1393 } 1394 if (err = usbms_service_wheel_state(q, mp->b_cont, 1395 VUIDSWHEELSTATE)) { 1396 1397 goto err; 1398 } 1399 freemsg(ioctmp); 1400 usbms_ack_ioctl(mp); 1401 1402 break; 1403 case MSIOSRESOLUTION: 1404 ioctmp = (mblk_t *)copyresp->cp_private; 1405 usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr; 1406 if (mp->b_cont == NULL) { 1407 err = EINVAL; 1408 1409 break; 1410 } 1411 if (err = usbms_get_screen_parms(q, mp->b_cont)) { 1412 1413 goto err; 1414 } 1415 freemsg(ioctmp); 1416 usbms_ack_ioctl(mp); 1417 1418 break; 1419 default: 1420 err = EINVAL; 1421 break; 1422 } 1423 1424 err: 1425 if (err) { 1426 mp->b_datap->db_type = M_IOCNAK; 1427 if (mp->b_cont) { 1428 freemsg(mp->b_cont); 1429 mp->b_cont = (mblk_t *)NULL; 1430 } 1431 if (copyresp->cp_private) { 1432 freemsg((mblk_t *)copyresp->cp_private); 1433 copyresp->cp_private = (mblk_t *)NULL; 1434 } 1435 iocbp->ioc_count = 0; 1436 iocbp->ioc_error = err; 1437 } 1438 qreply(q, mp); 1439 } 1440 1441 1442 /* 1443 * usbms_reioctl() : 1444 * This function is set up as call-back function should an ioctl fail. 1445 * It retries the ioctl. 1446 */ 1447 static void 1448 usbms_reioctl(void * usbms_addr) 1449 { 1450 usbms_state_t *usbmsp = (usbms_state_t *)usbms_addr; 1451 register queue_t *q; 1452 register mblk_t *mp; 1453 1454 q = usbmsp->usbms_wq_ptr; 1455 if ((mp = usbmsp->usbms_iocpending) != NULL) { 1456 usbmsp->usbms_iocpending = NULL; /* not pending any more */ 1457 usbms_ioctl(q, mp); 1458 } 1459 } 1460 1461 /* 1462 * usbms_getparms() : 1463 * Called from MSIOGETPARMS ioctl to get the 1464 * current jitter_thesh, speed_law and speed_limit 1465 * values. 1466 */ 1467 static int 1468 usbms_getparms(register Ms_parms *data, 1469 usbms_state_t *usbmsp) 1470 { 1471 data->jitter_thresh = usbmsp->usbms_jitter_thresh; 1472 data->speed_law = usbmsp->usbms_speedlaw; 1473 data->speed_limit = usbmsp->usbms_speedlimit; 1474 1475 return (0); 1476 } 1477 1478 1479 /* 1480 * usbms_setparms() : 1481 * Called from MSIOSETPARMS ioctl to set the 1482 * current jitter_thesh, speed_law and speed_limit 1483 * values. 1484 */ 1485 static int 1486 usbms_setparms(register Ms_parms *data, 1487 usbms_state_t *usbmsp) 1488 { 1489 usbmsp->usbms_jitter_thresh = data->jitter_thresh; 1490 usbmsp->usbms_speedlaw = data->speed_law; 1491 usbmsp->usbms_speedlimit = data->speed_limit; 1492 1493 return (0); 1494 } 1495 1496 /* 1497 * usbms_flush() : 1498 * Resets the ms_softc structure to default values 1499 * and sends M_FLUSH above. 1500 */ 1501 static void 1502 usbms_flush(usbms_state_t *usbmsp) 1503 { 1504 register struct ms_softc *ms = &usbmsp->usbms_softc; 1505 register queue_t *q; 1506 1507 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle, 1508 "usbms_flush entering"); 1509 1510 ms->ms_oldoff = 0; 1511 ms->ms_eventstate = EVENT_BUT(usbmsp->usbms_num_buttons); 1512 usbmsp->usbms_buf->mb_off = 0; 1513 ms->ms_prevbuttons = (char)USB_NO_BUT_PRESSED; 1514 usbmsp->usbms_oldbutt = ms->ms_prevbuttons; 1515 if ((q = usbmsp->usbms_rq_ptr) != NULL && q->q_next != NULL) { 1516 (void) putnextctl1(q, M_FLUSH, FLUSHR); 1517 } 1518 1519 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle, 1520 "usbms_flush exiting"); 1521 } 1522 1523 1524 /* 1525 * usbms_rput() : 1526 * Put procedure for input from driver end of stream (read queue). 1527 */ 1528 static void 1529 usbms_rput(queue_t *q, 1530 mblk_t *mp) 1531 { 1532 usbms_state_t *usbmsp = q->q_ptr; 1533 mblk_t *tmp_mp; 1534 ushort_t limit = (usbmsp->usbms_idf).tlen; 1535 1536 /* Maintain the original mp */ 1537 tmp_mp = mp; 1538 1539 if (usbmsp == 0) { 1540 freemsg(mp); /* nobody's listening */ 1541 1542 return; 1543 } 1544 1545 switch (mp->b_datap->db_type) { 1546 1547 case M_FLUSH: 1548 if (*mp->b_rptr & FLUSHW) 1549 flushq(WR(q), FLUSHDATA); 1550 if (*mp->b_rptr & FLUSHR) 1551 flushq(q, FLUSHDATA); 1552 freemsg(mp); 1553 1554 return; 1555 1556 case M_BREAK: 1557 /* 1558 * We don't have to handle this 1559 * because nothing is sent from the downstream 1560 */ 1561 1562 freemsg(mp); 1563 1564 return; 1565 1566 case M_DATA: 1567 if (!(usbmsp->usbms_flags & USBMS_OPEN)) { 1568 freemsg(mp); /* not ready to listen */ 1569 1570 return; 1571 } 1572 break; 1573 1574 case M_CTL: 1575 usbms_mctl_receive(q, mp); 1576 1577 return; 1578 1579 case M_ERROR: 1580 usbmsp->usbms_protoerr = 1; 1581 usbmsp->usbms_flags &= ~USBMS_QWAIT; 1582 freemsg(mp); 1583 1584 return; 1585 default: 1586 putnext(q, mp); 1587 1588 return; 1589 } 1590 1591 /* 1592 * A data message, consisting of bytes from the mouse. 1593 * Make sure there are atleast "limit" number of bytes. 1594 */ 1595 if (((tmp_mp->b_wptr - tmp_mp->b_rptr) < limit) || 1596 (((tmp_mp->b_wptr - tmp_mp->b_rptr) == limit) && 1597 (usbmsp->usbms_rptid != HID_REPORT_ID_UNDEFINED))) { 1598 freemsg(mp); 1599 return; 1600 } 1601 do { 1602 if (usbmsp->usbms_rptid != HID_REPORT_ID_UNDEFINED) { 1603 if (*(tmp_mp->b_rptr) != usbmsp->usbms_rptid) { 1604 freemsg(mp); 1605 1606 return; 1607 } else { 1608 /* We skip the report id prefix. */ 1609 tmp_mp->b_rptr++; 1610 } 1611 } 1612 1613 usbms_input(usbmsp, tmp_mp); 1614 } while ((tmp_mp = tmp_mp->b_cont) != NULL); /* next block, if any */ 1615 1616 freemsg(mp); 1617 } 1618 1619 1620 /* 1621 * usbms_mctl_receive() : 1622 * Handle M_CTL messages from hid. If 1623 * we don't understand the command, free message. 1624 */ 1625 static void 1626 usbms_mctl_receive(register queue_t *q, 1627 register mblk_t *mp) 1628 { 1629 usbms_state_t *usbmsd = (usbms_state_t *)q->q_ptr; 1630 struct iocblk *iocp; 1631 caddr_t data; 1632 1633 1634 iocp = (struct iocblk *)mp->b_rptr; 1635 if (mp->b_cont != NULL) 1636 data = (caddr_t)mp->b_cont->b_rptr; 1637 1638 switch (iocp->ioc_cmd) { 1639 1640 case HID_GET_PARSER_HANDLE: 1641 if ((data != NULL) && 1642 (iocp->ioc_count == sizeof (hidparser_handle_t)) && 1643 ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) == 1644 iocp->ioc_count)) { 1645 usbmsd->usbms_report_descr_handle = 1646 *(hidparser_handle_t *)data; 1647 } else { 1648 usbmsd->usbms_report_descr_handle = NULL; 1649 } 1650 freemsg(mp); 1651 usbmsd->usbms_flags &= ~USBMS_QWAIT; 1652 break; 1653 case HID_SET_PROTOCOL: 1654 usbmsd->usbms_flags &= ~USBMS_QWAIT; 1655 1656 /* FALLTHRU */ 1657 default: 1658 freemsg(mp); 1659 break; 1660 } 1661 } 1662 1663 1664 /* 1665 * usbms_input() : 1666 * 1667 * Mouse input routine; process a byte received from a mouse and 1668 * assemble into a mouseinfo message for the window system. 1669 * 1670 * The USB mouse send a three-byte packet organized as 1671 * button, dx, dy 1672 * where dx and dy can be any signed byte value. The mouseinfo message 1673 * is organized as 1674 * dx, dy, button, timestamp 1675 * Our strategy is to collect but, dx & dy three-byte packet, then 1676 * send the mouseinfo message up. 1677 * 1678 * Basic algorithm: throw away bytes until we get a [potential] 1679 * button byte. Collect button; Collect dx; Collect dy; Send button, 1680 * dx, dy, timestamp. 1681 * 1682 * Watch out for overflow! 1683 */ 1684 static void 1685 usbms_input(usbms_state_t *usbmsp, 1686 mblk_t *mp) 1687 { 1688 register struct usbmousebuf *b; 1689 register struct usbmouseinfo *mi; 1690 register int jitter_radius; 1691 register int32_t nbutt; 1692 ushort_t i; 1693 char c; 1694 1695 nbutt = usbmsp->usbms_num_buttons; 1696 b = usbmsp->usbms_buf; 1697 1698 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle, 1699 "usbms_input entering"); 1700 1701 if (b == NULL) { 1702 1703 return; 1704 } 1705 1706 mi = &b->mb_info[b->mb_off]; 1707 1708 /* 1709 * Lower 3 bits are middle, right, left. 1710 */ 1711 c = mp->b_rptr[(usbmsp->usbms_idf).bpos]; 1712 mi->mi_buttons = (char)USB_NO_BUT_PRESSED; 1713 if (c & USBMS_BUT(1)) { /* left button is pressed */ 1714 mi->mi_buttons = mi->mi_buttons & USB_LEFT_BUT_PRESSED; 1715 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, 1716 usbms_log_handle, 1717 "left button pressed"); 1718 } 1719 if (c & USBMS_BUT(2)) { /* right button is pressed */ 1720 mi->mi_buttons = mi->mi_buttons & USB_RIGHT_BUT_PRESSED; 1721 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, 1722 usbms_log_handle, 1723 "right button pressed"); 1724 } 1725 if (c & USBMS_BUT(3)) { /* middle button is pressed */ 1726 mi->mi_buttons = mi->mi_buttons & 1727 USB_MIDDLE_BUT_PRESSED; 1728 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, 1729 usbms_log_handle, 1730 "middle button pressed"); 1731 } 1732 1733 if (nbutt > 3) { 1734 for (i = 4; i < (nbutt + 1); i++) { 1735 if (c & USBMS_BUT(i)) { 1736 mi->mi_buttons = mi->mi_buttons & 1737 USB_BUT_PRESSED(i); 1738 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, 1739 usbms_log_handle, 1740 "%d button pressed", i); 1741 } 1742 } 1743 } 1744 1745 /* get the delta X and Y from the sample */ 1746 mi->mi_x += usbms_get_coordinate((usbmsp->usbms_idf).xpos, 1747 (usbmsp->usbms_idf).xlen, mp); 1748 1749 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, 1750 usbms_log_handle, "x = %d", (int)mi->mi_x); 1751 1752 uniqtime32(&mi->mi_time); /* record time when sample arrived */ 1753 1754 mi->mi_y += usbms_get_coordinate((usbmsp->usbms_idf).ypos, 1755 (usbmsp->usbms_idf).ylen, mp); 1756 1757 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle, 1758 "y = %d", (int)mi->mi_y); 1759 1760 /* 1761 * Check the wheel data in the current event. 1762 * If it exists, the wheel data is got from the sample. 1763 */ 1764 1765 if (usbmsp->usbms_num_wheels) { 1766 mi->mi_z += usbms_get_coordinate((usbmsp->usbms_idf).zpos, 1767 (usbmsp->usbms_idf).zlen, mp); 1768 1769 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle, 1770 "z = %d", (int)mi->mi_z); 1771 } 1772 1773 if (usbmsp->usbms_jitter) { 1774 (void) quntimeout(usbmsp->usbms_rq_ptr, 1775 (timeout_id_t)usbmsp->usbms_timeout_id); 1776 usbmsp->usbms_jitter = 0; 1777 } 1778 1779 if (!usbmsp->usbms_num_wheels) { 1780 mi->mi_z = 0; 1781 } 1782 1783 /* 1784 * If there is a wheel movement or a change in the button state, 1785 * send the data up immediately. 1786 */ 1787 if (!(mi->mi_z) && (mi->mi_buttons == usbmsp->usbms_oldbutt)) { 1788 /* 1789 * Buttons did not change; did position? 1790 */ 1791 if (mi->mi_x == 0 && mi->mi_y == 0) { 1792 /* no, position did not change */ 1793 1794 return; 1795 } 1796 1797 /* 1798 * Did the mouse move more than the jitter threshhold? 1799 */ 1800 jitter_radius = usbmsp->usbms_jitter_thresh; 1801 if (USB_ABS((int)mi->mi_x) <= jitter_radius && 1802 USB_ABS((int)mi->mi_y) <= jitter_radius) { 1803 /* 1804 * Mouse moved less than the jitter threshhold. 1805 * Don't indicate an event; keep accumulating motions. 1806 * After "jittertimeout" ticks expire, treat 1807 * the accumulated delta as the real delta. 1808 */ 1809 usbmsp->usbms_jitter = 1; 1810 usbmsp->usbms_timeout_id = 1811 qtimeout(usbmsp->usbms_rq_ptr, (void (*)())usbms_incr, 1812 (void *)usbmsp, (clock_t)usbmsp->usbms_jittertimeout); 1813 1814 return; 1815 } 1816 } 1817 usbmsp->usbms_oldbutt = mi->mi_buttons; 1818 usbms_incr(usbmsp); 1819 1820 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle, 1821 "usbms_input exiting"); 1822 } 1823 1824 1825 /* 1826 * usbms_get_coordinate(): 1827 * get the X, Y, WHEEL coordinate values 1828 */ 1829 static int 1830 usbms_get_coordinate(uint_t pos, uint_t len, mblk_t *mp) 1831 { 1832 uint_t utmp, bitval, val; 1833 int i, xyz; 1834 1835 /* get the unsigned int value from the bit stream */ 1836 utmp = 0; 1837 for (i = (pos + len - 1); i >= pos; i--) { 1838 bitval = (mp->b_rptr[i/8] & (1 << (i%8))) >> (i%8); 1839 utmp = utmp * 2 + bitval; 1840 } 1841 1842 /* convert the unsigned int value into int value */ 1843 val = 1 << (len - 1); 1844 xyz = (int)(utmp - val); 1845 if (xyz < 0) 1846 xyz += val; 1847 else if (xyz == 0) 1848 xyz = -(val - 1); 1849 else 1850 xyz -= val; 1851 1852 return (xyz); 1853 } 1854 1855 1856 /* 1857 * usbms_incr() : 1858 * Increment the mouse sample pointer. 1859 * Called either immediately after a sample or after a jitter timeout. 1860 */ 1861 static void 1862 usbms_incr(void *arg) 1863 { 1864 usbms_state_t *usbmsp = arg; 1865 register struct ms_softc *ms = &usbmsp->usbms_softc; 1866 register struct usbmousebuf *b; 1867 register struct usbmouseinfo *mi; 1868 register int xc, yc, zc; 1869 register int wake; 1870 register int speedl = usbmsp->usbms_speedlimit; 1871 register int xabs, yabs; 1872 1873 /* 1874 * No longer waiting for jitter timeout 1875 */ 1876 usbmsp->usbms_jitter = 0; 1877 1878 b = usbmsp->usbms_buf; 1879 1880 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle, 1881 "usbms_incr entering"); 1882 1883 if (b == NULL) { 1884 1885 return; 1886 } 1887 mi = &b->mb_info[b->mb_off]; 1888 if (usbmsp->usbms_speedlaw) { 1889 xabs = USB_ABS((int)mi->mi_x); 1890 yabs = USB_ABS((int)mi->mi_y); 1891 if (xabs > speedl || yabs > speedl) { 1892 usbmsp->usbms_speed_count++; 1893 } 1894 if (xabs > speedl) { 1895 mi->mi_x = 0; 1896 } 1897 if (yabs > speedl) { 1898 mi->mi_y = 0; 1899 } 1900 } 1901 1902 1903 xc = yc = zc = 0; 1904 1905 /* See if we need to wake up anyone waiting for input */ 1906 wake = b->mb_off == ms->ms_oldoff; 1907 1908 /* Adjust circular buffer pointer */ 1909 if (++b->mb_off >= b->mb_size) { 1910 b->mb_off = 0; 1911 mi = b->mb_info; 1912 } else { 1913 mi++; 1914 } 1915 1916 /* 1917 * If over-took read index then flush buffer so that mouse state 1918 * is consistent. 1919 */ 1920 if (b->mb_off == ms->ms_oldoff) { 1921 if (overrun_msg) { 1922 USB_DPRINTF_L1(PRINT_MASK_ALL, usbms_log_handle, 1923 "Mouse buffer flushed when overrun."); 1924 } 1925 usbms_flush(usbmsp); 1926 overrun_cnt++; 1927 mi = b->mb_info; 1928 } 1929 1930 /* Remember current buttons and fractional part of x & y */ 1931 mi->mi_buttons = (char)USB_NO_BUT_PRESSED; 1932 mi->mi_x = xc; 1933 mi->mi_y = yc; 1934 mi->mi_z = zc; 1935 1936 if (wake) { 1937 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle, 1938 "usbms_incr run service"); 1939 qenable(usbmsp->usbms_rq_ptr); /* run the service proc */ 1940 } 1941 USB_DPRINTF_L3(PRINT_MASK_INPUT_INCR, usbms_log_handle, 1942 "usbms_incr exiting"); 1943 } 1944 1945 1946 /* 1947 * usbms_check_for_wheels 1948 * return SUCCESS if wheel is found, else return FAILURE 1949 */ 1950 static int 1951 usbms_check_for_wheels(usbms_state_t *usbmsp) 1952 { 1953 int rval, report_id; 1954 1955 1956 if (usbmsp->usbms_report_descr_handle) { 1957 /* Get the report id that has mouse data */ 1958 if (hidparser_get_usage_attribute( 1959 usbmsp->usbms_report_descr_handle, 1960 0, /* Doesn't matter */ 1961 HIDPARSER_ITEM_INPUT, 1962 HID_GENERIC_DESKTOP, 1963 HID_GD_X, 1964 HIDPARSER_ITEM_REPORT_ID, 1965 &usbmsp->usbms_rptid) == HIDPARSER_NOT_FOUND) { 1966 usbmsp->usbms_rptid = HID_REPORT_ID_UNDEFINED; 1967 report_id = 0; 1968 } else { 1969 report_id = usbmsp->usbms_rptid; 1970 } 1971 1972 /* find no. of wheels in this report */ 1973 rval = hidparser_get_usage_attribute( 1974 usbmsp->usbms_report_descr_handle, 1975 report_id, 1976 HIDPARSER_ITEM_INPUT, 1977 HID_GENERIC_DESKTOP, 1978 HID_GD_WHEEL, 1979 HIDPARSER_ITEM_REPORT_COUNT, 1980 &usbmsp->usbms_num_wheels); 1981 if (rval == HIDPARSER_SUCCESS) { 1982 /* 1983 * Found wheel. By default enable the wheel. 1984 * Currently only enable only the first wheel. 1985 */ 1986 usbmsp->usbms_wheel_state_bf |= 1987 VUID_WHEEL_STATE_ENABLED; 1988 1989 return (USB_SUCCESS); 1990 } 1991 } 1992 usbmsp->usbms_num_wheels = 0; 1993 1994 return (USB_FAILURE); 1995 } 1996 1997 1998 /* 1999 * usbms_make_copyreq 2000 * helper function for usbms ioctls 2001 */ 2002 static int 2003 usbms_make_copyreq(mblk_t *mp, 2004 uint_t pvtsize, 2005 uint_t state, 2006 uint_t reqsize, 2007 uint_t contsize, 2008 uint_t copytype) 2009 { 2010 2011 struct copyreq *cq; 2012 struct copyresp *cr; 2013 mblk_t *ioctmp; 2014 mblk_t *conttmp; 2015 usbms_iocstate_t *usbmsioc; 2016 2017 if ((!pvtsize) && state) { 2018 cr = (struct copyresp *)mp->b_rptr; 2019 ioctmp = cr->cp_private; 2020 } 2021 cq = (struct copyreq *)mp->b_rptr; 2022 if (mp->b_cont == NULL) { 2023 2024 return (EINVAL); 2025 } 2026 cq->cq_addr = *((caddr_t *)mp->b_cont->b_rptr); 2027 cq->cq_size = reqsize; 2028 cq->cq_flag = 0; 2029 if (pvtsize) { 2030 ioctmp = (mblk_t *)allocb(pvtsize, BPRI_MED); 2031 if (ioctmp == NULL) { 2032 2033 return (EAGAIN); 2034 } 2035 cq->cq_private = ioctmp; 2036 ioctmp = cq->cq_private; 2037 } 2038 if (state) { 2039 usbmsioc = (usbms_iocstate_t *)ioctmp->b_rptr; 2040 usbmsioc->ioc_state = state; 2041 if (pvtsize) { 2042 usbmsioc->u_addr = cq->cq_addr; 2043 } else { 2044 cq->cq_addr = usbmsioc->u_addr; 2045 cq->cq_private = ioctmp; 2046 } 2047 ioctmp->b_wptr = ioctmp->b_rptr + sizeof (usbms_iocstate_t); 2048 } 2049 if (contsize) { 2050 conttmp = (mblk_t *)allocb(contsize, BPRI_MED); 2051 if (conttmp == NULL) { 2052 2053 return (EAGAIN); 2054 } 2055 if (mp->b_cont) { 2056 freemsg(mp->b_cont); 2057 mp->b_cont = conttmp; 2058 } 2059 } 2060 mp->b_datap->db_type = copytype; 2061 mp->b_wptr = mp->b_rptr + sizeof (struct copyreq); 2062 2063 return (USB_SUCCESS); 2064 } 2065 2066 2067 static int 2068 usbms_service_wheel_info(register queue_t *q, register mblk_t *datap) 2069 { 2070 2071 wheel_info *wi; 2072 usbms_state_t *usbmsp = (usbms_state_t *)q->q_ptr; 2073 uint_t err; 2074 2075 wi = (wheel_info *)datap->b_rptr; 2076 if (wi->vers != VUID_WHEEL_INFO_VERS) { 2077 err = EINVAL; 2078 2079 return (err); 2080 } 2081 if (wi->id > (usbmsp->usbms_num_wheels - 1)) { 2082 err = EINVAL; 2083 2084 return (err); 2085 } 2086 wi->format = (usbmsp->usbms_wheel_orient_bf & (1 << wi->id)) ? 2087 VUID_WHEEL_FORMAT_HORIZONTAL : VUID_WHEEL_FORMAT_VERTICAL; 2088 2089 return (USB_SUCCESS); 2090 } 2091 2092 2093 static int 2094 usbms_service_wheel_state(register queue_t *q, 2095 register mblk_t *datap, 2096 register uint_t cmd) 2097 { 2098 2099 wheel_state *ws; 2100 uint_t err; 2101 usbms_state_t *usbmsp = (usbms_state_t *)q->q_ptr; 2102 2103 ws = (wheel_state *)datap->b_rptr; 2104 if (ws->vers != VUID_WHEEL_STATE_VERS) { 2105 err = EINVAL; 2106 2107 return (err); 2108 } 2109 if (ws->id > (usbmsp->usbms_num_wheels - 1)) { 2110 err = EINVAL; 2111 2112 return (err); 2113 } 2114 2115 switch (cmd) { 2116 case VUIDGWHEELSTATE: 2117 ws->stateflags = (usbmsp->usbms_wheel_state_bf >> ws->id) & 2118 VUID_WHEEL_STATE_ENABLED; 2119 2120 break; 2121 case VUIDSWHEELSTATE: 2122 usbmsp->usbms_wheel_state_bf = (ws->stateflags << ws->id) | 2123 (~(1 << ws->id) & usbmsp->usbms_wheel_state_bf); 2124 2125 break; 2126 default: 2127 err = EINVAL; 2128 2129 return (err); 2130 } 2131 2132 return (USB_SUCCESS); 2133 } 2134 2135 2136 /* 2137 * usbms_get_screen_parms() : 2138 * Called from MSIOSRESOLUTION ioctl to get the 2139 * current screen height/width params from X. 2140 */ 2141 static int 2142 usbms_get_screen_parms(register queue_t *q, 2143 register mblk_t *datap) 2144 { 2145 2146 usbms_state_t *usbmsp = (usbms_state_t *)q->q_ptr; 2147 Ms_screen_resolution *res = &(usbmsp->usbms_resolution); 2148 Ms_screen_resolution *data; 2149 2150 data = (Ms_screen_resolution *)datap->b_rptr; 2151 res->height = data->height; 2152 res->width = data->width; 2153 2154 return (USB_SUCCESS); 2155 } 2156 2157 2158 static void 2159 usbms_ack_ioctl(mblk_t *mp) 2160 { 2161 2162 struct iocblk *iocbp = (struct iocblk *)mp->b_rptr; 2163 2164 mp->b_datap->db_type = M_IOCACK; 2165 mp->b_wptr = mp->b_rptr + sizeof (struct iocblk); 2166 iocbp->ioc_error = 0; 2167 iocbp->ioc_count = 0; 2168 iocbp->ioc_rval = 0; 2169 if (mp->b_cont != NULL) { 2170 freemsg(mp->b_cont); 2171 mp->b_cont = NULL; 2172 } 2173 } 2174 2175 2176 /* 2177 * usbms_read_input_data_format() : 2178 * Get the mouse packet length and usages' length. 2179 * Check whether X and Y are relative or absolute. 2180 * 2181 * If they are absolute, the X and Y logical max values 2182 * will be got. A firm event will be created and sent 2183 * to the upper level. 2184 */ 2185 int 2186 usbms_read_input_data_format(usbms_state_t *usbmsp) 2187 { 2188 2189 hidparser_rpt_t *ms_rpt; 2190 uint_t i, button_page; 2191 uint_t limit = 0; 2192 uint32_t rptcnt, rptsz; 2193 usbms_idf *idf = &(usbmsp->usbms_idf); 2194 Ms_screen_resolution *res = &(usbmsp->usbms_resolution); 2195 Firm_event *fep; 2196 mblk_t *mb; 2197 register queue_t *q; 2198 int rval; 2199 2200 /* allocate hidparser report structure */ 2201 ms_rpt = kmem_zalloc(sizeof (hidparser_rpt_t), KM_SLEEP); 2202 2203 /* 2204 * Check what is the total length of the mouse packet 2205 * and get the usages and their lengths in order 2206 */ 2207 2208 rval = hidparser_get_usage_list_in_order( 2209 usbmsp->usbms_report_descr_handle, 2210 usbmsp->usbms_rptid, 2211 HIDPARSER_ITEM_INPUT, 2212 ms_rpt); 2213 2214 if (rval != HIDPARSER_SUCCESS) { 2215 2216 kmem_free(ms_rpt, sizeof (hidparser_rpt_t)); 2217 return (USB_FAILURE); 2218 } 2219 2220 button_page = 0; 2221 for (i = 0; i < ms_rpt->no_of_usages; i++) { 2222 rptcnt = ms_rpt->usage_descr[i].rptcnt; 2223 rptsz = ms_rpt->usage_descr[i].rptsz; 2224 if ((ms_rpt->usage_descr[i].usage_page == 2225 HID_BUTTON_PAGE) && (!button_page)) { 2226 idf->bpos = limit; 2227 limit += (rptcnt * rptsz); 2228 button_page = 1; 2229 continue; 2230 } 2231 2232 switch (ms_rpt->usage_descr[i].usage_id) { 2233 2234 case HID_GD_X: 2235 idf->xpos = limit; 2236 idf->xlen = rptsz; 2237 limit += rptsz; 2238 break; 2239 case HID_GD_Y: 2240 idf->ypos = limit; 2241 idf->ylen = rptsz; 2242 limit += rptsz; 2243 break; 2244 case HID_GD_WHEEL: 2245 idf->zpos = limit; 2246 idf->zlen = rptsz; 2247 limit += rptsz; 2248 break; 2249 default: 2250 limit += rptcnt * rptsz; 2251 break; 2252 } 2253 } 2254 2255 kmem_free(ms_rpt, sizeof (hidparser_rpt_t)); 2256 2257 /* get the length of sending data */ 2258 idf->tlen = limit / 8; 2259 2260 /* Check whether X and Y are relative or absolute */ 2261 rval = hidparser_get_main_item_data_descr( 2262 usbmsp->usbms_report_descr_handle, 2263 usbmsp->usbms_rptid, 2264 HIDPARSER_ITEM_INPUT, 2265 HID_GENERIC_DESKTOP, 2266 HID_GD_X, 2267 &idf->xattr); 2268 2269 if (rval != HIDPARSER_SUCCESS) { 2270 2271 return (USB_FAILURE); 2272 } 2273 2274 /* For the time being assume that Y also has the same attr */ 2275 idf->yattr = idf->xattr; 2276 2277 /* get the logical_maximum for X and Y respectively */ 2278 if (!(idf->xattr & HID_MAIN_ITEM_RELATIVE)) { 2279 2280 /* the data format can't be parsed correctly */ 2281 if (limit % 8) { 2282 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle, 2283 "Wrong data packet include %d bits", limit); 2284 2285 return (USB_FAILURE); 2286 } 2287 if (hidparser_get_usage_attribute( 2288 usbmsp->usbms_report_descr_handle, 2289 usbmsp->usbms_rptid, 2290 HIDPARSER_ITEM_INPUT, 2291 HID_GENERIC_DESKTOP, 2292 HID_GD_X, 2293 HIDPARSER_ITEM_LOGICAL_MAXIMUM, 2294 &usbmsp->usbms_logical_Xmax) != HIDPARSER_SUCCESS) { 2295 2296 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle, 2297 "fail to get X logical max."); 2298 2299 return (USB_FAILURE); 2300 } 2301 if (hidparser_get_usage_attribute( 2302 usbmsp->usbms_report_descr_handle, 2303 usbmsp->usbms_rptid, 2304 HIDPARSER_ITEM_INPUT, 2305 HID_GENERIC_DESKTOP, 2306 HID_GD_Y, 2307 HIDPARSER_ITEM_LOGICAL_MAXIMUM, 2308 &usbmsp->usbms_logical_Ymax) != HIDPARSER_SUCCESS) { 2309 2310 USB_DPRINTF_L3(PRINT_MASK_ALL, usbms_log_handle, 2311 "fail to get Y logical max."); 2312 2313 return (USB_FAILURE); 2314 } 2315 2316 if (usbmsp->usbms_logical_Xmax == 0) { 2317 USB_DPRINTF_L3(PRINT_MASK_ALL, 2318 usbms_log_handle, 2319 "X logical max value is zero"); 2320 2321 return (USB_FAILURE); 2322 } 2323 2324 if (usbmsp->usbms_logical_Ymax == 0) { 2325 USB_DPRINTF_L3(PRINT_MASK_ALL, 2326 usbms_log_handle, 2327 "Y logical max value is zero"); 2328 2329 return (USB_FAILURE); 2330 } 2331 2332 res->height = USBMS_DEFAULT_RES_HEIGHT; 2333 res->width = USBMS_DEFAULT_RES_WIDTH; 2334 2335 /* The wheel is not supported in current remote kvms. */ 2336 usbmsp->usbms_num_wheels = 0; 2337 2338 if ((mb = allocb(sizeof (Firm_event), BPRI_HI)) == 2339 NULL) { 2340 2341 return (USB_NO_RESOURCES); 2342 } else { 2343 /* 2344 * notify the upper that it is an absolute mouse 2345 */ 2346 q = usbmsp->usbms_rq_ptr; 2347 2348 fep = (Firm_event *)mb->b_wptr; 2349 fep->id = MOUSE_TYPE_ABSOLUTE; 2350 fep->pair_type = FE_PAIR_NONE; 2351 fep->pair = NULL; 2352 fep->value = NULL; 2353 mb->b_wptr += sizeof (Firm_event); 2354 putnext(q, mb); 2355 } 2356 } 2357 2358 return (USB_SUCCESS); 2359 } 2360