wsmouse.c revision 1.4 1 /* $NetBSD: wsmouse.c,v 1.4 1998/07/27 22:33:22 drochner Exp $ */
2
3 /*
4 * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Christopher G. Demetriou
17 * for the NetBSD Project.
18 * 4. The name of the author may not be used to endorse or promote products
19 * derived from this software without specific prior written permission
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32
33 static const char _copyright[] __attribute__ ((unused)) =
34 "Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.";
35 static const char _rcsid[] __attribute__ ((unused)) =
36 "$NetBSD: wsmouse.c,v 1.4 1998/07/27 22:33:22 drochner Exp $";
37
38 /*
39 * Copyright (c) 1992, 1993
40 * The Regents of the University of California. All rights reserved.
41 *
42 * This software was developed by the Computer Systems Engineering group
43 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
44 * contributed to Berkeley.
45 *
46 * All advertising materials mentioning features or use of this software
47 * must display the following acknowledgement:
48 * This product includes software developed by the University of
49 * California, Lawrence Berkeley Laboratory.
50 *
51 * Redistribution and use in source and binary forms, with or without
52 * modification, are permitted provided that the following conditions
53 * are met:
54 * 1. Redistributions of source code must retain the above copyright
55 * notice, this list of conditions and the following disclaimer.
56 * 2. Redistributions in binary form must reproduce the above copyright
57 * notice, this list of conditions and the following disclaimer in the
58 * documentation and/or other materials provided with the distribution.
59 * 3. All advertising materials mentioning features or use of this software
60 * must display the following acknowledgement:
61 * This product includes software developed by the University of
62 * California, Berkeley and its contributors.
63 * 4. Neither the name of the University nor the names of its contributors
64 * may be used to endorse or promote products derived from this software
65 * without specific prior written permission.
66 *
67 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
68 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
69 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
70 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
71 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
72 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
73 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
74 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
75 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
76 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
77 * SUCH DAMAGE.
78 *
79 * @(#)ms.c 8.1 (Berkeley) 6/11/93
80 */
81
82 /*
83 * Mouse driver.
84 */
85
86 #include <sys/param.h>
87 #include <sys/conf.h>
88 #include <sys/ioctl.h>
89 #include <sys/kernel.h>
90 #include <sys/proc.h>
91 #include <sys/syslog.h>
92 #include <sys/systm.h>
93 #include <sys/tty.h>
94 #include <sys/signalvar.h>
95 #include <sys/device.h>
96
97 #include <dev/wscons/wsconsio.h>
98 #include <dev/wscons/wsmousevar.h>
99 #include <dev/wscons/wseventvar.h>
100
101 #include "wsmouse.h"
102
103 struct wsmouse_softc {
104 struct device sc_dv;
105
106 const struct wsmouse_accessops *sc_accessops;
107 void *sc_accesscookie;
108
109 int sc_ready; /* accepting events */
110 struct wseventvar sc_events; /* event queue state */
111
112 u_int sc_mb; /* mouse button state */
113 u_int sc_ub; /* user button state */
114 int sc_dx; /* delta-x */
115 int sc_dy; /* delta-y */
116 int sc_dz; /* delta-z */
117 };
118
119 int wsmouse_match __P((struct device *, struct cfdata *, void *));
120 void wsmouse_attach __P((struct device *, struct device *, void *));
121
122 struct cfattach wsmouse_ca = {
123 sizeof (struct wsmouse_softc), wsmouse_match, wsmouse_attach,
124 };
125
126 #if NWSMOUSE > 0
127 extern struct cfdriver wsmouse_cd;
128 #endif /* NWSMOUSE > 0 */
129
130 cdev_decl(wsmouse);
131
132 /*
133 * Print function (for parent devices).
134 */
135 int
136 wsmousedevprint(aux, pnp)
137 void *aux;
138 const char *pnp;
139 {
140
141 if (pnp)
142 printf("wsmouse at %s", pnp);
143 return (UNCONF);
144 }
145
146 int
147 wsmouse_match(parent, match, aux)
148 struct device *parent;
149 struct cfdata *match;
150 void *aux;
151 {
152
153 return (1);
154 }
155
156 void
157 wsmouse_attach(parent, self, aux)
158 struct device *parent, *self;
159 void *aux;
160 {
161 struct wsmouse_softc *sc = (struct wsmouse_softc *)self;
162 struct wsmousedev_attach_args *ap = aux;
163
164 printf("\n");
165
166 sc->sc_accessops = ap->accessops;
167 sc->sc_accesscookie = ap->accesscookie;
168 sc->sc_ready = 0; /* sanity */
169 }
170
171 void
172 wsmouse_input(wsmousedev, btns, dx, dy, dz)
173 struct device *wsmousedev;
174 u_int btns; /* 0 is up */
175 int dx, dy, dz;
176 {
177 struct wsmouse_softc *sc = (struct wsmouse_softc *)wsmousedev;
178 struct wscons_event *ev;
179 int mb, ub, d, get, put, any;
180
181 /*
182 * Discard input if not ready.
183 */
184 if (sc->sc_ready == 0)
185 return;
186
187 sc->sc_mb = btns;
188 sc->sc_dx += dx;
189 sc->sc_dy += dy;
190 sc->sc_dz += dz;
191
192 /*
193 * We have at least one event (mouse button, delta-X, or
194 * delta-Y; possibly all three, and possibly three separate
195 * button events). Deliver these events until we are out
196 * of changes or out of room. As events get delivered,
197 * mark them `unchanged'.
198 */
199 any = 0;
200 get = sc->sc_events.get;
201 put = sc->sc_events.put;
202 ev = &sc->sc_events.q[put];
203
204 /* NEXT prepares to put the next event, backing off if necessary */
205 #define NEXT \
206 if ((++put) % WSEVENT_QSIZE == get) { \
207 put--; \
208 goto out; \
209 }
210 /* ADVANCE completes the `put' of the event */
211 #define ADVANCE \
212 ev++; \
213 if (put >= WSEVENT_QSIZE) { \
214 put = 0; \
215 ev = &sc->sc_events.q[0]; \
216 } \
217 any = 1
218 /* TIMESTAMP sets `time' field of the event to the current time */
219 #define TIMESTAMP \
220 do { \
221 int s; \
222 s = splhigh(); \
223 TIMEVAL_TO_TIMESPEC(&time, &ev->time); \
224 splx(s); \
225 } while (0)
226
227 mb = sc->sc_mb;
228 ub = sc->sc_ub;
229 while ((d = mb ^ ub) != 0) {
230 /*
231 * Mouse button change. Find the first change and drop
232 * it into the event queue.
233 */
234 NEXT;
235 ev->value = ffs(d) - 1;
236
237 KASSERT(ev->value >= 0);
238
239 d = 1 << ev->value;
240 ev->type =
241 (mb & d) ? WSCONS_EVENT_MOUSE_DOWN : WSCONS_EVENT_MOUSE_UP;
242 TIMESTAMP;
243 ADVANCE;
244 ub ^= d;
245 }
246 if (sc->sc_dx) {
247 NEXT;
248 ev->type = WSCONS_EVENT_MOUSE_DELTA_X;
249 ev->value = sc->sc_dx;
250 TIMESTAMP;
251 ADVANCE;
252 sc->sc_dx = 0;
253 }
254 if (sc->sc_dy) {
255 NEXT;
256 ev->type = WSCONS_EVENT_MOUSE_DELTA_Y;
257 ev->value = sc->sc_dy;
258 TIMESTAMP;
259 ADVANCE;
260 sc->sc_dy = 0;
261 }
262 if (sc->sc_dz) {
263 NEXT;
264 ev->type = WSCONS_EVENT_MOUSE_DELTA_Z;
265 ev->value = sc->sc_dz;
266 TIMESTAMP;
267 ADVANCE;
268 sc->sc_dz = 0;
269 }
270 out:
271 if (any) {
272 sc->sc_ub = ub;
273 sc->sc_events.put = put;
274 WSEVENT_WAKEUP(&sc->sc_events);
275 }
276 }
277
278 int
279 wsmouseopen(dev, flags, mode, p)
280 dev_t dev;
281 int flags, mode;
282 struct proc *p;
283 {
284 #if NWSMOUSE > 0
285 struct wsmouse_softc *sc;
286 int error, unit;
287
288 unit = minor(dev);
289 if (unit >= wsmouse_cd.cd_ndevs || /* make sure it was attached */
290 (sc = wsmouse_cd.cd_devs[unit]) == NULL)
291 return (ENXIO);
292
293 if (sc->sc_events.io) /* and that it's not in use */
294 return (EBUSY);
295
296 sc->sc_events.io = p;
297 wsevent_init(&sc->sc_events); /* may cause sleep */
298
299 sc->sc_ready = 1; /* start accepting events */
300
301 /* enable the device, and punt if that's not possible */
302 error = (*sc->sc_accessops->enable)(sc->sc_accesscookie);
303 if (error) {
304 sc->sc_ready = 0; /* stop accepting events */
305 wsevent_fini(&sc->sc_events);
306 sc->sc_events.io = NULL;
307 return (error);
308 }
309
310 return (0);
311 #else
312 return (ENXIO);
313 #endif /* NWSMOUSE > 0 */
314 }
315
316 int
317 wsmouseclose(dev, flags, mode, p)
318 dev_t dev;
319 int flags, mode;
320 struct proc *p;
321 {
322 #if NWSMOUSE > 0
323 struct wsmouse_softc *sc;
324 int unit;
325
326 unit = minor(dev);
327 if (unit >= wsmouse_cd.cd_ndevs || /* make sure it was attached */
328 (sc = wsmouse_cd.cd_devs[unit]) == NULL)
329 return (ENXIO);
330
331 (*sc->sc_accessops->disable)(sc->sc_accesscookie);
332
333 sc->sc_ready = 0; /* stop accepting events */
334 wsevent_fini(&sc->sc_events);
335 sc->sc_events.io = NULL;
336 return (0);
337 #else
338 return (ENXIO);
339 #endif /* NWSMOUSE > 0 */
340 }
341
342 int
343 wsmouseread(dev, uio, flags)
344 dev_t dev;
345 struct uio *uio;
346 int flags;
347 {
348 #if NWSMOUSE > 0
349 struct wsmouse_softc *sc;
350 int unit;
351
352 unit = minor(dev);
353 if (unit >= wsmouse_cd.cd_ndevs || /* make sure it was attached */
354 (sc = wsmouse_cd.cd_devs[unit]) == NULL)
355 return (ENXIO);
356
357 return (wsevent_read(&sc->sc_events, uio, flags));
358 #else
359 return (ENXIO);
360 #endif /* NWSMOUSE > 0 */
361 }
362
363 int
364 wsmouseioctl(dev, cmd, data, flag, p)
365 dev_t dev;
366 u_long cmd;
367 caddr_t data;
368 int flag;
369 struct proc *p;
370 {
371 #if NWSMOUSE > 0
372 struct wsmouse_softc *sc;
373 int unit, error;
374
375 unit = minor(dev);
376 if (unit >= wsmouse_cd.cd_ndevs || /* make sure it was attached */
377 (sc = wsmouse_cd.cd_devs[unit]) == NULL)
378 return (ENXIO);
379
380 /*
381 * Try the generic ioctls that the wsmouse interface supports.
382 */
383 switch (cmd) {
384 case FIONBIO: /* we will remove this someday (soon???) */
385 return (0);
386
387 case FIOASYNC:
388 sc->sc_events.async = *(int *)data != 0;
389 return (0);
390
391 case TIOCSPGRP:
392 if (*(int *)data != sc->sc_events.io->p_pgid)
393 return (EPERM);
394 return (0);
395 }
396
397 /*
398 * Try the mouse driver for WSMOUSEIO ioctls. It returns -1
399 * if it didn't recognize the request.
400 */
401 error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd,
402 data, flag, p);
403 return (error != -1 ? error : ENOTTY);
404 #else
405 return (ENXIO);
406 #endif /* NWSMOUSE > 0 */
407 }
408
409 int
410 wsmousepoll(dev, events, p)
411 dev_t dev;
412 int events;
413 struct proc *p;
414 {
415 #if NWSMOUSE > 0
416 struct wsmouse_softc *sc = wsmouse_cd.cd_devs[minor(dev)];
417
418 return (wsevent_poll(&sc->sc_events, events, p));
419 #else
420 return (0);
421 #endif /* NWSMOUSE > 0 */
422 }
423