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