1 /* $NetBSD: ms.c,v 1.10 1996/10/16 20:43:40 gwr Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This software was developed by the Computer Systems Engineering group 8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 * contributed to Berkeley. 10 * 11 * All advertising materials mentioning features or use of this software 12 * must display the following acknowledgement: 13 * This product includes software developed by the University of 14 * California, Lawrence Berkeley Laboratory. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 3. All advertising materials mentioning features or use of this software 25 * must display the following acknowledgement: 26 * This product includes software developed by the University of 27 * California, Berkeley and its contributors. 28 * 4. Neither the name of the University nor the names of its contributors 29 * may be used to endorse or promote products derived from this software 30 * without specific prior written permission. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 42 * SUCH DAMAGE. 43 * 44 * @(#)ms.c 8.1 (Berkeley) 6/11/93 45 */ 46 47 /* 48 * Mouse driver (/dev/mouse) 49 */ 50 51 /* 52 * Zilog Z8530 Dual UART driver (mouse interface) 53 * 54 * This is the "slave" driver that will be attached to 55 * the "zsc" driver for a Sun mouse. 56 */ 57 58 #include <sys/param.h> 59 #include <sys/systm.h> 60 #include <sys/proc.h> 61 #include <sys/device.h> 62 #include <sys/conf.h> 63 #include <sys/ioctl.h> 64 #include <sys/kernel.h> 65 #include <sys/syslog.h> 66 #include <sys/select.h> 67 #include <sys/poll.h> 68 69 #include <dev/ic/z8530reg.h> 70 #include <machine/z8530var.h> 71 #include <machine/vuid_event.h> 72 73 #include "event_var.h" 74 75 /* 76 * How many input characters we can buffer. 77 * The port-specific var.h may override this. 78 * Note: must be a power of two! 79 */ 80 #define MS_RX_RING_SIZE 256 81 #define MS_RX_RING_MASK (MS_RX_RING_SIZE-1) 82 /* 83 * Output buffer. Only need a few chars. 84 */ 85 #define MS_TX_RING_SIZE 16 86 #define MS_TX_RING_MASK (MS_TX_RING_SIZE-1) 87 /* 88 * Keyboard serial line speed is fixed at 1200 bps. 89 */ 90 #define MS_BPS 1200 91 92 /* 93 * Mouse state. A Mouse Systems mouse is a fairly simple device, 94 * producing five-byte blobs of the form: 95 * 96 * b dx dy dx dy 97 * 98 * where b is the button state, encoded as 0x80|(~buttons)---there are 99 * three buttons (4=left, 2=middle, 1=right)---and dx,dy are X and Y 100 * delta values, none of which have are in [0x80..0x87]. (This lets 101 * us sync up with the mouse after an error.) 102 */ 103 struct ms_softc { 104 struct device ms_dev; /* required first: base device */ 105 struct zs_chanstate *ms_cs; 106 107 /* Flags to communicate with ms_softintr() */ 108 volatile int ms_intr_flags; 109 #define INTR_RX_OVERRUN 1 110 #define INTR_TX_EMPTY 2 111 #define INTR_ST_CHECK 4 112 113 /* 114 * The receive ring buffer. 115 */ 116 u_int ms_rbget; /* ring buffer `get' index */ 117 volatile u_int ms_rbput; /* ring buffer `put' index */ 118 u_short ms_rbuf[MS_RX_RING_SIZE]; /* rr1, data pairs */ 119 120 /* 121 * State of input translator 122 */ 123 short ms_byteno; /* input byte number, for decode */ 124 char ms_mb; /* mouse button state */ 125 char ms_ub; /* user button state */ 126 int ms_dx; /* delta-x */ 127 int ms_dy; /* delta-y */ 128 129 /* 130 * State of upper interface. 131 */ 132 volatile int ms_ready; /* event queue is ready */ 133 struct evvar ms_events; /* event queue state */ 134 } ms_softc; 135 136 cdev_decl(ms); /* open, close, read, write, ioctl, stop, ... */ 137 138 struct zsops zsops_ms; 139 140 /**************************************************************** 141 * Definition of the driver for autoconfig. 142 ****************************************************************/ 143 144 static int ms_match(struct device *, void *, void *); 145 static void ms_attach(struct device *, struct device *, void *); 146 147 struct cfattach ms_ca = { 148 sizeof(struct ms_softc), ms_match, ms_attach 149 }; 150 151 struct cfdriver ms_cd = { 152 NULL, "ms", DV_DULL 153 }; 154 155 156 /* 157 * ms_match: how is this zs channel configured? 158 */ 159 int 160 ms_match(parent, match, aux) 161 struct device *parent; 162 void *match, *aux; 163 { 164 struct cfdata *cf = match; 165 struct zsc_attach_args *args = aux; 166 167 /* Exact match required for keyboard. */ 168 if (cf->cf_loc[0] == args->channel) 169 return 2; 170 171 return 0; 172 } 173 174 void 175 ms_attach(parent, self, aux) 176 struct device *parent, *self; 177 void *aux; 178 179 { 180 struct zsc_softc *zsc = (void *) parent; 181 struct ms_softc *ms = (void *) self; 182 struct zsc_attach_args *args = aux; 183 struct zs_chanstate *cs; 184 struct cfdata *cf; 185 int channel, ms_unit; 186 int reset, s, tconst; 187 188 cf = ms->ms_dev.dv_cfdata; 189 ms_unit = ms->ms_dev.dv_unit; 190 channel = args->channel; 191 cs = &zsc->zsc_cs[channel]; 192 cs->cs_private = ms; 193 cs->cs_ops = &zsops_ms; 194 ms->ms_cs = cs; 195 196 printf("\n"); 197 198 /* Initialize the speed, etc. */ 199 tconst = BPS_TO_TCONST(cs->cs_brg_clk, MS_BPS); 200 s = splzs(); 201 /* May need reset... */ 202 reset = (channel == 0) ? 203 ZSWR9_A_RESET : ZSWR9_B_RESET; 204 zs_write_reg(cs, 9, reset); 205 /* These are OK as set by zscc: WR3, WR4, WR5 */ 206 cs->cs_preg[5] |= ZSWR5_DTR | ZSWR5_RTS; 207 cs->cs_preg[12] = tconst; 208 cs->cs_preg[13] = tconst >> 8; 209 zs_loadchannelregs(cs); 210 splx(s); 211 212 /* Initialize translator. */ 213 ms->ms_byteno = -1; 214 } 215 216 /**************************************************************** 217 * Entry points for /dev/mouse 218 * (open,close,read,write,...) 219 ****************************************************************/ 220 221 int 222 msopen(dev, flags, mode, p) 223 dev_t dev; 224 int flags, mode; 225 struct proc *p; 226 { 227 struct ms_softc *ms; 228 int error, s, unit; 229 230 unit = minor(dev); 231 if (unit >= ms_cd.cd_ndevs) 232 return (ENXIO); 233 ms = ms_cd.cd_devs[unit]; 234 if (ms == NULL) 235 return (ENXIO); 236 237 /* This is an exclusive open device. */ 238 if (ms->ms_events.ev_io) 239 return (EBUSY); 240 ms->ms_events.ev_io = p; 241 ev_init(&ms->ms_events); /* may cause sleep */ 242 243 ms->ms_ready = 1; /* start accepting events */ 244 return (0); 245 } 246 247 int 248 msclose(dev, flags, mode, p) 249 dev_t dev; 250 int flags, mode; 251 struct proc *p; 252 { 253 struct ms_softc *ms; 254 255 ms = ms_cd.cd_devs[minor(dev)]; 256 ms->ms_ready = 0; /* stop accepting events */ 257 ev_fini(&ms->ms_events); 258 259 ms->ms_events.ev_io = NULL; 260 return (0); 261 } 262 263 int 264 msread(dev, uio, flags) 265 dev_t dev; 266 struct uio *uio; 267 int flags; 268 { 269 struct ms_softc *ms; 270 271 ms = ms_cd.cd_devs[minor(dev)]; 272 return (ev_read(&ms->ms_events, uio, flags)); 273 } 274 275 /* this routine should not exist, but is convenient to write here for now */ 276 int 277 mswrite(dev, uio, flags) 278 dev_t dev; 279 struct uio *uio; 280 int flags; 281 { 282 283 return (EOPNOTSUPP); 284 } 285 286 int 287 msioctl(dev, cmd, data, flag, p) 288 dev_t dev; 289 u_long cmd; 290 register caddr_t data; 291 int flag; 292 struct proc *p; 293 { 294 struct ms_softc *ms; 295 296 ms = ms_cd.cd_devs[minor(dev)]; 297 298 switch (cmd) { 299 300 case FIONBIO: /* we will remove this someday (soon???) */ 301 return (0); 302 303 case FIOASYNC: 304 ms->ms_events.ev_async = *(int *)data != 0; 305 return (0); 306 307 case TIOCSPGRP: 308 if (*(int *)data != ms->ms_events.ev_io->p_pgid) 309 return (EPERM); 310 return (0); 311 312 case VUIDGFORMAT: 313 /* we only do firm_events */ 314 *(int *)data = VUID_FIRM_EVENT; 315 return (0); 316 317 case VUIDSFORMAT: 318 if (*(int *)data != VUID_FIRM_EVENT) 319 return (EINVAL); 320 return (0); 321 } 322 return (ENOTTY); 323 } 324 325 int 326 mspoll(dev, events, p) 327 dev_t dev; 328 int events; 329 struct proc *p; 330 { 331 struct ms_softc *ms; 332 333 ms = ms_cd.cd_devs[minor(dev)]; 334 return (ev_poll(&ms->ms_events, events, p)); 335 } 336 337 338 /**************************************************************** 339 * Middle layer (translator) 340 ****************************************************************/ 341 342 /* 343 * Called by our ms_softint() routine on input. 344 */ 345 void 346 ms_input(ms, c) 347 register struct ms_softc *ms; 348 register int c; 349 { 350 register struct firm_event *fe; 351 register int mb, ub, d, get, put, any; 352 static const char to_one[] = { 1, 2, 2, 4, 4, 4, 4 }; 353 static const int to_id[] = { MS_RIGHT, MS_MIDDLE, 0, MS_LEFT }; 354 355 /* 356 * Discard input if not ready. Drop sync on parity or framing 357 * error; gain sync on button byte. 358 */ 359 if (ms->ms_ready == 0) 360 return; 361 if (c == -1) { 362 ms->ms_byteno = -1; 363 return; 364 } 365 if ((c & ~7) == 0x80) /* if in 0x80..0x87 */ 366 ms->ms_byteno = 0; 367 368 /* 369 * Run the decode loop, adding to the current information. 370 * We add, rather than replace, deltas, so that if the event queue 371 * fills, we accumulate data for when it opens up again. 372 */ 373 switch (ms->ms_byteno) { 374 375 case -1: 376 return; 377 378 case 0: 379 /* buttons */ 380 ms->ms_byteno = 1; 381 ms->ms_mb = (~c) & 0x7; 382 return; 383 384 case 1: 385 /* first delta-x */ 386 ms->ms_byteno = 2; 387 ms->ms_dx += (char)c; 388 return; 389 390 case 2: 391 /* first delta-y */ 392 ms->ms_byteno = 3; 393 ms->ms_dy += (char)c; 394 return; 395 396 case 3: 397 /* second delta-x */ 398 ms->ms_byteno = 4; 399 ms->ms_dx += (char)c; 400 return; 401 402 case 4: 403 /* second delta-x */ 404 ms->ms_byteno = -1; /* wait for button-byte again */ 405 ms->ms_dy += (char)c; 406 break; 407 408 default: 409 panic("ms_rint"); 410 /* NOTREACHED */ 411 } 412 413 /* 414 * We have at least one event (mouse button, delta-X, or 415 * delta-Y; possibly all three, and possibly three separate 416 * button events). Deliver these events until we are out 417 * of changes or out of room. As events get delivered, 418 * mark them `unchanged'. 419 */ 420 any = 0; 421 get = ms->ms_events.ev_get; 422 put = ms->ms_events.ev_put; 423 fe = &ms->ms_events.ev_q[put]; 424 425 /* NEXT prepares to put the next event, backing off if necessary */ 426 #define NEXT \ 427 if ((++put) % EV_QSIZE == get) { \ 428 put--; \ 429 goto out; \ 430 } 431 /* ADVANCE completes the `put' of the event */ 432 #define ADVANCE \ 433 fe++; \ 434 if (put >= EV_QSIZE) { \ 435 put = 0; \ 436 fe = &ms->ms_events.ev_q[0]; \ 437 } \ 438 any = 1 439 440 mb = ms->ms_mb; 441 ub = ms->ms_ub; 442 while ((d = mb ^ ub) != 0) { 443 /* 444 * Mouse button change. Convert up to three changes 445 * to the `first' change, and drop it into the event queue. 446 */ 447 NEXT; 448 d = to_one[d - 1]; /* from 1..7 to {1,2,4} */ 449 fe->id = to_id[d - 1]; /* from {1,2,4} to ID */ 450 fe->value = mb & d ? VKEY_DOWN : VKEY_UP; 451 fe->time = time; 452 ADVANCE; 453 ub ^= d; 454 } 455 if (ms->ms_dx) { 456 NEXT; 457 fe->id = LOC_X_DELTA; 458 fe->value = ms->ms_dx; 459 fe->time = time; 460 ADVANCE; 461 ms->ms_dx = 0; 462 } 463 if (ms->ms_dy) { 464 NEXT; 465 fe->id = LOC_Y_DELTA; 466 fe->value = ms->ms_dy; 467 fe->time = time; 468 ADVANCE; 469 ms->ms_dy = 0; 470 } 471 out: 472 if (any) { 473 ms->ms_ub = ub; 474 ms->ms_events.ev_put = put; 475 EV_WAKEUP(&ms->ms_events); 476 } 477 } 478 479 /**************************************************************** 480 * Interface to the lower layer (zscc) 481 ****************************************************************/ 482 483 static void 484 ms_rxint(cs) 485 register struct zs_chanstate *cs; 486 { 487 register struct ms_softc *ms; 488 register int put, put_next; 489 register u_char c, rr1; 490 491 ms = cs->cs_private; 492 put = ms->ms_rbput; 493 494 /* 495 * First read the status, because reading the received char 496 * destroys the status of this char. 497 */ 498 rr1 = zs_read_reg(cs, 1); 499 c = zs_read_data(cs); 500 501 if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { 502 /* Clear the receive error. */ 503 zs_write_csr(cs, ZSWR0_RESET_ERRORS); 504 } 505 506 ms->ms_rbuf[put] = (c << 8) | rr1; 507 put_next = (put + 1) & MS_RX_RING_MASK; 508 509 /* Would overrun if increment makes (put==get). */ 510 if (put_next == ms->ms_rbget) { 511 ms->ms_intr_flags |= INTR_RX_OVERRUN; 512 } else { 513 /* OK, really increment. */ 514 put = put_next; 515 } 516 517 /* Done reading. */ 518 ms->ms_rbput = put; 519 520 /* Ask for softint() call. */ 521 cs->cs_softreq = 1; 522 } 523 524 525 static void 526 ms_txint(cs) 527 register struct zs_chanstate *cs; 528 { 529 register struct ms_softc *ms; 530 531 ms = cs->cs_private; 532 zs_write_csr(cs, ZSWR0_RESET_TXINT); 533 ms->ms_intr_flags |= INTR_TX_EMPTY; 534 /* Ask for softint() call. */ 535 cs->cs_softreq = 1; 536 } 537 538 539 static void 540 ms_stint(cs) 541 register struct zs_chanstate *cs; 542 { 543 register struct ms_softc *ms; 544 register int rr0; 545 546 ms = cs->cs_private; 547 548 rr0 = zs_read_csr(cs); 549 zs_write_csr(cs, ZSWR0_RESET_STATUS); 550 551 /* 552 * We have to accumulate status line changes here. 553 * Otherwise, if we get multiple status interrupts 554 * before the softint runs, we could fail to notice 555 * some status line changes in the softint routine. 556 * Fix from Bill Studenmund, October 1996. 557 */ 558 cs->cs_rr0_delta |= (cs->cs_rr0 ^ rr0); 559 cs->cs_rr0 = rr0; 560 ms->ms_intr_flags |= INTR_ST_CHECK; 561 562 /* Ask for softint() call. */ 563 cs->cs_softreq = 1; 564 } 565 566 567 static void 568 ms_softint(cs) 569 struct zs_chanstate *cs; 570 { 571 register struct ms_softc *ms; 572 register int get, c, s; 573 int intr_flags; 574 register u_short ring_data; 575 register u_char rr0, rr1; 576 577 ms = cs->cs_private; 578 579 /* Atomically get and clear flags. */ 580 s = splzs(); 581 intr_flags = ms->ms_intr_flags; 582 ms->ms_intr_flags = 0; 583 584 /* Now lower to spltty for the rest. */ 585 (void) spltty(); 586 587 /* 588 * Copy data from the receive ring to the event layer. 589 */ 590 get = ms->ms_rbget; 591 while (get != ms->ms_rbput) { 592 ring_data = ms->ms_rbuf[get]; 593 get = (get + 1) & MS_RX_RING_MASK; 594 595 /* low byte of ring_data is rr1 */ 596 c = (ring_data >> 8) & 0xff; 597 598 if (ring_data & ZSRR1_DO) 599 intr_flags |= INTR_RX_OVERRUN; 600 if (ring_data & (ZSRR1_FE | ZSRR1_PE)) { 601 log(LOG_ERR, "%s: input error (0x%x)\n", 602 ms->ms_dev.dv_xname, ring_data); 603 c = -1; /* signal input error */ 604 } 605 606 /* Pass this up to the "middle" layer. */ 607 ms_input(ms, c); 608 } 609 if (intr_flags & INTR_RX_OVERRUN) { 610 log(LOG_ERR, "%s: input overrun\n", 611 ms->ms_dev.dv_xname); 612 } 613 ms->ms_rbget = get; 614 615 if (intr_flags & INTR_TX_EMPTY) { 616 /* 617 * Transmit done. (Not expected.) 618 */ 619 log(LOG_ERR, "%s: transmit interrupt?\n", 620 ms->ms_dev.dv_xname); 621 } 622 623 if (intr_flags & INTR_ST_CHECK) { 624 /* 625 * Status line change. (Not expected.) 626 */ 627 log(LOG_ERR, "%s: status interrupt?\n", 628 ms->ms_dev.dv_xname); 629 cs->cs_rr0_delta = 0; 630 } 631 632 splx(s); 633 } 634 635 struct zsops zsops_ms = { 636 ms_rxint, /* receive char available */ 637 ms_stint, /* external/status */ 638 ms_txint, /* xmit buffer empty */ 639 ms_softint, /* process software interrupt */ 640 }; 641