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