1 /* $OpenBSD: z8530ms.c,v 1.4 2016/10/24 06:13:52 deraadt Exp $ */ 2 /* $NetBSD: ms.c,v 1.12 1997/07/17 01:17:47 jtk Exp $ */ 3 4 /* 5 * Copyright (c) 2002, 2009, Miodrag Vallat 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27 * 28 * 29 * Copyright (c) 1992, 1993 30 * The Regents of the University of California. All rights reserved. 31 * 32 * This software was developed by the Computer Systems Engineering group 33 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 34 * contributed to Berkeley. 35 * 36 * All advertising materials mentioning features or use of this software 37 * must display the following acknowledgement: 38 * This product includes software developed by the University of 39 * California, Lawrence Berkeley Laboratory. 40 * 41 * Redistribution and use in source and binary forms, with or without 42 * modification, are permitted provided that the following conditions 43 * are met: 44 * 1. Redistributions of source code must retain the above copyright 45 * notice, this list of conditions and the following disclaimer. 46 * 2. Redistributions in binary form must reproduce the above copyright 47 * notice, this list of conditions and the following disclaimer in the 48 * documentation and/or other materials provided with the distribution. 49 * 3. All advertising materials mentioning features or use of this software 50 * must display the following acknowledgement: 51 * This product includes software developed by the University of 52 * California, Berkeley and its contributors. 53 * 4. Neither the name of the University nor the names of its contributors 54 * may be used to endorse or promote products derived from this software 55 * without specific prior written permission. 56 * 57 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 58 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 59 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 60 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 61 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 62 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 63 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 64 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 65 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 66 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 67 * SUCH DAMAGE. 68 * 69 * @(#)ms.c 8.1 (Berkeley) 6/11/93 70 */ 71 72 /* 73 * Zilog Z8530 Dual UART driver (mouse interface) 74 * 75 * This is the "slave" driver that will be attached to 76 * the "zsc" driver for a Sun mouse. 77 */ 78 79 #include <sys/param.h> 80 #include <sys/systm.h> 81 #include <sys/conf.h> 82 #include <sys/device.h> 83 #include <sys/ioctl.h> 84 #include <sys/kernel.h> 85 #include <sys/proc.h> 86 #include <sys/syslog.h> 87 88 #include <dev/ic/z8530reg.h> 89 #include <machine/z8530var.h> 90 91 #include <dev/wscons/wsconsio.h> 92 #include <dev/wscons/wsmousevar.h> 93 #include <dev/sun/sunmsvar.h> 94 95 /* 96 * How many input characters we can buffer. 97 * Note: must be a power of two! 98 */ 99 #define MS_RX_RING_SIZE 256 100 #define MS_RX_RING_MASK (MS_RX_RING_SIZE-1) 101 102 struct zsms_softc { 103 struct sunms_softc sc_base; 104 struct zs_chanstate *sc_cs; 105 106 /* Flags to communicate with zsms_softint() */ 107 volatile int sc_intr_flags; 108 #define INTR_RX_OVERRUN 0x01 109 #define INTR_TX_EMPTY 0x02 110 #define INTR_ST_CHECK 0x04 111 #define INTR_BPS_CHANGE 0x08 112 113 /* 114 * The receive ring buffer. 115 */ 116 uint sc_rbget; /* ring buffer `get' index */ 117 volatile uint sc_rbput; /* ring buffer `put' index */ 118 uint16_t sc_rbuf[MS_RX_RING_SIZE]; /* rr1, data pairs */ 119 }; 120 121 /* 122 * autoconf glue. 123 */ 124 125 int zsms_match(struct device *, void *, void *); 126 void zsms_attach(struct device *, struct device *, void *); 127 128 const struct cfattach zsms_ca = { 129 sizeof(struct zsms_softc), zsms_match, zsms_attach 130 }; 131 132 struct cfdriver zsms_cd = { 133 NULL, "zsms", DV_DULL 134 }; 135 136 /* 137 * wsmouse accessops. 138 */ 139 140 void zsms_disable(void *); 141 int zsms_enable(void *); 142 143 const struct wsmouse_accessops zsms_accessops = { 144 zsms_enable, 145 sunms_ioctl, 146 zsms_disable 147 }; 148 149 /* 150 * zs glue. 151 */ 152 153 void zsms_rxint(struct zs_chanstate *); 154 void zsms_softint(struct zs_chanstate *); 155 void zsms_stint(struct zs_chanstate *, int); 156 void zsms_txint(struct zs_chanstate *); 157 158 struct zsops zsops_ms = { 159 zsms_rxint, /* receive char available */ 160 zsms_stint, /* external/status */ 161 zsms_txint, /* xmit buffer empty */ 162 zsms_softint /* process software interrupt */ 163 }; 164 165 void zsms_speed_change(void *, uint); 166 167 /* 168 * autoconf glue. 169 */ 170 171 int 172 zsms_match(struct device *parent, void *vcf, void *aux) 173 { 174 struct cfdata *cf = vcf; 175 struct zsc_attach_args *args = aux; 176 int rc; 177 178 /* If we're not looking for a mouse, just exit */ 179 if (strcmp(args->type, "mouse") != 0) 180 return 0; 181 182 rc = 10; 183 184 /* Exact match is better than wildcard. */ 185 if (cf->cf_loc[ZSCCF_CHANNEL] == args->channel) 186 rc += 2; 187 188 /* This driver accepts wildcard. */ 189 if (cf->cf_loc[ZSCCF_CHANNEL] == ZSCCF_CHANNEL_DEFAULT) 190 rc += 1; 191 192 return rc; 193 } 194 195 void 196 zsms_attach(struct device *parent, struct device *self, void *aux) 197 { 198 struct zsc_softc *zsc = (struct zsc_softc *)parent; 199 struct zsms_softc *sc = (struct zsms_softc *)self; 200 struct zsc_attach_args *args = aux; 201 struct zs_chanstate *cs; 202 int channel; 203 int s; 204 205 channel = args->channel; 206 cs = zsc->zsc_cs[channel]; 207 cs->cs_private = sc; 208 cs->cs_ops = &zsops_ms; 209 sc->sc_cs = cs; 210 211 /* Initialize hardware. */ 212 s = splzs(); 213 zs_write_reg(cs, 9, channel == 0 ? ZSWR9_A_RESET : ZSWR9_B_RESET); 214 /* disable interrupts until the mouse is enabled */ 215 CLR(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE | ZSWR1_TIE); 216 /* 8 data bits is already our default */ 217 /* no parity, 2 stop bits */ 218 CLR(cs->cs_preg[4], ZSWR4_SBMASK | ZSWR4_PARMASK); 219 SET(cs->cs_preg[4], ZSWR4_TWOSB); 220 (void)zs_set_speed(cs, INIT_SPEED); 221 zs_loadchannelregs(cs); 222 splx(s); 223 224 sc->sc_base.sc_speed_change = zsms_speed_change; 225 226 sunms_attach(&sc->sc_base, &zsms_accessops); 227 } 228 229 /* 230 * wsmouse accessops. 231 */ 232 233 void 234 zsms_disable(void *v) 235 { 236 struct zsms_softc *sc = v; 237 struct zs_chanstate *cs = sc->sc_cs; 238 int s; 239 240 s = splzs(); 241 /* disable RX and status change interrupts */ 242 CLR(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE); 243 zs_loadchannelregs(cs); 244 splx(s); 245 } 246 247 int 248 zsms_enable(void *v) 249 { 250 struct zsms_softc *sc = v; 251 struct zs_chanstate *cs = sc->sc_cs; 252 int s; 253 254 s = splzs(); 255 /* enable RX and status change interrupts */ 256 SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE); 257 zs_loadchannelregs(cs); 258 splx(s); 259 260 return 0; 261 } 262 263 /* 264 * zs glue. 265 */ 266 267 void 268 zsms_rxint(struct zs_chanstate *cs) 269 { 270 struct zsms_softc *sc = cs->cs_private; 271 int put, put_next; 272 u_char rr0, rr1, c; 273 274 put = sc->sc_rbput; 275 276 for (;;) { 277 /* 278 * First read the status, because reading the received char 279 * destroys the status of this char. 280 */ 281 rr1 = zs_read_reg(cs, 1); 282 c = zs_read_data(cs); 283 284 /* 285 * Note that we do not try to change speed upon encountering 286 * framing errors, as this is not as reliable as breaks. 287 */ 288 if (ISSET(rr1, ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { 289 /* Clear the receive error. */ 290 zs_write_csr(cs, ZSWR0_RESET_ERRORS); 291 } 292 293 if (sc->sc_base.sc_state != STATE_RATE_CHANGE) { 294 sc->sc_rbuf[put] = (c << 8) | rr1; 295 put_next = (put + 1) & MS_RX_RING_MASK; 296 297 /* Would overrun if increment makes (put==get). */ 298 if (put_next == sc->sc_rbget) { 299 sc->sc_intr_flags |= INTR_RX_OVERRUN; 300 break; 301 } else { 302 /* OK, really increment. */ 303 put = put_next; 304 } 305 } 306 307 rr0 = zs_read_csr(cs); 308 if (!ISSET(rr0, ZSRR0_RX_READY)) 309 break; 310 } 311 312 /* Done reading. */ 313 sc->sc_rbput = put; 314 315 cs->cs_softreq = 1; 316 } 317 318 void 319 zsms_txint(struct zs_chanstate *cs) 320 { 321 /* 322 * This function should never be invoked as we don't accept TX 323 * interrupts. If someone alters our configuration behind our 324 * back, just disable TX interrupts again. 325 */ 326 zs_write_csr(cs, ZSWR0_RESET_TXINT); 327 328 /* disable tx interrupts */ 329 CLR(cs->cs_preg[1], ZSWR1_TIE); 330 zs_loadchannelregs(cs); 331 } 332 333 void 334 zsms_stint(struct zs_chanstate *cs, int force) 335 { 336 struct zsms_softc *sc = cs->cs_private; 337 uint8_t rr0, delta; 338 339 rr0 = zs_read_csr(cs); 340 zs_write_csr(cs, ZSWR0_RESET_STATUS); 341 342 /* 343 * A break can occur if the speed is not correct. 344 * However, we do not change speed until we get the second 345 * break, for switching speed when the mouse is unplugged 346 * will trigger a break and thus we'd loop changing speeds 347 * until the mouse is plugged again. 348 */ 349 if (!force && ISSET(rr0, ZSRR0_BREAK)) { 350 if (sc->sc_base.sc_state != STATE_RATE_CHANGE && 351 ++sc->sc_base.sc_brk > 1) { 352 sc->sc_intr_flags |= INTR_BPS_CHANGE; 353 sc->sc_base.sc_state = STATE_RATE_CHANGE; 354 cs->cs_softreq = 1; 355 #ifdef DEBUG 356 printf("%s: break detected, changing speed\n", 357 sc->sc_base.sc_dev.dv_xname); 358 #endif 359 } 360 } 361 362 if (!force) 363 delta = rr0 ^ cs->cs_rr0; 364 else 365 delta = cs->cs_rr0_mask; 366 cs->cs_rr0 = rr0; 367 368 if (ISSET(delta, cs->cs_rr0_mask)) { 369 SET(cs->cs_rr0_delta, delta); 370 371 sc->sc_intr_flags |= INTR_ST_CHECK; 372 cs->cs_softreq = 1; 373 } 374 } 375 376 void 377 zsms_softint(struct zs_chanstate *cs) 378 { 379 struct zsms_softc *sc; 380 int get, c, s, s2; 381 int intr_flags; 382 u_short ring_data; 383 384 sc = cs->cs_private; 385 386 /* Atomically get and clear flags. */ 387 s = spltty(); 388 s2 = splzs(); 389 intr_flags = sc->sc_intr_flags; 390 sc->sc_intr_flags = 0; 391 /* Now lower to spltty for the rest. */ 392 splx(s2); 393 394 /* 395 * If we have a baud rate change pending, do it now. 396 * This will reset the rx ring, so we can proceed safely. 397 */ 398 if (ISSET(intr_flags, INTR_BPS_CHANGE)) { 399 CLR(intr_flags, INTR_RX_OVERRUN); 400 sunms_speed_change(&sc->sc_base); 401 } 402 403 /* 404 * Copy data from the receive ring, if any, to the event layer. 405 */ 406 get = sc->sc_rbget; 407 while (get != sc->sc_rbput) { 408 ring_data = sc->sc_rbuf[get]; 409 get = (get + 1) & MS_RX_RING_MASK; 410 411 /* low byte of ring_data is rr1 */ 412 c = (ring_data >> 8) & 0xff; 413 414 if (ring_data & ZSRR1_DO) 415 SET(intr_flags, INTR_RX_OVERRUN); 416 417 /* Pass this up to the "middle" layer. */ 418 sunms_input(&sc->sc_base, c); 419 } 420 if (ISSET(intr_flags, INTR_RX_OVERRUN)) 421 log(LOG_ERR, "%s: input overrun\n", 422 sc->sc_base.sc_dev.dv_xname); 423 sc->sc_rbget = get; 424 425 /* 426 * Status line change. Not expected except for break conditions. 427 */ 428 if (ISSET(intr_flags, INTR_ST_CHECK)) { 429 cs->cs_rr0_delta = 0; 430 } 431 432 splx(s); 433 } 434 435 /* 436 * Reinitialize the line to a different speed. Invoked at spltty(). 437 */ 438 void 439 zsms_speed_change(void *v, uint bps) 440 { 441 struct zsms_softc *sc = v; 442 struct zs_chanstate *cs = sc->sc_cs; 443 uint8_t rr0; 444 int s; 445 446 s = splzs(); 447 448 /* 449 * Eat everything on the line. 450 */ 451 for (;;) { 452 rr0 = zs_read_csr(cs); 453 if (!ISSET(rr0, ZSRR0_RX_READY)) 454 break; 455 (void)zs_read_data(cs); 456 } 457 458 (void)zs_set_speed(cs, sc->sc_base.sc_bps); 459 zs_loadchannelregs(cs); 460 zsms_stint(cs, 1); 461 462 sc->sc_rbget = sc->sc_rbput = 0; 463 464 splx(s); 465 } 466