1 /* $NetBSD: wsevent.c,v 1.24 2007/12/05 17:19:57 pooka 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.24 2007/12/05 17:19:57 pooka 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 (EINVAL); 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