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