xref: /original-bsd/sys/sparc/dev/event.c (revision 03bd62d7)
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