1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License, Version 1.0 only 6 * (the "License"). You may not use this file except in compliance 7 * with the License. 8 * 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10 * or http://www.opensolaris.org/os/licensing. 11 * See the License for the specific language governing permissions 12 * and limitations under the License. 13 * 14 * When distributing Covered Code, include this CDDL HEADER in each 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16 * If applicable, add the following below this CDDL HEADER, with the 17 * fields enclosed by brackets "[]" replaced with your own identifying 18 * information: Portions Copyright [yyyy] [name of copyright owner] 19 * 20 * CDDL HEADER END 21 */ 22 /* 23 * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 30 /* 31 * VUIDMICE module: put mouse events into vuid format 32 */ 33 34 #include <sys/param.h> 35 #include <sys/stream.h> 36 #include <sys/stropts.h> 37 #include <sys/strsun.h> 38 #include <sys/errno.h> 39 #include <sys/debug.h> 40 #include <sys/cmn_err.h> 41 #include <sys/sad.h> 42 #include <sys/vuid_event.h> 43 #include <sys/vuidmice.h> 44 #include <sys/vuid_wheel.h> 45 #include <sys/msio.h> 46 47 #include <sys/conf.h> 48 #include <sys/modctl.h> 49 50 #include <sys/kmem.h> 51 #include <sys/ddi.h> 52 #include <sys/sunddi.h> 53 54 static int vuidmice_open(queue_t *const, const dev_t *const, 55 const int, const int, const cred_t *const); 56 static int vuidmice_close(queue_t *const, const int, const cred_t *const); 57 static int vuidmice_rput(queue_t *const, mblk_t *); 58 static int vuidmice_rsrv(queue_t *const); 59 static int vuidmice_wput(queue_t *const, mblk_t *); 60 static void vuidmice_miocdata(queue_t *const, mblk_t *); 61 static int vuidmice_handle_wheel_resolution_ioctl(queue_t *const, 62 mblk_t *, int); 63 64 static int vuidmice_service_wheel_info(mblk_t *); 65 static int vuidmice_service_wheel_state(queue_t *, mblk_t *, uint_t); 66 67 void VUID_QUEUE(queue_t *const, mblk_t *); 68 int VUID_OPEN(queue_t *const); 69 void VUID_CLOSE(queue_t *const); 70 71 static kmutex_t vuidmice_lock; 72 73 static struct module_info vuidmice_iinfo = { 74 0, 75 VUID_NAME, 76 0, 77 INFPSZ, 78 1000, 79 100 80 }; 81 82 static struct qinit vuidmice_rinit = { 83 vuidmice_rput, 84 vuidmice_rsrv, 85 vuidmice_open, 86 vuidmice_close, 87 NULL, 88 &vuidmice_iinfo, 89 NULL 90 }; 91 92 static struct module_info vuidmice_oinfo = { 93 0, 94 VUID_NAME, 95 0, 96 INFPSZ, 97 1000, 98 100 99 }; 100 101 static struct qinit vuidmice_winit = { 102 vuidmice_wput, 103 NULL, 104 NULL, 105 NULL, 106 NULL, 107 &vuidmice_oinfo, 108 NULL 109 }; 110 111 struct streamtab vuidmice_info = { 112 &vuidmice_rinit, 113 &vuidmice_winit, 114 NULL, 115 NULL 116 }; 117 118 /* 119 * This is the loadable module wrapper. 120 */ 121 122 /* 123 * D_MTQPAIR effectively makes the module single threaded. 124 * There can be only one thread active in the module at any time. 125 * It may be a read or write thread. 126 */ 127 #define VUIDMICE_CONF_FLAG (D_MP | D_MTQPAIR) 128 129 static struct fmodsw fsw = { 130 VUID_NAME, 131 &vuidmice_info, 132 VUIDMICE_CONF_FLAG 133 }; 134 135 static struct modlstrmod modlstrmod = { 136 &mod_strmodops, 137 "mouse events to vuid events", 138 &fsw 139 }; 140 141 /* 142 * Module linkage information for the kernel. 143 */ 144 static struct modlinkage modlinkage = { 145 MODREV_1, 146 &modlstrmod, 147 NULL 148 }; 149 150 static int module_open = 0; /* allow only one open of this module */ 151 152 int 153 _init(void) 154 { 155 register int rc; 156 157 mutex_init(&vuidmice_lock, NULL, MUTEX_DEFAULT, NULL); 158 if ((rc = mod_install(&modlinkage)) != 0) { 159 mutex_destroy(&vuidmice_lock); 160 } 161 return (rc); 162 } 163 164 int 165 _fini(void) 166 { 167 register int rc; 168 169 if ((rc = mod_remove(&modlinkage)) == 0) 170 mutex_destroy(&vuidmice_lock); 171 return (rc); 172 } 173 174 int 175 _info(struct modinfo *modinfop) 176 { 177 return (mod_info(&modlinkage, modinfop)); 178 } 179 180 181 /* ARGSUSED1 */ 182 static int 183 vuidmice_open(queue_t *const qp, const dev_t *const devp, 184 const int oflag, const int sflag, const cred_t *const crp) 185 { 186 mutex_enter(&vuidmice_lock); 187 188 /* Allow only 1 open of this module */ 189 190 if (module_open) { 191 mutex_exit(&vuidmice_lock); 192 return (EBUSY); 193 } 194 195 module_open++; 196 197 /* 198 * If q_ptr already set, we've allocated a struct already 199 */ 200 if (qp->q_ptr != NULL) { 201 module_open--; 202 mutex_exit(&vuidmice_lock); 203 return (0); /* not failure -- just simultaneous open */ 204 } 205 206 /* 207 * Both the read and write queues share the same state structures. 208 */ 209 210 qp->q_ptr = kmem_zalloc(sizeof (struct MouseStateInfo), KM_SLEEP); 211 212 WR(qp)->q_ptr = qp->q_ptr; 213 214 /* initialize state */ 215 STATEP->format = VUID_NATIVE; 216 217 mutex_exit(&vuidmice_lock); 218 219 qprocson(qp); 220 221 #ifdef VUID_OPEN 222 if (VUID_OPEN(qp) != 0) { 223 qprocsoff(qp); 224 225 mutex_enter(&vuidmice_lock); 226 module_open--; 227 kmem_free(qp->q_ptr, sizeof (struct MouseStateInfo)); 228 qp->q_ptr = NULL; 229 mutex_exit(&vuidmice_lock); 230 231 return (ENXIO); 232 } 233 #endif 234 235 return (0); 236 } 237 238 /* ARGSUSED1 */ 239 static int 240 vuidmice_close(queue_t *const qp, const int flag, const cred_t *const crp) 241 { 242 ASSERT(qp != NULL); 243 244 qprocsoff(qp); 245 flushq(qp, FLUSHALL); 246 flushq(OTHERQ(qp), FLUSHALL); 247 248 mutex_enter(&vuidmice_lock); 249 250 #ifdef VUID_CLOSE 251 VUID_CLOSE(qp); 252 #endif 253 254 module_open--; 255 kmem_free(qp->q_ptr, sizeof (struct MouseStateInfo)); 256 qp->q_ptr = NULL; /* Dump the associated state structure */ 257 mutex_exit(&vuidmice_lock); 258 259 return (0); 260 } 261 262 /* 263 * Put procedure for input from driver end of stream (read queue). 264 */ 265 static int 266 vuidmice_rput(queue_t *const qp, mblk_t *mp) 267 { 268 ASSERT(qp != NULL); 269 ASSERT(mp != NULL); 270 271 /* 272 * Handle all the related high priority messages here, hence 273 * should spend the least amount of time here. 274 */ 275 276 if (DB_TYPE(mp) == M_DATA) { 277 if ((int)STATEP->format == VUID_FIRM_EVENT) 278 return (putq(qp, mp)); /* queue message & return */ 279 } else if (DB_TYPE(mp) == M_FLUSH) { 280 if (*mp->b_rptr & FLUSHR) 281 flushq(qp, FLUSHALL); 282 } 283 284 putnext(qp, mp); /* pass it on */ 285 return (0); 286 } 287 288 static int 289 vuidmice_rsrv(queue_t *const qp) 290 { 291 register mblk_t *mp; 292 293 ASSERT(qp != NULL); 294 295 while ((mp = getq(qp)) != NULL) { 296 ASSERT(DB_TYPE(mp) == M_DATA); 297 298 if (!canputnext(qp)) 299 return (putbq(qp, mp)); /* read side is blocked */ 300 301 switch (DB_TYPE(mp)) { 302 case M_DATA: { 303 if ((int)STATEP->format == VUID_FIRM_EVENT) 304 (void) VUID_QUEUE(qp, mp); 305 else 306 (void) putnext(qp, mp); 307 break; 308 } 309 310 default: 311 cmn_err(CE_WARN, 312 "vuidmice_rsrv: bad message type (0x%x)\n", 313 DB_TYPE(mp)); 314 315 (void) putnext(qp, mp); 316 break; 317 } 318 } 319 return (0); 320 } 321 322 /* 323 * Put procedure for write from user end of stream (write queue). 324 */ 325 static int 326 vuidmice_wput(queue_t *const qp, mblk_t *mp) 327 { 328 int error = 0; 329 330 ASSERT(qp != NULL); 331 ASSERT(mp != NULL); 332 333 /* 334 * Handle all the related high priority messages here, hence 335 * should spend the least amount of time here. 336 */ 337 switch (DB_TYPE(mp)) { /* handle hi pri messages here */ 338 case M_FLUSH: 339 if (*mp->b_rptr & FLUSHW) 340 flushq(qp, FLUSHALL); 341 putnext(qp, mp); /* pass it on */ 342 return (0); 343 344 case M_IOCTL: { 345 struct iocblk *iocbp = (struct iocblk *)mp->b_rptr; 346 347 switch (iocbp->ioc_cmd) { 348 case VUIDSFORMAT: 349 350 /* 351 * VUIDSFORMAT is known to the stream head and thus 352 * is guaranteed to be an I_STR ioctl. 353 */ 354 if (iocbp->ioc_count == TRANSPARENT) { 355 miocnak(qp, mp, 0, EINVAL); 356 return (0); 357 } else { 358 int format_type; 359 360 error = miocpullup(mp, sizeof (int)); 361 if (error != 0) { 362 miocnak(qp, mp, 0, error); 363 return (0); 364 } 365 366 format_type = *(int *)mp->b_cont->b_rptr; 367 STATEP->format = (uchar_t)format_type; 368 iocbp->ioc_rval = 0; 369 iocbp->ioc_count = 0; 370 iocbp->ioc_error = 0; 371 mp->b_datap->db_type = M_IOCACK; 372 } 373 374 /* return buffer to pool ASAP */ 375 if (mp->b_cont) { 376 freemsg(mp->b_cont); 377 mp->b_cont = NULL; 378 } 379 380 qreply(qp, mp); 381 return (0); 382 383 case VUIDGFORMAT: 384 385 /* return buffer to pool ASAP */ 386 if (mp->b_cont) { 387 freemsg(mp->b_cont); /* over written below */ 388 mp->b_cont = NULL; 389 } 390 391 /* 392 * VUIDGFORMAT is known to the stream head and thus 393 * is guaranteed to be an I_STR ioctl. 394 */ 395 if (iocbp->ioc_count == TRANSPARENT) { 396 miocnak(qp, mp, 0, EINVAL); 397 return (0); 398 } 399 400 mp->b_cont = allocb(sizeof (int), BPRI_MED); 401 if (mp->b_cont == NULL) { 402 miocnak(qp, mp, 0, EAGAIN); 403 return (0); 404 } 405 406 *(int *)mp->b_cont->b_rptr = (int)STATEP->format; 407 mp->b_cont->b_wptr += sizeof (int); 408 409 iocbp->ioc_count = sizeof (int); 410 mp->b_datap->db_type = M_IOCACK; 411 qreply(qp, mp); 412 return (0); 413 414 case VUID_NATIVE: 415 case VUIDSADDR: 416 case VUIDGADDR: 417 miocnak(qp, mp, 0, ENOTTY); 418 return (0); 419 420 case MSIOBUTTONS: 421 /* return buffer to pool ASAP */ 422 if (mp->b_cont) { 423 freemsg(mp->b_cont); /* over written below */ 424 mp->b_cont = NULL; 425 } 426 427 /* 428 * MSIOBUTTONS is known to streamio.c and this 429 * is assume to be non-I_STR & non-TRANSPARENT ioctl 430 */ 431 432 if (iocbp->ioc_count == TRANSPARENT) { 433 miocnak(qp, mp, 0, EINVAL); 434 return (0); 435 } 436 437 if (STATEP->nbuttons == 0) { 438 miocnak(qp, mp, 0, EINVAL); 439 return (0); 440 } 441 442 mp->b_cont = allocb(sizeof (int), BPRI_MED); 443 if (mp->b_cont == NULL) { 444 miocnak(qp, mp, 0, EAGAIN); 445 return (0); 446 } 447 448 *(int *)mp->b_cont->b_rptr = (int)STATEP->nbuttons; 449 mp->b_cont->b_wptr += sizeof (int); 450 451 iocbp->ioc_count = sizeof (int); 452 mp->b_datap->db_type = M_IOCACK; 453 qreply(qp, mp); 454 return (0); 455 456 /* 457 * New IOCTL support. Since it's explicitly mentioned 458 * that you can't add more ioctls to stream head's 459 * hard coded list, we have to do the transparent 460 * ioctl processing which is not very exciting. 461 */ 462 case VUIDGWHEELCOUNT: 463 case VUIDGWHEELINFO: 464 case VUIDGWHEELSTATE: 465 case VUIDSWHEELSTATE: 466 case MSIOSRESOLUTION: 467 error = vuidmice_handle_wheel_resolution_ioctl(qp, 468 mp, iocbp->ioc_cmd); 469 if (!error) { 470 471 return (0); 472 } else { 473 miocnak(qp, mp, 0, error); 474 475 return (0); 476 } 477 default: 478 putnext(qp, mp); /* nothing to process here */ 479 480 return (0); 481 } 482 483 } /* End of case M_IOCTL */ 484 485 case M_IOCDATA: 486 vuidmice_miocdata(qp, mp); 487 488 return (0); 489 default: 490 putnext(qp, mp); /* pass it on */ 491 return (0); 492 } 493 /*NOTREACHED*/ 494 } 495 496 void 497 VUID_PUTNEXT(queue_t *const qp, uchar_t event_id, uchar_t event_pair_type, 498 uchar_t event_pair, int event_value) 499 { 500 int strikes = 1; 501 mblk_t *bp; 502 Firm_event *fep; 503 504 /* 505 * Give this event 3 chances to allocate blocks, 506 * otherwise discard this mouse event. 3 Strikes and you're out. 507 */ 508 while ((bp = allocb((int)sizeof (Firm_event), BPRI_HI)) == NULL) { 509 if (++strikes > 3) 510 return; 511 drv_usecwait(10); 512 } 513 514 fep = (Firm_event *)bp->b_wptr; 515 fep->id = vuid_id_addr(VKEY_FIRST) | vuid_id_offset(event_id); 516 517 fep->pair_type = event_pair_type; 518 fep->pair = event_pair; 519 fep->value = event_value; 520 uniqtime32(&fep->time); 521 bp->b_wptr += sizeof (Firm_event); 522 523 if (canput(qp->q_next)) 524 putnext(qp, bp); 525 else 526 (void) putbq(qp, bp); /* read side is blocked */ 527 } 528 529 530 /* 531 * vuidmice_miocdata 532 * M_IOCDATA processing for IOCTL's: VUIDGWHEELCOUNT, VUIDGWHEELINFO, 533 * VUIDGWHEELSTATE, VUIDSWHEELSTATE & MSIOSRESOLUTION. 534 */ 535 static void 536 vuidmice_miocdata(queue_t *qp, mblk_t *mp) 537 { 538 struct copyresp *copyresp; 539 struct copyreq *copyreq; 540 struct iocblk *iocbp; 541 mblk_t *ioctmp; 542 mblk_t *datap; 543 Mouse_iocstate_t *Mouseioc; 544 int err = 0; 545 546 547 copyresp = (struct copyresp *)mp->b_rptr; 548 copyreq = (struct copyreq *)mp->b_rptr; 549 iocbp = (struct iocblk *)mp->b_rptr; 550 551 if (copyresp->cp_rval) { 552 err = EAGAIN; 553 554 goto err; 555 } 556 switch (copyresp->cp_cmd) { 557 case VUIDGWHEELCOUNT: 558 mp->b_datap->db_type = M_IOCACK; 559 mp->b_wptr = mp->b_rptr + sizeof (struct iocblk); 560 iocbp->ioc_error = 0; 561 iocbp->ioc_count = 0; 562 iocbp->ioc_rval = 0; 563 if (mp->b_cont != NULL) { 564 freemsg(mp->b_cont); 565 mp->b_cont = NULL; 566 } 567 568 break; 569 case VUIDGWHEELINFO: 570 case VUIDGWHEELSTATE: 571 ioctmp = (mblk_t *)copyresp->cp_private; 572 Mouseioc = (Mouse_iocstate_t *)ioctmp->b_rptr; 573 if (Mouseioc->ioc_state == GETSTRUCT) { 574 if (mp->b_cont == NULL) { 575 err = EINVAL; 576 577 break; 578 } 579 datap = mp->b_cont; 580 if (copyresp->cp_cmd == VUIDGWHEELSTATE) { 581 err = vuidmice_service_wheel_state(qp, datap, 582 VUIDGWHEELSTATE); 583 } else { 584 err = vuidmice_service_wheel_info(datap); 585 } 586 if (err) { 587 break; 588 } 589 590 if (copyresp->cp_cmd == VUIDGWHEELSTATE) { 591 copyreq->cq_size = sizeof (wheel_state); 592 } else { 593 copyreq->cq_size = sizeof (wheel_info); 594 copyreq->cq_flag = 0; 595 } 596 597 copyreq->cq_private = ioctmp; 598 copyreq->cq_addr = Mouseioc->u_addr; 599 Mouseioc->ioc_state = GETRESULT; 600 mp->b_datap->db_type = M_COPYOUT; 601 mp->b_wptr = mp->b_rptr + sizeof (struct copyreq); 602 } else if (Mouseioc->ioc_state == GETRESULT) { 603 freemsg(ioctmp); 604 mp->b_datap->db_type = M_IOCACK; 605 mp->b_wptr = mp->b_rptr + sizeof (struct iocblk); 606 iocbp->ioc_error = 0; 607 iocbp->ioc_count = 0; 608 iocbp->ioc_rval = 0; 609 if (mp->b_cont != NULL) { 610 freemsg(mp->b_cont); 611 mp->b_cont = NULL; 612 } 613 } 614 615 break; 616 case VUIDSWHEELSTATE: 617 case MSIOSRESOLUTION: 618 ioctmp = (mblk_t *)copyresp->cp_private; 619 Mouseioc = (Mouse_iocstate_t *)ioctmp->b_rptr; 620 if (mp->b_cont == NULL) { 621 err = EINVAL; 622 623 break; 624 } 625 datap = mp->b_cont; 626 627 if (copyresp->cp_cmd == VUIDSWHEELSTATE) { 628 err = vuidmice_service_wheel_state(qp, 629 datap, VUIDSWHEELSTATE); 630 } 631 632 if (err) { 633 break; 634 } 635 636 if (mp->b_cont) { 637 freemsg(mp->b_cont); 638 mp->b_cont = (mblk_t *)NULL; 639 } 640 freemsg(ioctmp); 641 iocbp->ioc_count = 0; 642 iocbp->ioc_error = 0; 643 iocbp->ioc_rval = 0; 644 mp->b_datap->db_type = M_IOCACK; 645 646 break; 647 default: 648 err = EINVAL; 649 650 break; 651 } 652 653 err: 654 if (err) { 655 mp->b_datap->db_type = M_IOCNAK; 656 if (mp->b_cont) { 657 freemsg(mp->b_cont); 658 mp->b_cont = (mblk_t *)NULL; 659 } 660 if (copyresp->cp_private) { 661 freemsg((mblk_t *)copyresp->cp_private); 662 copyresp->cp_private = (mblk_t *)NULL; 663 } 664 iocbp->ioc_count = 0; 665 iocbp->ioc_error = err; 666 } 667 qreply(qp, mp); 668 } 669 670 671 /* 672 * vuidmice_handle_wheel_resolution_ioctl 673 * Handle wheel mouse and MSIOSRESOLUTION ioctls. 674 * 675 * Here we also support non-transparent way of these ioctls 676 * just like usb mouse driver does, so the consms module is 677 * very simple to deal with these ioctls. 678 */ 679 static int 680 vuidmice_handle_wheel_resolution_ioctl(queue_t *qp, mblk_t *mp, int cmd) 681 { 682 int err = 0; 683 Mouse_iocstate_t *Mouseioc; 684 struct copyreq *copyreq; 685 mblk_t *ioctmp; 686 mblk_t *datap; 687 688 struct iocblk *iocbp = (struct iocblk *)mp->b_rptr; 689 690 if (iocbp->ioc_count == TRANSPARENT) { 691 copyreq = (struct copyreq *)mp->b_rptr; 692 if (mp->b_cont == NULL) { 693 err = EINVAL; 694 695 return (err); 696 } 697 copyreq->cq_addr = 698 (caddr_t)*((caddr_t *)mp->b_cont->b_rptr); 699 switch (cmd) { 700 case VUIDGWHEELCOUNT: 701 copyreq->cq_size = sizeof (int); 702 mp->b_datap->db_type = M_COPYOUT; 703 mp->b_wptr = mp->b_rptr 704 + sizeof (struct copyreq); 705 freemsg(mp->b_cont); 706 datap = allocb(sizeof (int), BPRI_HI); 707 *((int *)datap->b_wptr) = 708 STATEP->vuid_mouse_mode; 709 datap->b_wptr += sizeof (int); 710 mp->b_cont = datap; 711 qreply(qp, mp); 712 713 return (err); 714 case VUIDGWHEELINFO: 715 copyreq->cq_size = sizeof (wheel_info); 716 break; 717 718 case VUIDSWHEELSTATE: 719 case VUIDGWHEELSTATE: 720 copyreq->cq_size = sizeof (wheel_state); 721 break; 722 723 case MSIOSRESOLUTION: 724 copyreq->cq_size = sizeof (Ms_screen_resolution); 725 break; 726 } 727 728 if ((ioctmp = (mblk_t *)allocb(sizeof (Mouse_iocstate_t), 729 BPRI_MED)) == NULL) { 730 err = EAGAIN; 731 732 return (err); 733 } 734 copyreq->cq_private = ioctmp; 735 Mouseioc = (Mouse_iocstate_t *)ioctmp->b_rptr; 736 Mouseioc->ioc_state = GETSTRUCT; 737 Mouseioc->u_addr = copyreq->cq_addr; 738 ioctmp->b_wptr = ioctmp->b_rptr + sizeof (Mouse_iocstate_t); 739 copyreq->cq_flag = 0; 740 mp->b_datap->db_type = M_COPYIN; 741 freemsg(mp->b_cont); 742 mp->b_cont = (mblk_t *)NULL; 743 mp->b_wptr = mp->b_rptr + sizeof (struct copyreq); 744 qreply(qp, mp); 745 746 return (err); 747 } else { 748 switch (cmd) { 749 case VUIDGWHEELCOUNT: 750 if (mp->b_cont) { 751 freemsg(mp->b_cont); 752 mp->b_cont = NULL; 753 } 754 datap = allocb(sizeof (int), BPRI_HI); 755 *((int *)datap->b_wptr) = 756 STATEP->vuid_mouse_mode; 757 datap->b_wptr += sizeof (int); 758 mp->b_cont = datap; 759 break; 760 761 case VUIDGWHEELINFO: 762 if (mp->b_cont == NULL || 763 iocbp->ioc_count != sizeof (wheel_info)) { 764 err = EINVAL; 765 break; 766 } 767 datap = mp->b_cont; 768 err = vuidmice_service_wheel_info(datap); 769 break; 770 771 case VUIDSWHEELSTATE: 772 case VUIDGWHEELSTATE: 773 if (mp->b_cont == NULL || 774 iocbp->ioc_count != sizeof (wheel_state)) { 775 err = EINVAL; 776 break; 777 } 778 datap = mp->b_cont; 779 err = vuidmice_service_wheel_state(qp, datap, cmd); 780 break; 781 782 case MSIOSRESOLUTION: 783 /* 784 * Now we just make Xserver and 785 * the virtual mouse happy. Of course, 786 * the screen resolution value may 787 * be used later for absolute PS/2 mouse. 788 */ 789 err = 0; 790 break; 791 } 792 793 if (!err) { 794 mp->b_datap->db_type = M_IOCACK; 795 iocbp->ioc_rval = 0; 796 iocbp->ioc_error = 0; 797 qreply(qp, mp); 798 } 799 800 return (err); 801 } 802 } 803 804 static int 805 vuidmice_service_wheel_info(register mblk_t *datap) 806 { 807 wheel_info *wi; 808 int err = 0; 809 810 wi = (wheel_info *)datap->b_rptr; 811 if (wi->vers != VUID_WHEEL_INFO_VERS) { 812 err = EINVAL; 813 814 return (err); 815 } 816 817 if (wi->id > (VUIDMICE_NUM_WHEELS - 1)) { 818 err = EINVAL; 819 820 return (err); 821 } 822 wi->format = (wi->id == 823 VUIDMICE_VERTICAL_WHEEL_ID) ? 824 VUID_WHEEL_FORMAT_VERTICAL : 825 VUID_WHEEL_FORMAT_HORIZONTAL; 826 827 return (err); 828 } 829 830 831 static int 832 vuidmice_service_wheel_state(register queue_t *qp, 833 register mblk_t *datap, 834 register uint_t cmd) 835 { 836 wheel_state *ws; 837 uint_t err = 0; 838 839 ws = (wheel_state *)datap->b_rptr; 840 if (ws->vers != VUID_WHEEL_STATE_VERS) { 841 err = EINVAL; 842 843 return (err); 844 } 845 846 if (ws->id > (VUIDMICE_NUM_WHEELS - 1)) { 847 err = EINVAL; 848 849 return (err); 850 } 851 852 switch (cmd) { 853 case VUIDGWHEELSTATE: 854 ws->stateflags = 855 (STATEP->wheel_state_bf >> ws->id) & 1; 856 857 break; 858 case VUIDSWHEELSTATE: 859 STATEP->wheel_state_bf = (ws->stateflags << ws->id) | 860 (STATEP->wheel_state_bf & ~(1 << ws->id)); 861 862 break; 863 default: 864 err = EINVAL; 865 866 return (err); 867 } 868 869 return (err); 870 } 871