1 /* $NetBSD: zsms.c,v 1.9 2002/10/02 16:53:11 thorpej 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 * VSXXX mice attached with channel A of the 1st SCC 49 */ 50 51 #include <sys/cdefs.h> 52 __KERNEL_RCSID(0, "$NetBSD: zsms.c,v 1.9 2002/10/02 16:53:11 thorpej Exp $"); 53 54 #include <sys/param.h> 55 #include <sys/systm.h> 56 #include <sys/device.h> 57 #include <sys/ioctl.h> 58 #include <sys/syslog.h> 59 #include <sys/kernel.h> 60 #include <sys/proc.h> 61 #include <sys/tty.h> 62 63 #include <dev/ic/z8530reg.h> 64 #include <machine/z8530var.h> 65 66 #include <dev/dec/lk201.h> 67 68 #include <dev/wscons/wsconsio.h> 69 #include <dev/wscons/wsmousevar.h> 70 71 #include "locators.h" 72 73 /* 74 * How many input characters we can buffer. 75 * The port-specific var.h may override this. 76 * Note: must be a power of two! 77 */ 78 #define ZSMS_RX_RING_SIZE 256 79 #define ZSMS_RX_RING_MASK (ZSMS_RX_RING_SIZE-1) 80 /* 81 * Output buffer. Only need a few chars. 82 */ 83 #define ZSMS_TX_RING_SIZE 16 84 #define ZSMS_TX_RING_MASK (ZSMS_TX_RING_SIZE-1) 85 86 #define ZSMS_BPS 4800 87 88 struct zsms_softc { /* driver status information */ 89 struct device zsms_dev; /* required first: base device */ 90 struct zs_chanstate *zsms_cs; 91 92 /* Flags to communicate with zsms_softintr() */ 93 volatile int zsms_intr_flags; 94 #define INTR_RX_OVERRUN 1 95 #define INTR_TX_EMPTY 2 96 #define INTR_ST_CHECK 4 97 98 /* 99 * The receive ring buffer. 100 */ 101 u_int zsms_rbget; /* ring buffer `get' index */ 102 volatile u_int zsms_rbput; /* ring buffer `put' index */ 103 u_short zsms_rbuf[ZSMS_RX_RING_SIZE]; /* rr1, data pairs */ 104 105 int sc_enabled; /* input enabled? */ 106 int sc_selftest; /* self test in progress */ 107 108 int inputstate; 109 u_int buttons; 110 int dx, dy; 111 112 struct device *sc_wsmousedev; 113 }; 114 115 struct zsops zsops_zsms; 116 117 static int zsms_match __P((struct device *, struct cfdata *, void *)); 118 static void zsms_attach __P((struct device *, struct device *, void *)); 119 static void zsms_input __P((void *, int)); 120 121 CFATTACH_DECL(zsms, sizeof(struct zsms_softc), 122 zsms_match, zsms_attach, NULL, NULL); 123 124 static int zsms_enable __P((void *)); 125 static int zsms_ioctl __P((void *, u_long, caddr_t, int, struct proc *)); 126 static void zsms_disable __P((void *)); 127 128 const struct wsmouse_accessops zsms_accessops = { 129 zsms_enable, 130 zsms_ioctl, 131 zsms_disable, 132 }; 133 134 static int 135 zsms_match(parent, cf, aux) 136 struct device *parent; 137 struct cfdata *cf; 138 void *aux; 139 { 140 struct zsc_attach_args *args = aux; 141 142 /* Exact match is better than wildcard. */ 143 if (cf->cf_loc[ZSCCF_CHANNEL] == args->channel) 144 return 2; 145 146 /* This driver accepts wildcard. */ 147 if (cf->cf_loc[ZSCCF_CHANNEL] == ZSCCF_CHANNEL_DEFAULT) 148 return 1; 149 150 return 0; 151 } 152 153 static void 154 zsms_attach(parent, self, aux) 155 struct device *parent, *self; 156 void *aux; 157 { 158 struct zsc_softc *zsc = (void *)parent; 159 struct zsms_softc *zsms = (void *)self; 160 struct zsc_attach_args *args = aux; 161 struct zs_chanstate *cs; 162 struct wsmousedev_attach_args a; 163 int s; 164 165 cs = zsc->zsc_cs[args->channel]; 166 cs->cs_private = zsms; 167 cs->cs_ops = &zsops_zsms; 168 zsms->zsms_cs = cs; 169 170 printf("\n"); 171 172 /* Initialize the speed, etc. */ 173 s = splzs(); 174 /* May need reset... */ 175 zs_write_reg(cs, 9, ZSWR9_A_RESET); 176 /* These are OK as set by zscc: WR3, WR5 */ 177 /* We don't care about status or tx interrupts. */ 178 cs->cs_preg[1] = ZSWR1_RIE; 179 (void) zs_set_speed(cs, ZSMS_BPS); 180 181 /* mouse wants odd parity */ 182 cs->cs_preg[4] |= ZSWR4_PARENB; 183 /* cs->cs_preg[4] &= ~ZSWR4_EVENP; (no-op) */ 184 185 zs_loadchannelregs(cs); 186 splx(s); 187 188 a.accessops = &zsms_accessops; 189 a.accesscookie = zsms; 190 191 zsms->sc_enabled = 0; 192 zsms->sc_selftest = 0; 193 zsms->sc_wsmousedev = config_found(self, &a, wsmousedevprint); 194 } 195 196 static int 197 zsms_enable(v) 198 void *v; 199 { 200 struct zsms_softc *sc = v; 201 202 if (sc->sc_enabled) 203 return EBUSY; 204 205 sc->sc_selftest = 4; /* wait for 4 byte reply upto 1/2 sec */ 206 zs_write_data(sc->zsms_cs, MOUSE_SELF_TEST); 207 (void)tsleep(zsms_enable, TTIPRI, "zsmsopen", hz / 2); 208 if (sc->sc_selftest != 0) { 209 sc->sc_selftest = 0; 210 return ENXIO; 211 } 212 /* XXX DELAY before mode set? */ 213 zs_write_data(sc->zsms_cs, MOUSE_INCREMENTAL); 214 sc->sc_enabled = 1; 215 sc->inputstate = 0; 216 return 0; 217 } 218 219 static void 220 zsms_disable(v) 221 void *v; 222 { 223 struct zsms_softc *sc = v; 224 225 sc->sc_enabled = 0; 226 } 227 228 static int 229 zsms_ioctl(v, cmd, data, flag, p) 230 void *v; 231 u_long cmd; 232 caddr_t data; 233 int flag; 234 struct proc *p; 235 { 236 237 if (cmd == WSMOUSEIO_GTYPE) { 238 *(u_int *)data = WSMOUSE_TYPE_VSXXX; 239 return 0; 240 } 241 return EPASSTHROUGH; 242 } 243 244 static void 245 zsms_input(vsc, data) 246 void *vsc; 247 int data; 248 { 249 struct zsms_softc *sc = vsc; 250 251 if (sc->sc_enabled == 0) { 252 if (sc->sc_selftest > 0) { 253 sc->sc_selftest -= 1; 254 if (sc->sc_selftest == 0) 255 wakeup(zsms_enable); 256 } 257 return; 258 } 259 260 if ((data & MOUSE_START_FRAME) != 0) 261 sc->inputstate = 1; 262 else 263 sc->inputstate++; 264 265 if (sc->inputstate == 1) { 266 /* LMR -> RML: wsevents counts 0 for the left-most */ 267 sc->buttons = data & 02; 268 if (data & 01) 269 sc->buttons |= 04; 270 if (data & 04) 271 sc->buttons |= 01; 272 sc->dx = data & MOUSE_X_SIGN; 273 sc->dy = data & MOUSE_Y_SIGN; 274 } else if (sc->inputstate == 2) { 275 if (sc->dx == 0) 276 sc->dx = -data; 277 else 278 sc->dx = data; 279 } else if (sc->inputstate == 3) { 280 sc->inputstate = 0; 281 if (sc->dy == 0) 282 sc->dy = -data; 283 else 284 sc->dy = data; 285 wsmouse_input(sc->sc_wsmousedev, sc->buttons, 286 sc->dx, sc->dy, 0, WSMOUSE_INPUT_DELTA); 287 } 288 289 return; 290 } 291 292 /**************************************************************** 293 * Interface to the lower layer (zscc) 294 ****************************************************************/ 295 296 static void zsms_rxint __P((struct zs_chanstate *)); 297 static void zsms_stint __P((struct zs_chanstate *, int)); 298 static void zsms_txint __P((struct zs_chanstate *)); 299 static void zsms_softint __P((struct zs_chanstate *)); 300 301 static void 302 zsms_rxint(cs) 303 struct zs_chanstate *cs; 304 { 305 struct zsms_softc *zsms; 306 int put, put_next; 307 u_char c, rr1; 308 309 zsms = cs->cs_private; 310 put = zsms->zsms_rbput; 311 312 /* 313 * First read the status, because reading the received char 314 * destroys the status of this char. 315 */ 316 rr1 = zs_read_reg(cs, 1); 317 c = zs_read_data(cs); 318 if (rr1 & (ZSRR1_FE | ZSRR1_DO | ZSRR1_PE)) { 319 /* Clear the receive error. */ 320 zs_write_csr(cs, ZSWR0_RESET_ERRORS); 321 } 322 323 zsms->zsms_rbuf[put] = (c << 8) | rr1; 324 put_next = (put + 1) & ZSMS_RX_RING_MASK; 325 326 /* Would overrun if increment makes (put==get). */ 327 if (put_next == zsms->zsms_rbget) { 328 zsms->zsms_intr_flags |= INTR_RX_OVERRUN; 329 } else { 330 /* OK, really increment. */ 331 put = put_next; 332 } 333 334 /* Done reading. */ 335 zsms->zsms_rbput = put; 336 337 /* Ask for softint() call. */ 338 cs->cs_softreq = 1; 339 } 340 341 342 static void 343 zsms_txint(cs) 344 struct zs_chanstate *cs; 345 { 346 struct zsms_softc *zsms; 347 348 zsms = cs->cs_private; 349 zs_write_csr(cs, ZSWR0_RESET_TXINT); 350 zsms->zsms_intr_flags |= INTR_TX_EMPTY; 351 /* Ask for softint() call. */ 352 cs->cs_softreq = 1; 353 } 354 355 356 static void 357 zsms_stint(cs, force) 358 struct zs_chanstate *cs; 359 int force; 360 { 361 struct zsms_softc *zsms; 362 int rr0; 363 364 zsms = cs->cs_private; 365 366 rr0 = zs_read_csr(cs); 367 zs_write_csr(cs, ZSWR0_RESET_STATUS); 368 369 /* 370 * We have to accumulate status line changes here. 371 * Otherwise, if we get multiple status interrupts 372 * before the softint runs, we could fail to notice 373 * some status line changes in the softint routine. 374 * Fix from Bill Studenmund, October 1996. 375 */ 376 cs->cs_rr0_delta |= (cs->cs_rr0 ^ rr0); 377 cs->cs_rr0 = rr0; 378 zsms->zsms_intr_flags |= INTR_ST_CHECK; 379 380 /* Ask for softint() call. */ 381 cs->cs_softreq = 1; 382 } 383 384 385 static void 386 zsms_softint(cs) 387 struct zs_chanstate *cs; 388 { 389 struct zsms_softc *zsms; 390 int get, c, s; 391 int intr_flags; 392 u_short ring_data; 393 394 zsms = cs->cs_private; 395 396 /* Atomically get and clear flags. */ 397 s = splzs(); 398 intr_flags = zsms->zsms_intr_flags; 399 zsms->zsms_intr_flags = 0; 400 401 /* Now lower to spltty for the rest. */ 402 (void) spltty(); 403 404 /* 405 * Copy data from the receive ring to the event layer. 406 */ 407 get = zsms->zsms_rbget; 408 while (get != zsms->zsms_rbput) { 409 ring_data = zsms->zsms_rbuf[get]; 410 get = (get + 1) & ZSMS_RX_RING_MASK; 411 412 /* low byte of ring_data is rr1 */ 413 c = (ring_data >> 8) & 0xff; 414 415 if (ring_data & ZSRR1_DO) 416 intr_flags |= INTR_RX_OVERRUN; 417 if (ring_data & (ZSRR1_FE | ZSRR1_PE)) { 418 log(LOG_ERR, "%s: input error (0x%x)\n", 419 zsms->zsms_dev.dv_xname, ring_data); 420 c = -1; /* signal input error */ 421 } 422 423 /* Pass this up to the "middle" layer. */ 424 zsms_input(zsms, c); 425 } 426 if (intr_flags & INTR_RX_OVERRUN) { 427 log(LOG_ERR, "%s: input overrun\n", 428 zsms->zsms_dev.dv_xname); 429 } 430 zsms->zsms_rbget = get; 431 432 if (intr_flags & INTR_TX_EMPTY) { 433 /* 434 * Transmit done. (Not expected.) 435 */ 436 log(LOG_ERR, "%s: transmit interrupt?\n", 437 zsms->zsms_dev.dv_xname); 438 } 439 440 if (intr_flags & INTR_ST_CHECK) { 441 /* 442 * Status line change. (Not expected.) 443 */ 444 log(LOG_ERR, "%s: status interrupt?\n", 445 zsms->zsms_dev.dv_xname); 446 cs->cs_rr0_delta = 0; 447 } 448 449 splx(s); 450 } 451 452 struct zsops zsops_zsms = { 453 zsms_rxint, /* receive char available */ 454 zsms_stint, /* external/status */ 455 zsms_txint, /* xmit buffer empty */ 456 zsms_softint, /* process software interrupt */ 457 }; 458