xref: /csrg-svn/sys/sparc/dev/event.c (revision 55104)
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