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
ms_serial(tp,iopen,iclose)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
ms_rint(c)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
msopen(dev,flags,mode,p)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
msclose(dev,flags,mode,p)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
msread(dev,uio,flags)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
mswrite(dev,uio,flags)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
msioctl(dev,cmd,data,flag,p)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
msselect(dev,rw,p)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