wsmouse.c revision 1.1 1 /* $NetBSD: wsmouse.c,v 1.1 1998/03/22 14:24:04 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.1 1998/03/22 14:24:04 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 struct wsmouse_softc {
102 struct device sc_dv;
103
104 const struct wsmouse_accessops *sc_accessops;
105 void *sc_accesscookie;
106
107 int sc_ready; /* accepting events */
108 struct wseventvar sc_events; /* event queue state */
109
110 u_int sc_mb; /* mouse button state */
111 u_int sc_ub; /* user button state */
112 int sc_dx; /* delta-x */
113 int sc_dy; /* delta-y */
114 };
115
116 #ifdef __BROKEN_INDIRECT_CONFIG
117 int wsmouse_match __P((struct device *, void *, void *));
118 #else
119 int wsmouse_match __P((struct device *, struct cfdata *, void *));
120 #endif
121 void wsmouse_attach __P((struct device *, struct device *, void *));
122
123 struct cfattach wsmouse_ca = {
124 sizeof (struct wsmouse_softc), wsmouse_match, wsmouse_attach,
125 };
126
127 extern struct cfdriver wsmouse_cd;
128
129 cdev_decl(wsmouse);
130
131 /*
132 * Print function (for parent devices).
133 */
134 int
135 wsmousedevprint(aux, pnp)
136 void *aux;
137 const char *pnp;
138 {
139
140 if (pnp)
141 printf("wsmouse at %s", pnp);
142 return (UNCONF);
143 }
144
145 int
146 wsmouse_match(parent, match, aux)
147 struct device *parent;
148 #ifdef __BROKEN_INDIRECT_CONFIG
149 void *match;
150 #else
151 struct cfdata *match;
152 #endif
153 void *aux;
154 {
155
156 return (1);
157 }
158
159 void
160 wsmouse_attach(parent, self, aux)
161 struct device *parent, *self;
162 void *aux;
163 {
164 struct wsmouse_softc *sc = (struct wsmouse_softc *)self;
165 struct wsmousedev_attach_args *ap = aux;
166
167 printf("\n");
168
169 sc->sc_accessops = ap->accessops;
170 sc->sc_accesscookie = ap->accesscookie;
171 sc->sc_ready = 0; /* sanity */
172 }
173
174 void
175 wsmouse_input(wsmousedev, btns, dx, dy)
176 struct device *wsmousedev;
177 u_int btns; /* 0 is up */
178 int dx, dy;
179 {
180 struct wsmouse_softc *sc = (struct wsmouse_softc *)wsmousedev;
181 struct wscons_event *ev;
182 int mb, ub, d, get, put, any;
183
184 /*
185 * Discard input if not ready.
186 */
187 if (sc->sc_ready == 0)
188 return;
189
190 sc->sc_mb = btns;
191 sc->sc_dx += dx;
192 sc->sc_dy += dy;
193
194 /*
195 * We have at least one event (mouse button, delta-X, or
196 * delta-Y; possibly all three, and possibly three separate
197 * button events). Deliver these events until we are out
198 * of changes or out of room. As events get delivered,
199 * mark them `unchanged'.
200 */
201 any = 0;
202 get = sc->sc_events.get;
203 put = sc->sc_events.put;
204 ev = &sc->sc_events.q[put];
205
206 /* NEXT prepares to put the next event, backing off if necessary */
207 #define NEXT \
208 if ((++put) % WSEVENT_QSIZE == get) { \
209 put--; \
210 goto out; \
211 }
212 /* ADVANCE completes the `put' of the event */
213 #define ADVANCE \
214 ev++; \
215 if (put >= WSEVENT_QSIZE) { \
216 put = 0; \
217 ev = &sc->sc_events.q[0]; \
218 } \
219 any = 1
220 /* TIMESTAMP sets `time' field of the event to the current time */
221 #define TIMESTAMP \
222 do { \
223 int s; \
224 s = splhigh(); \
225 TIMEVAL_TO_TIMESPEC(&time, &ev->time); \
226 splx(s); \
227 } while (0)
228
229 mb = sc->sc_mb;
230 ub = sc->sc_ub;
231 while ((d = mb ^ ub) != 0) {
232 /*
233 * Mouse button change. Find the first change and drop
234 * it into the event queue.
235 */
236 NEXT;
237 ev->value = ffs(d) - 1;
238
239 KASSERT(ev->value >= 0);
240
241 d = 1 << ev->value;
242 ev->type =
243 (mb & d) ? WSCONS_EVENT_MOUSE_DOWN : WSCONS_EVENT_MOUSE_UP;
244 TIMESTAMP;
245 ADVANCE;
246 ub ^= d;
247 }
248 if (sc->sc_dx) {
249 NEXT;
250 ev->type = WSCONS_EVENT_MOUSE_DELTA_X;
251 ev->value = sc->sc_dx;
252 TIMESTAMP;
253 ADVANCE;
254 sc->sc_dx = 0;
255 }
256 if (sc->sc_dy) {
257 NEXT;
258 ev->type = WSCONS_EVENT_MOUSE_DELTA_Y;
259 ev->value = sc->sc_dy;
260 TIMESTAMP;
261 ADVANCE;
262 sc->sc_dy = 0;
263 }
264 out:
265 if (any) {
266 sc->sc_ub = ub;
267 sc->sc_events.put = put;
268 WSEVENT_WAKEUP(&sc->sc_events);
269 }
270 }
271
272 int
273 wsmouseopen(dev, flags, mode, p)
274 dev_t dev;
275 int flags, mode;
276 struct proc *p;
277 {
278 struct wsmouse_softc *sc;
279 int error, unit;
280
281 unit = minor(dev);
282 if (unit >= wsmouse_cd.cd_ndevs || /* make sure it was attached */
283 (sc = wsmouse_cd.cd_devs[unit]) == NULL)
284 return (ENXIO);
285
286 if (sc->sc_events.io) /* and that it's not in use */
287 return (EBUSY);
288
289 sc->sc_events.io = p;
290 wsevent_init(&sc->sc_events); /* may cause sleep */
291
292 sc->sc_ready = 1; /* start accepting events */
293
294 /* enable the device, and punt if that's not possible */
295 error = (*sc->sc_accessops->enable)(sc->sc_accesscookie);
296 if (error) {
297 sc->sc_ready = 0; /* stop accepting events */
298 wsevent_fini(&sc->sc_events);
299 sc->sc_events.io = NULL;
300 return (error);
301 }
302
303 return (0);
304 }
305
306 int
307 wsmouseclose(dev, flags, mode, p)
308 dev_t dev;
309 int flags, mode;
310 struct proc *p;
311 {
312 struct wsmouse_softc *sc;
313 int unit;
314
315 unit = minor(dev);
316 if (unit >= wsmouse_cd.cd_ndevs || /* make sure it was attached */
317 (sc = wsmouse_cd.cd_devs[unit]) == NULL)
318 return (ENXIO);
319
320 (*sc->sc_accessops->disable)(sc->sc_accesscookie);
321
322 sc->sc_ready = 0; /* stop accepting events */
323 wsevent_fini(&sc->sc_events);
324 sc->sc_events.io = NULL;
325 return (0);
326 }
327
328 int
329 wsmouseread(dev, uio, flags)
330 dev_t dev;
331 struct uio *uio;
332 int flags;
333 {
334 struct wsmouse_softc *sc;
335 int unit;
336
337 unit = minor(dev);
338 if (unit >= wsmouse_cd.cd_ndevs || /* make sure it was attached */
339 (sc = wsmouse_cd.cd_devs[unit]) == NULL)
340 return (ENXIO);
341
342 return (wsevent_read(&sc->sc_events, uio, flags));
343 }
344
345 int
346 wsmouseioctl(dev, cmd, data, flag, p)
347 dev_t dev;
348 u_long cmd;
349 caddr_t data;
350 int flag;
351 struct proc *p;
352 {
353 struct wsmouse_softc *sc;
354 int unit, error;
355
356 unit = minor(dev);
357 if (unit >= wsmouse_cd.cd_ndevs || /* make sure it was attached */
358 (sc = wsmouse_cd.cd_devs[unit]) == NULL)
359 return (ENXIO);
360
361 /*
362 * Try the generic ioctls that the wsmouse interface supports.
363 */
364 switch (cmd) {
365 case FIONBIO: /* we will remove this someday (soon???) */
366 return (0);
367
368 case FIOASYNC:
369 sc->sc_events.async = *(int *)data != 0;
370 return (0);
371
372 case TIOCSPGRP:
373 if (*(int *)data != sc->sc_events.io->p_pgid)
374 return (EPERM);
375 return (0);
376 }
377
378 /*
379 * Try the mouse driver for WSMOUSEIO ioctls. It returns -1
380 * if it didn't recognize the request.
381 */
382 error = (*sc->sc_accessops->ioctl)(sc->sc_accesscookie, cmd,
383 data, flag, p);
384 return (error != -1 ? error : ENOTTY);
385 }
386
387 int
388 wsmousepoll(dev, events, p)
389 dev_t dev;
390 int events;
391 struct proc *p;
392 {
393 struct wsmouse_softc *sc = wsmouse_cd.cd_devs[minor(dev)];
394
395 return (wsevent_poll(&sc->sc_events, events, p));
396 }
397