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 2008 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 27 /* 28 * Console mouse driver for Sun. 29 * The console "zs" port is linked under us, with the "ms" module pushed 30 * on top of it. 31 * 32 * This device merely provides a way to have "/dev/mouse" automatically 33 * have the "ms" module present. Due to problems with the way the "specfs" 34 * file system works, you can't use an indirect device (a "stat" on 35 * "/dev/mouse" won't get the right snode, so you won't get the right time 36 * of last access), and due to problems with the kernel window system code, 37 * you can't use a "cons"-like driver ("/dev/mouse" won't be a streams device, 38 * even though operations on it get turned into operations on the real stream). 39 * 40 * This module supports multiple mice connected to the system at the same time. 41 * All the mice are linked under consms, and act as a mouse with replicated 42 * clicks. Only USB and PS/2 mouse are supported to be virtual mouse now. 43 */ 44 45 #include <sys/types.h> 46 #include <sys/param.h> 47 #include <sys/stropts.h> 48 #include <sys/stream.h> 49 #include <sys/strsun.h> 50 #include <sys/conf.h> 51 #include <sys/stat.h> 52 #include <sys/errno.h> 53 #include <sys/modctl.h> 54 #include <sys/consdev.h> 55 #include <sys/ddi.h> 56 #include <sys/sunddi.h> 57 #include <sys/kstat.h> 58 #include <sys/vuid_wheel.h> 59 #include <sys/msio.h> 60 #include <sys/consms.h> 61 62 static void consms_plink(queue_t *, mblk_t *); 63 static int consms_punlink(queue_t *, mblk_t *); 64 static void 65 consms_lqs_ack_complete(consms_lq_t *, mblk_t *); 66 static void consms_add_lq(consms_lq_t *); 67 static void consms_check_caps(void); 68 static mblk_t *consms_new_firm_event(ushort_t, int); 69 70 static void consms_mux_max_wheel_report(mblk_t *); 71 static void consms_mux_cache_states(mblk_t *); 72 static void consms_mux_link_msg(consms_msg_t *); 73 static consms_msg_t *consms_mux_unlink_msg(uint_t); 74 static consms_msg_t *consms_mux_find_msg(uint_t); 75 76 static void consms_mux_iocdata(consms_msg_t *, mblk_t *); 77 static void consms_mux_disp_iocdata(consms_response_t *, mblk_t *); 78 static int consms_mux_disp_ioctl(queue_t *, mblk_t *); 79 static void consms_mux_copyreq(queue_t *, consms_msg_t *, mblk_t *); 80 static void consms_mux_ack(consms_msg_t *, mblk_t *); 81 static void consms_mux_disp_data(mblk_t *); 82 83 84 static int consmsopen(queue_t *, dev_t *, int, int, cred_t *); 85 static int consmsclose(queue_t *, int, cred_t *); 86 static int consmsuwput(queue_t *, mblk_t *); 87 static int consmslrput(queue_t *, mblk_t *); 88 static int consmslwserv(queue_t *); 89 90 static struct module_info consmsm_info = { 91 0, 92 "consms", 93 0, 94 1024, 95 2048, 96 128 97 }; 98 99 static struct qinit consmsurinit = { 100 putq, 101 (int (*)())NULL, 102 consmsopen, 103 consmsclose, 104 (int (*)())NULL, 105 &consmsm_info, 106 NULL 107 }; 108 109 static struct qinit consmsuwinit = { 110 consmsuwput, 111 (int (*)())NULL, 112 consmsopen, 113 consmsclose, 114 (int (*)())NULL, 115 &consmsm_info, 116 NULL 117 }; 118 119 static struct qinit consmslrinit = { 120 consmslrput, 121 (int (*)())NULL, 122 (int (*)())NULL, 123 (int (*)())NULL, 124 (int (*)())NULL, 125 &consmsm_info, 126 NULL 127 }; 128 129 static struct qinit consmslwinit = { 130 putq, 131 consmslwserv, 132 (int (*)())NULL, 133 (int (*)())NULL, 134 (int (*)())NULL, 135 &consmsm_info, 136 NULL 137 }; 138 139 static struct streamtab consms_str_info = { 140 &consmsurinit, 141 &consmsuwinit, 142 &consmslrinit, 143 &consmslwinit, 144 }; 145 146 static void consmsioctl(queue_t *q, mblk_t *mp); 147 static int consms_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 148 void **result); 149 static int consms_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); 150 static int consms_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); 151 static int consms_kstat_update(kstat_t *, int); 152 153 /* 154 * Module global data are protected by the per-module inner perimeter. 155 */ 156 static queue_t *upperqueue; /* regular mouse queue above us */ 157 static dev_info_t *consms_dip; /* private copy of devinfo pointer */ 158 static long consms_idle_stamp; /* seconds tstamp of latest mouse op */ 159 160 static consms_msg_t *consms_mux_msg; /* ioctl messages being processed */ 161 static kmutex_t consms_msg_lock; /* protect ioctl messages list */ 162 163 static consms_state_t consms_state; /* the global virtual mouse state */ 164 static kmutex_t consmslock; 165 166 167 /* 168 * Normally, kstats of type KSTAT_TYPE_NAMED have multiple elements. In 169 * this case we use this type for a single element because the ioctl code 170 * for it knows how to handle mixed kernel/user data models. Also, it 171 * will be easier to add new statistics later. 172 */ 173 static struct { 174 kstat_named_t idle_sec; /* seconds since last user op */ 175 } consms_kstat = { 176 { "idle_sec", KSTAT_DATA_LONG, } 177 }; 178 179 180 static struct cb_ops cb_consms_ops = { 181 nulldev, /* cb_open */ 182 nulldev, /* cb_close */ 183 nodev, /* cb_strategy */ 184 nodev, /* cb_print */ 185 nodev, /* cb_dump */ 186 nodev, /* cb_read */ 187 nodev, /* cb_write */ 188 nodev, /* cb_ioctl */ 189 nodev, /* cb_devmap */ 190 nodev, /* cb_mmap */ 191 nodev, /* cb_segmap */ 192 nochpoll, /* cb_chpoll */ 193 ddi_prop_op, /* cb_prop_op */ 194 &consms_str_info, /* cb_stream */ 195 D_MP | D_MTPERMOD /* cb_flag */ 196 }; 197 198 static struct dev_ops consms_ops = { 199 DEVO_REV, /* devo_rev */ 200 0, /* devo_refcnt */ 201 consms_info, /* devo_getinfo */ 202 nulldev, /* devo_identify */ 203 nulldev, /* devo_probe */ 204 consms_attach, /* devo_attach */ 205 consms_detach, /* devo_detach */ 206 nodev, /* devo_reset */ 207 &(cb_consms_ops), /* devo_cb_ops */ 208 (struct bus_ops *)NULL, /* devo_bus_ops */ 209 NULL, /* devo_power */ 210 ddi_quiesce_not_needed, /* devo_quiesce */ 211 }; 212 213 214 /* 215 * Module linkage information for the kernel. 216 */ 217 218 static struct modldrv modldrv = { 219 &mod_driverops, /* Type of module. This one is a pseudo driver */ 220 "Mouse Driver for Sun 'consms' 5.57", 221 &consms_ops, /* driver ops */ 222 }; 223 224 static struct modlinkage modlinkage = { 225 MODREV_1, 226 (void *)&modldrv, 227 NULL 228 }; 229 230 int 231 _init(void) 232 { 233 int error; 234 235 mutex_init(&consmslock, NULL, MUTEX_DRIVER, NULL); 236 mutex_init(&consms_msg_lock, NULL, MUTEX_DRIVER, NULL); 237 error = mod_install(&modlinkage); 238 if (error != 0) { 239 mutex_destroy(&consmslock); 240 mutex_destroy(&consms_msg_lock); 241 } 242 return (error); 243 } 244 245 int 246 _fini(void) 247 { 248 int error; 249 250 error = mod_remove(&modlinkage); 251 if (error != 0) 252 return (error); 253 mutex_destroy(&consmslock); 254 mutex_destroy(&consms_msg_lock); 255 return (0); 256 } 257 258 int 259 _info(struct modinfo *modinfop) 260 { 261 return (mod_info(&modlinkage, modinfop)); 262 } 263 264 static int 265 consms_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 266 { 267 kstat_t *ksp; 268 269 switch (cmd) { 270 case DDI_ATTACH: 271 break; 272 default: 273 return (DDI_FAILURE); 274 } 275 276 if (ddi_create_minor_node(devi, "mouse", S_IFCHR, 277 0, DDI_PSEUDO, 0) == DDI_FAILURE) { 278 ddi_remove_minor_node(devi, NULL); 279 return (-1); 280 } 281 consms_dip = devi; 282 (void) ddi_prop_update_int(DDI_DEV_T_NONE, devi, DDI_NO_AUTODETACH, 1); 283 284 ksp = kstat_create("consms", 0, "activity", "misc", KSTAT_TYPE_NAMED, 285 sizeof (consms_kstat) / sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL); 286 if (ksp) { 287 ksp->ks_data = (void *)&consms_kstat; 288 ksp->ks_update = consms_kstat_update; 289 kstat_install(ksp); 290 consms_idle_stamp = gethrestime_sec(); /* initial value */ 291 } 292 293 consms_state.consms_lqs = NULL; 294 consms_state.consms_num_lqs = 0; 295 296 /* default consms state values */ 297 consms_state.consms_vuid_format = VUID_FIRM_EVENT; 298 consms_state.consms_num_buttons = 0; 299 consms_state.consms_num_wheels = 0; 300 consms_state.consms_wheel_state_bf |= VUID_WHEEL_STATE_ENABLED; 301 consms_state.consms_ms_parms.jitter_thresh = 302 CONSMS_PARMS_DEFAULT_JITTER; 303 consms_state.consms_ms_parms.speed_limit = 304 CONSMS_PARMS_DEFAULT_SPEED_LIMIT; 305 consms_state.consms_ms_parms.speed_law = 306 CONSMS_PARMS_DEFAULT_SPEED_LAW; 307 consms_state.consms_ms_sr.height = CONSMS_SR_DEFAULT_HEIGHT; 308 consms_state.consms_ms_sr.width = CONSMS_SR_DEFAULT_WIDTH; 309 310 return (DDI_SUCCESS); 311 } 312 313 /*ARGSUSED*/ 314 static int 315 consms_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 316 { 317 switch (cmd) { 318 case DDI_DETACH: 319 default: 320 return (DDI_FAILURE); 321 } 322 } 323 324 /*ARGSUSED*/ 325 static int 326 consms_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 327 void **result) 328 { 329 int error; 330 331 switch (infocmd) { 332 case DDI_INFO_DEVT2DEVINFO: 333 if (consms_dip == NULL) { 334 error = DDI_FAILURE; 335 } else { 336 *result = (void *) consms_dip; 337 error = DDI_SUCCESS; 338 } 339 break; 340 case DDI_INFO_DEVT2INSTANCE: 341 *result = (void *)0; 342 error = DDI_SUCCESS; 343 break; 344 default: 345 error = DDI_FAILURE; 346 } 347 return (error); 348 } 349 350 351 /*ARGSUSED*/ 352 static int 353 consmsopen(queue_t *q, dev_t *devp, int flag, int sflag, cred_t *crp) 354 { 355 upperqueue = q; 356 qprocson(q); 357 return (0); 358 } 359 360 /*ARGSUSED*/ 361 static int 362 consmsclose(queue_t *q, int flag, cred_t *crp) 363 { 364 qprocsoff(q); 365 upperqueue = NULL; 366 return (0); 367 } 368 369 /* 370 * Put procedure for upper write queue. 371 */ 372 static int 373 consmsuwput(queue_t *q, mblk_t *mp) 374 { 375 struct iocblk *iocbp = (struct iocblk *)mp->b_rptr; 376 consms_msg_t *msg; 377 int error = 0; 378 379 switch (mp->b_datap->db_type) { 380 381 case M_IOCTL: 382 consmsioctl(q, mp); 383 break; 384 385 case M_FLUSH: 386 if (*mp->b_rptr & FLUSHW) 387 flushq(q, FLUSHDATA); 388 if (*mp->b_rptr & FLUSHR) 389 flushq(RD(q), FLUSHDATA); 390 if (consms_state.consms_num_lqs > 0) { 391 consms_mux_disp_data(mp); 392 } else { 393 /* 394 * No lower queue; just reflect this back upstream. 395 */ 396 *mp->b_rptr &= ~FLUSHW; 397 if (*mp->b_rptr & FLUSHR) 398 qreply(q, mp); 399 else 400 freemsg(mp); 401 } 402 break; 403 404 case M_DATA: 405 if (consms_state.consms_num_lqs > 0) { 406 consms_mux_disp_data(mp); 407 } else { 408 freemsg(mp); 409 } 410 break; 411 412 case M_IOCDATA: 413 if ((msg = consms_mux_find_msg(iocbp->ioc_id)) != NULL) { 414 consms_mux_iocdata(msg, mp); 415 } else { 416 error = EINVAL; 417 } 418 break; 419 420 default: 421 error = EINVAL; 422 break; 423 } 424 425 if (error) { 426 /* 427 * Pass an error message up. 428 */ 429 mp->b_datap->db_type = M_ERROR; 430 if (mp->b_cont) { 431 freemsg(mp->b_cont); 432 mp->b_cont = NULL; 433 } 434 mp->b_rptr = mp->b_datap->db_base; 435 mp->b_wptr = mp->b_rptr + sizeof (char); 436 *mp->b_rptr = (char)error; 437 qreply(q, mp); 438 } 439 return (0); 440 } 441 442 static void 443 consmsioctl(queue_t *q, mblk_t *mp) 444 { 445 struct iocblk *iocp; 446 int error; 447 mblk_t *datap; 448 449 iocp = (struct iocblk *)mp->b_rptr; 450 451 switch (iocp->ioc_cmd) { 452 453 case I_LINK: 454 case I_PLINK: 455 mutex_enter(&consmslock); 456 consms_plink(q, mp); 457 mutex_exit(&consmslock); 458 return; 459 460 case I_UNLINK: 461 case I_PUNLINK: 462 mutex_enter(&consmslock); 463 if ((error = consms_punlink(q, mp)) != 0) { 464 mutex_exit(&consmslock); 465 miocnak(q, mp, 0, error); 466 return; 467 } 468 mutex_exit(&consmslock); 469 iocp->ioc_count = 0; 470 break; 471 472 case MSIOBUTTONS: /* query the number of buttons */ 473 if ((consms_state.consms_num_lqs <= 0) || 474 ((datap = allocb(sizeof (int), BPRI_HI)) == NULL)) { 475 miocnak(q, mp, 0, ENOMEM); 476 return; 477 } 478 *(int *)datap->b_wptr = consms_state.consms_num_buttons; 479 datap->b_wptr += sizeof (int); 480 if (mp->b_cont) { 481 freemsg(mp->b_cont); 482 } 483 mp->b_cont = datap; 484 iocp->ioc_count = sizeof (int); 485 break; 486 487 default: 488 /* 489 * Pass this through, if there's something to pass it 490 * through to; otherwise, reject it. 491 */ 492 if (consms_state.consms_num_lqs <= 0) { 493 miocnak(q, mp, 0, EINVAL); 494 return; 495 } 496 if ((error = consms_mux_disp_ioctl(q, mp)) != 0) 497 miocnak(q, mp, 0, error); 498 499 return; 500 } 501 502 /* 503 * Common exit path for calls that return a positive 504 * acknowledgment with a return value of 0. 505 */ 506 miocack(q, mp, iocp->ioc_count, 0); 507 } 508 509 /* 510 * Service procedure for lower write queue. 511 * Puts things on the queue below us, if it lets us. 512 */ 513 static int 514 consmslwserv(queue_t *q) 515 { 516 mblk_t *mp; 517 518 while (canput(q->q_next) && (mp = getq(q)) != NULL) 519 putnext(q, mp); 520 return (0); 521 } 522 523 /* 524 * Put procedure for lower read queue. 525 */ 526 static int 527 consmslrput(queue_t *q, mblk_t *mp) 528 { 529 struct iocblk *iocbp = (struct iocblk *)mp->b_rptr; 530 struct copyreq *copyreq = (struct copyreq *)mp->b_rptr; 531 consms_msg_t *msg; 532 consms_lq_t *lq = (consms_lq_t *)q->q_ptr; 533 534 ASSERT(lq != NULL); 535 536 switch (mp->b_datap->db_type) { 537 case M_FLUSH: 538 if (*mp->b_rptr & FLUSHW) 539 flushq(WR(q), FLUSHDATA); 540 if (*mp->b_rptr & FLUSHR) 541 flushq(q, FLUSHDATA); 542 if (upperqueue != NULL) 543 putnext(upperqueue, mp); /* pass it through */ 544 else { 545 /* 546 * No upper queue; just reflect this back downstream. 547 */ 548 *mp->b_rptr &= ~FLUSHR; 549 if (*mp->b_rptr & FLUSHW) 550 qreply(q, mp); 551 else 552 freemsg(mp); 553 } 554 break; 555 556 case M_DATA: 557 if (upperqueue != NULL) 558 putnext(upperqueue, mp); 559 else 560 freemsg(mp); 561 consms_idle_stamp = gethrestime_sec(); 562 break; 563 564 case M_IOCACK: 565 case M_IOCNAK: 566 /* 567 * First, check to see if this device 568 * is still being initialized. 569 */ 570 if (lq->lq_ioc_reply_func != NULL) { 571 mutex_enter(&consmslock); 572 lq->lq_ioc_reply_func(lq, mp); 573 mutex_exit(&consmslock); 574 freemsg(mp); 575 break; 576 } 577 578 /* 579 * This is normal ioctl ack for upper layer. 580 */ 581 if ((msg = consms_mux_find_msg(iocbp->ioc_id)) != NULL) { 582 consms_mux_ack(msg, mp); 583 } else { 584 freemsg(mp); 585 } 586 consms_idle_stamp = gethrestime_sec(); 587 break; 588 589 case M_COPYIN: 590 case M_COPYOUT: 591 if ((msg = consms_mux_find_msg(copyreq->cq_id)) != NULL) { 592 consms_mux_copyreq(q, msg, mp); 593 } else 594 freemsg(mp); 595 consms_idle_stamp = gethrestime_sec(); 596 break; 597 598 case M_ERROR: 599 case M_HANGUP: 600 default: 601 freemsg(mp); /* anything useful here? */ 602 break; 603 } 604 return (0); 605 } 606 607 /* ARGSUSED */ 608 static int 609 consms_kstat_update(kstat_t *ksp, int rw) 610 { 611 if (rw == KSTAT_WRITE) 612 return (EACCES); 613 614 consms_kstat.idle_sec.value.l = gethrestime_sec() - consms_idle_stamp; 615 return (0); 616 } 617 618 /*ARGSUSED*/ 619 static int 620 consms_punlink(queue_t *q, mblk_t *mp) 621 { 622 struct linkblk *linkp; 623 consms_lq_t *lq; 624 consms_lq_t *prev_lq; 625 626 ASSERT(MUTEX_HELD(&consmslock)); 627 628 linkp = (struct linkblk *)mp->b_cont->b_rptr; 629 630 prev_lq = NULL; 631 for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) { 632 if (lq->lq_queue == linkp->l_qbot) { 633 if (prev_lq) 634 prev_lq->lq_next = lq->lq_next; 635 else 636 consms_state.consms_lqs = lq->lq_next; 637 kmem_free(lq, sizeof (*lq)); 638 consms_state.consms_num_lqs--; 639 640 /* 641 * Check to see if mouse capabilities 642 * have changed. 643 */ 644 consms_check_caps(); 645 646 return (0); 647 } 648 prev_lq = lq; 649 } 650 651 return (EINVAL); 652 } 653 654 /* 655 * Link a specific mouse into our mouse list. 656 */ 657 static void 658 consms_plink(queue_t *q, mblk_t *mp) 659 { 660 struct linkblk *linkp; 661 consms_lq_t *lq; 662 queue_t *lowq; 663 664 ASSERT(MUTEX_HELD(&consmslock)); 665 666 linkp = (struct linkblk *)mp->b_cont->b_rptr; 667 lowq = linkp->l_qbot; 668 669 lq = kmem_zalloc(sizeof (*lq), KM_SLEEP); 670 671 lowq->q_ptr = (void *)lq; 672 OTHERQ(lowq)->q_ptr = (void *)lq; 673 lq->lq_queue = lowq; 674 lq->lq_pending_plink = mp; 675 lq->lq_pending_queue = q; 676 677 /* 678 * Set the number of buttons to 3 by default 679 * in case the following MSIOBUTTONS ioctl fails. 680 */ 681 lq->lq_num_buttons = 3; 682 683 /* 684 * Begin to initialize this mouse. 685 */ 686 lq->lq_state = LQS_START; 687 consms_lqs_ack_complete(lq, NULL); 688 } 689 690 /* 691 * Initialize the newly hotplugged-in mouse, 692 * e.g. get the number of buttons, set event 693 * format. Then we add it into our list. 694 */ 695 static void 696 consms_lqs_ack_complete(consms_lq_t *lq, mblk_t *mp) 697 { 698 mblk_t *req = NULL; 699 boolean_t skipped = B_FALSE; 700 wheel_state *ws; 701 Ms_screen_resolution *sr; 702 Ms_parms *params; 703 704 ASSERT(MUTEX_HELD(&consmslock)); 705 706 /* 707 * We try each ioctl even if the previous one fails 708 * until we reach LQS_DONE, and then add this lq 709 * into our lq list. 710 * 711 * If the message allocation fails, we skip this ioctl, 712 * set skipped flag to B_TRUE in order to skip the ioctl 713 * result, then we try next ioctl, go to next state. 714 */ 715 while ((lq->lq_state < LQS_DONE) && (req == NULL)) { 716 switch (lq->lq_state) { 717 case LQS_START: 718 /* 719 * First, issue MSIOBUTTONS ioctl 720 * to get the number of buttons. 721 */ 722 req = mkiocb(MSIOBUTTONS); 723 if (req && ((req->b_cont = allocb(sizeof (int), 724 BPRI_MED)) == NULL)) { 725 freemsg(req); 726 req = NULL; 727 } 728 if (req == NULL) 729 skipped = B_TRUE; 730 lq->lq_state++; 731 break; 732 733 case LQS_BUTTON_COUNT_PENDING: 734 if (!skipped && mp && mp->b_cont && 735 (mp->b_datap->db_type == M_IOCACK)) 736 lq->lq_num_buttons = 737 *(int *)mp->b_cont->b_rptr; 738 739 /* 740 * Second, issue VUIDGWHEELCOUNT ioctl 741 * to get the count of wheels. 742 */ 743 req = mkiocb(VUIDGWHEELCOUNT); 744 if (req && ((req->b_cont = allocb(sizeof (int), 745 BPRI_MED)) == NULL)) { 746 freemsg(req); 747 req = NULL; 748 } 749 if (req == NULL) 750 skipped = B_TRUE; 751 lq->lq_state++; 752 break; 753 754 case LQS_WHEEL_COUNT_PENDING: 755 if (!skipped && mp && mp->b_cont && 756 (mp->b_datap->db_type == M_IOCACK)) 757 lq->lq_num_wheels = 758 *(int *)mp->b_cont->b_rptr; 759 760 /* 761 * Third, issue VUIDSFORMAT ioctl 762 * to set the event format. 763 */ 764 req = mkiocb(VUIDSFORMAT); 765 if (req && ((req->b_cont = allocb(sizeof (int), 766 BPRI_MED)) == NULL)) { 767 freemsg(req); 768 req = NULL; 769 } 770 if (req) { 771 *(int *)req->b_cont->b_wptr = 772 consms_state.consms_vuid_format; 773 req->b_cont->b_wptr += sizeof (int); 774 } 775 lq->lq_state++; 776 break; 777 778 case LQS_SET_VUID_FORMAT_PENDING: 779 /* 780 * Fourth, issue VUIDSWHEELSTATE ioctl 781 * to set the wheel state (enable or disable). 782 */ 783 req = mkiocb(VUIDSWHEELSTATE); 784 if (req && ((req->b_cont = allocb(sizeof (wheel_state), 785 BPRI_MED)) == NULL)) { 786 freemsg(req); 787 req = NULL; 788 } 789 if (req) { 790 ws = (wheel_state *)req->b_cont->b_wptr; 791 ws->vers = VUID_WHEEL_STATE_VERS; 792 ws->id = 0; /* the first wheel */ 793 ws->stateflags = 794 consms_state.consms_wheel_state_bf & 1; 795 req->b_cont->b_wptr += sizeof (wheel_state); 796 } 797 lq->lq_state++; 798 break; 799 800 case LQS_SET_WHEEL_STATE_PENDING: 801 /* 802 * Fifth, issue MSIOSETPARMS ioctl 803 * to set the parameters for USB mouse. 804 */ 805 req = mkiocb(MSIOSETPARMS); 806 if (req && ((req->b_cont = allocb(sizeof (Ms_parms), 807 BPRI_MED)) == NULL)) { 808 freemsg(req); 809 req = NULL; 810 } 811 if (req) { 812 params = (Ms_parms *)req->b_cont->b_wptr; 813 *params = consms_state.consms_ms_parms; 814 req->b_cont->b_wptr += sizeof (Ms_parms); 815 } 816 lq->lq_state++; 817 break; 818 819 case LQS_SET_PARMS_PENDING: 820 /* 821 * Sixth, issue MSIOSRESOLUTION ioctl 822 * to set the screen resolution for absolute mouse. 823 */ 824 req = mkiocb(MSIOSRESOLUTION); 825 if (req && ((req->b_cont = 826 allocb(sizeof (Ms_screen_resolution), 827 BPRI_MED)) == NULL)) { 828 freemsg(req); 829 req = NULL; 830 } 831 if (req) { 832 sr = 833 (Ms_screen_resolution *)req->b_cont->b_wptr; 834 *sr = consms_state.consms_ms_sr; 835 req->b_cont->b_wptr += 836 sizeof (Ms_screen_resolution); 837 } 838 lq->lq_state++; 839 break; 840 841 case LQS_SET_RESOLUTION_PENDING: 842 /* 843 * All jobs are done, lq->lq_state is turned into 844 * LQS_DONE, and this lq is added into our list. 845 */ 846 lq->lq_state++; 847 consms_add_lq(lq); 848 break; 849 } 850 } 851 852 if (lq->lq_state < LQS_DONE) { 853 lq->lq_ioc_reply_func = consms_lqs_ack_complete; 854 (void) putq(lq->lq_queue, req); 855 } 856 } 857 858 /* 859 * Add this specific lq into our list, finally reply 860 * the previous pending I_PLINK ioctl. Also check to 861 * see if mouse capabilities have changed, and send 862 * a dynamical notification event to upper layer if 863 * necessary. 864 */ 865 static void 866 consms_add_lq(consms_lq_t *lq) 867 { 868 struct iocblk *iocp; 869 870 ASSERT(MUTEX_HELD(&consmslock)); 871 872 lq->lq_ioc_reply_func = NULL; 873 iocp = (struct iocblk *)lq->lq_pending_plink->b_rptr; 874 iocp->ioc_error = 0; 875 iocp->ioc_count = 0; 876 iocp->ioc_rval = 0; 877 lq->lq_pending_plink->b_datap->db_type = M_IOCACK; 878 879 /* Reply to the I_PLINK ioctl. */ 880 qreply(lq->lq_pending_queue, lq->lq_pending_plink); 881 882 lq->lq_pending_plink = NULL; 883 lq->lq_pending_queue = NULL; 884 885 /* 886 * Add this lq into list. 887 */ 888 consms_state.consms_num_lqs++; 889 890 lq->lq_next = consms_state.consms_lqs; 891 consms_state.consms_lqs = lq; 892 893 /* 894 * Check to see if mouse capabilities 895 * have changed. 896 */ 897 consms_check_caps(); 898 899 } 900 901 902 static void 903 consms_check_caps(void) 904 { 905 consms_lq_t *lq; 906 int max_buttons = 0; 907 int max_wheels = 0; 908 mblk_t *mp; 909 910 /* 911 * Check to see if the number of buttons 912 * and the number of wheels have changed. 913 */ 914 for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) { 915 max_buttons = CONSMS_MAX(max_buttons, lq->lq_num_buttons); 916 max_wheels = CONSMS_MAX(max_wheels, lq->lq_num_wheels); 917 } 918 919 if (max_buttons != consms_state.consms_num_buttons) { 920 /* 921 * Since the number of buttons have changed, 922 * send a MOUSE_CAP_CHANGE_NUM_BUT dynamical 923 * notification event to upper layer. 924 */ 925 consms_state.consms_num_buttons = max_buttons; 926 if (upperqueue != NULL) { 927 if ((mp = consms_new_firm_event( 928 MOUSE_CAP_CHANGE_NUM_BUT, 929 consms_state.consms_num_buttons)) != NULL) { 930 putnext(upperqueue, mp); 931 } 932 } 933 } 934 935 if (max_wheels != consms_state.consms_num_wheels) { 936 /* 937 * Since the number of wheels have changed, 938 * send a MOUSE_CAP_CHANGE_NUM_WHEEL dynamical 939 * notification event to upper layer. 940 */ 941 consms_state.consms_num_wheels = max_wheels; 942 if (upperqueue != NULL) { 943 if ((mp = consms_new_firm_event( 944 MOUSE_CAP_CHANGE_NUM_WHEEL, 945 consms_state.consms_num_wheels)) != NULL) { 946 putnext(upperqueue, mp); 947 } 948 } 949 } 950 } 951 952 /* 953 * Allocate a dynamical notification event. 954 */ 955 static mblk_t * 956 consms_new_firm_event(ushort_t id, int value) 957 { 958 Firm_event *fep; 959 mblk_t *tmp; 960 961 if ((tmp = allocb(sizeof (Firm_event), BPRI_HI)) != NULL) { 962 fep = (Firm_event *)tmp->b_wptr; 963 fep->id = id; 964 fep->pair_type = FE_PAIR_NONE; 965 fep->pair = '\0'; 966 fep->value = value; 967 tmp->b_wptr += sizeof (Firm_event); 968 } 969 970 return (tmp); 971 } 972 973 /* 974 * Start of dispatching interfaces as a multiplexor 975 */ 976 977 /* 978 * There is a global msg list (consms_mux_msg), 979 * which is used to link all ioctl messages from 980 * upper layer, which are currently being processed. 981 * 982 * consms_mux_link_msg links a msg into the list, 983 * consms_mux_unlink_msg unlinks a msg from the list, 984 * consms_mux_find_msg finds a msg from the list 985 * according to its unique id. 986 * 987 * The id of each msg is taken from stream's mp, 988 * so the id is supposed to be unique. 989 */ 990 static void 991 consms_mux_link_msg(consms_msg_t *msg) 992 { 993 mutex_enter(&consms_msg_lock); 994 msg->msg_next = consms_mux_msg; 995 consms_mux_msg = msg; 996 mutex_exit(&consms_msg_lock); 997 } 998 999 static consms_msg_t * 1000 consms_mux_unlink_msg(uint_t msg_id) 1001 { 1002 consms_msg_t *msg; 1003 consms_msg_t *prev_msg; 1004 1005 mutex_enter(&consms_msg_lock); 1006 prev_msg = NULL; 1007 for (msg = consms_mux_msg; msg != NULL; 1008 prev_msg = msg, msg = msg->msg_next) { 1009 if (msg->msg_id == msg_id) 1010 break; 1011 } 1012 1013 if (msg != NULL) { 1014 if (prev_msg != NULL) { 1015 prev_msg->msg_next = msg->msg_next; 1016 } else { 1017 consms_mux_msg = consms_mux_msg->msg_next; 1018 } 1019 msg->msg_next = NULL; 1020 } 1021 mutex_exit(&consms_msg_lock); 1022 1023 return (msg); 1024 } 1025 1026 static consms_msg_t * 1027 consms_mux_find_msg(uint_t msg_id) 1028 { 1029 consms_msg_t *msg; 1030 1031 mutex_enter(&consms_msg_lock); 1032 for (msg = consms_mux_msg; msg != NULL; msg = msg->msg_next) { 1033 if (msg->msg_id == msg_id) 1034 break; 1035 } 1036 mutex_exit(&consms_msg_lock); 1037 1038 return (msg); 1039 } 1040 1041 /* 1042 * Received ACK or NAK from lower mice 1043 * 1044 * For non-transparent ioctl, the msg->msg_rsp_list 1045 * is always NULL; for transparent ioctl, it 1046 * remembers the M_COPYIN/M_COPYOUT request 1047 * messages from lower mice. So here if msg->msg_rsp_list 1048 * is NULL (after receiving all ACK/NAKs), we 1049 * are done with this specific ioctl. 1050 * 1051 * As long as one of lower mice responds success, 1052 * we treat it success for a ioctl. 1053 */ 1054 static void 1055 consms_mux_ack(consms_msg_t *msg, mblk_t *mp) 1056 { 1057 mblk_t *ack_mp; 1058 1059 /* increment response_nums */ 1060 msg->msg_num_responses++; 1061 1062 if (mp->b_datap->db_type == M_IOCACK) { 1063 /* 1064 * Received ACK from lower, then 1065 * this is the last step for both 1066 * non-transparent and transparent 1067 * ioctl. We only need to remember 1068 * one of the ACKs, finally reply 1069 * this ACK to upper layer for this 1070 * specific ioctl. 1071 */ 1072 ASSERT(msg->msg_rsp_list == NULL); 1073 if (msg->msg_ack_mp == NULL) { 1074 msg->msg_ack_mp = mp; 1075 mp = NULL; 1076 } 1077 } 1078 1079 /* 1080 * Check to see if all lower mice have responded 1081 * to our dispatching ioctl. 1082 */ 1083 if (msg->msg_num_responses == msg->msg_num_requests) { 1084 if ((msg->msg_ack_mp == NULL) && 1085 (msg->msg_rsp_list == NULL)) { 1086 /* 1087 * All are NAKed. 1088 */ 1089 ack_mp = mp; 1090 mp = NULL; 1091 } else if (msg->msg_rsp_list == NULL) { 1092 /* 1093 * The last step and at least one ACKed. 1094 */ 1095 ack_mp = msg->msg_ack_mp; 1096 consms_mux_cache_states(msg->msg_request); 1097 consms_mux_max_wheel_report(ack_mp); 1098 } else { 1099 /* 1100 * This is a NAK, but we have 1101 * already received M_COPYIN 1102 * or M_COPYOUT request from 1103 * at least one of lower mice. 1104 * (msg->msg_rsp_list != NULL) 1105 * 1106 * Still copyin or copyout. 1107 */ 1108 ack_mp = msg->msg_rsp_list->rsp_mp; 1109 consms_mux_max_wheel_report(ack_mp); 1110 } 1111 1112 qreply(msg->msg_queue, ack_mp); 1113 1114 if (msg->msg_rsp_list == NULL) { 1115 /* 1116 * We are done with this ioctl. 1117 */ 1118 if (msg->msg_request) 1119 freemsg(msg->msg_request); 1120 (void) consms_mux_unlink_msg(msg->msg_id); 1121 kmem_free(msg, sizeof (*msg)); 1122 } 1123 } 1124 1125 if (mp) { 1126 freemsg(mp); 1127 } 1128 } 1129 1130 /* 1131 * Received M_COPYIN or M_COPYOUT request from 1132 * lower mice for transparent ioctl 1133 * 1134 * We remember each M_COPYIN/M_COPYOUT into the 1135 * msg->msg_rsp_list, reply upper layer using the first 1136 * M_COPYIN/M_COPYOUT in the list after receiving 1137 * all responses from lower mice, even if some of 1138 * them return NAKs. 1139 */ 1140 static void 1141 consms_mux_copyreq(queue_t *q, consms_msg_t *msg, mblk_t *mp) 1142 { 1143 consms_response_t *rsp; 1144 1145 rsp = (consms_response_t *)kmem_zalloc(sizeof (*rsp), KM_SLEEP); 1146 rsp->rsp_mp = mp; 1147 rsp->rsp_queue = q; 1148 if (msg->msg_rsp_list) { 1149 rsp->rsp_next = msg->msg_rsp_list; 1150 } 1151 msg->msg_rsp_list = rsp; 1152 msg->msg_num_responses++; 1153 1154 if (msg->msg_num_responses == msg->msg_num_requests) { 1155 consms_mux_max_wheel_report(msg->msg_rsp_list->rsp_mp); 1156 qreply(msg->msg_queue, msg->msg_rsp_list->rsp_mp); 1157 } 1158 } 1159 1160 /* 1161 * Do the real job for updating M_COPYIN/M_COPYOUT 1162 * request with the mp of M_IOCDATA, then put it 1163 * down to lower mice. 1164 */ 1165 static void 1166 consms_mux_disp_iocdata(consms_response_t *rsp, mblk_t *mp) 1167 { 1168 mblk_t *down_mp = rsp->rsp_mp; 1169 struct copyresp *copyresp = (struct copyresp *)mp->b_rptr; 1170 struct copyresp *newresp = (struct copyresp *)down_mp->b_rptr; 1171 1172 /* 1173 * Update the rval. 1174 */ 1175 newresp->cp_rval = copyresp->cp_rval; 1176 1177 /* 1178 * Update the db_type to M_IOCDATA. 1179 */ 1180 down_mp->b_datap->db_type = mp->b_datap->db_type; 1181 1182 /* 1183 * Update the b_cont. 1184 */ 1185 if (down_mp->b_cont != NULL) { 1186 freemsg(down_mp->b_cont); 1187 down_mp->b_cont = NULL; 1188 } 1189 if (mp->b_cont != NULL) { 1190 down_mp->b_cont = copymsg(mp->b_cont); 1191 } 1192 1193 /* 1194 * Put it down. 1195 */ 1196 (void) putq(WR(rsp->rsp_queue), down_mp); 1197 } 1198 1199 /* 1200 * Dispatch M_IOCDATA down to all lower mice 1201 * for transparent ioctl. 1202 * 1203 * We update each M_COPYIN/M_COPYOUT in the 1204 * msg->msg_rsp_list with the M_IOCDATA. 1205 */ 1206 static void 1207 consms_mux_iocdata(consms_msg_t *msg, mblk_t *mp) 1208 { 1209 consms_response_t *rsp; 1210 consms_response_t *tmp; 1211 consms_response_t *first; 1212 struct copyresp *copyresp; 1213 int request_nums; 1214 1215 ASSERT(msg->msg_rsp_list != NULL); 1216 1217 /* 1218 * We should remember the ioc data for 1219 * VUIDSWHEELSTATE, and MSIOSRESOLUTION, 1220 * for we will cache the wheel state and 1221 * the screen resolution later if ACKed. 1222 */ 1223 copyresp = (struct copyresp *)mp->b_rptr; 1224 if ((copyresp->cp_cmd == VUIDSWHEELSTATE) || 1225 (copyresp->cp_cmd == MSIOSRESOLUTION)) { 1226 freemsg(msg->msg_request); 1227 msg->msg_request = copymsg(mp); 1228 } 1229 1230 /* 1231 * Update request numbers and response numbers. 1232 */ 1233 msg->msg_num_requests = msg->msg_num_responses; 1234 msg->msg_num_responses = 0; 1235 request_nums = 1; 1236 1237 /* 1238 * Since we have use the first M_COPYIN/M_COPYOUT 1239 * in the msg_rsp_list to reply upper layer, the mp 1240 * of M_IOCDATA can be directly used for that. 1241 */ 1242 first = msg->msg_rsp_list; 1243 rsp = first->rsp_next; 1244 msg->msg_rsp_list = NULL; 1245 1246 for (rsp = first->rsp_next; rsp != NULL; ) { 1247 tmp = rsp; 1248 rsp = rsp->rsp_next; 1249 consms_mux_disp_iocdata(tmp, mp); 1250 kmem_free(tmp, sizeof (*tmp)); 1251 request_nums++; 1252 } 1253 1254 /* Must set the request number before the last q. */ 1255 msg->msg_num_requests = request_nums; 1256 1257 /* the first one */ 1258 (void) putq(WR(first->rsp_queue), mp); 1259 kmem_free(first, sizeof (*first)); 1260 } 1261 1262 1263 /* 1264 * Here we update the number of wheels with 1265 * the virtual mouse for VUIDGWHEELCOUNT ioctl. 1266 */ 1267 static void 1268 consms_mux_max_wheel_report(mblk_t *mp) 1269 { 1270 struct iocblk *iocp; 1271 int num_wheels; 1272 1273 if (mp == NULL || mp->b_cont == NULL) 1274 return; 1275 1276 iocp = (struct iocblk *)mp->b_rptr; 1277 1278 if ((iocp->ioc_cmd == VUIDGWHEELCOUNT) && 1279 (mp->b_datap->db_type == M_COPYOUT)) { 1280 num_wheels = *(int *)mp->b_cont->b_rptr; 1281 if (num_wheels < consms_state.consms_num_wheels) { 1282 *(int *)mp->b_cont->b_rptr = 1283 consms_state.consms_num_wheels; 1284 } 1285 } 1286 } 1287 1288 /* 1289 * Update the virtual mouse state variables with 1290 * the latest value from upper layer when these 1291 * set ioctls return success. Thus we can update 1292 * low mice with the latest state values during 1293 * hotplug. 1294 */ 1295 static void 1296 consms_mux_cache_states(mblk_t *mp) 1297 { 1298 struct iocblk *iocp; 1299 Ms_parms *parms; 1300 Ms_screen_resolution *sr; 1301 wheel_state *ws; 1302 1303 if (mp == NULL || mp->b_cont == NULL) 1304 return; 1305 1306 iocp = (struct iocblk *)mp->b_rptr; 1307 switch (iocp->ioc_cmd) { 1308 case VUIDSFORMAT: 1309 consms_state.consms_vuid_format = *(int *)mp->b_cont->b_rptr; 1310 break; 1311 1312 case MSIOSETPARMS: 1313 parms = (Ms_parms *)mp->b_cont->b_rptr; 1314 consms_state.consms_ms_parms = *parms; 1315 break; 1316 1317 case MSIOSRESOLUTION: 1318 sr = (Ms_screen_resolution *)mp->b_cont->b_rptr; 1319 consms_state.consms_ms_sr = *sr; 1320 break; 1321 1322 case VUIDSWHEELSTATE: 1323 ws = (wheel_state *)mp->b_cont->b_rptr; 1324 consms_state.consms_wheel_state_bf = 1325 (ws->stateflags << ws->id) | 1326 (consms_state.consms_wheel_state_bf & ~(1 << ws->id)); 1327 break; 1328 } 1329 } 1330 1331 /* 1332 * Dispatch ioctl mp (non-transparent and transparent) 1333 * down to all lower mice. 1334 * 1335 * First, create a pending message for this mp, link it into 1336 * the global messages list. Then wait for ACK/NAK for 1337 * non-transparent ioctl, COPYIN/COPYOUT for transparent 1338 * ioctl. 1339 */ 1340 static int 1341 consms_mux_disp_ioctl(queue_t *q, mblk_t *mp) 1342 { 1343 struct iocblk *iocp; 1344 consms_msg_t *msg; 1345 consms_lq_t *lq; 1346 mblk_t *copy_mp; 1347 int error = 0; 1348 1349 iocp = (struct iocblk *)mp->b_rptr; 1350 msg = (consms_msg_t *)kmem_zalloc(sizeof (*msg), KM_SLEEP); 1351 msg->msg_id = iocp->ioc_id; 1352 msg->msg_request = mp; 1353 msg->msg_queue = q; 1354 msg->msg_num_requests = consms_state.consms_num_lqs; 1355 consms_mux_link_msg(msg); 1356 1357 for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) { 1358 if ((copy_mp = copymsg(mp)) != NULL) { 1359 (void) putq(lq->lq_queue, copy_mp); 1360 } else { 1361 /* 1362 * If copymsg fails, we ignore this lq and 1363 * try next one. As long as one of them succeeds, 1364 * we dispatch this ioctl down. And later as long 1365 * as one of the lower drivers return success, we 1366 * reply to this ioctl with success. 1367 */ 1368 msg->msg_num_requests--; 1369 } 1370 } 1371 1372 if (msg->msg_num_requests <= 0) { 1373 /* 1374 * Since copymsg fails for all lqs, we NAK this ioctl. 1375 */ 1376 (void) consms_mux_unlink_msg(msg->msg_id); 1377 kmem_free(msg, sizeof (*msg)); 1378 error = ENOMEM; 1379 } 1380 1381 return (error); 1382 } 1383 1384 /* 1385 * Dispatch M_DATA and M_FLUSH message down to all 1386 * lower mice, and there are no acknowledgements 1387 * for them. Here we just copy the mp and then 1388 * put it into the lower queues. 1389 */ 1390 static void 1391 consms_mux_disp_data(mblk_t *mp) 1392 { 1393 consms_lq_t *lq; 1394 mblk_t *copy_mp; 1395 1396 for (lq = consms_state.consms_lqs; lq != NULL; lq = lq->lq_next) { 1397 if ((copy_mp = copymsg(mp)) != NULL) { 1398 (void) putq(lq->lq_queue, copy_mp); 1399 } 1400 } 1401 1402 freemsg(mp); 1403 } 1404