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