wsevent.c revision 1.23 1 /* $NetBSD: wsevent.c,v 1.23 2007/02/09 21:55:30 ad Exp $ */
2
3 /*-
4 * Copyright (c) 2006 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Julio M. Merino Vidal.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
50 * 3. All advertising materials mentioning features or use of this software
51 * must display the following acknowledgement:
52 * This product includes software developed by Christopher G. Demetriou
53 * for the NetBSD Project.
54 * 4. The name of the author may not be used to endorse or promote products
55 * derived from this software without specific prior written permission
56 *
57 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
58 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
59 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
60 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
61 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
62 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
63 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
64 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
65 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
66 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
67 */
68
69 /*
70 * Copyright (c) 1992, 1993
71 * The Regents of the University of California. All rights reserved.
72 *
73 * This software was developed by the Computer Systems Engineering group
74 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
75 * contributed to Berkeley.
76 *
77 * All advertising materials mentioning features or use of this software
78 * must display the following acknowledgement:
79 * This product includes software developed by the University of
80 * California, Lawrence Berkeley Laboratory.
81 *
82 * Redistribution and use in source and binary forms, with or without
83 * modification, are permitted provided that the following conditions
84 * are met:
85 * 1. Redistributions of source code must retain the above copyright
86 * notice, this list of conditions and the following disclaimer.
87 * 2. Redistributions in binary form must reproduce the above copyright
88 * notice, this list of conditions and the following disclaimer in the
89 * documentation and/or other materials provided with the distribution.
90 * 3. Neither the name of the University nor the names of its contributors
91 * may be used to endorse or promote products derived from this software
92 * without specific prior written permission.
93 *
94 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
95 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
96 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
97 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
98 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
99 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
100 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
101 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
102 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
103 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
104 * SUCH DAMAGE.
105 *
106 * @(#)event.c 8.1 (Berkeley) 6/11/93
107 */
108
109 /*
110 * Internal "wscons_event" queue interface for the keyboard and mouse drivers.
111 */
112
113 #include <sys/cdefs.h>
114 __KERNEL_RCSID(0, "$NetBSD: wsevent.c,v 1.23 2007/02/09 21:55:30 ad Exp $");
115
116 #include <sys/param.h>
117 #include <sys/kernel.h>
118 #include <sys/fcntl.h>
119 #include <sys/malloc.h>
120 #include <sys/proc.h>
121 #include <sys/systm.h>
122 #include <sys/vnode.h>
123 #include <sys/select.h>
124 #include <sys/poll.h>
125
126 #include <dev/wscons/wsconsio.h>
127 #include <dev/wscons/wseventvar.h>
128
129 /*
130 * Size of a wsevent queue (measured in number of events).
131 * Should be a power of two so that `%' is fast.
132 * At the moment, the value below makes the queues use 2 Kbytes each; this
133 * value may need tuning.
134 */
135 #define WSEVENT_QSIZE 256
136
137 /*
138 * Priority of code managing wsevent queues. PWSEVENT is set just above
139 * PSOCK, which is just above TTIPRI, on the theory that mouse and keyboard
140 * `user' input should be quick.
141 */
142 #define PWSEVENT 23
143 #define splwsevent() spltty()
144
145 /*
146 * Initialize a wscons_event queue.
147 */
148 void
149 wsevent_init(struct wseventvar *ev, struct proc *p)
150 {
151
152 if (ev->q != NULL) {
153 #ifdef DIAGNOSTIC
154 printf("wsevent_init: already init\n");
155 #endif
156 return;
157 }
158 ev->get = ev->put = 0;
159 ev->q = malloc((u_long)WSEVENT_QSIZE * sizeof(struct wscons_event),
160 M_DEVBUF, M_WAITOK|M_ZERO);
161 ev->io = p;
162 }
163
164 /*
165 * Tear down a wscons_event queue.
166 */
167 void
168 wsevent_fini(struct wseventvar *ev)
169 {
170 if (ev->q == NULL) {
171 #ifdef DIAGNOSTIC
172 printf("wsevent_fini: already fini\n");
173 #endif
174 return;
175 }
176 free(ev->q, M_DEVBUF);
177 ev->q = NULL;
178 }
179
180 /*
181 * User-level interface: read, poll.
182 * (User cannot write an event queue.)
183 */
184 int
185 wsevent_read(struct wseventvar *ev, struct uio *uio, int flags)
186 {
187 int s, n, cnt, error;
188
189 /*
190 * Make sure we can return at least 1.
191 */
192 if (uio->uio_resid < sizeof(struct wscons_event))
193 return (EMSGSIZE); /* ??? */
194 s = splwsevent();
195 while (ev->get == ev->put) {
196 if (flags & IO_NDELAY) {
197 splx(s);
198 return (EWOULDBLOCK);
199 }
200 ev->wanted = 1;
201 error = tsleep(ev, PWSEVENT | PCATCH,
202 "wsevent_read", 0);
203 if (error) {
204 splx(s);
205 return (error);
206 }
207 }
208 /*
209 * Move wscons_event from tail end of queue (there is at least one
210 * there).
211 */
212 if (ev->put < ev->get)
213 cnt = WSEVENT_QSIZE - ev->get; /* events in [get..QSIZE) */
214 else
215 cnt = ev->put - ev->get; /* events in [get..put) */
216 splx(s);
217 n = howmany(uio->uio_resid, sizeof(struct wscons_event));
218 if (cnt > n)
219 cnt = n;
220 error = uiomove(&ev->q[ev->get],
221 cnt * sizeof(struct wscons_event), uio);
222 n -= cnt;
223 /*
224 * If we do not wrap to 0, used up all our space, or had an error,
225 * stop. Otherwise move from front of queue to put index, if there
226 * is anything there to move.
227 */
228 if ((ev->get = (ev->get + cnt) % WSEVENT_QSIZE) != 0 ||
229 n == 0 || error || (cnt = ev->put) == 0)
230 return (error);
231 if (cnt > n)
232 cnt = n;
233 error = uiomove(&ev->q[0],
234 cnt * sizeof(struct wscons_event), uio);
235 ev->get = cnt;
236 return (error);
237 }
238
239 int
240 wsevent_poll(struct wseventvar *ev, int events, struct lwp *l)
241 {
242 int revents = 0;
243 int s = splwsevent();
244
245 if (events & (POLLIN | POLLRDNORM)) {
246 if (ev->get != ev->put)
247 revents |= events & (POLLIN | POLLRDNORM);
248 else
249 selrecord(l, &ev->sel);
250 }
251
252 splx(s);
253 return (revents);
254 }
255
256 static void
257 filt_wseventrdetach(struct knote *kn)
258 {
259 struct wseventvar *ev = kn->kn_hook;
260 int s;
261
262 s = splwsevent();
263 SLIST_REMOVE(&ev->sel.sel_klist, kn, knote, kn_selnext);
264 splx(s);
265 }
266
267 static int
268 filt_wseventread(struct knote *kn, long hint)
269 {
270 struct wseventvar *ev = kn->kn_hook;
271
272 if (ev->get == ev->put)
273 return (0);
274
275 if (ev->get < ev->put)
276 kn->kn_data = ev->put - ev->get;
277 else
278 kn->kn_data = (WSEVENT_QSIZE - ev->get) +
279 ev->put;
280
281 kn->kn_data *= sizeof(struct wscons_event);
282
283 return (1);
284 }
285
286 static const struct filterops wsevent_filtops =
287 { 1, NULL, filt_wseventrdetach, filt_wseventread };
288
289 int
290 wsevent_kqfilter(struct wseventvar *ev, struct knote *kn)
291 {
292 struct klist *klist;
293 int s;
294
295 switch (kn->kn_filter) {
296 case EVFILT_READ:
297 klist = &ev->sel.sel_klist;
298 kn->kn_fop = &wsevent_filtops;
299 break;
300
301 default:
302 return (1);
303 }
304
305 kn->kn_hook = ev;
306
307 s = splwsevent();
308 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
309 splx(s);
310
311 return (0);
312 }
313
314 /*
315 * Wakes up all listener of the 'ev' queue.
316 */
317 void
318 wsevent_wakeup(struct wseventvar *ev)
319 {
320
321 selnotify(&ev->sel, 0);
322
323 if (ev->wanted) {
324 ev->wanted = 0;
325 wakeup(ev);
326 }
327
328 if (ev->async) {
329 mutex_enter(&proclist_mutex);
330 psignal(ev->io, SIGIO);
331 mutex_exit(&proclist_mutex);
332 }
333 }
334
335 /*
336 * Injects the set of events given in 'events', whose size is 'nevents',
337 * into the 'ev' queue. If there is not enough free space to inject them
338 * all, returns ENOSPC and the queue is left intact; otherwise returns 0
339 * and wakes up all listeners.
340 */
341 int
342 wsevent_inject(struct wseventvar *ev, struct wscons_event *events,
343 size_t nevents)
344 {
345 size_t avail, i;
346 struct timespec t;
347
348 /* Calculate number of free slots in the queue. */
349 if (ev->put < ev->get)
350 avail = ev->get - ev->put;
351 else
352 avail = WSEVENT_QSIZE - (ev->put - ev->get);
353 KASSERT(avail <= WSEVENT_QSIZE);
354
355 /* Fail if there is all events will not fit in the queue. */
356 if (avail < nevents)
357 return ENOSPC;
358
359 /* Use the current time for all events. */
360 getnanotime(&t);
361
362 /* Inject the events. */
363 for (i = 0; i < nevents; i++) {
364 struct wscons_event *we;
365
366 we = &ev->q[ev->put];
367 we->type = events[i].type;
368 we->value = events[i].value;
369 we->time = t;
370
371 ev->put = (ev->put + 1) % WSEVENT_QSIZE;
372 }
373
374 wsevent_wakeup(ev);
375
376 return 0;
377 }
378