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