xref: /original-bsd/sys/sparc/dev/ms.c (revision 3705696b)
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