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