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 /* Copyright (c) 1990, 1991 UNIX System Laboratories, Inc. */
22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989, 1990 AT&T */
23 /* All Rights Reserved */
24
25 /*
26 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
27 * Use is subject to license terms.
28 */
29
30
31 /*
32 * PS/2 type Mouse Module - Streams
33 */
34
35 #include <sys/param.h>
36 #include <sys/types.h>
37 #include <sys/kmem.h>
38 #include <sys/signal.h>
39 #include <sys/errno.h>
40 #include <sys/file.h>
41 #include <sys/termio.h>
42 #include <sys/stream.h>
43 #include <sys/stropts.h>
44 #include <sys/strtty.h>
45 #include <sys/strsun.h>
46 #include <sys/debug.h>
47 #include <sys/ddi.h>
48 #include <sys/stat.h>
49 #include <sys/cmn_err.h>
50 #include <sys/sunddi.h>
51
52 #include <sys/promif.h>
53 #include <sys/cred.h>
54
55 #include <sys/i8042.h>
56 #include <sys/note.h>
57 #include <sys/mouse.h>
58
59 #define DRIVER_NAME(dip) ddi_driver_name(dip)
60
61 #define MOUSE8042_INTERNAL_OPEN(minor) (((minor) & 0x1) == 1)
62 #define MOUSE8042_MINOR_TO_INSTANCE(minor) ((minor) / 2)
63 #define MOUSE8042_INTERNAL_MINOR(minor) ((minor) + 1)
64
65 #define MOUSE8042_RESET_TIMEOUT_USECS 500000 /* 500 ms */
66
67 extern int ddi_create_internal_pathname(dev_info_t *, char *, int, minor_t);
68 extern void consconfig_link(major_t major, minor_t minor);
69 extern int consconfig_unlink(major_t major, minor_t minor);
70
71
72 /*
73 *
74 * Local Static Data
75 *
76 */
77
78 /*
79 * We only support one instance. Yes, it's theoretically possible to
80 * plug in more than one, but it's not worth the implementation cost.
81 *
82 * The introduction of USB keyboards might make it worth reassessing
83 * this decision, as they might free up the keyboard port for a second
84 * PS/2 style mouse.
85 */
86 static dev_info_t *mouse8042_dip;
87
88 /*
89 * RESET states
90 */
91 typedef enum {
92 MSE_RESET_IDLE, /* No reset in progress */
93 MSE_RESET_PRE, /* Send reset, waiting for ACK */
94 MSE_RESET_ACK, /* Got ACK, waiting for 0xAA */
95 MSE_RESET_AA, /* Got 0xAA, waiting for 0x00 */
96 MSE_RESET_FAILED
97 } mouse8042_reset_state_e;
98
99 struct mouse_state {
100 queue_t *ms_rqp;
101 queue_t *ms_wqp;
102 ddi_iblock_cookie_t ms_iblock_cookie;
103 ddi_acc_handle_t ms_handle;
104 uint8_t *ms_addr;
105 kmutex_t ms_mutex;
106
107 minor_t ms_minor;
108 boolean_t ms_opened;
109 kmutex_t reset_mutex;
110 kcondvar_t reset_cv;
111 mouse8042_reset_state_e reset_state;
112 timeout_id_t reset_tid;
113 int ready;
114 mblk_t *reply_mp;
115 mblk_t *reset_ack_mp;
116 bufcall_id_t bc_id;
117 };
118
119 static uint_t mouse8042_intr(caddr_t arg);
120 static int mouse8042_open(queue_t *q, dev_t *devp, int flag, int sflag,
121 cred_t *cred_p);
122 static int mouse8042_close(queue_t *q, int flag, cred_t *cred_p);
123 static int mouse8042_wsrv(queue_t *qp);
124 static int mouse8042_wput(queue_t *q, mblk_t *mp);
125
126 static int mouse8042_getinfo(dev_info_t *dip, ddi_info_cmd_t infocmd,
127 void *arg, void **result);
128 static int mouse8042_attach(dev_info_t *dev, ddi_attach_cmd_t cmd);
129 static int mouse8042_detach(dev_info_t *dev, ddi_detach_cmd_t cmd);
130
131
132 /*
133 * Streams module info.
134 */
135 #define MODULE_NAME "mouse8042"
136
137 static struct module_info mouse8042_minfo = {
138 23, /* Module ID number */
139 MODULE_NAME,
140 0, INFPSZ, /* minimum & maximum packet sizes */
141 256, 128 /* hi and low water marks */
142 };
143
144 static struct qinit mouse8042_rinit = {
145 NULL, /* put */
146 NULL, /* service */
147 mouse8042_open,
148 mouse8042_close,
149 NULL, /* admin */
150 &mouse8042_minfo,
151 NULL /* statistics */
152 };
153
154 static struct qinit mouse8042_winit = {
155 mouse8042_wput, /* put */
156 mouse8042_wsrv, /* service */
157 NULL, /* open */
158 NULL, /* close */
159 NULL, /* admin */
160 &mouse8042_minfo,
161 NULL /* statistics */
162 };
163
164 static struct streamtab mouse8042_strinfo = {
165 &mouse8042_rinit,
166 &mouse8042_winit,
167 NULL, /* muxrinit */
168 NULL, /* muxwinit */
169 };
170
171 /*
172 * Local Function Declarations
173 */
174
175 static struct cb_ops mouse8042_cb_ops = {
176 nodev, /* open */
177 nodev, /* close */
178 nodev, /* strategy */
179 nodev, /* print */
180 nodev, /* dump */
181 nodev, /* read */
182 nodev, /* write */
183 nodev, /* ioctl */
184 nodev, /* devmap */
185 nodev, /* mmap */
186 nodev, /* segmap */
187 nochpoll, /* poll */
188 ddi_prop_op, /* cb_prop_op */
189 &mouse8042_strinfo, /* streamtab */
190 D_MP | D_NEW
191 };
192
193
194 static struct dev_ops mouse8042_ops = {
195 DEVO_REV, /* devo_rev, */
196 0, /* refcnt */
197 mouse8042_getinfo, /* getinfo */
198 nulldev, /* identify */
199 nulldev, /* probe */
200 mouse8042_attach, /* attach */
201 mouse8042_detach, /* detach */
202 nodev, /* reset */
203 &mouse8042_cb_ops, /* driver operations */
204 (struct bus_ops *)0, /* bus operations */
205 NULL, /* power */
206 ddi_quiesce_not_needed, /* quiesce */
207 };
208
209 /*
210 * This is the loadable module wrapper.
211 */
212 #include <sys/modctl.h>
213
214 extern struct mod_ops mod_driverops;
215
216 /*
217 * Module linkage information for the kernel.
218 */
219
220 static struct modldrv modldrv = {
221 &mod_driverops, /* Type of module. This one is a driver */
222 "PS/2 Mouse",
223 &mouse8042_ops, /* driver ops */
224 };
225
226 static struct modlinkage modlinkage = {
227 MODREV_1,
228 { (void *)&modldrv, NULL }
229 };
230
231 /*
232 * This is the driver initialization routine.
233 */
234 int
235 _init()
236 {
237 int rv;
238
239 rv = mod_install(&modlinkage);
240 return (rv);
241 }
242
243
244 int
245 _fini(void)
246 {
247 return (mod_remove(&modlinkage));
248 }
249
250
251 int
252 _info(struct modinfo *modinfop)
253 {
254 return (mod_info(&modlinkage, modinfop));
255 }
256
257 static int
258 mouse8042_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
259 {
260 struct mouse_state *state;
261 mblk_t *mp;
262 int instance = ddi_get_instance(dip);
263 static ddi_device_acc_attr_t attr = {
264 DDI_DEVICE_ATTR_V0,
265 DDI_NEVERSWAP_ACC,
266 DDI_STRICTORDER_ACC,
267 };
268 int rc;
269
270
271 if (cmd == DDI_RESUME) {
272 state = (struct mouse_state *)ddi_get_driver_private(dip);
273
274 /* Ready to handle inbound data from mouse8042_intr */
275 state->ready = 1;
276
277 /*
278 * Send a 0xaa 0x00 upstream.
279 * This causes the vuid module to reset the mouse.
280 */
281 if (state->ms_rqp != NULL) {
282 if (mp = allocb(1, BPRI_MED)) {
283 *mp->b_wptr++ = 0xaa;
284 putnext(state->ms_rqp, mp);
285 }
286 if (mp = allocb(1, BPRI_MED)) {
287 *mp->b_wptr++ = 0x0;
288 putnext(state->ms_rqp, mp);
289 }
290 }
291 return (DDI_SUCCESS);
292 }
293
294 if (cmd != DDI_ATTACH)
295 return (DDI_FAILURE);
296
297 if (mouse8042_dip != NULL)
298 return (DDI_FAILURE);
299
300 /* allocate and initialize state structure */
301 state = kmem_zalloc(sizeof (struct mouse_state), KM_SLEEP);
302 state->ms_opened = B_FALSE;
303 state->reset_state = MSE_RESET_IDLE;
304 state->reset_tid = 0;
305 state->bc_id = 0;
306 ddi_set_driver_private(dip, state);
307
308 /*
309 * In order to support virtual keyboard/mouse, we should distinguish
310 * between internal virtual open and external physical open.
311 *
312 * When the physical devices are opened by application, they will
313 * be unlinked from the virtual device and their data stream will
314 * not be sent to the virtual device. When the opened physical
315 * devices are closed, they will be relinked to the virtual devices.
316 *
317 * All these automatic switch between virtual and physical are
318 * transparent.
319 *
320 * So we change minor node numbering scheme to be:
321 * external node minor num == instance * 2
322 * internal node minor num == instance * 2 + 1
323 */
324 rc = ddi_create_minor_node(dip, "mouse", S_IFCHR, instance * 2,
325 DDI_NT_MOUSE, NULL);
326 if (rc != DDI_SUCCESS) {
327 goto fail_1;
328 }
329
330 if (ddi_create_internal_pathname(dip, "internal_mouse", S_IFCHR,
331 instance * 2 + 1) != DDI_SUCCESS) {
332 goto fail_2;
333 }
334
335 rc = ddi_regs_map_setup(dip, 0, (caddr_t *)&state->ms_addr,
336 (offset_t)0, (offset_t)0, &attr, &state->ms_handle);
337 if (rc != DDI_SUCCESS) {
338 goto fail_2;
339 }
340
341 rc = ddi_get_iblock_cookie(dip, 0, &state->ms_iblock_cookie);
342 if (rc != DDI_SUCCESS) {
343 goto fail_3;
344 }
345
346 mutex_init(&state->ms_mutex, NULL, MUTEX_DRIVER,
347 state->ms_iblock_cookie);
348 mutex_init(&state->reset_mutex, NULL, MUTEX_DRIVER,
349 state->ms_iblock_cookie);
350 cv_init(&state->reset_cv, NULL, CV_DRIVER, NULL);
351
352 rc = ddi_add_intr(dip, 0,
353 (ddi_iblock_cookie_t *)NULL, (ddi_idevice_cookie_t *)NULL,
354 mouse8042_intr, (caddr_t)state);
355 if (rc != DDI_SUCCESS) {
356 goto fail_3;
357 }
358
359 mouse8042_dip = dip;
360
361 /* Ready to handle inbound data from mouse8042_intr */
362 state->ready = 1;
363
364 /* Now that we're attached, announce our presence to the world. */
365 ddi_report_dev(dip);
366 return (DDI_SUCCESS);
367
368 fail_3:
369 ddi_regs_map_free(&state->ms_handle);
370
371 fail_2:
372 ddi_remove_minor_node(dip, NULL);
373
374 fail_1:
375 kmem_free(state, sizeof (struct mouse_state));
376 return (rc);
377 }
378
379 /*ARGSUSED*/
380 static int
381 mouse8042_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
382 {
383 struct mouse_state *state;
384
385 state = ddi_get_driver_private(dip);
386
387 switch (cmd) {
388 case DDI_SUSPEND:
389 /* Ignore all data from mouse8042_intr until we fully resume */
390 state->ready = 0;
391 return (DDI_SUCCESS);
392
393 case DDI_DETACH:
394 ddi_remove_intr(dip, 0, state->ms_iblock_cookie);
395 mouse8042_dip = NULL;
396 cv_destroy(&state->reset_cv);
397 mutex_destroy(&state->reset_mutex);
398 mutex_destroy(&state->ms_mutex);
399 ddi_prop_remove_all(dip);
400 ddi_regs_map_free(&state->ms_handle);
401 ddi_remove_minor_node(dip, NULL);
402 kmem_free(state, sizeof (struct mouse_state));
403 return (DDI_SUCCESS);
404
405 default:
406 return (DDI_FAILURE);
407 }
408 }
409
410
411 /* ARGSUSED */
412 static int
413 mouse8042_getinfo(
414 dev_info_t *dip,
415 ddi_info_cmd_t infocmd,
416 void *arg,
417 void **result)
418 {
419 dev_t dev = (dev_t)arg;
420 minor_t minor = getminor(dev);
421 int instance = MOUSE8042_MINOR_TO_INSTANCE(minor);
422
423 switch (infocmd) {
424 case DDI_INFO_DEVT2DEVINFO:
425 if (mouse8042_dip == NULL)
426 return (DDI_FAILURE);
427
428 *result = (void *)mouse8042_dip;
429 break;
430 case DDI_INFO_DEVT2INSTANCE:
431 *result = (void *)(uintptr_t)instance;
432 break;
433 default:
434 return (DDI_FAILURE);
435 }
436 return (DDI_SUCCESS);
437 }
438
439 /*ARGSUSED*/
440 static int
441 mouse8042_open(
442 queue_t *q,
443 dev_t *devp,
444 int flag,
445 int sflag,
446 cred_t *cred_p)
447 {
448 struct mouse_state *state;
449 minor_t minor = getminor(*devp);
450 int rval;
451
452 if (mouse8042_dip == NULL)
453 return (ENXIO);
454
455 state = ddi_get_driver_private(mouse8042_dip);
456
457 mutex_enter(&state->ms_mutex);
458
459 if (state->ms_opened) {
460 /*
461 * Exit if the same minor node is already open
462 */
463 if (state->ms_minor == minor) {
464 mutex_exit(&state->ms_mutex);
465 return (0);
466 }
467
468 /*
469 * Check whether it is switch between physical and virtual
470 *
471 * Opening from virtual while the device is being physically
472 * opened by an application should not happen. So we ASSERT
473 * this in DEBUG version, and return error in the non-DEBUG
474 * case.
475 */
476 ASSERT(!MOUSE8042_INTERNAL_OPEN(minor));
477
478 if (MOUSE8042_INTERNAL_OPEN(minor)) {
479 mutex_exit(&state->ms_mutex);
480 return (EINVAL);
481 }
482
483 /*
484 * Opening the physical one while it is being underneath
485 * the virtual one.
486 *
487 * consconfig_unlink is called to unlink this device from
488 * the virtual one, thus the old stream serving for this
489 * device under the virtual one is closed, and then the
490 * lower driver's close routine (here is mouse8042_close)
491 * is also called to accomplish the whole stream close.
492 * Here we have to drop the lock because mouse8042_close
493 * also needs the lock.
494 *
495 * For mouse, the old stream is:
496 * consms->["pushmod"->]"mouse_vp driver"
497 *
498 * After the consconfig_unlink returns, the old stream is closed
499 * and we grab the lock again to reopen this device as normal.
500 */
501 mutex_exit(&state->ms_mutex);
502
503 /*
504 * If unlink fails, fail the physical open.
505 */
506 if ((rval = consconfig_unlink(ddi_driver_major(mouse8042_dip),
507 MOUSE8042_INTERNAL_MINOR(minor))) != 0) {
508 return (rval);
509 }
510
511 mutex_enter(&state->ms_mutex);
512 }
513
514
515 q->q_ptr = (caddr_t)state;
516 WR(q)->q_ptr = (caddr_t)state;
517 state->ms_rqp = q;
518 state->ms_wqp = WR(q);
519
520 qprocson(q);
521
522 state->ms_minor = minor;
523 state->ms_opened = B_TRUE;
524
525 mutex_exit(&state->ms_mutex);
526
527 return (0);
528 }
529
530
531 /*ARGSUSED*/
532 static int
533 mouse8042_close(queue_t *q, int flag, cred_t *cred_p)
534 {
535 struct mouse_state *state;
536 minor_t minor;
537
538 state = (struct mouse_state *)q->q_ptr;
539
540 /*
541 * Disable queue processing now, so that another reset cannot get in
542 * after we wait for the current reset (if any) to complete.
543 */
544 qprocsoff(q);
545
546 mutex_enter(&state->reset_mutex);
547 while (state->reset_state != MSE_RESET_IDLE) {
548 /*
549 * Waiting for the previous reset to finish is
550 * non-interruptible. Some upper-level clients
551 * cannot deal with EINTR and will not close the
552 * STREAM properly, resulting in failure to reopen it
553 * within the same process.
554 */
555 cv_wait(&state->reset_cv, &state->reset_mutex);
556 }
557
558 if (state->reset_tid != 0) {
559 (void) quntimeout(q, state->reset_tid);
560 state->reset_tid = 0;
561 }
562
563 if (state->reply_mp != NULL) {
564 freemsg(state->reply_mp);
565 state->reply_mp = NULL;
566 }
567
568 if (state->reset_ack_mp != NULL) {
569 freemsg(state->reset_ack_mp);
570 state->reset_ack_mp = NULL;
571 }
572
573 mutex_exit(&state->reset_mutex);
574
575 mutex_enter(&state->ms_mutex);
576
577 if (state->bc_id != 0) {
578 (void) qunbufcall(q, state->bc_id);
579 state->bc_id = 0;
580 }
581
582 q->q_ptr = NULL;
583 WR(q)->q_ptr = NULL;
584 state->ms_rqp = NULL;
585 state->ms_wqp = NULL;
586
587 state->ms_opened = B_FALSE;
588
589 minor = state->ms_minor;
590
591 mutex_exit(&state->ms_mutex);
592
593 if (!MOUSE8042_INTERNAL_OPEN(minor)) {
594 /*
595 * Closing physical PS/2 mouse
596 *
597 * Link it back to virtual mouse, and
598 * mouse8042_open will be called as a result
599 * of the consconfig_link call. Do NOT try
600 * this if the mouse is about to be detached!
601 *
602 * If linking back fails, this specific mouse
603 * will not be available underneath the virtual
604 * mouse, and can only be accessed via physical
605 * open.
606 */
607 consconfig_link(ddi_driver_major(mouse8042_dip),
608 MOUSE8042_INTERNAL_MINOR(minor));
609 }
610
611 return (0);
612 }
613
614 static void
615 mouse8042_iocnack(
616 queue_t *qp,
617 mblk_t *mp,
618 struct iocblk *iocp,
619 int error,
620 int rval)
621 {
622 mp->b_datap->db_type = M_IOCNAK;
623 iocp->ioc_rval = rval;
624 iocp->ioc_error = error;
625 qreply(qp, mp);
626 }
627
628 static void
629 mouse8042_reset_timeout(void *argp)
630 {
631 struct mouse_state *state = (struct mouse_state *)argp;
632 mblk_t *mp;
633
634 mutex_enter(&state->reset_mutex);
635
636 /*
637 * If the interrupt handler hasn't completed the reset handling
638 * (reset_state would be IDLE or FAILED in that case), then
639 * drop the 8042 lock, and send a faked retry reply upstream,
640 * then enable the queue for further message processing.
641 */
642 if (state->reset_state != MSE_RESET_IDLE &&
643 state->reset_state != MSE_RESET_FAILED) {
644
645 state->reset_tid = 0;
646 state->reset_state = MSE_RESET_IDLE;
647 cv_signal(&state->reset_cv);
648
649 (void) ddi_get8(state->ms_handle, state->ms_addr +
650 I8042_UNLOCK);
651
652 mp = state->reply_mp;
653 *mp->b_wptr++ = MSERESEND;
654 state->reply_mp = NULL;
655
656 if (state->ms_rqp != NULL)
657 putnext(state->ms_rqp, mp);
658 else
659 freemsg(mp);
660
661 ASSERT(state->ms_wqp != NULL);
662
663 enableok(state->ms_wqp);
664 qenable(state->ms_wqp);
665 }
666
667 mutex_exit(&state->reset_mutex);
668 }
669
670 /*
671 * Returns 1 if the caller should put the message (bp) back on the queue
672 */
673 static int
674 mouse8042_initiate_reset(queue_t *q, mblk_t *mp, struct mouse_state *state)
675 {
676 mutex_enter(&state->reset_mutex);
677 /*
678 * If we're in the middle of a reset, put the message back on the queue
679 * for processing later.
680 */
681 if (state->reset_state != MSE_RESET_IDLE) {
682 /*
683 * We noenable the queue again here in case it was backenabled
684 * by an upper-level module.
685 */
686 noenable(q);
687
688 mutex_exit(&state->reset_mutex);
689 return (1);
690 }
691
692 /*
693 * Drop the reset state lock before allocating the response message and
694 * grabbing the 8042 exclusive-access lock (since those operations
695 * may take an extended period of time to complete).
696 */
697 mutex_exit(&state->reset_mutex);
698
699 if (state->reply_mp == NULL)
700 state->reply_mp = allocb(2, BPRI_MED);
701 if (state->reset_ack_mp == NULL)
702 state->reset_ack_mp = allocb(1, BPRI_MED);
703
704 if (state->reply_mp == NULL || state->reset_ack_mp == NULL) {
705 /*
706 * Allocation failed -- set up a bufcall to enable the queue
707 * whenever there is enough memory to allocate the response
708 * message.
709 */
710 state->bc_id = qbufcall(q, (state->reply_mp == NULL) ? 2 : 1,
711 BPRI_MED, (void (*)(void *))qenable, q);
712
713 if (state->bc_id == 0) {
714 /*
715 * If the qbufcall failed, we cannot proceed, so use the
716 * message we were sent to respond with an error.
717 */
718 *mp->b_rptr = MSEERROR;
719 mp->b_wptr = mp->b_rptr + 1;
720 qreply(q, mp);
721 return (0);
722 }
723
724 return (1);
725 } else {
726 /* Bufcall completed successfully (or wasn't needed) */
727 state->bc_id = 0;
728 }
729
730 /*
731 * Gain exclusive access to the 8042 for the duration of the reset.
732 * The unlock will occur when the reset has either completed or timed
733 * out.
734 */
735 (void) ddi_get8(state->ms_handle,
736 state->ms_addr + I8042_LOCK);
737
738 mutex_enter(&state->reset_mutex);
739
740 state->reset_state = MSE_RESET_PRE;
741 noenable(q);
742
743 state->reset_tid = qtimeout(q,
744 mouse8042_reset_timeout,
745 state,
746 drv_usectohz(
747 MOUSE8042_RESET_TIMEOUT_USECS));
748
749 ddi_put8(state->ms_handle,
750 state->ms_addr +
751 I8042_INT_OUTPUT_DATA, MSERESET);
752
753 mp->b_rptr++;
754
755 mutex_exit(&state->reset_mutex);
756 return (1);
757 }
758
759 /*
760 * Returns 1 if the caller should stop processing messages
761 */
762 static int
763 mouse8042_process_data_msg(queue_t *q, mblk_t *mp, struct mouse_state *state)
764 {
765 mblk_t *bp;
766 mblk_t *next;
767
768 bp = mp;
769 do {
770 while (bp->b_rptr < bp->b_wptr) {
771 /*
772 * Detect an attempt to reset the mouse. Lock out any
773 * further mouse writes until the reset has completed.
774 */
775 if (*bp->b_rptr == MSERESET) {
776
777 /*
778 * If we couldn't allocate memory and we
779 * we couldn't register a bufcall,
780 * mouse8042_initiate_reset returns 0 and
781 * has already used the message to send an
782 * error reply back upstream, so there is no
783 * need to deallocate or put this message back
784 * on the queue.
785 */
786 if (mouse8042_initiate_reset(q, bp, state) == 0)
787 return (1);
788
789 /*
790 * If there's no data remaining in this block,
791 * free this block and put the following blocks
792 * of this message back on the queue. If putting
793 * the rest of the message back on the queue
794 * fails, free the the message.
795 */
796 if (MBLKL(bp) == 0) {
797 next = bp->b_cont;
798 freeb(bp);
799 bp = next;
800 }
801 if (bp != NULL) {
802 if (!putbq(q, bp))
803 freemsg(bp);
804 }
805
806 return (1);
807
808 }
809 ddi_put8(state->ms_handle,
810 state->ms_addr + I8042_INT_OUTPUT_DATA,
811 *bp->b_rptr++);
812 }
813 next = bp->b_cont;
814 freeb(bp);
815 } while ((bp = next) != NULL);
816
817 return (0);
818 }
819
820 static int
821 mouse8042_process_msg(queue_t *q, mblk_t *mp, struct mouse_state *state)
822 {
823 struct iocblk *iocbp;
824 int rv = 0;
825
826 iocbp = (struct iocblk *)mp->b_rptr;
827
828 switch (mp->b_datap->db_type) {
829 case M_FLUSH:
830 if (*mp->b_rptr & FLUSHW) {
831 flushq(q, FLUSHDATA);
832 *mp->b_rptr &= ~FLUSHW;
833 }
834 if (*mp->b_rptr & FLUSHR) {
835 qreply(q, mp);
836 } else
837 freemsg(mp);
838 break;
839 case M_IOCTL:
840 mouse8042_iocnack(q, mp, iocbp, EINVAL, 0);
841 break;
842 case M_IOCDATA:
843 mouse8042_iocnack(q, mp, iocbp, EINVAL, 0);
844 break;
845 case M_DATA:
846 rv = mouse8042_process_data_msg(q, mp, state);
847 break;
848 default:
849 freemsg(mp);
850 break;
851 }
852
853 return (rv);
854 }
855
856 /*
857 * This is the main mouse input routine. Commands and parameters
858 * from upstream are sent to the mouse device immediately, unless
859 * the mouse is in the process of being reset, in which case
860 * commands are queued and executed later in the service procedure.
861 */
862 static int
863 mouse8042_wput(queue_t *q, mblk_t *mp)
864 {
865 struct mouse_state *state;
866 state = (struct mouse_state *)q->q_ptr;
867
868 /*
869 * Process all messages immediately, unless a reset is in
870 * progress. If a reset is in progress, deflect processing to
871 * the service procedure.
872 */
873 if (state->reset_state != MSE_RESET_IDLE)
874 return (putq(q, mp));
875
876 /*
877 * If there are still messages outstanding in the queue that
878 * the service procedure hasn't processed yet, put this
879 * message in the queue also, to ensure proper message
880 * ordering.
881 */
882 if (q->q_first)
883 return (putq(q, mp));
884
885 (void) mouse8042_process_msg(q, mp, state);
886
887 return (0);
888 }
889
890 static int
891 mouse8042_wsrv(queue_t *qp)
892 {
893 mblk_t *mp;
894 struct mouse_state *state;
895 state = (struct mouse_state *)qp->q_ptr;
896
897 while ((mp = getq(qp)) != NULL) {
898 if (mouse8042_process_msg(qp, mp, state) != 0)
899 break;
900 }
901
902 return (0);
903 }
904
905 /*
906 * Returns the next reset state, given the current state and the byte
907 * received from the mouse. Error and Resend codes are handled by the
908 * caller.
909 */
910 static mouse8042_reset_state_e
911 mouse8042_reset_fsm(mouse8042_reset_state_e reset_state, uint8_t mdata)
912 {
913 switch (reset_state) {
914 case MSE_RESET_PRE: /* RESET sent, now we expect an ACK */
915 if (mdata == MSE_ACK) /* Got the ACK */
916 return (MSE_RESET_ACK);
917 break;
918
919 case MSE_RESET_ACK: /* ACK received; now we expect 0xAA */
920 if (mdata == MSE_AA) /* Got the 0xAA */
921 return (MSE_RESET_AA);
922 break;
923
924 case MSE_RESET_AA: /* 0xAA received; now we expect 0x00 */
925 if (mdata == MSE_00)
926 return (MSE_RESET_IDLE);
927 break;
928 }
929
930 return (reset_state);
931 }
932
933 static uint_t
934 mouse8042_intr(caddr_t arg)
935 {
936 unsigned char mdata;
937 mblk_t *mp;
938 struct mouse_state *state = (struct mouse_state *)arg;
939 int rc;
940
941 mutex_enter(&state->ms_mutex);
942
943 rc = DDI_INTR_UNCLAIMED;
944
945 for (;;) {
946
947 if (ddi_get8(state->ms_handle,
948 state->ms_addr + I8042_INT_INPUT_AVAIL) == 0) {
949 break;
950 }
951
952 mdata = ddi_get8(state->ms_handle,
953 state->ms_addr + I8042_INT_INPUT_DATA);
954
955 rc = DDI_INTR_CLAIMED;
956
957 /*
958 * If we're not ready for this data, discard it.
959 */
960 if (!state->ready)
961 continue;
962
963 mutex_enter(&state->reset_mutex);
964 if (state->reset_state != MSE_RESET_IDLE) {
965
966 if (mdata == MSEERROR || mdata == MSERESET) {
967 state->reset_state = MSE_RESET_FAILED;
968 } else {
969 state->reset_state =
970 mouse8042_reset_fsm(state->reset_state,
971 mdata);
972 }
973
974 if (state->reset_state == MSE_RESET_ACK) {
975
976 /*
977 * We received an ACK from the mouse, so
978 * send it upstream immediately so that
979 * consumers depending on the immediate
980 * ACK don't time out.
981 */
982 if (state->reset_ack_mp != NULL) {
983
984 mp = state->reset_ack_mp;
985
986 state->reset_ack_mp = NULL;
987
988 if (state->ms_rqp != NULL) {
989 *mp->b_wptr++ = MSE_ACK;
990 putnext(state->ms_rqp, mp);
991 } else
992 freemsg(mp);
993 }
994
995 if (state->ms_wqp != NULL) {
996 enableok(state->ms_wqp);
997 qenable(state->ms_wqp);
998 }
999
1000 } else if (state->reset_state == MSE_RESET_IDLE ||
1001 state->reset_state == MSE_RESET_FAILED) {
1002
1003 /*
1004 * If we transitioned back to the idle reset state (or
1005 * the reset failed), disable the timeout, release the
1006 * 8042 exclusive-access lock, then send the response
1007 * the the upper-level modules. Finally, enable the
1008 * queue and schedule queue service procedures so that
1009 * upper-level modules can process the response.
1010 * Otherwise, if we're still in the middle of the
1011 * reset sequence, do not send the data up (since the
1012 * response is sent at the end of the sequence, or
1013 * on timeout/error).
1014 */
1015
1016 mutex_exit(&state->reset_mutex);
1017 (void) quntimeout(state->ms_wqp,
1018 state->reset_tid);
1019 mutex_enter(&state->reset_mutex);
1020
1021 (void) ddi_get8(state->ms_handle,
1022 state->ms_addr + I8042_UNLOCK);
1023
1024 state->reset_tid = 0;
1025 if (state->reply_mp != NULL) {
1026 mp = state->reply_mp;
1027 if (state->reset_state ==
1028 MSE_RESET_FAILED) {
1029 *mp->b_wptr++ = mdata;
1030 } else {
1031 *mp->b_wptr++ = MSE_AA;
1032 *mp->b_wptr++ = MSE_00;
1033 }
1034 state->reply_mp = NULL;
1035 } else {
1036 mp = NULL;
1037 }
1038
1039 state->reset_state = MSE_RESET_IDLE;
1040 cv_signal(&state->reset_cv);
1041
1042 if (mp != NULL) {
1043 if (state->ms_rqp != NULL)
1044 putnext(state->ms_rqp, mp);
1045 else
1046 freemsg(mp);
1047 }
1048
1049 if (state->ms_wqp != NULL) {
1050 enableok(state->ms_wqp);
1051 qenable(state->ms_wqp);
1052 }
1053 }
1054
1055 mutex_exit(&state->reset_mutex);
1056 mutex_exit(&state->ms_mutex);
1057 return (rc);
1058 }
1059 mutex_exit(&state->reset_mutex);
1060
1061 if (state->ms_rqp != NULL && (mp = allocb(1, BPRI_MED))) {
1062 *mp->b_wptr++ = mdata;
1063 putnext(state->ms_rqp, mp);
1064 }
1065 }
1066 mutex_exit(&state->ms_mutex);
1067
1068 return (rc);
1069 }