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