1 /* $NetBSD: ms.c,v 1.40 2014/07/25 08:10:39 dholland 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.40 2014/07/25 08:10:39 dholland 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 .d_open = msopen,
94 .d_close = msclose,
95 .d_read = msread,
96 .d_write = nowrite,
97 .d_ioctl = msioctl,
98 .d_stop = nostop,
99 .d_tty = notty,
100 .d_poll = mspoll,
101 .d_mmap = nommap,
102 .d_kqfilter = mskqfilter,
103 .d_discard = nodiscard,
104 .d_flag = D_OTHER
105 };
106
107 /****************************************************************
108 * Entry points for /dev/mouse
109 * (open,close,read,write,...)
110 ****************************************************************/
111
112 int
msopen(dev_t dev,int flags,int mode,struct lwp * l)113 msopen(dev_t dev, int flags, int mode, struct lwp *l)
114 {
115 struct ms_softc *ms;
116
117 ms = device_lookup_private(&ms_cd, minor(dev));
118 if (ms == NULL)
119 return ENXIO;
120
121 /* This is an exclusive open device. */
122 if (ms->ms_events.ev_io)
123 return EBUSY;
124
125 if (ms->ms_deviopen) {
126 int err;
127 err = (*ms->ms_deviopen)(ms->ms_dev, flags);
128 if (err)
129 return err;
130 }
131 ms->ms_events.ev_io = l->l_proc;
132 ev_init(&ms->ms_events); /* may cause sleep */
133
134 ms->ms_ready = 1; /* start accepting events */
135 return 0;
136 }
137
138 int
msclose(dev_t dev,int flags,int mode,struct lwp * l)139 msclose(dev_t dev, int flags, int mode, struct lwp *l)
140 {
141 struct ms_softc *ms;
142
143 ms = device_lookup_private(&ms_cd, minor(dev));
144 ms->ms_ready = 0; /* stop accepting events */
145 ev_fini(&ms->ms_events);
146
147 ms->ms_events.ev_io = NULL;
148 if (ms->ms_deviclose) {
149 int err;
150 err = (*ms->ms_deviclose)(ms->ms_dev, flags);
151 if (err)
152 return err;
153 }
154 return 0;
155 }
156
157 int
msread(dev_t dev,struct uio * uio,int flags)158 msread(dev_t dev, struct uio *uio, int flags)
159 {
160 struct ms_softc *ms;
161
162 ms = device_lookup_private(&ms_cd, minor(dev));
163 return ev_read(&ms->ms_events, uio, flags);
164 }
165
166 int
msioctl(dev_t dev,u_long cmd,void * data,int flag,struct lwp * l)167 msioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
168 {
169 struct ms_softc *ms;
170
171 ms = device_lookup_private(&ms_cd, minor(dev));
172
173 switch (cmd) {
174
175 case FIONBIO: /* we will remove this someday (soon???) */
176 return 0;
177
178 case FIOASYNC:
179 ms->ms_events.ev_async = *(int *)data != 0;
180 return 0;
181
182 case FIOSETOWN:
183 if (-*(int *)data != ms->ms_events.ev_io->p_pgid
184 && *(int *)data != ms->ms_events.ev_io->p_pid)
185 return EPERM;
186 return 0;
187
188 case TIOCSPGRP:
189 if (*(int *)data != ms->ms_events.ev_io->p_pgid)
190 return EPERM;
191 return 0;
192
193 case VUIDGFORMAT:
194 /* we only do firm_events */
195 *(int *)data = VUID_FIRM_EVENT;
196 return 0;
197
198 case VUIDSFORMAT:
199 if (*(int *)data != VUID_FIRM_EVENT)
200 return EINVAL;
201 return 0;
202 }
203 return ENOTTY;
204 }
205
206 int
mspoll(dev_t dev,int events,struct lwp * l)207 mspoll(dev_t dev, int events, struct lwp *l)
208 {
209 struct ms_softc *ms;
210
211 ms = device_lookup_private(&ms_cd, minor(dev));
212 return ev_poll(&ms->ms_events, events, l);
213 }
214
215 int
mskqfilter(dev_t dev,struct knote * kn)216 mskqfilter(dev_t dev, struct knote *kn)
217 {
218 struct ms_softc *ms;
219
220 ms = device_lookup_private(&ms_cd, minor(dev));
221 return ev_kqfilter(&ms->ms_events, kn);
222 }
223
224 /****************************************************************
225 * Middle layer (translator)
226 ****************************************************************/
227
228 /*
229 * Called by our ms_softint() routine on input.
230 */
231 void
ms_input(struct ms_softc * ms,int c)232 ms_input(struct ms_softc *ms, int c)
233 {
234 struct firm_event *fe;
235 int mb, ub, d, get, put, any;
236 static const char to_one[] = { 1, 2, 2, 4, 4, 4, 4 };
237 static const int to_id[] = { MS_RIGHT, MS_MIDDLE, 0, MS_LEFT };
238
239 /*
240 * Discard input if not ready. Drop sync on parity or framing
241 * error; gain sync on button byte.
242 */
243 if (ms->ms_ready == 0)
244 return;
245 if (c == -1) {
246 ms->ms_byteno = -1;
247 return;
248 }
249 if ((c & 0xb0) == 0x80) { /* if in 0x80..0x8f of 0xc0..0xcf */
250 if (c & 8) {
251 ms->ms_byteno = 1; /* short form (3 bytes) */
252 } else {
253 ms->ms_byteno = 0; /* long form (5 bytes) */
254 }
255 }
256
257 /*
258 * Run the decode loop, adding to the current information.
259 * We add, rather than replace, deltas, so that if the event queue
260 * fills, we accumulate data for when it opens up again.
261 */
262 switch (ms->ms_byteno) {
263
264 case -1:
265 return;
266
267 case 0:
268 /* buttons (long form) */
269 ms->ms_byteno = 2;
270 ms->ms_mb = (~c) & 0x7;
271 return;
272
273 case 1:
274 /* buttons (short form) */
275 ms->ms_byteno = 4;
276 ms->ms_mb = (~c) & 0x7;
277 return;
278
279 case 2:
280 /* first delta-x */
281 ms->ms_byteno = 3;
282 ms->ms_dx += (char)c;
283 return;
284
285 case 3:
286 /* first delta-y */
287 ms->ms_byteno = 4;
288 ms->ms_dy += (char)c;
289 return;
290
291 case 4:
292 /* second delta-x */
293 ms->ms_byteno = 5;
294 ms->ms_dx += (char)c;
295 return;
296
297 case 5:
298 /* second delta-y */
299 ms->ms_byteno = -1; /* wait for button-byte again */
300 ms->ms_dy += (char)c;
301 break;
302
303 default:
304 panic("ms_rint");
305 /* NOTREACHED */
306 }
307
308 #if NWSMOUSE > 0
309 if (ms->ms_wsmousedev != NULL && ms->ms_ready == 2) {
310 mb = ((ms->ms_mb & 4) >> 2) |
311 (ms->ms_mb & 2) |
312 ((ms->ms_mb & 1) << 2);
313 wsmouse_input(ms->ms_wsmousedev,
314 mb,
315 ms->ms_dx, ms->ms_dy, 0, 0,
316 WSMOUSE_INPUT_DELTA);
317 ms->ms_dx = 0;
318 ms->ms_dy = 0;
319 return;
320 }
321 #endif
322 /*
323 * We have at least one event (mouse button, delta-X, or
324 * delta-Y; possibly all three, and possibly three separate
325 * button events). Deliver these events until we are out
326 * of changes or out of room. As events get delivered,
327 * mark them `unchanged'.
328 */
329 any = 0;
330 get = ms->ms_events.ev_get;
331 put = ms->ms_events.ev_put;
332 fe = &ms->ms_events.ev_q[put];
333
334 /* NEXT prepares to put the next event, backing off if necessary */
335 #define NEXT \
336 if ((++put) % EV_QSIZE == get) { \
337 put--; \
338 goto out; \
339 }
340 /* ADVANCE completes the `put' of the event */
341 #define ADVANCE \
342 fe++; \
343 if (put >= EV_QSIZE) { \
344 put = 0; \
345 fe = &ms->ms_events.ev_q[0]; \
346 } \
347 any = 1
348
349 mb = ms->ms_mb;
350 ub = ms->ms_ub;
351 while ((d = mb ^ ub) != 0) {
352 /*
353 * Mouse button change. Convert up to three changes
354 * to the `first' change, and drop it into the event queue.
355 */
356 NEXT;
357 d = to_one[d - 1]; /* from 1..7 to {1,2,4} */
358 fe->id = to_id[d - 1]; /* from {1,2,4} to ID */
359 fe->value = mb & d ? VKEY_DOWN : VKEY_UP;
360 firm_gettime(fe);
361 ADVANCE;
362 ub ^= d;
363 }
364 if (ms->ms_dx) {
365 NEXT;
366 fe->id = LOC_X_DELTA;
367 fe->value = ms->ms_dx;
368 firm_gettime(fe);
369 ADVANCE;
370 ms->ms_dx = 0;
371 }
372 if (ms->ms_dy) {
373 NEXT;
374 fe->id = LOC_Y_DELTA;
375 fe->value = ms->ms_dy;
376 firm_gettime(fe);
377 ADVANCE;
378 ms->ms_dy = 0;
379 }
380 out:
381 if (any) {
382 ms->ms_ub = ub;
383 ms->ms_events.ev_put = put;
384 EV_WAKEUP(&ms->ms_events);
385 }
386 }
387