wsevent.c revision 1.26 1 /* $NetBSD: wsevent.c,v 1.26 2008/04/24 15:35:28 ad Exp $ */
2
3 /*-
4 * Copyright (c) 2006, 2008 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.26 2008/04/24 15:35:28 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 static void wsevent_intr(void *);
146
147 /*
148 * Initialize a wscons_event queue.
149 */
150 void
151 wsevent_init(struct wseventvar *ev, struct proc *p)
152 {
153
154 if (ev->q != NULL) {
155 #ifdef DIAGNOSTIC
156 printf("wsevent_init: already init\n");
157 #endif
158 return;
159 }
160 ev->get = ev->put = 0;
161 ev->q = malloc((u_long)WSEVENT_QSIZE * sizeof(struct wscons_event),
162 M_DEVBUF, M_WAITOK|M_ZERO);
163 selinit(&ev->sel);
164 ev->io = p;
165 ev->sih = softint_establish(SOFTINT_MPSAFE | SOFTINT_CLOCK,
166 wsevent_intr, ev);
167 }
168
169 /*
170 * Tear down a wscons_event queue.
171 */
172 void
173 wsevent_fini(struct wseventvar *ev)
174 {
175 if (ev->q == NULL) {
176 #ifdef DIAGNOSTIC
177 printf("wsevent_fini: already fini\n");
178 #endif
179 return;
180 }
181 seldestroy(&ev->sel);
182 free(ev->q, M_DEVBUF);
183 ev->q = NULL;
184 softint_disestablish(ev->sih);
185 }
186
187 /*
188 * User-level interface: read, poll.
189 * (User cannot write an event queue.)
190 */
191 int
192 wsevent_read(struct wseventvar *ev, struct uio *uio, int flags)
193 {
194 int s, n, cnt, error;
195
196 /*
197 * Make sure we can return at least 1.
198 */
199 if (uio->uio_resid < sizeof(struct wscons_event))
200 return (EMSGSIZE); /* ??? */
201 s = splwsevent();
202 while (ev->get == ev->put) {
203 if (flags & IO_NDELAY) {
204 splx(s);
205 return (EWOULDBLOCK);
206 }
207 ev->wanted = 1;
208 error = tsleep(ev, PWSEVENT | PCATCH,
209 "wsevent_read", 0);
210 if (error) {
211 splx(s);
212 return (error);
213 }
214 }
215 /*
216 * Move wscons_event from tail end of queue (there is at least one
217 * there).
218 */
219 if (ev->put < ev->get)
220 cnt = WSEVENT_QSIZE - ev->get; /* events in [get..QSIZE) */
221 else
222 cnt = ev->put - ev->get; /* events in [get..put) */
223 splx(s);
224 n = howmany(uio->uio_resid, sizeof(struct wscons_event));
225 if (cnt > n)
226 cnt = n;
227 error = uiomove(&ev->q[ev->get],
228 cnt * sizeof(struct wscons_event), uio);
229 n -= cnt;
230 /*
231 * If we do not wrap to 0, used up all our space, or had an error,
232 * stop. Otherwise move from front of queue to put index, if there
233 * is anything there to move.
234 */
235 if ((ev->get = (ev->get + cnt) % WSEVENT_QSIZE) != 0 ||
236 n == 0 || error || (cnt = ev->put) == 0)
237 return (error);
238 if (cnt > n)
239 cnt = n;
240 error = uiomove(&ev->q[0],
241 cnt * sizeof(struct wscons_event), uio);
242 ev->get = cnt;
243 return (error);
244 }
245
246 int
247 wsevent_poll(struct wseventvar *ev, int events, struct lwp *l)
248 {
249 int revents = 0;
250 int s = splwsevent();
251
252 if (events & (POLLIN | POLLRDNORM)) {
253 if (ev->get != ev->put)
254 revents |= events & (POLLIN | POLLRDNORM);
255 else
256 selrecord(l, &ev->sel);
257 }
258
259 splx(s);
260 return (revents);
261 }
262
263 static void
264 filt_wseventrdetach(struct knote *kn)
265 {
266 struct wseventvar *ev = kn->kn_hook;
267 int s;
268
269 s = splwsevent();
270 SLIST_REMOVE(&ev->sel.sel_klist, kn, knote, kn_selnext);
271 splx(s);
272 }
273
274 static int
275 filt_wseventread(struct knote *kn, long hint)
276 {
277 struct wseventvar *ev = kn->kn_hook;
278
279 if (ev->get == ev->put)
280 return (0);
281
282 if (ev->get < ev->put)
283 kn->kn_data = ev->put - ev->get;
284 else
285 kn->kn_data = (WSEVENT_QSIZE - ev->get) +
286 ev->put;
287
288 kn->kn_data *= sizeof(struct wscons_event);
289
290 return (1);
291 }
292
293 static const struct filterops wsevent_filtops =
294 { 1, NULL, filt_wseventrdetach, filt_wseventread };
295
296 int
297 wsevent_kqfilter(struct wseventvar *ev, struct knote *kn)
298 {
299 struct klist *klist;
300 int s;
301
302 switch (kn->kn_filter) {
303 case EVFILT_READ:
304 klist = &ev->sel.sel_klist;
305 kn->kn_fop = &wsevent_filtops;
306 break;
307
308 default:
309 return (EINVAL);
310 }
311
312 kn->kn_hook = ev;
313
314 s = splwsevent();
315 SLIST_INSERT_HEAD(klist, kn, kn_selnext);
316 splx(s);
317
318 return (0);
319 }
320
321 /*
322 * Wakes up all listener of the 'ev' queue.
323 */
324 void
325 wsevent_wakeup(struct wseventvar *ev)
326 {
327
328 selnotify(&ev->sel, 0, 0);
329
330 if (ev->wanted) {
331 ev->wanted = 0;
332 wakeup(ev);
333 }
334
335 if (ev->async) {
336 softint_schedule(ev->sih);
337 }
338 }
339
340 /*
341 * Soft interrupt handler: sends signal to async proc.
342 */
343 static void
344 wsevent_intr(void *cookie)
345 {
346 struct wseventvar *ev;
347
348 ev = cookie;
349
350 if (ev->async) {
351 mutex_enter(proc_lock);
352 psignal(ev->io, SIGIO);
353 mutex_exit(proc_lock);
354 }
355 }
356
357 /*
358 * Injects the set of events given in 'events', whose size is 'nevents',
359 * into the 'ev' queue. If there is not enough free space to inject them
360 * all, returns ENOSPC and the queue is left intact; otherwise returns 0
361 * and wakes up all listeners.
362 */
363 int
364 wsevent_inject(struct wseventvar *ev, struct wscons_event *events,
365 size_t nevents)
366 {
367 size_t avail, i;
368 struct timespec t;
369
370 /* Calculate number of free slots in the queue. */
371 if (ev->put < ev->get)
372 avail = ev->get - ev->put;
373 else
374 avail = WSEVENT_QSIZE - (ev->put - ev->get);
375 KASSERT(avail <= WSEVENT_QSIZE);
376
377 /* Fail if there is all events will not fit in the queue. */
378 if (avail < nevents)
379 return ENOSPC;
380
381 /* Use the current time for all events. */
382 getnanotime(&t);
383
384 /* Inject the events. */
385 for (i = 0; i < nevents; i++) {
386 struct wscons_event *we;
387
388 we = &ev->q[ev->put];
389 we->type = events[i].type;
390 we->value = events[i].value;
391 we->time = t;
392
393 ev->put = (ev->put + 1) % WSEVENT_QSIZE;
394 }
395
396 wsevent_wakeup(ev);
397
398 return 0;
399 }
400