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