1 /* $OpenBSD: wsevent.c,v 1.29 2025/01/21 20:13:19 mvs Exp $ */ 2 /* $NetBSD: wsevent.c,v 1.16 2003/08/07 16:31:29 agc Exp $ */ 3 4 /* 5 * Copyright (c) 1996, 1997 Christopher G. Demetriou. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Christopher G. Demetriou 18 * for the NetBSD Project. 19 * 4. The name of the author may not be used to endorse or promote products 20 * derived from this software without specific prior written permission 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 23 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 24 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 25 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 26 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 27 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 31 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 /* 35 * Copyright (c) 1992, 1993 36 * The Regents of the University of California. All rights reserved. 37 * 38 * This software was developed by the Computer Systems Engineering group 39 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 40 * contributed to Berkeley. 41 * 42 * All advertising materials mentioning features or use of this software 43 * must display the following acknowledgement: 44 * This product includes software developed by the University of 45 * California, Lawrence Berkeley Laboratory. 46 * 47 * Redistribution and use in source and binary forms, with or without 48 * modification, are permitted provided that the following conditions 49 * are met: 50 * 1. Redistributions of source code must retain the above copyright 51 * notice, this list of conditions and the following disclaimer. 52 * 2. Redistributions in binary form must reproduce the above copyright 53 * notice, this list of conditions and the following disclaimer in the 54 * documentation and/or other materials provided with the distribution. 55 * 3. Neither the name of the University nor the names of its contributors 56 * may be used to endorse or promote products derived from this software 57 * without specific prior written permission. 58 * 59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 69 * SUCH DAMAGE. 70 * 71 * @(#)event.c 8.1 (Berkeley) 6/11/93 72 */ 73 74 /* 75 * Internal "wscons_event" queue interface for the keyboard and mouse drivers. 76 */ 77 78 #include <sys/param.h> 79 #include <sys/malloc.h> 80 #include <sys/systm.h> 81 #include <sys/vnode.h> 82 83 #include <dev/wscons/wsconsio.h> 84 #include <dev/wscons/wseventvar.h> 85 86 void filt_wseventdetach(struct knote *); 87 int filt_wseventread(struct knote *, long); 88 int filt_wseventmodify(struct kevent *, struct knote *); 89 int filt_wseventprocess(struct knote *, struct kevent *); 90 91 static void 92 wsevent_klist_assertlk(void *arg) 93 { 94 struct wseventvar *ev = arg; 95 96 if((ev->ws_flags & WSEVENT_MPSAFE) == 0) 97 KERNEL_ASSERT_LOCKED(); 98 MUTEX_ASSERT_LOCKED(&ev->ws_mtx); 99 } 100 101 static int 102 wsevent_klist_lock(void *arg) 103 { 104 struct wseventvar *ev = arg; 105 106 if((ev->ws_flags & WSEVENT_MPSAFE) == 0) 107 KERNEL_LOCK(); 108 mtx_enter(&ev->ws_mtx); 109 110 return (0); 111 } 112 113 static void 114 wsevent_klist_unlock(void *arg, int s) 115 { 116 struct wseventvar *ev = arg; 117 118 mtx_leave(&ev->ws_mtx); 119 if ((ev->ws_flags & WSEVENT_MPSAFE) == 0) 120 KERNEL_UNLOCK(); 121 } 122 123 static const struct klistops wsevent_klistops = { 124 .klo_assertlk = wsevent_klist_assertlk, 125 .klo_lock = wsevent_klist_lock, 126 .klo_unlock = wsevent_klist_unlock, 127 }; 128 129 const struct filterops wsevent_filtops = { 130 .f_flags = FILTEROP_ISFD | FILTEROP_MPSAFE, 131 .f_attach = NULL, 132 .f_detach = filt_wseventdetach, 133 .f_event = filt_wseventread, 134 .f_modify = filt_wseventmodify, 135 .f_process = filt_wseventprocess, 136 }; 137 138 /* 139 * Initialize a wscons_event queue. 140 */ 141 int 142 wsevent_init_flags(struct wseventvar *ev, int flags) 143 { 144 struct wscons_event *queue; 145 146 if (ev->ws_q != NULL) 147 return (0); 148 149 queue = mallocarray(WSEVENT_QSIZE, sizeof(struct wscons_event), 150 M_DEVBUF, M_WAITOK | M_ZERO); 151 if (ev->ws_q != NULL) { 152 free(queue, M_DEVBUF, 153 WSEVENT_QSIZE * sizeof(struct wscons_event)); 154 return (1); 155 } 156 157 mtx_init_flags(&ev->ws_mtx, IPL_TTY, "wsmtx", 0); 158 klist_init(&ev->ws_klist, &wsevent_klistops, ev); 159 160 ev->ws_flags = flags; 161 ev->ws_q = queue; 162 ev->ws_get = ev->ws_put = 0; 163 164 sigio_init(&ev->ws_sigio); 165 166 return (0); 167 } 168 169 /* 170 * Tear down a wscons_event queue. 171 */ 172 void 173 wsevent_fini(struct wseventvar *ev) 174 { 175 if (ev->ws_q == NULL) { 176 #ifdef DIAGNOSTIC 177 printf("wsevent_fini: already invoked\n"); 178 #endif 179 return; 180 } 181 free(ev->ws_q, M_DEVBUF, WSEVENT_QSIZE * sizeof(struct wscons_event)); 182 ev->ws_q = NULL; 183 184 klist_invalidate(&ev->ws_klist); 185 186 sigio_free(&ev->ws_sigio); 187 } 188 189 /* 190 * User-level interface: read, kqueue. 191 * (User cannot write an event queue.) 192 */ 193 int 194 wsevent_read(struct wseventvar *ev, struct uio *uio, int flags) 195 { 196 int error, wrap = 0; 197 u_int cnt, tcnt, get; 198 size_t n; 199 200 /* 201 * Make sure we can return at least 1. 202 */ 203 if (uio->uio_resid < sizeof(struct wscons_event)) 204 return (EMSGSIZE); /* ??? */ 205 n = howmany(uio->uio_resid, sizeof(struct wscons_event)); 206 207 mtx_enter(&ev->ws_mtx); 208 209 while (ev->ws_get == ev->ws_put) { 210 if (flags & IO_NDELAY) { 211 mtx_leave(&ev->ws_mtx); 212 return (EWOULDBLOCK); 213 } 214 ev->ws_wanted = 1; 215 error = msleep_nsec(ev, &ev->ws_mtx, PWSEVENT | PCATCH, 216 "wsevent_read", INFSLP); 217 if (error) { 218 mtx_leave(&ev->ws_mtx); 219 return (error); 220 } 221 } 222 /* 223 * Move wscons_event from tail end of queue (there is at least one 224 * there). 225 */ 226 if (ev->ws_put < ev->ws_get) 227 cnt = WSEVENT_QSIZE - ev->ws_get; /* events in [get..QSIZE) */ 228 else 229 cnt = ev->ws_put - ev->ws_get; /* events in [get..put) */ 230 231 if (cnt > n) 232 cnt = n; 233 234 get = ev->ws_get; 235 tcnt = ev->ws_put; 236 n -= cnt; 237 238 ev->ws_get = (get + cnt) % WSEVENT_QSIZE; 239 if (!(ev->ws_get != 0 || n == 0 || tcnt == 0)) { 240 wrap = 1; 241 242 if (tcnt > n) 243 tcnt = n; 244 ev->ws_get = tcnt; 245 } 246 247 mtx_leave(&ev->ws_mtx); 248 249 error = uiomove((caddr_t)&ev->ws_q[get], 250 cnt * sizeof(struct wscons_event), uio); 251 252 /* 253 * If we do wrap to 0, move from front of queue to put index, if 254 * there is anything there to move. 255 */ 256 if (wrap && error == 0) { 257 error = uiomove((caddr_t)&ev->ws_q[0], 258 tcnt * sizeof(struct wscons_event), uio); 259 } 260 261 return (error); 262 } 263 264 int 265 wsevent_kqfilter(struct wseventvar *ev, struct knote *kn) 266 { 267 switch (kn->kn_filter) { 268 case EVFILT_READ: 269 kn->kn_fop = &wsevent_filtops; 270 break; 271 default: 272 return (EINVAL); 273 } 274 275 kn->kn_hook = ev; 276 klist_insert(&ev->ws_klist, kn); 277 278 return (0); 279 } 280 281 void 282 filt_wseventdetach(struct knote *kn) 283 { 284 struct wseventvar *ev = kn->kn_hook; 285 286 klist_remove(&ev->ws_klist, kn); 287 } 288 289 int 290 filt_wseventread(struct knote *kn, long hint) 291 { 292 struct wseventvar *ev = kn->kn_hook; 293 294 if((ev->ws_flags & WSEVENT_MPSAFE) == 0) 295 KERNEL_ASSERT_LOCKED(); 296 MUTEX_ASSERT_LOCKED(&ev->ws_mtx); 297 298 if (ev->ws_get == ev->ws_put) 299 return (0); 300 301 if (ev->ws_get < ev->ws_put) 302 kn->kn_data = ev->ws_put - ev->ws_get; 303 else 304 kn->kn_data = (WSEVENT_QSIZE - ev->ws_get) + ev->ws_put; 305 306 return (1); 307 } 308 309 int 310 filt_wseventmodify(struct kevent *kev, struct knote *kn) 311 { 312 struct wseventvar *ev = kn->kn_hook; 313 int active, dolock = ((ev->ws_flags & WSEVENT_MPSAFE) == 0); 314 315 if (dolock) 316 KERNEL_LOCK(); 317 mtx_enter(&ev->ws_mtx); 318 active = knote_modify(kev, kn); 319 mtx_leave(&ev->ws_mtx); 320 if (dolock) 321 KERNEL_UNLOCK(); 322 323 return (active); 324 } 325 326 int 327 filt_wseventprocess(struct knote *kn, struct kevent *kev) 328 { 329 struct wseventvar *ev = kn->kn_hook; 330 int active, dolock = ((ev->ws_flags & WSEVENT_MPSAFE) == 0); 331 332 if (dolock) 333 KERNEL_LOCK(); 334 mtx_enter(&ev->ws_mtx); 335 active = knote_process(kn, kev); 336 mtx_leave(&ev->ws_mtx); 337 if (dolock) 338 KERNEL_UNLOCK(); 339 340 return (active); 341 342 } 343