1 /* $OpenBSD: z8530ms.c,v 1.3 2015/09/18 20:22:22 kettenis 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/wsmousevar.h> 92 #include <dev/sun/sunmsvar.h> 93 94 /* 95 * How many input characters we can buffer. 96 * Note: must be a power of two! 97 */ 98 #define MS_RX_RING_SIZE 256 99 #define MS_RX_RING_MASK (MS_RX_RING_SIZE-1) 100 101 struct zsms_softc { 102 struct sunms_softc sc_base; 103 struct zs_chanstate *sc_cs; 104 105 /* Flags to communicate with zsms_softint() */ 106 volatile int sc_intr_flags; 107 #define INTR_RX_OVERRUN 0x01 108 #define INTR_TX_EMPTY 0x02 109 #define INTR_ST_CHECK 0x04 110 #define INTR_BPS_CHANGE 0x08 111 112 /* 113 * The receive ring buffer. 114 */ 115 uint sc_rbget; /* ring buffer `get' index */ 116 volatile uint sc_rbput; /* ring buffer `put' index */ 117 uint16_t sc_rbuf[MS_RX_RING_SIZE]; /* rr1, data pairs */ 118 }; 119 120 /* 121 * autoconf glue. 122 */ 123 124 int zsms_match(struct device *, void *, void *); 125 void zsms_attach(struct device *, struct device *, void *); 126 127 const struct cfattach zsms_ca = { 128 sizeof(struct zsms_softc), zsms_match, zsms_attach 129 }; 130 131 struct cfdriver zsms_cd = { 132 NULL, "zsms", DV_DULL 133 }; 134 135 /* 136 * wsmouse accessops. 137 */ 138 139 void zsms_disable(void *); 140 int zsms_enable(void *); 141 142 const struct wsmouse_accessops zsms_accessops = { 143 zsms_enable, 144 sunms_ioctl, 145 zsms_disable 146 }; 147 148 /* 149 * zs glue. 150 */ 151 152 void zsms_rxint(struct zs_chanstate *); 153 void zsms_softint(struct zs_chanstate *); 154 void zsms_stint(struct zs_chanstate *, int); 155 void zsms_txint(struct zs_chanstate *); 156 157 struct zsops zsops_ms = { 158 zsms_rxint, /* receive char available */ 159 zsms_stint, /* external/status */ 160 zsms_txint, /* xmit buffer empty */ 161 zsms_softint /* process software interrupt */ 162 }; 163 164 void zsms_speed_change(void *, uint); 165 166 /* 167 * autoconf glue. 168 */ 169 170 int 171 zsms_match(struct device *parent, void *vcf, void *aux) 172 { 173 struct cfdata *cf = vcf; 174 struct zsc_attach_args *args = aux; 175 int rc; 176 177 /* If we're not looking for a mouse, just exit */ 178 if (strcmp(args->type, "mouse") != 0) 179 return 0; 180 181 rc = 10; 182 183 /* Exact match is better than wildcard. */ 184 if (cf->cf_loc[ZSCCF_CHANNEL] == args->channel) 185 rc += 2; 186 187 /* This driver accepts wildcard. */ 188 if (cf->cf_loc[ZSCCF_CHANNEL] == ZSCCF_CHANNEL_DEFAULT) 189 rc += 1; 190 191 return rc; 192 } 193 194 void 195 zsms_attach(struct device *parent, struct device *self, void *aux) 196 { 197 struct zsc_softc *zsc = (struct zsc_softc *)parent; 198 struct zsms_softc *sc = (struct zsms_softc *)self; 199 struct zsc_attach_args *args = aux; 200 struct zs_chanstate *cs; 201 int channel; 202 int s; 203 204 channel = args->channel; 205 cs = zsc->zsc_cs[channel]; 206 cs->cs_private = sc; 207 cs->cs_ops = &zsops_ms; 208 sc->sc_cs = cs; 209 210 /* Initialize hardware. */ 211 s = splzs(); 212 zs_write_reg(cs, 9, channel == 0 ? ZSWR9_A_RESET : ZSWR9_B_RESET); 213 /* disable interrupts until the mouse is enabled */ 214 CLR(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE | ZSWR1_TIE); 215 /* 8 data bits is already our default */ 216 /* no parity, 2 stop bits */ 217 CLR(cs->cs_preg[4], ZSWR4_SBMASK | ZSWR4_PARMASK); 218 SET(cs->cs_preg[4], ZSWR4_TWOSB); 219 (void)zs_set_speed(cs, INIT_SPEED); 220 zs_loadchannelregs(cs); 221 splx(s); 222 223 sc->sc_base.sc_speed_change = zsms_speed_change; 224 225 sunms_attach(&sc->sc_base, &zsms_accessops); 226 } 227 228 /* 229 * wsmouse accessops. 230 */ 231 232 void 233 zsms_disable(void *v) 234 { 235 struct zsms_softc *sc = v; 236 struct zs_chanstate *cs = sc->sc_cs; 237 int s; 238 239 s = splzs(); 240 /* disable RX and status change interrupts */ 241 CLR(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE); 242 zs_loadchannelregs(cs); 243 splx(s); 244 } 245 246 int 247 zsms_enable(void *v) 248 { 249 struct zsms_softc *sc = v; 250 struct zs_chanstate *cs = sc->sc_cs; 251 int s; 252 253 s = splzs(); 254 /* enable RX and status change interrupts */ 255 SET(cs->cs_preg[1], ZSWR1_RIE | ZSWR1_SIE); 256 zs_loadchannelregs(cs); 257 splx(s); 258 259 return 0; 260 } 261 262 /* 263 * zs glue. 264 */ 265 266 void 267 zsms_rxint(struct zs_chanstate *cs) 268 { 269 struct zsms_softc *sc = cs->cs_private; 270 int put, put_next; 271 u_char rr0, rr1, c; 272 273 put = sc->sc_rbput; 274 275 for (;;) { 276 /* 277 * First read the status, because reading the received char 278 * destroys the status of this char. 279 */ 280 rr1 = zs_read_reg(cs, 1); 281 c = zs_read_data(cs); 282 283 /* 284 * Note that we do not try to change speed upon encountering 285 * framing errors, as this is not as reliable as breaks. 286 */ 287 if (ISSET(rr1, ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { 288 /* Clear the receive error. */ 289 zs_write_csr(cs, ZSWR0_RESET_ERRORS); 290 } 291 292 if (sc->sc_base.sc_state != STATE_RATE_CHANGE) { 293 sc->sc_rbuf[put] = (c << 8) | rr1; 294 put_next = (put + 1) & MS_RX_RING_MASK; 295 296 /* Would overrun if increment makes (put==get). */ 297 if (put_next == sc->sc_rbget) { 298 sc->sc_intr_flags |= INTR_RX_OVERRUN; 299 break; 300 } else { 301 /* OK, really increment. */ 302 put = put_next; 303 } 304 } 305 306 rr0 = zs_read_csr(cs); 307 if (!ISSET(rr0, ZSRR0_RX_READY)) 308 break; 309 } 310 311 /* Done reading. */ 312 sc->sc_rbput = put; 313 314 cs->cs_softreq = 1; 315 } 316 317 void 318 zsms_txint(struct zs_chanstate *cs) 319 { 320 /* 321 * This function should never be invoked as we don't accept TX 322 * interrupts. If someone alters our configuration behind our 323 * back, just disable TX interrupts again. 324 */ 325 zs_write_csr(cs, ZSWR0_RESET_TXINT); 326 327 /* disable tx interrupts */ 328 CLR(cs->cs_preg[1], ZSWR1_TIE); 329 zs_loadchannelregs(cs); 330 } 331 332 void 333 zsms_stint(struct zs_chanstate *cs, int force) 334 { 335 struct zsms_softc *sc = cs->cs_private; 336 uint8_t rr0, delta; 337 338 rr0 = zs_read_csr(cs); 339 zs_write_csr(cs, ZSWR0_RESET_STATUS); 340 341 /* 342 * A break can occur if the speed is not correct. 343 * However, we do not change speed until we get the second 344 * break, for switching speed when the mouse is unplugged 345 * will trigger a break and thus we'd loop changing speeds 346 * until the mouse is plugged again. 347 */ 348 if (!force && ISSET(rr0, ZSRR0_BREAK)) { 349 if (sc->sc_base.sc_state != STATE_RATE_CHANGE && 350 ++sc->sc_base.sc_brk > 1) { 351 sc->sc_intr_flags |= INTR_BPS_CHANGE; 352 sc->sc_base.sc_state = STATE_RATE_CHANGE; 353 cs->cs_softreq = 1; 354 #ifdef DEBUG 355 printf("%s: break detected, changing speed\n", 356 sc->sc_base.sc_dev.dv_xname); 357 #endif 358 } 359 } 360 361 if (!force) 362 delta = rr0 ^ cs->cs_rr0; 363 else 364 delta = cs->cs_rr0_mask; 365 cs->cs_rr0 = rr0; 366 367 if (ISSET(delta, cs->cs_rr0_mask)) { 368 SET(cs->cs_rr0_delta, delta); 369 370 sc->sc_intr_flags |= INTR_ST_CHECK; 371 cs->cs_softreq = 1; 372 } 373 } 374 375 void 376 zsms_softint(struct zs_chanstate *cs) 377 { 378 struct zsms_softc *sc; 379 int get, c, s, s2; 380 int intr_flags; 381 u_short ring_data; 382 383 sc = cs->cs_private; 384 385 /* Atomically get and clear flags. */ 386 s = spltty(); 387 s2 = splzs(); 388 intr_flags = sc->sc_intr_flags; 389 sc->sc_intr_flags = 0; 390 /* Now lower to spltty for the rest. */ 391 splx(s2); 392 393 /* 394 * If we have a baud rate change pending, do it now. 395 * This will reset the rx ring, so we can proceed safely. 396 */ 397 if (ISSET(intr_flags, INTR_BPS_CHANGE)) { 398 CLR(intr_flags, INTR_RX_OVERRUN); 399 sunms_speed_change(&sc->sc_base); 400 } 401 402 /* 403 * Copy data from the receive ring, if any, to the event layer. 404 */ 405 get = sc->sc_rbget; 406 while (get != sc->sc_rbput) { 407 ring_data = sc->sc_rbuf[get]; 408 get = (get + 1) & MS_RX_RING_MASK; 409 410 /* low byte of ring_data is rr1 */ 411 c = (ring_data >> 8) & 0xff; 412 413 if (ring_data & ZSRR1_DO) 414 SET(intr_flags, INTR_RX_OVERRUN); 415 416 /* Pass this up to the "middle" layer. */ 417 sunms_input(&sc->sc_base, c); 418 } 419 if (ISSET(intr_flags, INTR_RX_OVERRUN)) 420 log(LOG_ERR, "%s: input overrun\n", 421 sc->sc_base.sc_dev.dv_xname); 422 sc->sc_rbget = get; 423 424 /* 425 * Status line change. Not expected except for break conditions. 426 */ 427 if (ISSET(intr_flags, INTR_ST_CHECK)) { 428 cs->cs_rr0_delta = 0; 429 } 430 431 splx(s); 432 } 433 434 /* 435 * Reinitialize the line to a different speed. Invoked at spltty(). 436 */ 437 void 438 zsms_speed_change(void *v, uint bps) 439 { 440 struct zsms_softc *sc = v; 441 struct zs_chanstate *cs = sc->sc_cs; 442 uint8_t rr0; 443 int s; 444 445 s = splzs(); 446 447 /* 448 * Eat everything on the line. 449 */ 450 for (;;) { 451 rr0 = zs_read_csr(cs); 452 if (!ISSET(rr0, ZSRR0_RX_READY)) 453 break; 454 (void)zs_read_data(cs); 455 } 456 457 (void)zs_set_speed(cs, sc->sc_base.sc_bps); 458 zs_loadchannelregs(cs); 459 zsms_stint(cs, 1); 460 461 sc->sc_rbget = sc->sc_rbput = 0; 462 463 splx(s); 464 } 465