1 /* $NetBSD: wsevent.c,v 1.33 2009/02/13 22:41:04 apb Exp $ */
4 * Copyright (c) 2006, 2008 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Julio M. Merino Vidal.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
33 * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.
35 * Redistribution and use in source and binary forms, with or without
36 * modification, are permitted provided that the following conditions
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 * 2. Redistributions in binary form must reproduce the above copyright
41 * notice, this list of conditions and the following disclaimer in the
42 * documentation and/or other materials provided with the distribution.
43 * 3. All advertising materials mentioning features or use of this software
44 * must display the following acknowledgement:
45 * This product includes software developed by Christopher G. Demetriou
46 * for the NetBSD Project.
47 * 4. The name of the author may not be used to endorse or promote products
48 * derived from this software without specific prior written permission
50 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
51 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
52 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
53 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
54 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
55 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
59 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63 * Copyright (c) 1992, 1993
64 * The Regents of the University of California. All rights reserved.
66 * This software was developed by the Computer Systems Engineering group
67 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
68 * contributed to Berkeley.
70 * All advertising materials mentioning features or use of this software
71 * must display the following acknowledgement:
72 * This product includes software developed by the University of
73 * California, Lawrence Berkeley Laboratory.
75 * Redistribution and use in source and binary forms, with or without
76 * modification, are permitted provided that the following conditions
78 * 1. Redistributions of source code must retain the above copyright
79 * notice, this list of conditions and the following disclaimer.
80 * 2. Redistributions in binary form must reproduce the above copyright
81 * notice, this list of conditions and the following disclaimer in the
82 * documentation and/or other materials provided with the distribution.
83 * 3. Neither the name of the University nor the names of its contributors
84 * may be used to endorse or promote products derived from this software
85 * without specific prior written permission.
87 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
88 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
89 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
90 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
91 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
92 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
93 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
94 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
95 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
96 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
99 * @(#)event.c 8.1 (Berkeley) 6/11/93
103 * Internal "wscons_event" queue interface for the keyboard and mouse drivers.
106 #include <sys/cdefs.h>
107 __KERNEL_RCSID(0, "$NetBSD: wsevent.c,v 1.33 2009/02/13 22:41:04 apb Exp $");
109 #include "opt_compat_netbsd.h"
110 #include "opt_modular.h"
112 #include <sys/param.h>
113 #include <sys/kernel.h>
114 #include <sys/fcntl.h>
115 #include <sys/kmem.h>
116 #include <sys/proc.h>
117 #include <sys/systm.h>
118 #include <sys/vnode.h>
119 #include <sys/select.h>
120 #include <sys/poll.h>
122 #include <dev/wscons/wsconsio.h>
123 #include <dev/wscons/wseventvar.h>
126 * Size of a wsevent queue (measured in number of events).
127 * Should be a power of two so that `%' is fast.
128 * At the moment, the value below makes the queues use 2 Kbytes each; this
129 * value may need tuning.
131 #define WSEVENT_QSIZE 256
133 #define EVSIZE(ver) ((ver) == WSEVENT_VERSION ? \
134 sizeof(struct wscons_event) : \
135 sizeof(struct owscons_event))
136 #define EVARRAY(ev, idx) (&(ev)->q[(idx)])
139 * Priority of code managing wsevent queues. PWSEVENT is set just above
140 * PSOCK, which is just above TTIPRI, on the theory that mouse and keyboard
141 * `user' input should be quick.
144 #define splwsevent() spltty()
146 static void wsevent_intr(void *);
149 * Initialize a wscons_event queue.
152 wsevent_init(struct wseventvar
*ev
, struct proc
*p
)
157 printf("wsevent_init: already init\n");
162 ev
->get
= ev
->put
= 0;
163 ev
->q
= kmem_alloc(WSEVENT_QSIZE
* sizeof(*ev
->q
), KM_SLEEP
);
166 ev
->sih
= softint_establish(SOFTINT_MPSAFE
| SOFTINT_CLOCK
,
171 * Tear down a wscons_event queue.
174 wsevent_fini(struct wseventvar
*ev
)
178 printf("wsevent_fini: already fini\n");
182 seldestroy(&ev
->sel
);
183 kmem_free(ev
->q
, WSEVENT_QSIZE
* sizeof(*ev
->q
));
185 softint_disestablish(ev
->sih
);
188 #if defined(COMPAT_50) || defined(MODULAR)
190 wsevent_copyout_events50(const struct wscons_event
*events
, int cnt
,
195 for (i
= 0; i
< cnt
; i
++) {
196 const struct wscons_event
*ev
= &events
[i
];
197 struct owscons_event ev50
;
200 ev50
.type
= ev
->type
;
201 ev50
.value
= ev
->value
;
202 timespec_to_timespec50(&ev
->time
, &ev50
.time
);
204 error
= uiomove(&ev50
, sizeof(ev50
), uio
);
211 #else /* defined(COMPAT_50) || defined(MODULAR) */
213 wsevent_copyout_events50(const struct wscons_event
*events
, int cnt
,
219 #endif /* defined(COMPAT_50) || defined(MODULAR) */
222 wsevent_copyout_events(const struct wscons_event
*events
, int cnt
,
223 struct uio
*uio
, int ver
)
228 return wsevent_copyout_events50(events
, cnt
, uio
);
229 case WSEVENT_VERSION
:
230 return uiomove(__UNCONST(events
), cnt
* sizeof(*events
), uio
);
232 panic("%s: unknown version %d", __func__
, ver
);
237 * User-level interface: read, poll.
238 * (User cannot write an event queue.)
241 wsevent_read(struct wseventvar
*ev
, struct uio
*uio
, int flags
)
243 int s
, n
, cnt
, error
;
244 const int ver
= ev
->version
;
245 const size_t evsize
= EVSIZE(ver
);
248 * Make sure we can return at least 1.
250 if (uio
->uio_resid
< evsize
)
251 return (EMSGSIZE
); /* ??? */
253 while (ev
->get
== ev
->put
) {
254 if (flags
& IO_NDELAY
) {
256 return (EWOULDBLOCK
);
259 error
= tsleep(ev
, PWSEVENT
| PCATCH
, "wsevent_read", 0);
266 * Move wscons_event from tail end of queue (there is at least one
269 if (ev
->put
< ev
->get
)
270 cnt
= WSEVENT_QSIZE
- ev
->get
; /* events in [get..QSIZE) */
272 cnt
= ev
->put
- ev
->get
; /* events in [get..put) */
274 n
= howmany(uio
->uio_resid
, evsize
);
277 error
= wsevent_copyout_events(EVARRAY(ev
, ev
->get
), cnt
, uio
, ver
);
280 * If we do not wrap to 0, used up all our space, or had an error,
281 * stop. Otherwise move from front of queue to put index, if there
282 * is anything there to move.
284 if ((ev
->get
= (ev
->get
+ cnt
) % WSEVENT_QSIZE
) != 0 ||
285 n
== 0 || error
|| (cnt
= ev
->put
) == 0)
289 error
= wsevent_copyout_events(EVARRAY(ev
, 0), cnt
, uio
, ver
);
295 wsevent_poll(struct wseventvar
*ev
, int events
, struct lwp
*l
)
298 int s
= splwsevent();
300 if (events
& (POLLIN
| POLLRDNORM
)) {
301 if (ev
->get
!= ev
->put
)
302 revents
|= events
& (POLLIN
| POLLRDNORM
);
304 selrecord(l
, &ev
->sel
);
312 filt_wseventrdetach(struct knote
*kn
)
314 struct wseventvar
*ev
= kn
->kn_hook
;
318 SLIST_REMOVE(&ev
->sel
.sel_klist
, kn
, knote
, kn_selnext
);
323 filt_wseventread(struct knote
*kn
, long hint
)
325 struct wseventvar
*ev
= kn
->kn_hook
;
327 if (ev
->get
== ev
->put
)
330 if (ev
->get
< ev
->put
)
331 kn
->kn_data
= ev
->put
- ev
->get
;
333 kn
->kn_data
= (WSEVENT_QSIZE
- ev
->get
) + ev
->put
;
335 kn
->kn_data
*= EVSIZE(ev
->version
);
340 static const struct filterops wsevent_filtops
=
341 { 1, NULL
, filt_wseventrdetach
, filt_wseventread
};
344 wsevent_kqfilter(struct wseventvar
*ev
, struct knote
*kn
)
349 switch (kn
->kn_filter
) {
351 klist
= &ev
->sel
.sel_klist
;
352 kn
->kn_fop
= &wsevent_filtops
;
362 SLIST_INSERT_HEAD(klist
, kn
, kn_selnext
);
369 * Wakes up all listener of the 'ev' queue.
372 wsevent_wakeup(struct wseventvar
*ev
)
375 selnotify(&ev
->sel
, 0, 0);
383 softint_schedule(ev
->sih
);
388 * Soft interrupt handler: sends signal to async proc.
391 wsevent_intr(void *cookie
)
393 struct wseventvar
*ev
;
398 mutex_enter(proc_lock
);
399 psignal(ev
->io
, SIGIO
);
400 mutex_exit(proc_lock
);
405 * Injects the set of events given in 'events', whose size is 'nevents',
406 * into the 'ev' queue. If there is not enough free space to inject them
407 * all, returns ENOSPC and the queue is left intact; otherwise returns 0
408 * and wakes up all listeners.
411 wsevent_inject(struct wseventvar
*ev
, struct wscons_event
*events
,
417 /* Calculate number of free slots in the queue. */
418 if (ev
->put
< ev
->get
)
419 avail
= ev
->get
- ev
->put
;
421 avail
= WSEVENT_QSIZE
- (ev
->put
- ev
->get
);
422 KASSERT(avail
<= WSEVENT_QSIZE
);
424 /* Fail if there is all events will not fit in the queue. */
428 /* Use the current time for all events. */
431 /* Inject the events. */
432 for (i
= 0; i
< nevents
; i
++) {
433 struct wscons_event
*we
;
435 we
= EVARRAY(ev
, ev
->put
);
436 we
->type
= events
[i
].type
;
437 we
->value
= events
[i
].value
;
440 ev
->put
= (ev
->put
+ 1) % WSEVENT_QSIZE
;
448 wsevent_setversion(struct wseventvar
*ev
, int vers
)
455 case WSEVENT_VERSION
:
461 if (vers
== ev
->version
)
464 ev
->get
= ev
->put
= 0;