1 /* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This software was developed by the Computer Systems Engineering group 6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7 * contributed to Berkeley. 8 * 9 * All advertising materials mentioning features or use of this software 10 * must display the following acknowledgement: 11 * This product includes software developed by the University of 12 * California, Lawrence Berkeley Laboratory. 13 * 14 * %sccs.include.redist.c% 15 * 16 * @(#)ms.c 8.1 (Berkeley) 06/11/93 17 * 18 * from: $Header: ms.c,v 1.5 92/11/26 01:28:47 torek Exp $ (LBL) 19 */ 20 21 /* 22 * Mouse driver. 23 */ 24 25 #include <sys/param.h> 26 #include <sys/conf.h> 27 #include <sys/ioctl.h> 28 #include <sys/kernel.h> 29 #include <sys/proc.h> 30 #include <sys/syslog.h> 31 #include <sys/systm.h> 32 #include <sys/tty.h> 33 34 #include <sparc/dev/vuid_event.h> 35 #include <sparc/dev/event_var.h> 36 37 /* 38 * Mouse state. A Mouse Systems mouse is a fairly simple device, 39 * producing five-byte blobs of the form: 40 * 41 * b dx dy dx dy 42 * 43 * where b is the button state, encoded as 0x80|(~buttons)---there are 44 * three buttons (4=left, 2=middle, 1=right)---and dx,dy are X and Y 45 * delta values, none of which have are in [0x80..0x87]. (This lets 46 * us sync up with the mouse after an error.) 47 */ 48 struct ms_softc { 49 short ms_byteno; /* input byte number, for decode */ 50 char ms_mb; /* mouse button state */ 51 char ms_ub; /* user button state */ 52 int ms_dx; /* delta-x */ 53 int ms_dy; /* delta-y */ 54 struct tty *ms_mouse; /* downlink for output to mouse */ 55 void (*ms_open) __P((struct tty *)); /* enable dataflow */ 56 void (*ms_close) __P((struct tty *));/* disable dataflow */ 57 volatile int ms_ready; /* event queue is ready */ 58 struct evvar ms_events; /* event queue state */ 59 } ms_softc; 60 61 /* 62 * Attach the mouse serial (down-link) interface. 63 * Do we need to set it to 1200 baud, 8 bits? 64 * Test by power cycling and not booting SunOS before BSD? 65 */ 66 void 67 ms_serial(tp, iopen, iclose) 68 struct tty *tp; 69 void (*iopen)(), (*iclose)(); 70 { 71 72 ms_softc.ms_mouse = tp; 73 ms_softc.ms_open = iopen; 74 ms_softc.ms_close = iclose; 75 } 76 77 void 78 ms_rint(c) 79 register int c; 80 { 81 register struct firm_event *fe; 82 register struct ms_softc *ms = &ms_softc; 83 register int mb, ub, d, get, put, any; 84 static const char to_one[] = { 1, 2, 2, 4, 4, 4, 4 }; 85 static const int to_id[] = { MS_RIGHT, MS_MIDDLE, 0, MS_LEFT }; 86 87 /* 88 * Discard input if not ready. Drop sync on parity or framing 89 * error; gain sync on button byte. 90 */ 91 if (ms->ms_ready == 0) 92 return; 93 if (c & (TTY_FE|TTY_PE)) { 94 log(LOG_WARNING, 95 "mouse input parity or framing error (0x%x)\n", c); 96 ms->ms_byteno = -1; 97 return; 98 } 99 if ((unsigned)(c - 0x80) < 8) /* if in 0x80..0x87 */ 100 ms->ms_byteno = 0; 101 102 /* 103 * Run the decode loop, adding to the current information. 104 * We add, rather than replace, deltas, so that if the event queue 105 * fills, we accumulate data for when it opens up again. 106 */ 107 switch (ms->ms_byteno) { 108 109 case -1: 110 return; 111 112 case 0: 113 /* buttons */ 114 ms->ms_byteno = 1; 115 ms->ms_mb = (~c) & 0x7; 116 return; 117 118 case 1: 119 /* first delta-x */ 120 ms->ms_byteno = 2; 121 ms->ms_dx += (char)c; 122 return; 123 124 case 2: 125 /* first delta-y */ 126 ms->ms_byteno = 3; 127 ms->ms_dy += (char)c; 128 return; 129 130 case 3: 131 /* second delta-x */ 132 ms->ms_byteno = 4; 133 ms->ms_dx += (char)c; 134 return; 135 136 case 4: 137 /* second delta-x */ 138 ms->ms_byteno = -1; /* wait for button-byte again */ 139 ms->ms_dy += (char)c; 140 break; 141 142 default: 143 panic("ms_rint"); 144 /* NOTREACHED */ 145 } 146 147 /* 148 * We have at least one event (mouse button, delta-X, or 149 * delta-Y; possibly all three, and possibly three separate 150 * button events). Deliver these events until we are out 151 * of changes or out of room. As events get delivered, 152 * mark them `unchanged'. 153 */ 154 any = 0; 155 get = ms->ms_events.ev_get; 156 put = ms->ms_events.ev_put; 157 fe = &ms->ms_events.ev_q[put]; 158 159 /* NEXT prepares to put the next event, backing off if necessary */ 160 #define NEXT \ 161 if ((++put) % EV_QSIZE == get) { \ 162 put--; \ 163 goto out; \ 164 } 165 /* ADVANCE completes the `put' of the event */ 166 #define ADVANCE \ 167 fe++; \ 168 if (put >= EV_QSIZE) { \ 169 put = 0; \ 170 fe = &ms->ms_events.ev_q[0]; \ 171 } \ 172 any = 1 173 174 mb = ms->ms_mb; 175 ub = ms->ms_ub; 176 while ((d = mb ^ ub) != 0) { 177 /* 178 * Mouse button change. Convert up to three changes 179 * to the `first' change, and drop it into the event queue. 180 */ 181 NEXT; 182 d = to_one[d - 1]; /* from 1..7 to {1,2,4} */ 183 fe->id = to_id[d - 1]; /* from {1,2,4} to ID */ 184 fe->value = mb & d ? VKEY_DOWN : VKEY_UP; 185 fe->time = time; 186 ADVANCE; 187 ub ^= d; 188 } 189 if (ms->ms_dx) { 190 NEXT; 191 fe->id = LOC_X_DELTA; 192 fe->value = ms->ms_dx; 193 fe->time = time; 194 ADVANCE; 195 ms->ms_dx = 0; 196 } 197 if (ms->ms_dy) { 198 NEXT; 199 fe->id = LOC_Y_DELTA; 200 fe->value = ms->ms_dy; 201 fe->time = time; 202 ADVANCE; 203 ms->ms_dy = 0; 204 } 205 out: 206 if (any) { 207 ms->ms_ub = ub; 208 ms->ms_events.ev_put = put; 209 EV_WAKEUP(&ms->ms_events); 210 } 211 } 212 213 int 214 msopen(dev, flags, mode, p) 215 dev_t dev; 216 int flags, mode; 217 struct proc *p; 218 { 219 int s, error; 220 221 if (ms_softc.ms_events.ev_io) 222 return (EBUSY); 223 ms_softc.ms_events.ev_io = p; 224 ev_init(&ms_softc.ms_events); /* may cause sleep */ 225 ms_softc.ms_ready = 1; /* start accepting events */ 226 (*ms_softc.ms_open)(ms_softc.ms_mouse); 227 return (0); 228 } 229 230 int 231 msclose(dev, flags, mode, p) 232 dev_t dev; 233 int flags, mode; 234 struct proc *p; 235 { 236 237 ms_softc.ms_ready = 0; /* stop accepting events */ 238 ev_fini(&ms_softc.ms_events); 239 (*ms_softc.ms_close)(ms_softc.ms_mouse); 240 ms_softc.ms_events.ev_io = NULL; 241 return (0); 242 } 243 244 int 245 msread(dev, uio, flags) 246 dev_t dev; 247 struct uio *uio; 248 int flags; 249 { 250 251 return (ev_read(&ms_softc.ms_events, uio, flags)); 252 } 253 254 /* this routine should not exist, but is convenient to write here for now */ 255 int 256 mswrite(dev, uio, flags) 257 dev_t dev; 258 struct uio *uio; 259 int flags; 260 { 261 262 return (EOPNOTSUPP); 263 } 264 265 int 266 msioctl(dev, cmd, data, flag, p) 267 dev_t dev; 268 int cmd; 269 register caddr_t data; 270 int flag; 271 struct proc *p; 272 { 273 int s; 274 275 switch (cmd) { 276 277 case FIONBIO: /* we will remove this someday (soon???) */ 278 return (0); 279 280 case FIOASYNC: 281 ms_softc.ms_events.ev_async = *(int *)data != 0; 282 return (0); 283 284 case TIOCSPGRP: 285 if (*(int *)data != ms_softc.ms_events.ev_io->p_pgid) 286 return (EPERM); 287 return (0); 288 289 case VUIDGFORMAT: 290 /* we only do firm_events */ 291 *(int *)data = VUID_FIRM_EVENT; 292 return (0); 293 294 case VUIDSFORMAT: 295 if (*(int *)data != VUID_FIRM_EVENT) 296 return (EINVAL); 297 return (0); 298 } 299 return (ENOTTY); 300 } 301 302 int 303 msselect(dev, rw, p) 304 dev_t dev; 305 int rw; 306 struct proc *p; 307 { 308 309 return (ev_select(&ms_softc.ms_events, rw, p)); 310 } 311