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, NULL);
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