1 /* 2 * Copyright (c) 1992 The Regents of the University of California. 3 * All rights reserved. 4 * 5 * This software was developed by the Computer Systems Engineering group 6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7 * contributed to Berkeley. 8 * 9 * %sccs.include.redist.c% 10 * 11 * @(#)event.c 7.1 (Berkeley) 07/13/92 12 * 13 * from: $Header: event.c,v 1.4 92/06/17 05:35:45 torek Exp $ (LBL) 14 */ 15 16 /* 17 * Internal `Firm_event' interface for the keyboard and mouse drivers. 18 */ 19 20 #include "sys/param.h" 21 #include "sys/fcntl.h" 22 #include "sys/malloc.h" 23 #include "sys/proc.h" 24 #include "sys/systm.h" 25 #include "sys/vnode.h" 26 27 #include "vuid_event.h" 28 #include "event_var.h" 29 30 /* 31 * Initialize a firm_event queue. 32 */ 33 void 34 ev_init(ev) 35 register struct evvar *ev; 36 { 37 38 ev->ev_get = ev->ev_put = 0; 39 ev->ev_q = malloc((u_long)EV_QSIZE * sizeof(struct firm_event), 40 M_DEVBUF, M_WAITOK); 41 bzero((caddr_t)ev->ev_q, EV_QSIZE * sizeof(struct firm_event)); 42 } 43 44 /* 45 * Tear down a firm_event queue. 46 */ 47 void 48 ev_fini(ev) 49 register struct evvar *ev; 50 { 51 52 free(ev->ev_q, M_DEVBUF); 53 } 54 55 /* 56 * User-level interface: read, select. 57 * (User cannot write an event queue.) 58 */ 59 int 60 ev_read(ev, uio, flags) 61 register struct evvar *ev; 62 struct uio *uio; 63 int flags; 64 { 65 int s, n, cnt, error; 66 67 /* 68 * Make sure we can return at least 1. 69 */ 70 if (uio->uio_resid < sizeof(struct firm_event)) 71 return (EMSGSIZE); /* ??? */ 72 s = splev(); 73 while (ev->ev_get == ev->ev_put) { 74 if (flags & IO_NDELAY) { 75 splx(s); 76 return (EWOULDBLOCK); 77 } 78 ev->ev_wanted = 1; 79 error = tsleep((caddr_t)ev, PEVENT | PCATCH, "firm_event", 0); 80 if (error) { 81 splx(s); 82 return (error); 83 } 84 } 85 /* 86 * Move firm_events from tail end of queue (there is at least one 87 * there). 88 */ 89 if (ev->ev_put < ev->ev_get) 90 cnt = EV_QSIZE - ev->ev_get; /* events in [get..QSIZE) */ 91 else 92 cnt = ev->ev_put - ev->ev_get; /* events in [get..put) */ 93 splx(s); 94 n = howmany(uio->uio_resid, sizeof(struct firm_event)); 95 if (cnt > n) 96 cnt = n; 97 error = uiomove((caddr_t)&ev->ev_q[ev->ev_get], 98 cnt * sizeof(struct firm_event), uio); 99 n -= cnt; 100 /* 101 * If we do not wrap to 0, used up all our space, or had an error, 102 * stop. Otherwise move from front of queue to put index, if there 103 * is anything there to move. 104 */ 105 if ((ev->ev_get = (ev->ev_get + cnt) % EV_QSIZE) != 0 || 106 n == 0 || error || (cnt = ev->ev_put) == 0) 107 return (error); 108 if (cnt > n) 109 cnt = n; 110 error = uiomove((caddr_t)&ev->ev_q[0], 111 cnt * sizeof(struct firm_event), uio); 112 ev->ev_get = cnt; 113 return (error); 114 } 115 116 int 117 ev_select(ev, rw, p) 118 register struct evvar *ev; 119 int rw; 120 struct proc *p; 121 { 122 int s = splev(); 123 124 switch (rw) { 125 126 case FREAD: 127 /* succeed if there is something to read */ 128 if (ev->ev_get != ev->ev_put) { 129 splx(s); 130 return (1); 131 } 132 selrecord(p, &ev->ev_sel); 133 break; 134 135 case FWRITE: 136 return (1); /* always fails => never blocks */ 137 } 138 splx(s); 139 return (0); 140 } 141