xref: /illumos-gate/usr/src/uts/common/io/mouse8042.c (revision 9315a2f214fdc5269609ad1be3a248822dabf7f2)
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,
229 	NULL
230 };
231 
232 /*
233  * This is the driver initialization routine.
234  */
235 int
_init()236 _init()
237 {
238 	int	rv;
239 
240 	rv = mod_install(&modlinkage);
241 	return (rv);
242 }
243 
244 
245 int
_fini(void)246 _fini(void)
247 {
248 	return (mod_remove(&modlinkage));
249 }
250 
251 
252 int
_info(struct modinfo * modinfop)253 _info(struct modinfo *modinfop)
254 {
255 	return (mod_info(&modlinkage, modinfop));
256 }
257 
258 static int
mouse8042_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)259 mouse8042_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
260 {
261 	struct mouse_state *state;
262 	mblk_t *mp;
263 	int instance = ddi_get_instance(dip);
264 	static ddi_device_acc_attr_t attr = {
265 		DDI_DEVICE_ATTR_V0,
266 		DDI_NEVERSWAP_ACC,
267 		DDI_STRICTORDER_ACC,
268 	};
269 	int rc;
270 
271 
272 	if (cmd == DDI_RESUME) {
273 		state = (struct mouse_state *)ddi_get_driver_private(dip);
274 
275 		/* Ready to handle inbound data from mouse8042_intr */
276 		state->ready = 1;
277 
278 		/*
279 		 * Send a 0xaa 0x00 upstream.
280 		 * This causes the vuid module to reset the mouse.
281 		 */
282 		if (state->ms_rqp != NULL) {
283 			if (mp = allocb(1, BPRI_MED)) {
284 				*mp->b_wptr++ = 0xaa;
285 				putnext(state->ms_rqp, mp);
286 			}
287 			if (mp = allocb(1, BPRI_MED)) {
288 				*mp->b_wptr++ = 0x0;
289 				putnext(state->ms_rqp, mp);
290 			}
291 		}
292 		return (DDI_SUCCESS);
293 	}
294 
295 	if (cmd != DDI_ATTACH)
296 		return (DDI_FAILURE);
297 
298 	if (mouse8042_dip != NULL)
299 		return (DDI_FAILURE);
300 
301 	/* allocate and initialize state structure */
302 	state = kmem_zalloc(sizeof (struct mouse_state), KM_SLEEP);
303 	state->ms_opened = B_FALSE;
304 	state->reset_state = MSE_RESET_IDLE;
305 	state->reset_tid = 0;
306 	state->bc_id = 0;
307 	ddi_set_driver_private(dip, state);
308 
309 	/*
310 	 * In order to support virtual keyboard/mouse, we should distinguish
311 	 * between internal virtual open and external physical open.
312 	 *
313 	 * When the physical devices are opened by application, they will
314 	 * be unlinked from the virtual device and their data stream will
315 	 * not be sent to the virtual device. When the opened physical
316 	 * devices are closed, they will be relinked to the virtual devices.
317 	 *
318 	 * All these automatic switch between virtual and physical are
319 	 * transparent.
320 	 *
321 	 * So we change minor node numbering scheme to be:
322 	 *	external node minor num == instance * 2
323 	 *	internal node minor num == instance * 2 + 1
324 	 */
325 	rc = ddi_create_minor_node(dip, "mouse", S_IFCHR, instance * 2,
326 	    DDI_NT_MOUSE, 0);
327 	if (rc != DDI_SUCCESS) {
328 		goto fail_1;
329 	}
330 
331 	if (ddi_create_internal_pathname(dip, "internal_mouse", S_IFCHR,
332 	    instance * 2 + 1) != DDI_SUCCESS) {
333 		goto fail_2;
334 	}
335 
336 	rc = ddi_regs_map_setup(dip, 0, (caddr_t *)&state->ms_addr,
337 	    (offset_t)0, (offset_t)0, &attr, &state->ms_handle);
338 	if (rc != DDI_SUCCESS) {
339 		goto fail_2;
340 	}
341 
342 	rc = ddi_get_iblock_cookie(dip, 0, &state->ms_iblock_cookie);
343 	if (rc != DDI_SUCCESS) {
344 		goto fail_3;
345 	}
346 
347 	mutex_init(&state->ms_mutex, NULL, MUTEX_DRIVER,
348 	    state->ms_iblock_cookie);
349 	mutex_init(&state->reset_mutex, NULL, MUTEX_DRIVER,
350 	    state->ms_iblock_cookie);
351 	cv_init(&state->reset_cv, NULL, CV_DRIVER, NULL);
352 
353 	rc = ddi_add_intr(dip, 0,
354 	    (ddi_iblock_cookie_t *)NULL, (ddi_idevice_cookie_t *)NULL,
355 	    mouse8042_intr, (caddr_t)state);
356 	if (rc != DDI_SUCCESS) {
357 		goto fail_3;
358 	}
359 
360 	mouse8042_dip = dip;
361 
362 	/* Ready to handle inbound data from mouse8042_intr */
363 	state->ready = 1;
364 
365 	/* Now that we're attached, announce our presence to the world. */
366 	ddi_report_dev(dip);
367 	return (DDI_SUCCESS);
368 
369 fail_3:
370 	ddi_regs_map_free(&state->ms_handle);
371 
372 fail_2:
373 	ddi_remove_minor_node(dip, NULL);
374 
375 fail_1:
376 	kmem_free(state, sizeof (struct mouse_state));
377 	return (rc);
378 }
379 
380 /*ARGSUSED*/
381 static int
mouse8042_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)382 mouse8042_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
383 {
384 	struct mouse_state *state;
385 
386 	state = ddi_get_driver_private(dip);
387 
388 	switch (cmd) {
389 	case DDI_SUSPEND:
390 		/* Ignore all data from mouse8042_intr until we fully resume */
391 		state->ready = 0;
392 		return (DDI_SUCCESS);
393 
394 	case DDI_DETACH:
395 		ddi_remove_intr(dip, 0, state->ms_iblock_cookie);
396 		mouse8042_dip = NULL;
397 		cv_destroy(&state->reset_cv);
398 		mutex_destroy(&state->reset_mutex);
399 		mutex_destroy(&state->ms_mutex);
400 		ddi_prop_remove_all(dip);
401 		ddi_regs_map_free(&state->ms_handle);
402 		ddi_remove_minor_node(dip, NULL);
403 		kmem_free(state, sizeof (struct mouse_state));
404 		return (DDI_SUCCESS);
405 
406 	default:
407 		return (DDI_FAILURE);
408 	}
409 }
410 
411 
412 /* ARGSUSED */
413 static int
mouse8042_getinfo(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)414 mouse8042_getinfo(
415     dev_info_t *dip,
416     ddi_info_cmd_t infocmd,
417     void *arg,
418     void **result)
419 {
420 	dev_t dev = (dev_t)arg;
421 	minor_t	minor = getminor(dev);
422 	int	instance = MOUSE8042_MINOR_TO_INSTANCE(minor);
423 
424 	switch (infocmd) {
425 	case DDI_INFO_DEVT2DEVINFO:
426 		if (mouse8042_dip == NULL)
427 			return (DDI_FAILURE);
428 
429 		*result = (void *)mouse8042_dip;
430 		break;
431 	case DDI_INFO_DEVT2INSTANCE:
432 		*result = (void *)(uintptr_t)instance;
433 		break;
434 	default:
435 		return (DDI_FAILURE);
436 	}
437 	return (DDI_SUCCESS);
438 }
439 
440 /*ARGSUSED*/
441 static int
mouse8042_open(queue_t * q,dev_t * devp,int flag,int sflag,cred_t * cred_p)442 mouse8042_open(
443 	queue_t	*q,
444 	dev_t	*devp,
445 	int	flag,
446 	int	sflag,
447 	cred_t	*cred_p)
448 {
449 	struct mouse_state *state;
450 	minor_t	minor = getminor(*devp);
451 	int rval;
452 
453 	if (mouse8042_dip == NULL)
454 		return (ENXIO);
455 
456 	state = ddi_get_driver_private(mouse8042_dip);
457 
458 	mutex_enter(&state->ms_mutex);
459 
460 	if (state->ms_opened) {
461 		/*
462 		 * Exit if the same minor node is already open
463 		 */
464 		if (state->ms_minor == minor) {
465 			mutex_exit(&state->ms_mutex);
466 			return (0);
467 		}
468 
469 		/*
470 		 * Check whether it is switch between physical and virtual
471 		 *
472 		 * Opening from virtual while the device is being physically
473 		 * opened by an application should not happen. So we ASSERT
474 		 * this in DEBUG version, and return error in the non-DEBUG
475 		 * case.
476 		 */
477 		ASSERT(!MOUSE8042_INTERNAL_OPEN(minor));
478 
479 		if (MOUSE8042_INTERNAL_OPEN(minor)) {
480 			mutex_exit(&state->ms_mutex);
481 			return (EINVAL);
482 		}
483 
484 		/*
485 		 * Opening the physical one while it is being underneath
486 		 * the virtual one.
487 		 *
488 		 * consconfig_unlink is called to unlink this device from
489 		 * the virtual one, thus the old stream serving for this
490 		 * device under the virtual one is closed, and then the
491 		 * lower driver's close routine (here is mouse8042_close)
492 		 * is also called to accomplish the whole stream close.
493 		 * Here we have to drop the lock because mouse8042_close
494 		 * also needs the lock.
495 		 *
496 		 * For mouse, the old stream is:
497 		 *	consms->["pushmod"->]"mouse_vp driver"
498 		 *
499 		 * After the consconfig_unlink returns, the old stream is closed
500 		 * and we grab the lock again to reopen this device as normal.
501 		 */
502 		mutex_exit(&state->ms_mutex);
503 
504 		/*
505 		 * If unlink fails, fail the physical open.
506 		 */
507 		if ((rval = consconfig_unlink(ddi_driver_major(mouse8042_dip),
508 		    MOUSE8042_INTERNAL_MINOR(minor))) != 0) {
509 			return (rval);
510 		}
511 
512 		mutex_enter(&state->ms_mutex);
513 	}
514 
515 
516 	q->q_ptr = (caddr_t)state;
517 	WR(q)->q_ptr = (caddr_t)state;
518 	state->ms_rqp = q;
519 	state->ms_wqp = WR(q);
520 
521 	qprocson(q);
522 
523 	state->ms_minor = minor;
524 	state->ms_opened = B_TRUE;
525 
526 	mutex_exit(&state->ms_mutex);
527 
528 	return (0);
529 }
530 
531 
532 /*ARGSUSED*/
533 static int
mouse8042_close(queue_t * q,int flag,cred_t * cred_p)534 mouse8042_close(queue_t *q, int flag, cred_t *cred_p)
535 {
536 	struct mouse_state *state;
537 	minor_t	minor;
538 
539 	state = (struct mouse_state *)q->q_ptr;
540 
541 	/*
542 	 * Disable queue processing now, so that another reset cannot get in
543 	 * after we wait for the current reset (if any) to complete.
544 	 */
545 	qprocsoff(q);
546 
547 	mutex_enter(&state->reset_mutex);
548 	while (state->reset_state != MSE_RESET_IDLE) {
549 		/*
550 		 * Waiting for the previous reset to finish is
551 		 * non-interruptible.  Some upper-level clients
552 		 * cannot deal with EINTR and will not close the
553 		 * STREAM properly, resulting in failure to reopen it
554 		 * within the same process.
555 		 */
556 		cv_wait(&state->reset_cv, &state->reset_mutex);
557 	}
558 
559 	if (state->reset_tid != 0) {
560 		(void) quntimeout(q, state->reset_tid);
561 		state->reset_tid = 0;
562 	}
563 
564 	if (state->reply_mp != NULL) {
565 		freemsg(state->reply_mp);
566 		state->reply_mp = NULL;
567 	}
568 
569 	if (state->reset_ack_mp != NULL) {
570 		freemsg(state->reset_ack_mp);
571 		state->reset_ack_mp = NULL;
572 	}
573 
574 	mutex_exit(&state->reset_mutex);
575 
576 	mutex_enter(&state->ms_mutex);
577 
578 	if (state->bc_id != 0) {
579 		(void) qunbufcall(q, state->bc_id);
580 		state->bc_id = 0;
581 	}
582 
583 	q->q_ptr = NULL;
584 	WR(q)->q_ptr = NULL;
585 	state->ms_rqp = NULL;
586 	state->ms_wqp = NULL;
587 
588 	state->ms_opened = B_FALSE;
589 
590 	minor = state->ms_minor;
591 
592 	mutex_exit(&state->ms_mutex);
593 
594 	if (!MOUSE8042_INTERNAL_OPEN(minor)) {
595 		/*
596 		 * Closing physical PS/2 mouse
597 		 *
598 		 * Link it back to virtual mouse, and
599 		 * mouse8042_open will be called as a result
600 		 * of the consconfig_link call.  Do NOT try
601 		 * this if the mouse is about to be detached!
602 		 *
603 		 * If linking back fails, this specific mouse
604 		 * will not be available underneath the virtual
605 		 * mouse, and can only be accessed via physical
606 		 * open.
607 		 */
608 		consconfig_link(ddi_driver_major(mouse8042_dip),
609 		    MOUSE8042_INTERNAL_MINOR(minor));
610 	}
611 
612 	return (0);
613 }
614 
615 static void
mouse8042_iocnack(queue_t * qp,mblk_t * mp,struct iocblk * iocp,int error,int rval)616 mouse8042_iocnack(
617     queue_t *qp,
618     mblk_t *mp,
619     struct iocblk *iocp,
620     int error,
621     int rval)
622 {
623 	mp->b_datap->db_type = M_IOCNAK;
624 	iocp->ioc_rval = rval;
625 	iocp->ioc_error = error;
626 	qreply(qp, mp);
627 }
628 
629 static void
mouse8042_reset_timeout(void * argp)630 mouse8042_reset_timeout(void *argp)
631 {
632 	struct mouse_state *state = (struct mouse_state *)argp;
633 	mblk_t *mp;
634 
635 	mutex_enter(&state->reset_mutex);
636 
637 	/*
638 	 * If the interrupt handler hasn't completed the reset handling
639 	 * (reset_state would be IDLE or FAILED in that case), then
640 	 * drop the 8042 lock, and send a faked retry reply upstream,
641 	 * then enable the queue for further message processing.
642 	 */
643 	if (state->reset_state != MSE_RESET_IDLE &&
644 	    state->reset_state != MSE_RESET_FAILED) {
645 
646 		state->reset_tid = 0;
647 		state->reset_state = MSE_RESET_IDLE;
648 		cv_signal(&state->reset_cv);
649 
650 		(void) ddi_get8(state->ms_handle, state->ms_addr +
651 		    I8042_UNLOCK);
652 
653 		mp = state->reply_mp;
654 		*mp->b_wptr++ = MSERESEND;
655 		state->reply_mp = NULL;
656 
657 		if (state->ms_rqp != NULL)
658 			putnext(state->ms_rqp, mp);
659 		else
660 			freemsg(mp);
661 
662 		ASSERT(state->ms_wqp != NULL);
663 
664 		enableok(state->ms_wqp);
665 		qenable(state->ms_wqp);
666 	}
667 
668 	mutex_exit(&state->reset_mutex);
669 }
670 
671 /*
672  * Returns 1 if the caller should put the message (bp) back on the queue
673  */
674 static int
mouse8042_initiate_reset(queue_t * q,mblk_t * mp,struct mouse_state * state)675 mouse8042_initiate_reset(queue_t *q, mblk_t *mp, struct mouse_state *state)
676 {
677 	mutex_enter(&state->reset_mutex);
678 	/*
679 	 * If we're in the middle of a reset, put the message back on the queue
680 	 * for processing later.
681 	 */
682 	if (state->reset_state != MSE_RESET_IDLE) {
683 		/*
684 		 * We noenable the queue again here in case it was backenabled
685 		 * by an upper-level module.
686 		 */
687 		noenable(q);
688 
689 		mutex_exit(&state->reset_mutex);
690 		return (1);
691 	}
692 
693 	/*
694 	 * Drop the reset state lock before allocating the response message and
695 	 * grabbing the 8042 exclusive-access lock (since those operations
696 	 * may take an extended period of time to complete).
697 	 */
698 	mutex_exit(&state->reset_mutex);
699 
700 	if (state->reply_mp == NULL)
701 		state->reply_mp = allocb(2, BPRI_MED);
702 	if (state->reset_ack_mp == NULL)
703 		state->reset_ack_mp = allocb(1, BPRI_MED);
704 
705 	if (state->reply_mp == NULL || state->reset_ack_mp == NULL) {
706 		/*
707 		 * Allocation failed -- set up a bufcall to enable the queue
708 		 * whenever there is enough memory to allocate the response
709 		 * message.
710 		 */
711 		state->bc_id = qbufcall(q, (state->reply_mp == NULL) ? 2 : 1,
712 		    BPRI_MED, (void (*)(void *))qenable, q);
713 
714 		if (state->bc_id == 0) {
715 			/*
716 			 * If the qbufcall failed, we cannot proceed, so use the
717 			 * message we were sent to respond with an error.
718 			 */
719 			*mp->b_rptr = MSEERROR;
720 			mp->b_wptr = mp->b_rptr + 1;
721 			qreply(q, mp);
722 			return (0);
723 		}
724 
725 		return (1);
726 	} else {
727 		/* Bufcall completed successfully (or wasn't needed) */
728 		state->bc_id = 0;
729 	}
730 
731 	/*
732 	 * Gain exclusive access to the 8042 for the duration of the reset.
733 	 * The unlock will occur when the reset has either completed or timed
734 	 * out.
735 	 */
736 	(void) ddi_get8(state->ms_handle,
737 	    state->ms_addr + I8042_LOCK);
738 
739 	mutex_enter(&state->reset_mutex);
740 
741 	state->reset_state = MSE_RESET_PRE;
742 	noenable(q);
743 
744 	state->reset_tid = qtimeout(q,
745 	    mouse8042_reset_timeout,
746 	    state,
747 	    drv_usectohz(
748 	    MOUSE8042_RESET_TIMEOUT_USECS));
749 
750 	ddi_put8(state->ms_handle,
751 	    state->ms_addr +
752 	    I8042_INT_OUTPUT_DATA, MSERESET);
753 
754 	mp->b_rptr++;
755 
756 	mutex_exit(&state->reset_mutex);
757 	return (1);
758 }
759 
760 /*
761  * Returns 1 if the caller should stop processing messages
762  */
763 static int
mouse8042_process_data_msg(queue_t * q,mblk_t * mp,struct mouse_state * state)764 mouse8042_process_data_msg(queue_t *q, mblk_t *mp, struct mouse_state *state)
765 {
766 	mblk_t *bp;
767 	mblk_t *next;
768 
769 	bp = mp;
770 	do {
771 		while (bp->b_rptr < bp->b_wptr) {
772 			/*
773 			 * Detect an attempt to reset the mouse.  Lock out any
774 			 * further mouse writes until the reset has completed.
775 			 */
776 			if (*bp->b_rptr == MSERESET) {
777 
778 				/*
779 				 * If we couldn't allocate memory and we
780 				 * we couldn't register a bufcall,
781 				 * mouse8042_initiate_reset returns 0 and
782 				 * has already used the message to send an
783 				 * error reply back upstream, so there is no
784 				 * need to deallocate or put this message back
785 				 * on the queue.
786 				 */
787 				if (mouse8042_initiate_reset(q, bp, state) == 0)
788 					return (1);
789 
790 				/*
791 				 * If there's no data remaining in this block,
792 				 * free this block and put the following blocks
793 				 * of this message back on the queue. If putting
794 				 * the rest of the message back on the queue
795 				 * fails, free the the message.
796 				 */
797 				if (MBLKL(bp) == 0) {
798 					next = bp->b_cont;
799 					freeb(bp);
800 					bp = next;
801 				}
802 				if (bp != NULL) {
803 					if (!putbq(q, bp))
804 						freemsg(bp);
805 				}
806 
807 				return (1);
808 
809 			}
810 			ddi_put8(state->ms_handle,
811 			    state->ms_addr + I8042_INT_OUTPUT_DATA,
812 			    *bp->b_rptr++);
813 		}
814 		next = bp->b_cont;
815 		freeb(bp);
816 	} while ((bp = next) != NULL);
817 
818 	return (0);
819 }
820 
821 static int
mouse8042_process_msg(queue_t * q,mblk_t * mp,struct mouse_state * state)822 mouse8042_process_msg(queue_t *q, mblk_t *mp, struct mouse_state *state)
823 {
824 	struct iocblk *iocbp;
825 	int rv = 0;
826 
827 	iocbp = (struct iocblk *)mp->b_rptr;
828 
829 	switch (mp->b_datap->db_type) {
830 	case M_FLUSH:
831 		if (*mp->b_rptr & FLUSHW) {
832 			flushq(q, FLUSHDATA);
833 			*mp->b_rptr &= ~FLUSHW;
834 		}
835 		if (*mp->b_rptr & FLUSHR) {
836 			qreply(q, mp);
837 		} else
838 			freemsg(mp);
839 		break;
840 	case M_IOCTL:
841 		mouse8042_iocnack(q, mp, iocbp, EINVAL, 0);
842 		break;
843 	case M_IOCDATA:
844 		mouse8042_iocnack(q, mp, iocbp, EINVAL, 0);
845 		break;
846 	case M_DATA:
847 		rv = mouse8042_process_data_msg(q, mp, state);
848 		break;
849 	default:
850 		freemsg(mp);
851 		break;
852 	}
853 
854 	return (rv);
855 }
856 
857 /*
858  * This is the main mouse input routine.  Commands and parameters
859  * from upstream are sent to the mouse device immediately, unless
860  * the mouse is in the process of being reset, in which case
861  * commands are queued and executed later in the service procedure.
862  */
863 static int
mouse8042_wput(queue_t * q,mblk_t * mp)864 mouse8042_wput(queue_t *q, mblk_t *mp)
865 {
866 	struct mouse_state *state;
867 	state = (struct mouse_state *)q->q_ptr;
868 
869 	/*
870 	 * Process all messages immediately, unless a reset is in
871 	 * progress.  If a reset is in progress, deflect processing to
872 	 * the service procedure.
873 	 */
874 	if (state->reset_state != MSE_RESET_IDLE)
875 		return (putq(q, mp));
876 
877 	/*
878 	 * If there are still messages outstanding in the queue that
879 	 * the service procedure hasn't processed yet, put this
880 	 * message in the queue also, to ensure proper message
881 	 * ordering.
882 	 */
883 	if (q->q_first)
884 		return (putq(q, mp));
885 
886 	(void) mouse8042_process_msg(q, mp, state);
887 
888 	return (0);
889 }
890 
891 static int
mouse8042_wsrv(queue_t * qp)892 mouse8042_wsrv(queue_t *qp)
893 {
894 	mblk_t *mp;
895 	struct mouse_state *state;
896 	state = (struct mouse_state *)qp->q_ptr;
897 
898 	while ((mp = getq(qp)) != NULL) {
899 		if (mouse8042_process_msg(qp, mp, state) != 0)
900 			break;
901 	}
902 
903 	return (0);
904 }
905 
906 /*
907  * Returns the next reset state, given the current state and the byte
908  * received from the mouse.  Error and Resend codes are handled by the
909  * caller.
910  */
911 static mouse8042_reset_state_e
mouse8042_reset_fsm(mouse8042_reset_state_e reset_state,uint8_t mdata)912 mouse8042_reset_fsm(mouse8042_reset_state_e reset_state, uint8_t mdata)
913 {
914 	switch (reset_state) {
915 	case MSE_RESET_PRE:	/* RESET sent, now we expect an ACK */
916 		if (mdata == MSE_ACK)	/* Got the ACK */
917 			return (MSE_RESET_ACK);
918 		break;
919 
920 	case MSE_RESET_ACK:	/* ACK received; now we expect 0xAA */
921 		if (mdata == MSE_AA)	/* Got the 0xAA */
922 			return (MSE_RESET_AA);
923 		break;
924 
925 	case MSE_RESET_AA:	/* 0xAA received; now we expect 0x00 */
926 		if (mdata == MSE_00)
927 			return (MSE_RESET_IDLE);
928 		break;
929 	}
930 
931 	return (reset_state);
932 }
933 
934 static uint_t
mouse8042_intr(caddr_t arg)935 mouse8042_intr(caddr_t arg)
936 {
937 	unsigned char    mdata;
938 	mblk_t *mp;
939 	struct mouse_state *state = (struct mouse_state *)arg;
940 	int rc;
941 
942 	mutex_enter(&state->ms_mutex);
943 
944 	rc = DDI_INTR_UNCLAIMED;
945 
946 	for (;;) {
947 
948 		if (ddi_get8(state->ms_handle,
949 		    state->ms_addr + I8042_INT_INPUT_AVAIL) == 0) {
950 			break;
951 		}
952 
953 		mdata = ddi_get8(state->ms_handle,
954 		    state->ms_addr + I8042_INT_INPUT_DATA);
955 
956 		rc = DDI_INTR_CLAIMED;
957 
958 		/*
959 		 * If we're not ready for this data, discard it.
960 		 */
961 		if (!state->ready)
962 			continue;
963 
964 		mutex_enter(&state->reset_mutex);
965 		if (state->reset_state != MSE_RESET_IDLE) {
966 
967 			if (mdata == MSEERROR || mdata == MSERESET) {
968 				state->reset_state = MSE_RESET_FAILED;
969 			} else {
970 				state->reset_state =
971 				    mouse8042_reset_fsm(state->reset_state,
972 				    mdata);
973 			}
974 
975 			if (state->reset_state == MSE_RESET_ACK) {
976 
977 			/*
978 			 * We received an ACK from the mouse, so
979 			 * send it upstream immediately so that
980 			 * consumers depending on the immediate
981 			 * ACK don't time out.
982 			 */
983 				if (state->reset_ack_mp != NULL) {
984 
985 					mp = state->reset_ack_mp;
986 
987 					state->reset_ack_mp = NULL;
988 
989 					if (state->ms_rqp != NULL) {
990 						*mp->b_wptr++ = MSE_ACK;
991 						putnext(state->ms_rqp, mp);
992 					} else
993 						freemsg(mp);
994 				}
995 
996 				if (state->ms_wqp != NULL) {
997 					enableok(state->ms_wqp);
998 					qenable(state->ms_wqp);
999 				}
1000 
1001 			} else if (state->reset_state == MSE_RESET_IDLE ||
1002 			    state->reset_state == MSE_RESET_FAILED) {
1003 
1004 			/*
1005 			 * If we transitioned back to the idle reset state (or
1006 			 * the reset failed), disable the timeout, release the
1007 			 * 8042 exclusive-access lock, then send the response
1008 			 * the the upper-level modules. Finally, enable the
1009 			 * queue and schedule queue service procedures so that
1010 			 * upper-level modules can process the response.
1011 			 * Otherwise, if we're still in the middle of the
1012 			 * reset sequence, do not send the data up (since the
1013 			 * response is sent at the end of the sequence, or
1014 			 * on timeout/error).
1015 			 */
1016 
1017 				mutex_exit(&state->reset_mutex);
1018 				(void) quntimeout(state->ms_wqp,
1019 				    state->reset_tid);
1020 				mutex_enter(&state->reset_mutex);
1021 
1022 				(void) ddi_get8(state->ms_handle,
1023 				    state->ms_addr + I8042_UNLOCK);
1024 
1025 				state->reset_tid = 0;
1026 				if (state->reply_mp != NULL) {
1027 					mp = state->reply_mp;
1028 					if (state->reset_state ==
1029 					    MSE_RESET_FAILED) {
1030 						*mp->b_wptr++ = mdata;
1031 					} else {
1032 						*mp->b_wptr++ = MSE_AA;
1033 						*mp->b_wptr++ = MSE_00;
1034 					}
1035 					state->reply_mp = NULL;
1036 				} else {
1037 					mp = NULL;
1038 				}
1039 
1040 				state->reset_state = MSE_RESET_IDLE;
1041 				cv_signal(&state->reset_cv);
1042 
1043 				if (mp != NULL) {
1044 					if (state->ms_rqp != NULL)
1045 						putnext(state->ms_rqp, mp);
1046 					else
1047 						freemsg(mp);
1048 				}
1049 
1050 				if (state->ms_wqp != NULL) {
1051 					enableok(state->ms_wqp);
1052 					qenable(state->ms_wqp);
1053 				}
1054 			}
1055 
1056 			mutex_exit(&state->reset_mutex);
1057 			mutex_exit(&state->ms_mutex);
1058 			return (rc);
1059 		}
1060 		mutex_exit(&state->reset_mutex);
1061 
1062 		if (state->ms_rqp != NULL && (mp = allocb(1, BPRI_MED))) {
1063 			*mp->b_wptr++ = mdata;
1064 			putnext(state->ms_rqp, mp);
1065 		}
1066 	}
1067 	mutex_exit(&state->ms_mutex);
1068 
1069 	return (rc);
1070 }
1071