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