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