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