ms.c revision 1.21 1 /* $NetBSD: ms.c,v 1.21 2001/11/13 06:54:32 lukem 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.21 2001/11/13 06:54:32 lukem 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
223 /****************************************************************
224 * Middle layer (translator)
225 ****************************************************************/
226
227 /*
228 * Called by our ms_softint() routine on input.
229 */
230 void
231 ms_input(ms, c)
232 struct ms_softc *ms;
233 int c;
234 {
235 struct firm_event *fe;
236 int mb, ub, d, get, put, any;
237 static const char to_one[] = { 1, 2, 2, 4, 4, 4, 4 };
238 static const int to_id[] = { MS_RIGHT, MS_MIDDLE, 0, MS_LEFT };
239
240 /*
241 * Discard input if not ready. Drop sync on parity or framing
242 * error; gain sync on button byte.
243 */
244 if (ms->ms_ready == 0)
245 return;
246 if (c == -1) {
247 ms->ms_byteno = -1;
248 return;
249 }
250 if ((c & ~0x0f) == 0x80) { /* if in 0x80..0x8f */
251 if (c & 8) {
252 ms->ms_byteno = 1; /* short form (3 bytes) */
253 } else {
254 ms->ms_byteno = 0; /* long form (5 bytes) */
255 }
256 }
257
258 /*
259 * Run the decode loop, adding to the current information.
260 * We add, rather than replace, deltas, so that if the event queue
261 * fills, we accumulate data for when it opens up again.
262 */
263 switch (ms->ms_byteno) {
264
265 case -1:
266 return;
267
268 case 0:
269 /* buttons (long form) */
270 ms->ms_byteno = 2;
271 ms->ms_mb = (~c) & 0x7;
272 return;
273
274 case 1:
275 /* buttons (short form) */
276 ms->ms_byteno = 4;
277 ms->ms_mb = (~c) & 0x7;
278 return;
279
280 case 2:
281 /* first delta-x */
282 ms->ms_byteno = 3;
283 ms->ms_dx += (char)c;
284 return;
285
286 case 3:
287 /* first delta-y */
288 ms->ms_byteno = 4;
289 ms->ms_dy += (char)c;
290 return;
291
292 case 4:
293 /* second delta-x */
294 ms->ms_byteno = 5;
295 ms->ms_dx += (char)c;
296 return;
297
298 case 5:
299 /* second delta-y */
300 ms->ms_byteno = -1; /* wait for button-byte again */
301 ms->ms_dy += (char)c;
302 break;
303
304 default:
305 panic("ms_rint");
306 /* NOTREACHED */
307 }
308
309 /*
310 * We have at least one event (mouse button, delta-X, or
311 * delta-Y; possibly all three, and possibly three separate
312 * button events). Deliver these events until we are out
313 * of changes or out of room. As events get delivered,
314 * mark them `unchanged'.
315 */
316 any = 0;
317 get = ms->ms_events.ev_get;
318 put = ms->ms_events.ev_put;
319 fe = &ms->ms_events.ev_q[put];
320
321 /* NEXT prepares to put the next event, backing off if necessary */
322 #define NEXT \
323 if ((++put) % EV_QSIZE == get) { \
324 put--; \
325 goto out; \
326 }
327 /* ADVANCE completes the `put' of the event */
328 #define ADVANCE \
329 fe++; \
330 if (put >= EV_QSIZE) { \
331 put = 0; \
332 fe = &ms->ms_events.ev_q[0]; \
333 } \
334 any = 1
335
336 mb = ms->ms_mb;
337 ub = ms->ms_ub;
338 while ((d = mb ^ ub) != 0) {
339 /*
340 * Mouse button change. Convert up to three changes
341 * to the `first' change, and drop it into the event queue.
342 */
343 NEXT;
344 d = to_one[d - 1]; /* from 1..7 to {1,2,4} */
345 fe->id = to_id[d - 1]; /* from {1,2,4} to ID */
346 fe->value = mb & d ? VKEY_DOWN : VKEY_UP;
347 fe->time = time;
348 ADVANCE;
349 ub ^= d;
350 }
351 if (ms->ms_dx) {
352 NEXT;
353 fe->id = LOC_X_DELTA;
354 fe->value = ms->ms_dx;
355 fe->time = time;
356 ADVANCE;
357 ms->ms_dx = 0;
358 }
359 if (ms->ms_dy) {
360 NEXT;
361 fe->id = LOC_Y_DELTA;
362 fe->value = ms->ms_dy;
363 fe->time = time;
364 ADVANCE;
365 ms->ms_dy = 0;
366 }
367 out:
368 if (any) {
369 ms->ms_ub = ub;
370 ms->ms_events.ev_put = put;
371 EV_WAKEUP(&ms->ms_events);
372 }
373 }
374