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