155104Storek /*
2*63318Sbostic * Copyright (c) 1992, 1993
3*63318Sbostic * The Regents of the University of California. All rights reserved.
455104Storek *
555104Storek * This software was developed by the Computer Systems Engineering group
655104Storek * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
755104Storek * contributed to Berkeley.
855104Storek *
955499Sbostic * All advertising materials mentioning features or use of this software
1055499Sbostic * must display the following acknowledgement:
1155499Sbostic * This product includes software developed by the University of
1259186Storek * California, Lawrence Berkeley Laboratory.
1355499Sbostic *
1455104Storek * %sccs.include.redist.c%
1555104Storek *
16*63318Sbostic * @(#)event.c 8.1 (Berkeley) 06/11/93
1755104Storek *
1859186Storek * from: $Header: event.c,v 1.5 92/11/26 01:10:44 torek Exp $ (LBL)
1955104Storek */
2055104Storek
2155104Storek /*
2255104Storek * Internal `Firm_event' interface for the keyboard and mouse drivers.
2355104Storek */
2455104Storek
2556536Sbostic #include <sys/param.h>
2656536Sbostic #include <sys/fcntl.h>
2756536Sbostic #include <sys/malloc.h>
2856536Sbostic #include <sys/proc.h>
2956536Sbostic #include <sys/systm.h>
3056536Sbostic #include <sys/vnode.h>
3155104Storek
3256536Sbostic #include <sparc/dev/vuid_event.h>
3356536Sbostic #include <sparc/dev/event_var.h>
3455104Storek
3555104Storek /*
3655104Storek * Initialize a firm_event queue.
3755104Storek */
3855104Storek void
ev_init(ev)3955104Storek ev_init(ev)
4055104Storek register struct evvar *ev;
4155104Storek {
4255104Storek
4355104Storek ev->ev_get = ev->ev_put = 0;
4455104Storek ev->ev_q = malloc((u_long)EV_QSIZE * sizeof(struct firm_event),
4555104Storek M_DEVBUF, M_WAITOK);
4655104Storek bzero((caddr_t)ev->ev_q, EV_QSIZE * sizeof(struct firm_event));
4755104Storek }
4855104Storek
4955104Storek /*
5055104Storek * Tear down a firm_event queue.
5155104Storek */
5255104Storek void
ev_fini(ev)5355104Storek ev_fini(ev)
5455104Storek register struct evvar *ev;
5555104Storek {
5655104Storek
5755104Storek free(ev->ev_q, M_DEVBUF);
5855104Storek }
5955104Storek
6055104Storek /*
6155104Storek * User-level interface: read, select.
6255104Storek * (User cannot write an event queue.)
6355104Storek */
6455104Storek int
ev_read(ev,uio,flags)6555104Storek ev_read(ev, uio, flags)
6655104Storek register struct evvar *ev;
6755104Storek struct uio *uio;
6855104Storek int flags;
6955104Storek {
7055104Storek int s, n, cnt, error;
7155104Storek
7255104Storek /*
7355104Storek * Make sure we can return at least 1.
7455104Storek */
7555104Storek if (uio->uio_resid < sizeof(struct firm_event))
7655104Storek return (EMSGSIZE); /* ??? */
7755104Storek s = splev();
7855104Storek while (ev->ev_get == ev->ev_put) {
7955104Storek if (flags & IO_NDELAY) {
8055104Storek splx(s);
8155104Storek return (EWOULDBLOCK);
8255104Storek }
8355104Storek ev->ev_wanted = 1;
8455104Storek error = tsleep((caddr_t)ev, PEVENT | PCATCH, "firm_event", 0);
8555104Storek if (error) {
8655104Storek splx(s);
8755104Storek return (error);
8855104Storek }
8955104Storek }
9055104Storek /*
9155104Storek * Move firm_events from tail end of queue (there is at least one
9255104Storek * there).
9355104Storek */
9455104Storek if (ev->ev_put < ev->ev_get)
9555104Storek cnt = EV_QSIZE - ev->ev_get; /* events in [get..QSIZE) */
9655104Storek else
9755104Storek cnt = ev->ev_put - ev->ev_get; /* events in [get..put) */
9855104Storek splx(s);
9955104Storek n = howmany(uio->uio_resid, sizeof(struct firm_event));
10055104Storek if (cnt > n)
10155104Storek cnt = n;
10255104Storek error = uiomove((caddr_t)&ev->ev_q[ev->ev_get],
10355104Storek cnt * sizeof(struct firm_event), uio);
10455104Storek n -= cnt;
10555104Storek /*
10655104Storek * If we do not wrap to 0, used up all our space, or had an error,
10755104Storek * stop. Otherwise move from front of queue to put index, if there
10855104Storek * is anything there to move.
10955104Storek */
11055104Storek if ((ev->ev_get = (ev->ev_get + cnt) % EV_QSIZE) != 0 ||
11155104Storek n == 0 || error || (cnt = ev->ev_put) == 0)
11255104Storek return (error);
11355104Storek if (cnt > n)
11455104Storek cnt = n;
11555104Storek error = uiomove((caddr_t)&ev->ev_q[0],
11655104Storek cnt * sizeof(struct firm_event), uio);
11755104Storek ev->ev_get = cnt;
11855104Storek return (error);
11955104Storek }
12055104Storek
12155104Storek int
ev_select(ev,rw,p)12255104Storek ev_select(ev, rw, p)
12355104Storek register struct evvar *ev;
12455104Storek int rw;
12555104Storek struct proc *p;
12655104Storek {
12755104Storek int s = splev();
12855104Storek
12955104Storek switch (rw) {
13055104Storek
13155104Storek case FREAD:
13255104Storek /* succeed if there is something to read */
13355104Storek if (ev->ev_get != ev->ev_put) {
13455104Storek splx(s);
13555104Storek return (1);
13655104Storek }
13755104Storek selrecord(p, &ev->ev_sel);
13855104Storek break;
13955104Storek
14055104Storek case FWRITE:
14155104Storek return (1); /* always fails => never blocks */
14255104Storek }
14355104Storek splx(s);
14455104Storek return (0);
14555104Storek }
146