xref: /netbsd-src/sys/dev/sun/ms.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: ms.c,v 1.38 2009/01/11 23:36:39 christos 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. Neither the name of the University nor the names of its contributors
25  *    may be used to endorse or promote products derived from this software
26  *    without specific prior written permission.
27  *
28  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
29  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
30  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
31  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
32  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
33  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
34  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
35  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
36  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
37  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
38  * SUCH DAMAGE.
39  *
40  *	@(#)ms.c	8.1 (Berkeley) 6/11/93
41  */
42 
43 /*
44  * Mouse driver (/dev/mouse)
45  */
46 
47 /*
48  * Zilog Z8530 Dual UART driver (mouse interface)
49  *
50  * This is the "slave" driver that will be attached to
51  * the "zsc" driver for a Sun mouse.
52  */
53 
54 #include <sys/cdefs.h>
55 __KERNEL_RCSID(0, "$NetBSD: ms.c,v 1.38 2009/01/11 23:36:39 christos Exp $");
56 
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/conf.h>
60 #include <sys/device.h>
61 #include <sys/ioctl.h>
62 #include <sys/kernel.h>
63 #include <sys/proc.h>
64 #include <sys/signal.h>
65 #include <sys/signalvar.h>
66 #include <sys/time.h>
67 #include <sys/syslog.h>
68 #include <sys/select.h>
69 #include <sys/poll.h>
70 
71 #include <machine/vuid_event.h>
72 
73 #include <dev/ic/z8530reg.h>
74 #include <machine/z8530var.h>
75 #include <dev/sun/event_var.h>
76 #include <dev/sun/msvar.h>
77 
78 #include <dev/wscons/wsconsio.h>
79 #include <dev/wscons/wsmousevar.h>
80 
81 #include "ioconf.h"
82 #include "locators.h"
83 #include "wsmouse.h"
84 
85 dev_type_open(msopen);
86 dev_type_close(msclose);
87 dev_type_read(msread);
88 dev_type_ioctl(msioctl);
89 dev_type_poll(mspoll);
90 dev_type_kqfilter(mskqfilter);
91 
92 const struct cdevsw ms_cdevsw = {
93 	msopen, msclose, msread, nowrite, msioctl,
94 	nostop, notty, mspoll, nommap, mskqfilter, D_OTHER
95 };
96 
97 /****************************************************************
98  *  Entry points for /dev/mouse
99  *  (open,close,read,write,...)
100  ****************************************************************/
101 
102 int
103 msopen(dev_t dev, int flags, int mode, struct lwp *l)
104 {
105 	struct ms_softc *ms;
106 
107 	ms = device_lookup_private(&ms_cd, minor(dev));
108 	if (ms == NULL)
109 		return ENXIO;
110 
111 	/* This is an exclusive open device. */
112 	if (ms->ms_events.ev_io)
113 		return EBUSY;
114 
115 	if (ms->ms_deviopen) {
116 		int err;
117 		err = (*ms->ms_deviopen)(ms->ms_dev, flags);
118 		if (err)
119 			return err;
120 	}
121 	ms->ms_events.ev_io = l->l_proc;
122 	ev_init(&ms->ms_events);	/* may cause sleep */
123 
124 	ms->ms_ready = 1;		/* start accepting events */
125 	return 0;
126 }
127 
128 int
129 msclose(dev_t dev, int flags, int mode, struct lwp *l)
130 {
131 	struct ms_softc *ms;
132 
133 	ms = device_lookup_private(&ms_cd, minor(dev));
134 	ms->ms_ready = 0;		/* stop accepting events */
135 	ev_fini(&ms->ms_events);
136 
137 	ms->ms_events.ev_io = NULL;
138 	if (ms->ms_deviclose) {
139 		int err;
140 		err = (*ms->ms_deviclose)(ms->ms_dev, flags);
141 		if (err)
142 			return err;
143 	}
144 	return 0;
145 }
146 
147 int
148 msread(dev_t dev, struct uio *uio, int flags)
149 {
150 	struct ms_softc *ms;
151 
152 	ms = device_lookup_private(&ms_cd, minor(dev));
153 	return ev_read(&ms->ms_events, uio, flags);
154 }
155 
156 int
157 msioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
158 {
159 	struct ms_softc *ms;
160 
161 	ms = device_lookup_private(&ms_cd, minor(dev));
162 
163 	switch (cmd) {
164 
165 	case FIONBIO:		/* we will remove this someday (soon???) */
166 		return 0;
167 
168 	case FIOASYNC:
169 		ms->ms_events.ev_async = *(int *)data != 0;
170 		return 0;
171 
172 	case FIOSETOWN:
173 		if (-*(int *)data != ms->ms_events.ev_io->p_pgid
174 		    && *(int *)data != ms->ms_events.ev_io->p_pid)
175 			return EPERM;
176 		return 0;
177 
178 	case TIOCSPGRP:
179 		if (*(int *)data != ms->ms_events.ev_io->p_pgid)
180 			return EPERM;
181 		return 0;
182 
183 	case VUIDGFORMAT:
184 		/* we only do firm_events */
185 		*(int *)data = VUID_FIRM_EVENT;
186 		return 0;
187 
188 	case VUIDSFORMAT:
189 		if (*(int *)data != VUID_FIRM_EVENT)
190 			return EINVAL;
191 		return 0;
192 	}
193 	return ENOTTY;
194 }
195 
196 int
197 mspoll(dev_t dev, int events, struct lwp *l)
198 {
199 	struct ms_softc *ms;
200 
201 	ms = device_lookup_private(&ms_cd, minor(dev));
202 	return ev_poll(&ms->ms_events, events, l);
203 }
204 
205 int
206 mskqfilter(dev_t dev, struct knote *kn)
207 {
208 	struct ms_softc *ms;
209 
210 	ms = device_lookup_private(&ms_cd, minor(dev));
211 	return ev_kqfilter(&ms->ms_events, kn);
212 }
213 
214 /****************************************************************
215  * Middle layer (translator)
216  ****************************************************************/
217 
218 /*
219  * Called by our ms_softint() routine on input.
220  */
221 void
222 ms_input(struct ms_softc *ms, int c)
223 {
224 	struct firm_event *fe;
225 	int mb, ub, d, get, put, any;
226 	static const char to_one[] = { 1, 2, 2, 4, 4, 4, 4 };
227 	static const int to_id[] = { MS_RIGHT, MS_MIDDLE, 0, MS_LEFT };
228 
229 	/*
230 	 * Discard input if not ready.  Drop sync on parity or framing
231 	 * error; gain sync on button byte.
232 	 */
233 	if (ms->ms_ready == 0)
234 		return;
235 	if (c == -1) {
236 		ms->ms_byteno = -1;
237 		return;
238 	}
239 	if ((c & 0xb0) == 0x80) {	/* if in 0x80..0x8f of 0xc0..0xcf */
240 		if (c & 8) {
241 			ms->ms_byteno = 1;	/* short form (3 bytes) */
242 		} else {
243 			ms->ms_byteno = 0;	/* long form (5 bytes) */
244 		}
245 	}
246 
247 	/*
248 	 * Run the decode loop, adding to the current information.
249 	 * We add, rather than replace, deltas, so that if the event queue
250 	 * fills, we accumulate data for when it opens up again.
251 	 */
252 	switch (ms->ms_byteno) {
253 
254 	case -1:
255 		return;
256 
257 	case 0:
258 		/* buttons (long form) */
259 		ms->ms_byteno = 2;
260 		ms->ms_mb = (~c) & 0x7;
261 		return;
262 
263 	case 1:
264 		/* buttons (short form) */
265 		ms->ms_byteno = 4;
266 		ms->ms_mb = (~c) & 0x7;
267 		return;
268 
269 	case 2:
270 		/* first delta-x */
271 		ms->ms_byteno = 3;
272 		ms->ms_dx += (char)c;
273 		return;
274 
275 	case 3:
276 		/* first delta-y */
277 		ms->ms_byteno = 4;
278 		ms->ms_dy += (char)c;
279 		return;
280 
281 	case 4:
282 		/* second delta-x */
283 		ms->ms_byteno = 5;
284 		ms->ms_dx += (char)c;
285 		return;
286 
287 	case 5:
288 		/* second delta-y */
289 		ms->ms_byteno = -1;	/* wait for button-byte again */
290 		ms->ms_dy += (char)c;
291 		break;
292 
293 	default:
294 		panic("ms_rint");
295 		/* NOTREACHED */
296 	}
297 
298 #if NWSMOUSE > 0
299 	if (ms->ms_wsmousedev != NULL && ms->ms_ready == 2) {
300 		mb = ((ms->ms_mb & 4) >> 2) |
301 			(ms->ms_mb & 2) |
302 			((ms->ms_mb & 1) << 2);
303 		wsmouse_input(ms->ms_wsmousedev,
304 				mb,
305 				ms->ms_dx, ms->ms_dy, 0, 0,
306 				WSMOUSE_INPUT_DELTA);
307 		ms->ms_dx = 0;
308 		ms->ms_dy = 0;
309 		return;
310 	}
311 #endif
312 	/*
313 	 * We have at least one event (mouse button, delta-X, or
314 	 * delta-Y; possibly all three, and possibly three separate
315 	 * button events).  Deliver these events until we are out
316 	 * of changes or out of room.  As events get delivered,
317 	 * mark them `unchanged'.
318 	 */
319 	any = 0;
320 	get = ms->ms_events.ev_get;
321 	put = ms->ms_events.ev_put;
322 	fe = &ms->ms_events.ev_q[put];
323 
324 	/* NEXT prepares to put the next event, backing off if necessary */
325 #define	NEXT \
326 	if ((++put) % EV_QSIZE == get) { \
327 		put--; \
328 		goto out; \
329 	}
330 	/* ADVANCE completes the `put' of the event */
331 #define	ADVANCE \
332 	fe++; \
333 	if (put >= EV_QSIZE) { \
334 		put = 0; \
335 		fe = &ms->ms_events.ev_q[0]; \
336 	} \
337 	any = 1
338 
339 	mb = ms->ms_mb;
340 	ub = ms->ms_ub;
341 	while ((d = mb ^ ub) != 0) {
342 		/*
343 		 * Mouse button change.  Convert up to three changes
344 		 * to the `first' change, and drop it into the event queue.
345 		 */
346 		NEXT;
347 		d = to_one[d - 1];		/* from 1..7 to {1,2,4} */
348 		fe->id = to_id[d - 1];		/* from {1,2,4} to ID */
349 		fe->value = mb & d ? VKEY_DOWN : VKEY_UP;
350 		firm_gettime(fe);
351 		ADVANCE;
352 		ub ^= d;
353 	}
354 	if (ms->ms_dx) {
355 		NEXT;
356 		fe->id = LOC_X_DELTA;
357 		fe->value = ms->ms_dx;
358 		firm_gettime(fe);
359 		ADVANCE;
360 		ms->ms_dx = 0;
361 	}
362 	if (ms->ms_dy) {
363 		NEXT;
364 		fe->id = LOC_Y_DELTA;
365 		fe->value = ms->ms_dy;
366 		firm_gettime(fe);
367 		ADVANCE;
368 		ms->ms_dy = 0;
369 	}
370 out:
371 	if (any) {
372 		ms->ms_ub = ub;
373 		ms->ms_events.ev_put = put;
374 		EV_WAKEUP(&ms->ms_events);
375 	}
376 }
377