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