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