1 1.20 tsutsui /* $NetBSD: event.c,v 1.20 2022/05/26 14:30:36 tsutsui Exp $ */ 2 1.1 oki 3 1.1 oki /* 4 1.1 oki * Copyright (c) 1992, 1993 5 1.1 oki * The Regents of the University of California. All rights reserved. 6 1.1 oki * 7 1.1 oki * This software was developed by the Computer Systems Engineering group 8 1.1 oki * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 1.1 oki * contributed to Berkeley. 10 1.1 oki * 11 1.1 oki * All advertising materials mentioning features or use of this software 12 1.1 oki * must display the following acknowledgement: 13 1.1 oki * This product includes software developed by the University of 14 1.1 oki * California, Lawrence Berkeley Laboratory. 15 1.1 oki * 16 1.1 oki * Redistribution and use in source and binary forms, with or without 17 1.1 oki * modification, are permitted provided that the following conditions 18 1.1 oki * are met: 19 1.1 oki * 1. Redistributions of source code must retain the above copyright 20 1.1 oki * notice, this list of conditions and the following disclaimer. 21 1.1 oki * 2. Redistributions in binary form must reproduce the above copyright 22 1.1 oki * notice, this list of conditions and the following disclaimer in the 23 1.1 oki * documentation and/or other materials provided with the distribution. 24 1.9 agc * 3. Neither the name of the University nor the names of its contributors 25 1.1 oki * may be used to endorse or promote products derived from this software 26 1.1 oki * without specific prior written permission. 27 1.1 oki * 28 1.1 oki * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 1.1 oki * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 1.1 oki * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 1.1 oki * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 1.1 oki * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 1.1 oki * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 1.1 oki * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 1.1 oki * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 1.1 oki * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 1.1 oki * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 1.1 oki * SUCH DAMAGE. 39 1.1 oki * 40 1.1 oki * @(#)event.c 8.1 (Berkeley) 6/11/93 41 1.1 oki */ 42 1.1 oki 43 1.1 oki /* 44 1.1 oki * Internal `Firm_event' interface for the keyboard and mouse drivers. 45 1.1 oki */ 46 1.8 lukem 47 1.8 lukem #include <sys/cdefs.h> 48 1.20 tsutsui __KERNEL_RCSID(0, "$NetBSD: event.c,v 1.20 2022/05/26 14:30:36 tsutsui Exp $"); 49 1.1 oki 50 1.1 oki #include <sys/param.h> 51 1.1 oki #include <sys/fcntl.h> 52 1.14 tsutsui #include <sys/kmem.h> 53 1.1 oki #include <sys/proc.h> 54 1.1 oki #include <sys/systm.h> 55 1.1 oki #include <sys/vnode.h> 56 1.3 oki #include <sys/select.h> 57 1.3 oki #include <sys/poll.h> 58 1.14 tsutsui #include <sys/mutex.h> 59 1.14 tsutsui #include <sys/condvar.h> 60 1.1 oki 61 1.1 oki #include <machine/vuid_event.h> 62 1.1 oki #include <x68k/dev/event_var.h> 63 1.1 oki 64 1.1 oki /* 65 1.1 oki * Initialize a firm_event queue. 66 1.1 oki */ 67 1.1 oki void 68 1.14 tsutsui ev_init(struct evvar *ev, const char *name, kmutex_t *mtx) 69 1.1 oki { 70 1.1 oki 71 1.1 oki ev->ev_get = ev->ev_put = 0; 72 1.14 tsutsui ev->ev_q = kmem_zalloc((size_t)EV_QSIZE * sizeof(struct firm_event), 73 1.14 tsutsui KM_SLEEP); 74 1.13 rmind selinit(&ev->ev_sel); 75 1.14 tsutsui ev->ev_lock = mtx; 76 1.14 tsutsui cv_init(&ev->ev_cv, name); 77 1.1 oki } 78 1.1 oki 79 1.1 oki /* 80 1.1 oki * Tear down a firm_event queue. 81 1.1 oki */ 82 1.1 oki void 83 1.10 chs ev_fini(struct evvar *ev) 84 1.1 oki { 85 1.1 oki 86 1.14 tsutsui cv_destroy(&ev->ev_cv); 87 1.13 rmind seldestroy(&ev->ev_sel); 88 1.14 tsutsui kmem_free(ev->ev_q, (size_t)EV_QSIZE * sizeof(struct firm_event)); 89 1.1 oki } 90 1.1 oki 91 1.1 oki /* 92 1.1 oki * User-level interface: read, select. 93 1.1 oki * (User cannot write an event queue.) 94 1.1 oki */ 95 1.1 oki int 96 1.10 chs ev_read(struct evvar *ev, struct uio *uio, int flags) 97 1.1 oki { 98 1.14 tsutsui int n, cnt, put, error; 99 1.1 oki 100 1.1 oki /* 101 1.1 oki * Make sure we can return at least 1. 102 1.1 oki */ 103 1.1 oki if (uio->uio_resid < sizeof(struct firm_event)) 104 1.20 tsutsui return EMSGSIZE; /* ??? */ 105 1.14 tsutsui mutex_enter(ev->ev_lock); 106 1.1 oki while (ev->ev_get == ev->ev_put) { 107 1.1 oki if (flags & IO_NDELAY) { 108 1.14 tsutsui mutex_exit(ev->ev_lock); 109 1.20 tsutsui return EWOULDBLOCK; 110 1.1 oki } 111 1.14 tsutsui ev->ev_wanted = true; 112 1.14 tsutsui error = cv_wait_sig(&ev->ev_cv, ev->ev_lock); 113 1.14 tsutsui if (error != 0) { 114 1.14 tsutsui mutex_exit(ev->ev_lock); 115 1.20 tsutsui return error; 116 1.1 oki } 117 1.1 oki } 118 1.1 oki /* 119 1.1 oki * Move firm_events from tail end of queue (there is at least one 120 1.1 oki * there). 121 1.1 oki */ 122 1.1 oki if (ev->ev_put < ev->ev_get) 123 1.1 oki cnt = EV_QSIZE - ev->ev_get; /* events in [get..QSIZE) */ 124 1.1 oki else 125 1.1 oki cnt = ev->ev_put - ev->ev_get; /* events in [get..put) */ 126 1.14 tsutsui put = ev->ev_put; 127 1.14 tsutsui mutex_exit(ev->ev_lock); 128 1.1 oki n = howmany(uio->uio_resid, sizeof(struct firm_event)); 129 1.1 oki if (cnt > n) 130 1.1 oki cnt = n; 131 1.12 christos error = uiomove((void *)&ev->ev_q[ev->ev_get], 132 1.1 oki cnt * sizeof(struct firm_event), uio); 133 1.1 oki n -= cnt; 134 1.1 oki /* 135 1.1 oki * If we do not wrap to 0, used up all our space, or had an error, 136 1.1 oki * stop. Otherwise move from front of queue to put index, if there 137 1.1 oki * is anything there to move. 138 1.1 oki */ 139 1.1 oki if ((ev->ev_get = (ev->ev_get + cnt) % EV_QSIZE) != 0 || 140 1.14 tsutsui n == 0 || error || (cnt = put) == 0) 141 1.20 tsutsui return error; 142 1.1 oki if (cnt > n) 143 1.1 oki cnt = n; 144 1.12 christos error = uiomove((void *)&ev->ev_q[0], 145 1.1 oki cnt * sizeof(struct firm_event), uio); 146 1.1 oki ev->ev_get = cnt; 147 1.20 tsutsui return error; 148 1.1 oki } 149 1.1 oki 150 1.1 oki int 151 1.11 christos ev_poll(struct evvar *ev, int events, struct lwp *l) 152 1.1 oki { 153 1.14 tsutsui int revents = 0; 154 1.1 oki 155 1.14 tsutsui mutex_enter(ev->ev_lock); 156 1.3 oki if (events & (POLLIN | POLLRDNORM)) { 157 1.3 oki if (ev->ev_get == ev->ev_put) 158 1.11 christos selrecord(l, &ev->ev_sel); 159 1.3 oki else 160 1.3 oki revents |= events & (POLLIN | POLLRDNORM); 161 1.3 oki } 162 1.3 oki revents |= events & (POLLOUT | POLLWRNORM); 163 1.14 tsutsui mutex_exit(ev->ev_lock); 164 1.20 tsutsui return revents; 165 1.6 jdolecek } 166 1.6 jdolecek 167 1.14 tsutsui void 168 1.14 tsutsui ev_wakeup(struct evvar *ev) 169 1.14 tsutsui { 170 1.14 tsutsui 171 1.14 tsutsui mutex_enter(ev->ev_lock); 172 1.14 tsutsui selnotify(&ev->ev_sel, 0, 0); 173 1.14 tsutsui if (ev->ev_wanted) { 174 1.14 tsutsui ev->ev_wanted = false; 175 1.14 tsutsui cv_signal(&ev->ev_cv); 176 1.14 tsutsui } 177 1.14 tsutsui mutex_exit(ev->ev_lock); 178 1.14 tsutsui 179 1.14 tsutsui if (ev->ev_async) { 180 1.16 ad mutex_enter(&proc_lock); 181 1.14 tsutsui psignal(ev->ev_io, SIGIO); 182 1.16 ad mutex_exit(&proc_lock); 183 1.14 tsutsui } 184 1.14 tsutsui } 185 1.14 tsutsui 186 1.6 jdolecek static void 187 1.6 jdolecek filt_evrdetach(struct knote *kn) 188 1.6 jdolecek { 189 1.6 jdolecek struct evvar *ev = kn->kn_hook; 190 1.6 jdolecek 191 1.14 tsutsui mutex_enter(ev->ev_lock); 192 1.17 thorpej selremove_knote(&ev->ev_sel, kn); 193 1.14 tsutsui mutex_exit(ev->ev_lock); 194 1.6 jdolecek } 195 1.6 jdolecek 196 1.6 jdolecek static int 197 1.6 jdolecek filt_evread(struct knote *kn, long hint) 198 1.6 jdolecek { 199 1.6 jdolecek struct evvar *ev = kn->kn_hook; 200 1.14 tsutsui int rv = 1; 201 1.6 jdolecek 202 1.14 tsutsui mutex_enter(ev->ev_lock); 203 1.14 tsutsui if (ev->ev_get == ev->ev_put) { 204 1.14 tsutsui rv = 0; 205 1.14 tsutsui } else { 206 1.14 tsutsui if (ev->ev_get < ev->ev_put) 207 1.14 tsutsui kn->kn_data = ev->ev_put - ev->ev_get; 208 1.14 tsutsui else 209 1.14 tsutsui kn->kn_data = (EV_QSIZE - ev->ev_get) + 210 1.14 tsutsui ev->ev_put; 211 1.6 jdolecek 212 1.14 tsutsui kn->kn_data *= sizeof(struct firm_event); 213 1.14 tsutsui } 214 1.14 tsutsui mutex_exit(ev->ev_lock); 215 1.6 jdolecek 216 1.14 tsutsui return rv; 217 1.6 jdolecek } 218 1.6 jdolecek 219 1.15 maya static const struct filterops ev_filtops = { 220 1.18 thorpej .f_flags = FILTEROP_ISFD, 221 1.15 maya .f_attach = NULL, 222 1.15 maya .f_detach = filt_evrdetach, 223 1.15 maya .f_event = filt_evread, 224 1.15 maya }; 225 1.6 jdolecek 226 1.6 jdolecek int 227 1.6 jdolecek ev_kqfilter(struct evvar *ev, struct knote *kn) 228 1.6 jdolecek { 229 1.6 jdolecek 230 1.6 jdolecek switch (kn->kn_filter) { 231 1.6 jdolecek case EVFILT_READ: 232 1.6 jdolecek kn->kn_fop = &ev_filtops; 233 1.6 jdolecek break; 234 1.6 jdolecek 235 1.6 jdolecek default: 236 1.20 tsutsui return EINVAL; 237 1.6 jdolecek } 238 1.6 jdolecek 239 1.6 jdolecek kn->kn_hook = ev; 240 1.6 jdolecek 241 1.14 tsutsui mutex_enter(ev->ev_lock); 242 1.17 thorpej selrecord_knote(&ev->ev_sel, kn); 243 1.14 tsutsui mutex_exit(ev->ev_lock); 244 1.6 jdolecek 245 1.20 tsutsui return 0; 246 1.1 oki } 247