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