xref: /dflybsd-src/sys/dev/misc/evdev/cdev.c (revision a162a738eca94f99d45d88429e86cfd0fbfbe95d)
1d3d1dd3eSPeeter Must /*-
2d3d1dd3eSPeeter Must  * Copyright (c) 2014 Jakub Wojciech Klama <jceel@FreeBSD.org>
3d3d1dd3eSPeeter Must  * Copyright (c) 2015-2016 Vladimir Kondratyev <wulf@FreeBSD.org>
4d3d1dd3eSPeeter Must  * All rights reserved.
5d3d1dd3eSPeeter Must  *
6d3d1dd3eSPeeter Must  * Redistribution and use in source and binary forms, with or without
7d3d1dd3eSPeeter Must  * modification, are permitted provided that the following conditions
8d3d1dd3eSPeeter Must  * are met:
9d3d1dd3eSPeeter Must  * 1. Redistributions of source code must retain the above copyright
10d3d1dd3eSPeeter Must  *    notice, this list of conditions and the following disclaimer.
11d3d1dd3eSPeeter Must  * 2. Redistributions in binary form must reproduce the above copyright
12d3d1dd3eSPeeter Must  *    notice, this list of conditions and the following disclaimer in the
13d3d1dd3eSPeeter Must  *    documentation and/or other materials provided with the distribution.
14d3d1dd3eSPeeter Must  *
15d3d1dd3eSPeeter Must  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16d3d1dd3eSPeeter Must  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17d3d1dd3eSPeeter Must  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18d3d1dd3eSPeeter Must  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19d3d1dd3eSPeeter Must  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20d3d1dd3eSPeeter Must  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21d3d1dd3eSPeeter Must  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22d3d1dd3eSPeeter Must  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23d3d1dd3eSPeeter Must  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24d3d1dd3eSPeeter Must  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25d3d1dd3eSPeeter Must  * SUCH DAMAGE.
26d3d1dd3eSPeeter Must  *
27d3d1dd3eSPeeter Must  * $FreeBSD$
28d3d1dd3eSPeeter Must  */
29d3d1dd3eSPeeter Must 
30d3d1dd3eSPeeter Must #include "opt_evdev.h"
31d3d1dd3eSPeeter Must 
32d3d1dd3eSPeeter Must #include <sys/types.h>
33d3d1dd3eSPeeter Must #include <sys/module.h>
34d3d1dd3eSPeeter Must #include <sys/devfs.h>
35d3d1dd3eSPeeter Must 
36d3d1dd3eSPeeter Must #include <sys/param.h>
37857fcb57SMatthew Dillon #include <sys/caps.h>
38d3d1dd3eSPeeter Must #include <sys/conf.h>
39d3d1dd3eSPeeter Must #include <sys/filio.h>
40d3d1dd3eSPeeter Must #include <sys/fcntl.h>
41d3d1dd3eSPeeter Must #include <sys/kernel.h>
42d3d1dd3eSPeeter Must #include <sys/malloc.h>
43d3d1dd3eSPeeter Must #include <sys/poll.h>
44d3d1dd3eSPeeter Must #include <sys/proc.h>
45d3d1dd3eSPeeter Must #include <sys/systm.h>
46d3d1dd3eSPeeter Must #include <sys/time.h>
47d3d1dd3eSPeeter Must #include <sys/vnode.h> /* IO_NDELAY in read() */
48d3d1dd3eSPeeter Must #include <sys/uio.h>
49d3d1dd3eSPeeter Must 
50d3d1dd3eSPeeter Must #include <sys/errno.h>
51d3d1dd3eSPeeter Must 
52d3d1dd3eSPeeter Must #include <sys/device.h>
53d3d1dd3eSPeeter Must #include <sys/bus.h>
54d3d1dd3eSPeeter Must 
55d3d1dd3eSPeeter Must /* Use FreeBSD bitstring locally. */
56d3d1dd3eSPeeter Must #include "freebsd-bitstring.h"
57d3d1dd3eSPeeter Must 
58d3d1dd3eSPeeter Must #include <dev/misc/evdev/evdev.h>
59d3d1dd3eSPeeter Must #include <dev/misc/evdev/evdev_private.h>
60d3d1dd3eSPeeter Must #include <dev/misc/evdev/input.h>
61d3d1dd3eSPeeter Must 
62d3d1dd3eSPeeter Must #ifdef EVDEV_DEBUG
63d3d1dd3eSPeeter Must #define	debugf(client, fmt, args...)	kprintf("evdev cdev: "fmt"\n", ##args)
64d3d1dd3eSPeeter Must #else
65d3d1dd3eSPeeter Must #define	debugf(client, fmt, args...)
66d3d1dd3eSPeeter Must #endif
67d3d1dd3eSPeeter Must 
68d3d1dd3eSPeeter Must #define	DEF_RING_REPORTS	8
69d3d1dd3eSPeeter Must 
70d3d1dd3eSPeeter Must static d_open_t		evdev_open;
71d3d1dd3eSPeeter Must static d_read_t		evdev_read;
72d3d1dd3eSPeeter Must static d_write_t	evdev_write;
73d3d1dd3eSPeeter Must static d_ioctl_t	evdev_ioctl;
74d3d1dd3eSPeeter Must static d_kqfilter_t	evdev_kqfilter;
75d56bec7aSAaron LI static d_priv_dtor_t	evdev_dtor;
76d3d1dd3eSPeeter Must 
77d3d1dd3eSPeeter Must static int evdev_kqread(struct knote *kn, long hint);
78d3d1dd3eSPeeter Must static void evdev_kqdetach(struct knote *kn);
79d3d1dd3eSPeeter Must static int evdev_ioctl_eviocgbit(struct evdev_dev *, int, int, caddr_t);
80d3d1dd3eSPeeter Must static void evdev_client_filter_queue(struct evdev_client *, uint16_t);
81d3d1dd3eSPeeter Must 
82d3d1dd3eSPeeter Must static struct dev_ops evdev_cdevsw = {
83d3d1dd3eSPeeter Must 	{ "evdev", 0, 0 },
84d3d1dd3eSPeeter Must 	.d_open = evdev_open,
85d3d1dd3eSPeeter Must 	.d_read = evdev_read,
86d3d1dd3eSPeeter Must 	.d_write = evdev_write,
87d3d1dd3eSPeeter Must 	.d_ioctl = evdev_ioctl,
88d3d1dd3eSPeeter Must 	.d_kqfilter = evdev_kqfilter,
89d3d1dd3eSPeeter Must };
90d3d1dd3eSPeeter Must 
91d3d1dd3eSPeeter Must static struct filterops evdev_cdev_filterops = {
92d3d1dd3eSPeeter Must 	.f_flags = FILTEROP_ISFD,
93d3d1dd3eSPeeter Must 	.f_attach = NULL,
94d3d1dd3eSPeeter Must 	.f_detach = evdev_kqdetach,
95d3d1dd3eSPeeter Must 	.f_event = evdev_kqread,
96d3d1dd3eSPeeter Must };
97d3d1dd3eSPeeter Must 
98d3d1dd3eSPeeter Must static int
evdev_open(struct dev_open_args * ap)99d3d1dd3eSPeeter Must evdev_open(struct dev_open_args *ap)
100d3d1dd3eSPeeter Must {
101d3d1dd3eSPeeter Must 	cdev_t dev = ap->a_head.a_dev;
102d3d1dd3eSPeeter Must 	struct evdev_dev *evdev = dev->si_drv1;
103d3d1dd3eSPeeter Must 	struct evdev_client *client;
104d3d1dd3eSPeeter Must 	size_t buffer_size;
105d3d1dd3eSPeeter Must 	int ret;
106d3d1dd3eSPeeter Must 
107857fcb57SMatthew Dillon 	/*
108857fcb57SMatthew Dillon 	 * Disallow access to disk volumes if RESTRICTEDROOT
109857fcb57SMatthew Dillon 	 */
110857fcb57SMatthew Dillon 	if (caps_priv_check_self(SYSCAP_RESTRICTEDROOT))
111857fcb57SMatthew Dillon 		return (EPERM);
112857fcb57SMatthew Dillon 
113d3d1dd3eSPeeter Must 	if (evdev == NULL)
114d3d1dd3eSPeeter Must 		return (ENODEV);
115d3d1dd3eSPeeter Must 
116d3d1dd3eSPeeter Must 	/* Initialize client structure */
117d3d1dd3eSPeeter Must 	buffer_size = evdev->ev_report_size * DEF_RING_REPORTS;
118d3d1dd3eSPeeter Must 	client = kmalloc(offsetof(struct evdev_client, ec_buffer) +
119d3d1dd3eSPeeter Must 	    sizeof(struct input_event) * buffer_size,
120d3d1dd3eSPeeter Must 	    M_EVDEV, M_WAITOK | M_ZERO);
121d3d1dd3eSPeeter Must 
122d3d1dd3eSPeeter Must 	/* Initialize ring buffer */
123d3d1dd3eSPeeter Must 	client->ec_buffer_size = buffer_size;
124d3d1dd3eSPeeter Must 	client->ec_buffer_head = 0;
125d3d1dd3eSPeeter Must 	client->ec_buffer_tail = 0;
126d3d1dd3eSPeeter Must 	client->ec_buffer_ready = 0;
127d3d1dd3eSPeeter Must 
128d3d1dd3eSPeeter Must 	client->ec_evdev = evdev;
129d3d1dd3eSPeeter Must 	lockinit(&client->ec_buffer_mtx, "evclient", 0, LK_CANRECURSE);
130d3d1dd3eSPeeter Must 
131d3d1dd3eSPeeter Must 	/* Avoid race with evdev_unregister */
132d3d1dd3eSPeeter Must 	EVDEV_LOCK(evdev);
133d3d1dd3eSPeeter Must 	if (dev->si_drv1 == NULL)
134d3d1dd3eSPeeter Must 		ret = ENODEV;
135d3d1dd3eSPeeter Must 	else
136d3d1dd3eSPeeter Must 		ret = evdev_register_client(evdev, client);
137d3d1dd3eSPeeter Must 
138d3d1dd3eSPeeter Must 	if (ret != 0)
139d3d1dd3eSPeeter Must 		evdev_revoke_client(client);
140d3d1dd3eSPeeter Must 	/*
141d3d1dd3eSPeeter Must 	 * Unlock evdev here because non-sleepable lock held
142d3d1dd3eSPeeter Must 	 * while calling devfs_set_cdevpriv upsets WITNESS
143d3d1dd3eSPeeter Must 	 */
144d3d1dd3eSPeeter Must 	EVDEV_UNLOCK(evdev);
145d3d1dd3eSPeeter Must 
1465bd45597SMatthew Dillon 	if (ret == 0) {
1475bd45597SMatthew Dillon 		struct file *fp;
1485bd45597SMatthew Dillon 
1495bd45597SMatthew Dillon 		fp = (ap->a_fpp) ? *ap->a_fpp : NULL;
1505bd45597SMatthew Dillon 		ret = devfs_set_cdevpriv(fp, client, &evdev_dtor);
1515bd45597SMatthew Dillon 	}
152d3d1dd3eSPeeter Must 
153d3d1dd3eSPeeter Must 	if (ret != 0) {
154d3d1dd3eSPeeter Must 		debugf(client, "cannot register evdev client");
155d3d1dd3eSPeeter Must 	}
156d3d1dd3eSPeeter Must 
157d3d1dd3eSPeeter Must 	return (ret);
158d3d1dd3eSPeeter Must }
159d3d1dd3eSPeeter Must 
160d3d1dd3eSPeeter Must static void
evdev_dtor(void * data)161d3d1dd3eSPeeter Must evdev_dtor(void *data)
162d3d1dd3eSPeeter Must {
163d3d1dd3eSPeeter Must 	struct evdev_client *client = (struct evdev_client *)data;
164d3d1dd3eSPeeter Must 
165d3d1dd3eSPeeter Must 	EVDEV_LOCK(client->ec_evdev);
166d3d1dd3eSPeeter Must 	if (!client->ec_revoked)
167d3d1dd3eSPeeter Must 		evdev_dispose_client(client->ec_evdev, client);
168d3d1dd3eSPeeter Must 	EVDEV_UNLOCK(client->ec_evdev);
169d3d1dd3eSPeeter Must 
170d3d1dd3eSPeeter Must 	funsetown(&client->ec_sigio);
171d3d1dd3eSPeeter Must 	lockuninit(&client->ec_buffer_mtx);
172d3d1dd3eSPeeter Must 	kfree(client, M_EVDEV);
173d3d1dd3eSPeeter Must }
174d3d1dd3eSPeeter Must 
175d3d1dd3eSPeeter Must static int
evdev_read(struct dev_read_args * ap)176d3d1dd3eSPeeter Must evdev_read(struct dev_read_args *ap)
177d3d1dd3eSPeeter Must {
178d3d1dd3eSPeeter Must 	struct uio *uio = ap->a_uio;
179d3d1dd3eSPeeter Must 	int ioflag = ap->a_ioflag;
180d3d1dd3eSPeeter Must 	struct evdev_client *client;
181d3d1dd3eSPeeter Must 	struct input_event event;
182d3d1dd3eSPeeter Must 	int ret = 0;
183d3d1dd3eSPeeter Must 	int remaining;
184d3d1dd3eSPeeter Must 
185d3d1dd3eSPeeter Must 	ret = devfs_get_cdevpriv(ap->a_fp, (void **)&client);
186d3d1dd3eSPeeter Must 	if (ret != 0)
187d3d1dd3eSPeeter Must 		return (ret);
188d3d1dd3eSPeeter Must 
189d3d1dd3eSPeeter Must 	debugf(client, "read %zd bytes by thread %d", uio->uio_resid, 0);
190d3d1dd3eSPeeter Must 
191d3d1dd3eSPeeter Must 	if (client->ec_revoked)
192d3d1dd3eSPeeter Must 		return (ENODEV);
193d3d1dd3eSPeeter Must 
194d3d1dd3eSPeeter Must 	/* Zero-sized reads are allowed for error checking */
195d3d1dd3eSPeeter Must 	if (uio->uio_resid != 0 && uio->uio_resid < sizeof(struct input_event))
196d3d1dd3eSPeeter Must 		return (EINVAL);
197d3d1dd3eSPeeter Must 
198d3d1dd3eSPeeter Must 	remaining = uio->uio_resid / sizeof(struct input_event);
199d3d1dd3eSPeeter Must 
200d3d1dd3eSPeeter Must 	EVDEV_CLIENT_LOCKQ(client);
201d3d1dd3eSPeeter Must 
202d3d1dd3eSPeeter Must 	if (EVDEV_CLIENT_EMPTYQ(client)) {
203d3d1dd3eSPeeter Must 		if (ioflag & IO_NDELAY) {
204d3d1dd3eSPeeter Must 			ret = EWOULDBLOCK;
205d3d1dd3eSPeeter Must 		} else {
206d3d1dd3eSPeeter Must 			if (remaining != 0) {
207d3d1dd3eSPeeter Must 				client->ec_blocked = true;
208d3d1dd3eSPeeter Must 				ret = lksleep(client, &client->ec_buffer_mtx,
209d3d1dd3eSPeeter Must 				    PCATCH, "evread", 0);
210*a162a738SMichael Neumann 				if (ret == 0 && client->ec_revoked)
211*a162a738SMichael Neumann 					ret = ENODEV;
212d3d1dd3eSPeeter Must 			}
213d3d1dd3eSPeeter Must 		}
214d3d1dd3eSPeeter Must 	}
215d3d1dd3eSPeeter Must 
216d3d1dd3eSPeeter Must 	while (ret == 0 && !EVDEV_CLIENT_EMPTYQ(client) && remaining > 0) {
217d3d1dd3eSPeeter Must 		memcpy(&event, &client->ec_buffer[client->ec_buffer_head],
218d3d1dd3eSPeeter Must 		    sizeof(struct input_event));
219d3d1dd3eSPeeter Must 		client->ec_buffer_head =
220d3d1dd3eSPeeter Must 		    (client->ec_buffer_head + 1) % client->ec_buffer_size;
221d3d1dd3eSPeeter Must 		remaining--;
222d3d1dd3eSPeeter Must 
223d3d1dd3eSPeeter Must 		EVDEV_CLIENT_UNLOCKQ(client);
224d3d1dd3eSPeeter Must 		ret = uiomove((void *)&event, sizeof(struct input_event), uio);
225d3d1dd3eSPeeter Must 		EVDEV_CLIENT_LOCKQ(client);
226d3d1dd3eSPeeter Must 	}
227d3d1dd3eSPeeter Must 
228d3d1dd3eSPeeter Must 	EVDEV_CLIENT_UNLOCKQ(client);
229d3d1dd3eSPeeter Must 
230d3d1dd3eSPeeter Must 	return (ret);
231d3d1dd3eSPeeter Must }
232d3d1dd3eSPeeter Must 
233d3d1dd3eSPeeter Must static int
evdev_write(struct dev_write_args * ap)234d3d1dd3eSPeeter Must evdev_write(struct dev_write_args *ap)
235d3d1dd3eSPeeter Must {
236d3d1dd3eSPeeter Must 	cdev_t dev = ap->a_head.a_dev;
237d3d1dd3eSPeeter Must 	struct uio *uio = ap->a_uio;
238d3d1dd3eSPeeter Must 	struct evdev_dev *evdev = dev->si_drv1;
239d3d1dd3eSPeeter Must 	struct evdev_client *client;
240d3d1dd3eSPeeter Must 	struct input_event event;
241d3d1dd3eSPeeter Must 	int ret = 0;
242d3d1dd3eSPeeter Must 
243d3d1dd3eSPeeter Must 	ret = devfs_get_cdevpriv(ap->a_fp, (void **)&client);
244d3d1dd3eSPeeter Must 	if (ret != 0)
245d3d1dd3eSPeeter Must 		return (ret);
246d3d1dd3eSPeeter Must 
247d3d1dd3eSPeeter Must 	debugf(client, "write %zd bytes by thread %d", uio->uio_resid, 0);
248d3d1dd3eSPeeter Must 
249d3d1dd3eSPeeter Must 	if (client->ec_revoked || evdev == NULL)
250d3d1dd3eSPeeter Must 		return (ENODEV);
251d3d1dd3eSPeeter Must 
252d3d1dd3eSPeeter Must 	if (uio->uio_resid % sizeof(struct input_event) != 0) {
253d3d1dd3eSPeeter Must 		debugf(client, "write size not multiple of input_event size");
254d3d1dd3eSPeeter Must 		return (EINVAL);
255d3d1dd3eSPeeter Must 	}
256d3d1dd3eSPeeter Must 
257d3d1dd3eSPeeter Must 	while (uio->uio_resid > 0 && ret == 0) {
258d3d1dd3eSPeeter Must 		ret = uiomove((void *)&event, sizeof(struct input_event), uio);
259d3d1dd3eSPeeter Must 		if (ret == 0)
260d3d1dd3eSPeeter Must 			ret = evdev_inject_event(evdev, event.type, event.code,
261d3d1dd3eSPeeter Must 			    event.value);
262d3d1dd3eSPeeter Must 	}
263d3d1dd3eSPeeter Must 
264d3d1dd3eSPeeter Must 	return (ret);
265d3d1dd3eSPeeter Must }
266d3d1dd3eSPeeter Must 
267d3d1dd3eSPeeter Must static int
evdev_kqfilter(struct dev_kqfilter_args * ap)268d3d1dd3eSPeeter Must evdev_kqfilter(struct dev_kqfilter_args *ap)
269d3d1dd3eSPeeter Must {
270d3d1dd3eSPeeter Must 	struct knote *kn = ap->a_kn;
271d3d1dd3eSPeeter Must 	struct klist *klist;
272d3d1dd3eSPeeter Must 	struct evdev_client *client;
273d3d1dd3eSPeeter Must 	int ret;
274d3d1dd3eSPeeter Must 
275d3d1dd3eSPeeter Must 	ret = devfs_get_cdevpriv(ap->a_fp, (void **)&client);
276d3d1dd3eSPeeter Must 	if (ret != 0)
277d3d1dd3eSPeeter Must 		return (ret);
278d3d1dd3eSPeeter Must 
279d3d1dd3eSPeeter Must 	if (client->ec_revoked)
280d3d1dd3eSPeeter Must 		return (ENODEV);
281d3d1dd3eSPeeter Must 
282d3d1dd3eSPeeter Must 	switch(kn->kn_filter) {
283d3d1dd3eSPeeter Must 	case EVFILT_READ:
284d3d1dd3eSPeeter Must 		kn->kn_fop = &evdev_cdev_filterops;
285d3d1dd3eSPeeter Must 		break;
286d3d1dd3eSPeeter Must 	default:
287d3d1dd3eSPeeter Must 		return(EINVAL);
288d3d1dd3eSPeeter Must 	}
289d3d1dd3eSPeeter Must 	kn->kn_hook = (caddr_t)client;
290d3d1dd3eSPeeter Must 
291d3d1dd3eSPeeter Must 	klist = &client->kqinfo.ki_note;
292d3d1dd3eSPeeter Must 	knote_insert(klist, kn);
293d3d1dd3eSPeeter Must 	return (0);
294d3d1dd3eSPeeter Must }
295d3d1dd3eSPeeter Must 
296d3d1dd3eSPeeter Must static int
evdev_kqread(struct knote * kn,long hint)297d3d1dd3eSPeeter Must evdev_kqread(struct knote *kn, long hint)
298d3d1dd3eSPeeter Must {
299d3d1dd3eSPeeter Must 	struct evdev_client *client;
300d3d1dd3eSPeeter Must 	int ret;
301d3d1dd3eSPeeter Must 	int locked = 0;
302d3d1dd3eSPeeter Must 
303d3d1dd3eSPeeter Must 	client = (struct evdev_client *)kn->kn_hook;
304d3d1dd3eSPeeter Must 
305d3d1dd3eSPeeter Must 	/* NOTE on DragonFly v FreeBSD.
306d3d1dd3eSPeeter Must 	 * FreeBSD locks the klist when calling f_event, i.e. evdev_kqread().
307d3d1dd3eSPeeter Must 	 * That's why the plain assertion EVDEV_CLIENT_LOCKQ_ASSERT(client)
308d3d1dd3eSPeeter Must 	 * fails on DragonFly: DragonFly does not ensure the lock associated
309d3d1dd3eSPeeter Must 	 * with the klist is locked.
310d3d1dd3eSPeeter Must 	 * To mimic FreeBSD's behavior, we will lock ec_buffer_mtx if
311d3d1dd3eSPeeter Must 	 * it was not locked, and unlock when leaving.
312d3d1dd3eSPeeter Must 	 */
313d3d1dd3eSPeeter Must 	locked = lockowned(&(client)->ec_buffer_mtx);
314d3d1dd3eSPeeter Must 	if (!locked)
315d3d1dd3eSPeeter Must 		EVDEV_CLIENT_LOCKQ(client);
316d3d1dd3eSPeeter Must 
317d3d1dd3eSPeeter Must 	EVDEV_CLIENT_LOCKQ_ASSERT(client);
318d3d1dd3eSPeeter Must 
319d3d1dd3eSPeeter Must 	if (client->ec_revoked) {
320d3d1dd3eSPeeter Must 		kn->kn_flags |= EV_EOF;
321d3d1dd3eSPeeter Must 		ret = 1;
322d3d1dd3eSPeeter Must 	} else {
323d3d1dd3eSPeeter Must 		kn->kn_data = EVDEV_CLIENT_SIZEQ(client) *
324d3d1dd3eSPeeter Must 		    sizeof(struct input_event);
325d3d1dd3eSPeeter Must 		ret = !EVDEV_CLIENT_EMPTYQ(client);
326d3d1dd3eSPeeter Must 	}
327d3d1dd3eSPeeter Must 
328d3d1dd3eSPeeter Must 	/* Unlock if ec_buffer_mtx was not locked. */
329d3d1dd3eSPeeter Must 	if (!locked) {
330d3d1dd3eSPeeter Must 		EVDEV_CLIENT_UNLOCKQ(client);
331d3d1dd3eSPeeter Must 	}
332d3d1dd3eSPeeter Must 
333d3d1dd3eSPeeter Must 	return (ret);
334d3d1dd3eSPeeter Must }
335d3d1dd3eSPeeter Must 
336d3d1dd3eSPeeter Must static void
evdev_kqdetach(struct knote * kn)337d3d1dd3eSPeeter Must evdev_kqdetach(struct knote *kn)
338d3d1dd3eSPeeter Must {
339d3d1dd3eSPeeter Must 	struct evdev_client *client;
340d3d1dd3eSPeeter Must 
341d3d1dd3eSPeeter Must 	client = (struct evdev_client *)kn->kn_hook;
342d3d1dd3eSPeeter Must 	knote_remove(&client->kqinfo.ki_note, kn);
343d3d1dd3eSPeeter Must }
344d3d1dd3eSPeeter Must 
345d3d1dd3eSPeeter Must static int
evdev_ioctl(struct dev_ioctl_args * ap)346d3d1dd3eSPeeter Must evdev_ioctl(struct dev_ioctl_args *ap)
347d3d1dd3eSPeeter Must {
348d3d1dd3eSPeeter Must 	cdev_t dev = ap->a_head.a_dev;
349d3d1dd3eSPeeter Must 	u_long cmd = ap->a_cmd;
350d3d1dd3eSPeeter Must 	caddr_t data = ap->a_data;
351d3d1dd3eSPeeter Must 	struct evdev_dev *evdev = dev->si_drv1;
352d3d1dd3eSPeeter Must 	struct evdev_client *client;
353d3d1dd3eSPeeter Must 	struct input_keymap_entry *ke;
354d3d1dd3eSPeeter Must 	int ret, len, limit, type_num;
355d3d1dd3eSPeeter Must 	uint32_t code;
356d3d1dd3eSPeeter Must 	size_t nvalues;
357d3d1dd3eSPeeter Must 
358d3d1dd3eSPeeter Must 	ret = devfs_get_cdevpriv(ap->a_fp, (void **)&client);
359d3d1dd3eSPeeter Must 	if (ret != 0)
360d3d1dd3eSPeeter Must 		return (ret);
361d3d1dd3eSPeeter Must 
362d3d1dd3eSPeeter Must 	if (client->ec_revoked || evdev == NULL)
363d3d1dd3eSPeeter Must 		return (ENODEV);
364d3d1dd3eSPeeter Must 
365d3d1dd3eSPeeter Must 	/* file I/O ioctl handling */
366d3d1dd3eSPeeter Must 	switch (cmd) {
367d3d1dd3eSPeeter Must 	case FIOSETOWN:
368d3d1dd3eSPeeter Must 		return (fsetown(*(int *)data, &client->ec_sigio));
369d3d1dd3eSPeeter Must 
370d3d1dd3eSPeeter Must 	case FIOGETOWN:
371d3d1dd3eSPeeter Must 		*(int *)data = fgetown(&client->ec_sigio);
372d3d1dd3eSPeeter Must 		return (0);
373d3d1dd3eSPeeter Must 
374d3d1dd3eSPeeter Must 	case FIONBIO:
375d3d1dd3eSPeeter Must 		return (0);
376d3d1dd3eSPeeter Must 
377d3d1dd3eSPeeter Must 	case FIOASYNC:
378d3d1dd3eSPeeter Must 		if (*(int *)data)
379d3d1dd3eSPeeter Must 			client->ec_async = true;
380d3d1dd3eSPeeter Must 		else
381d3d1dd3eSPeeter Must 			client->ec_async = false;
382d3d1dd3eSPeeter Must 
383d3d1dd3eSPeeter Must 		return (0);
384d3d1dd3eSPeeter Must 
385d3d1dd3eSPeeter Must 	case FIONREAD:
386d3d1dd3eSPeeter Must 		EVDEV_CLIENT_LOCKQ(client);
387d3d1dd3eSPeeter Must 		*(int *)data =
388d3d1dd3eSPeeter Must 		    EVDEV_CLIENT_SIZEQ(client) * sizeof(struct input_event);
389d3d1dd3eSPeeter Must 		EVDEV_CLIENT_UNLOCKQ(client);
390d3d1dd3eSPeeter Must 		return (0);
391d3d1dd3eSPeeter Must 	}
392d3d1dd3eSPeeter Must 
393d3d1dd3eSPeeter Must 	len = IOCPARM_LEN(cmd);
394d3d1dd3eSPeeter Must 	debugf(client, "ioctl called: cmd=0x%08lx, data=%p", cmd, data);
395d3d1dd3eSPeeter Must 
396d3d1dd3eSPeeter Must 	/* evdev fixed-length ioctls handling */
397d3d1dd3eSPeeter Must 	switch (cmd) {
398d3d1dd3eSPeeter Must 	case EVIOCGVERSION:
399d3d1dd3eSPeeter Must 		*(int *)data = EV_VERSION;
400d3d1dd3eSPeeter Must 		return (0);
401d3d1dd3eSPeeter Must 
402d3d1dd3eSPeeter Must 	case EVIOCGID:
403d3d1dd3eSPeeter Must 		debugf(client, "EVIOCGID: bus=%d vendor=0x%04x product=0x%04x",
404d3d1dd3eSPeeter Must 		    evdev->ev_id.bustype, evdev->ev_id.vendor,
405d3d1dd3eSPeeter Must 		    evdev->ev_id.product);
406d3d1dd3eSPeeter Must 		memcpy(data, &evdev->ev_id, sizeof(struct input_id));
407d3d1dd3eSPeeter Must 		return (0);
408d3d1dd3eSPeeter Must 
409d3d1dd3eSPeeter Must 	case EVIOCGREP:
410d3d1dd3eSPeeter Must 		if (!evdev_event_supported(evdev, EV_REP))
411d3d1dd3eSPeeter Must 			return (ENOTSUP);
412d3d1dd3eSPeeter Must 
413d3d1dd3eSPeeter Must 		memcpy(data, evdev->ev_rep, sizeof(evdev->ev_rep));
414d3d1dd3eSPeeter Must 		return (0);
415d3d1dd3eSPeeter Must 
416d3d1dd3eSPeeter Must 	case EVIOCSREP:
417d3d1dd3eSPeeter Must 		if (!evdev_event_supported(evdev, EV_REP))
418d3d1dd3eSPeeter Must 			return (ENOTSUP);
419d3d1dd3eSPeeter Must 
420d3d1dd3eSPeeter Must 		evdev_inject_event(evdev, EV_REP, REP_DELAY, ((int *)data)[0]);
421d3d1dd3eSPeeter Must 		evdev_inject_event(evdev, EV_REP, REP_PERIOD,
422d3d1dd3eSPeeter Must 		    ((int *)data)[1]);
423d3d1dd3eSPeeter Must 		return (0);
424d3d1dd3eSPeeter Must 
425d3d1dd3eSPeeter Must 	case EVIOCGKEYCODE:
426d3d1dd3eSPeeter Must 		/* Fake unsupported ioctl */
427d3d1dd3eSPeeter Must 		return (0);
428d3d1dd3eSPeeter Must 
429d3d1dd3eSPeeter Must 	case EVIOCGKEYCODE_V2:
430d3d1dd3eSPeeter Must 		if (evdev->ev_methods == NULL ||
431d3d1dd3eSPeeter Must 		    evdev->ev_methods->ev_get_keycode == NULL)
432d3d1dd3eSPeeter Must 			return (ENOTSUP);
433d3d1dd3eSPeeter Must 
434d3d1dd3eSPeeter Must 		ke = (struct input_keymap_entry *)data;
435*a162a738SMichael Neumann 		evdev->ev_methods->ev_get_keycode(evdev, ke);
436d3d1dd3eSPeeter Must 		return (0);
437d3d1dd3eSPeeter Must 
438d3d1dd3eSPeeter Must 	case EVIOCSKEYCODE:
439d3d1dd3eSPeeter Must 		/* Fake unsupported ioctl */
440d3d1dd3eSPeeter Must 		return (0);
441d3d1dd3eSPeeter Must 
442d3d1dd3eSPeeter Must 	case EVIOCSKEYCODE_V2:
443d3d1dd3eSPeeter Must 		if (evdev->ev_methods == NULL ||
444d3d1dd3eSPeeter Must 		    evdev->ev_methods->ev_set_keycode == NULL)
445d3d1dd3eSPeeter Must 			return (ENOTSUP);
446d3d1dd3eSPeeter Must 
447d3d1dd3eSPeeter Must 		ke = (struct input_keymap_entry *)data;
448*a162a738SMichael Neumann 		evdev->ev_methods->ev_set_keycode(evdev, ke);
449d3d1dd3eSPeeter Must 		return (0);
450d3d1dd3eSPeeter Must 
451d3d1dd3eSPeeter Must 	case EVIOCGABS(0) ... EVIOCGABS(ABS_MAX):
452d3d1dd3eSPeeter Must 		if (evdev->ev_absinfo == NULL)
453d3d1dd3eSPeeter Must 			return (EINVAL);
454d3d1dd3eSPeeter Must 
455d3d1dd3eSPeeter Must 		memcpy(data, &evdev->ev_absinfo[cmd - EVIOCGABS(0)],
456d3d1dd3eSPeeter Must 		    sizeof(struct input_absinfo));
457d3d1dd3eSPeeter Must 		return (0);
458d3d1dd3eSPeeter Must 
459d3d1dd3eSPeeter Must 	case EVIOCSABS(0) ... EVIOCSABS(ABS_MAX):
460d3d1dd3eSPeeter Must 		if (evdev->ev_absinfo == NULL)
461d3d1dd3eSPeeter Must 			return (EINVAL);
462d3d1dd3eSPeeter Must 
463d3d1dd3eSPeeter Must 		code = cmd - EVIOCSABS(0);
464d3d1dd3eSPeeter Must 		/* mt-slot number can not be changed */
465d3d1dd3eSPeeter Must 		if (code == ABS_MT_SLOT)
466d3d1dd3eSPeeter Must 			return (EINVAL);
467d3d1dd3eSPeeter Must 
468d3d1dd3eSPeeter Must 		EVDEV_LOCK(evdev);
469d3d1dd3eSPeeter Must 		evdev_set_absinfo(evdev, code, (struct input_absinfo *)data);
470d3d1dd3eSPeeter Must 		EVDEV_UNLOCK(evdev);
471d3d1dd3eSPeeter Must 		return (0);
472d3d1dd3eSPeeter Must 
473d3d1dd3eSPeeter Must 	case EVIOCSFF:
474d3d1dd3eSPeeter Must 	case EVIOCRMFF:
475d3d1dd3eSPeeter Must 	case EVIOCGEFFECTS:
476d3d1dd3eSPeeter Must 		/* Fake unsupported ioctls */
477d3d1dd3eSPeeter Must 		return (0);
478d3d1dd3eSPeeter Must 
479d3d1dd3eSPeeter Must 	case EVIOCGRAB:
480d3d1dd3eSPeeter Must 		EVDEV_LOCK(evdev);
481d3d1dd3eSPeeter Must 		if (*(int *)data)
482d3d1dd3eSPeeter Must 			ret = evdev_grab_client(evdev, client);
483d3d1dd3eSPeeter Must 		else
484d3d1dd3eSPeeter Must 			ret = evdev_release_client(evdev, client);
485d3d1dd3eSPeeter Must 		EVDEV_UNLOCK(evdev);
486d3d1dd3eSPeeter Must 		return (ret);
487d3d1dd3eSPeeter Must 
488d3d1dd3eSPeeter Must 	case EVIOCREVOKE:
489d3d1dd3eSPeeter Must 		if (*(int *)data != 0)
490d3d1dd3eSPeeter Must 			return (EINVAL);
491d3d1dd3eSPeeter Must 
492d3d1dd3eSPeeter Must 		EVDEV_LOCK(evdev);
493d3d1dd3eSPeeter Must 		if (dev->si_drv1 != NULL && !client->ec_revoked) {
494d3d1dd3eSPeeter Must 			evdev_dispose_client(evdev, client);
495d3d1dd3eSPeeter Must 			evdev_revoke_client(client);
496d3d1dd3eSPeeter Must 		}
497d3d1dd3eSPeeter Must 		EVDEV_UNLOCK(evdev);
498d3d1dd3eSPeeter Must 		return (0);
499d3d1dd3eSPeeter Must 
500d3d1dd3eSPeeter Must 	case EVIOCSCLOCKID:
501d3d1dd3eSPeeter Must 		switch (*(int *)data) {
502d3d1dd3eSPeeter Must 		case CLOCK_REALTIME:
503d3d1dd3eSPeeter Must 			client->ec_clock_id = EV_CLOCK_REALTIME;
504d3d1dd3eSPeeter Must 			return (0);
505d3d1dd3eSPeeter Must 		case CLOCK_MONOTONIC:
506d3d1dd3eSPeeter Must 			client->ec_clock_id = EV_CLOCK_MONOTONIC;
507d3d1dd3eSPeeter Must 			return (0);
508d3d1dd3eSPeeter Must 		default:
509d3d1dd3eSPeeter Must 			return (EINVAL);
510d3d1dd3eSPeeter Must 		}
511d3d1dd3eSPeeter Must 	}
512d3d1dd3eSPeeter Must 
513d3d1dd3eSPeeter Must 	/* evdev variable-length ioctls handling */
514d3d1dd3eSPeeter Must 	switch (IOCBASECMD(cmd)) {
515d3d1dd3eSPeeter Must 	case EVIOCGNAME(0):
516d3d1dd3eSPeeter Must 		strlcpy(data, evdev->ev_name, len);
517d3d1dd3eSPeeter Must 		return (0);
518d3d1dd3eSPeeter Must 
519d3d1dd3eSPeeter Must 	case EVIOCGPHYS(0):
520d3d1dd3eSPeeter Must 		if (evdev->ev_shortname[0] == 0)
521d3d1dd3eSPeeter Must 			return (ENOENT);
522d3d1dd3eSPeeter Must 
523d3d1dd3eSPeeter Must 		strlcpy(data, evdev->ev_shortname, len);
524d3d1dd3eSPeeter Must 		return (0);
525d3d1dd3eSPeeter Must 
526d3d1dd3eSPeeter Must 	case EVIOCGUNIQ(0):
527d3d1dd3eSPeeter Must 		if (evdev->ev_serial[0] == 0)
528d3d1dd3eSPeeter Must 			return (ENOENT);
529d3d1dd3eSPeeter Must 
530d3d1dd3eSPeeter Must 		strlcpy(data, evdev->ev_serial, len);
531d3d1dd3eSPeeter Must 		return (0);
532d3d1dd3eSPeeter Must 
533d3d1dd3eSPeeter Must 	case EVIOCGPROP(0):
534d3d1dd3eSPeeter Must 		limit = MIN(len, bitstr_size(INPUT_PROP_CNT));
535d3d1dd3eSPeeter Must 		memcpy(data, evdev->ev_prop_flags, limit);
536d3d1dd3eSPeeter Must 		return (0);
537d3d1dd3eSPeeter Must 
538d3d1dd3eSPeeter Must 	case EVIOCGMTSLOTS(0):
539d3d1dd3eSPeeter Must 		if (evdev->ev_mt == NULL)
540d3d1dd3eSPeeter Must 			return (EINVAL);
541d3d1dd3eSPeeter Must 		if (len < sizeof(uint32_t))
542d3d1dd3eSPeeter Must 			return (EINVAL);
543d3d1dd3eSPeeter Must 		code = *(uint32_t *)data;
544d3d1dd3eSPeeter Must 		if (!ABS_IS_MT(code))
545d3d1dd3eSPeeter Must 			return (EINVAL);
546d3d1dd3eSPeeter Must 
547d3d1dd3eSPeeter Must 		nvalues =
548d3d1dd3eSPeeter Must 		    MIN(len / sizeof(int32_t) - 1, MAXIMAL_MT_SLOT(evdev) + 1);
549d3d1dd3eSPeeter Must 		for (int i = 0; i < nvalues; i++)
550d3d1dd3eSPeeter Must 			((int32_t *)data)[i + 1] =
551*a162a738SMichael Neumann 			    evdev_mt_get_value(evdev, i, code);
552d3d1dd3eSPeeter Must 		return (0);
553d3d1dd3eSPeeter Must 
554d3d1dd3eSPeeter Must 	case EVIOCGKEY(0):
555d3d1dd3eSPeeter Must 		limit = MIN(len, bitstr_size(KEY_CNT));
556d3d1dd3eSPeeter Must 		EVDEV_LOCK(evdev);
557d3d1dd3eSPeeter Must 		evdev_client_filter_queue(client, EV_KEY);
558d3d1dd3eSPeeter Must 		memcpy(data, evdev->ev_key_states, limit);
559d3d1dd3eSPeeter Must 		EVDEV_UNLOCK(evdev);
560d3d1dd3eSPeeter Must 		return (0);
561d3d1dd3eSPeeter Must 
562d3d1dd3eSPeeter Must 	case EVIOCGLED(0):
563d3d1dd3eSPeeter Must 		limit = MIN(len, bitstr_size(LED_CNT));
564d3d1dd3eSPeeter Must 		EVDEV_LOCK(evdev);
565d3d1dd3eSPeeter Must 		evdev_client_filter_queue(client, EV_LED);
566d3d1dd3eSPeeter Must 		memcpy(data, evdev->ev_led_states, limit);
567d3d1dd3eSPeeter Must 		EVDEV_UNLOCK(evdev);
568d3d1dd3eSPeeter Must 		return (0);
569d3d1dd3eSPeeter Must 
570d3d1dd3eSPeeter Must 	case EVIOCGSND(0):
571d3d1dd3eSPeeter Must 		limit = MIN(len, bitstr_size(SND_CNT));
572d3d1dd3eSPeeter Must 		EVDEV_LOCK(evdev);
573d3d1dd3eSPeeter Must 		evdev_client_filter_queue(client, EV_SND);
574d3d1dd3eSPeeter Must 		memcpy(data, evdev->ev_snd_states, limit);
575d3d1dd3eSPeeter Must 		EVDEV_UNLOCK(evdev);
576d3d1dd3eSPeeter Must 		return (0);
577d3d1dd3eSPeeter Must 
578d3d1dd3eSPeeter Must 	case EVIOCGSW(0):
579d3d1dd3eSPeeter Must 		limit = MIN(len, bitstr_size(SW_CNT));
580d3d1dd3eSPeeter Must 		EVDEV_LOCK(evdev);
581d3d1dd3eSPeeter Must 		evdev_client_filter_queue(client, EV_SW);
582d3d1dd3eSPeeter Must 		memcpy(data, evdev->ev_sw_states, limit);
583d3d1dd3eSPeeter Must 		EVDEV_UNLOCK(evdev);
584d3d1dd3eSPeeter Must 		return (0);
585d3d1dd3eSPeeter Must 
586d3d1dd3eSPeeter Must 	case EVIOCGBIT(0, 0) ... EVIOCGBIT(EV_MAX, 0):
587d3d1dd3eSPeeter Must 		type_num = IOCBASECMD(cmd) - EVIOCGBIT(0, 0);
588d3d1dd3eSPeeter Must 		debugf(client, "EVIOCGBIT(%d): data=%p, len=%d", type_num,
589d3d1dd3eSPeeter Must 		    data, len);
590d3d1dd3eSPeeter Must 		return (evdev_ioctl_eviocgbit(evdev, type_num, len, data));
591d3d1dd3eSPeeter Must 	}
592d3d1dd3eSPeeter Must 
593d3d1dd3eSPeeter Must 	return (EINVAL);
594d3d1dd3eSPeeter Must }
595d3d1dd3eSPeeter Must 
596d3d1dd3eSPeeter Must static int
evdev_ioctl_eviocgbit(struct evdev_dev * evdev,int type,int len,caddr_t data)597d3d1dd3eSPeeter Must evdev_ioctl_eviocgbit(struct evdev_dev *evdev, int type, int len, caddr_t data)
598d3d1dd3eSPeeter Must {
599d3d1dd3eSPeeter Must 	/*
600d3d1dd3eSPeeter Must 	 * We will use freebsd-bitstring.h locally. This ensures bitmap
601d3d1dd3eSPeeter Must 	 * is of type (unsigned long *). DragonFly's original bitmap
602d3d1dd3eSPeeter Must 	 * is (unsigned char *).
603d3d1dd3eSPeeter Must 	 */
604d3d1dd3eSPeeter Must 	unsigned long *bitmap;
605d3d1dd3eSPeeter Must 	int limit;
606d3d1dd3eSPeeter Must 
607d3d1dd3eSPeeter Must 	switch (type) {
608d3d1dd3eSPeeter Must 	case 0:
609d3d1dd3eSPeeter Must 		bitmap = evdev->ev_type_flags;
610d3d1dd3eSPeeter Must 		limit = EV_CNT;
611d3d1dd3eSPeeter Must 		break;
612d3d1dd3eSPeeter Must 	case EV_KEY:
613d3d1dd3eSPeeter Must 		bitmap = evdev->ev_key_flags;
614d3d1dd3eSPeeter Must 		limit = KEY_CNT;
615d3d1dd3eSPeeter Must 		break;
616d3d1dd3eSPeeter Must 	case EV_REL:
617d3d1dd3eSPeeter Must 		bitmap = evdev->ev_rel_flags;
618d3d1dd3eSPeeter Must 		limit = REL_CNT;
619d3d1dd3eSPeeter Must 		break;
620d3d1dd3eSPeeter Must 	case EV_ABS:
621d3d1dd3eSPeeter Must 		bitmap = evdev->ev_abs_flags;
622d3d1dd3eSPeeter Must 		limit = ABS_CNT;
623d3d1dd3eSPeeter Must 		break;
624d3d1dd3eSPeeter Must 	case EV_MSC:
625d3d1dd3eSPeeter Must 		bitmap = evdev->ev_msc_flags;
626d3d1dd3eSPeeter Must 		limit = MSC_CNT;
627d3d1dd3eSPeeter Must 		break;
628d3d1dd3eSPeeter Must 	case EV_LED:
629d3d1dd3eSPeeter Must 		bitmap = evdev->ev_led_flags;
630d3d1dd3eSPeeter Must 		limit = LED_CNT;
631d3d1dd3eSPeeter Must 		break;
632d3d1dd3eSPeeter Must 	case EV_SND:
633d3d1dd3eSPeeter Must 		bitmap = evdev->ev_snd_flags;
634d3d1dd3eSPeeter Must 		limit = SND_CNT;
635d3d1dd3eSPeeter Must 		break;
636d3d1dd3eSPeeter Must 	case EV_SW:
637d3d1dd3eSPeeter Must 		bitmap = evdev->ev_sw_flags;
638d3d1dd3eSPeeter Must 		limit = SW_CNT;
639d3d1dd3eSPeeter Must 		break;
640d3d1dd3eSPeeter Must 	case EV_FF:
641d3d1dd3eSPeeter Must 		/*
642d3d1dd3eSPeeter Must 		 * We don't support EV_FF now, so let's
643d3d1dd3eSPeeter Must 		 * just fake it returning only zeros.
644d3d1dd3eSPeeter Must 		 */
645d3d1dd3eSPeeter Must 		bzero(data, len);
646d3d1dd3eSPeeter Must 		return (0);
647d3d1dd3eSPeeter Must 	default:
648d3d1dd3eSPeeter Must 		return (ENOTTY);
649d3d1dd3eSPeeter Must 	}
650d3d1dd3eSPeeter Must 
651d3d1dd3eSPeeter Must 	/*
652d3d1dd3eSPeeter Must 	 * Clear ioctl data buffer in case it's bigger than
653d3d1dd3eSPeeter Must 	 * bitmap size
654d3d1dd3eSPeeter Must 	 */
655d3d1dd3eSPeeter Must 	bzero(data, len);
656d3d1dd3eSPeeter Must 
657d3d1dd3eSPeeter Must 	limit = bitstr_size(limit);
658d3d1dd3eSPeeter Must 	len = MIN(limit, len);
659d3d1dd3eSPeeter Must 	memcpy(data, bitmap, len);
660d3d1dd3eSPeeter Must 	return (0);
661d3d1dd3eSPeeter Must }
662d3d1dd3eSPeeter Must 
663d3d1dd3eSPeeter Must void
evdev_revoke_client(struct evdev_client * client)664d3d1dd3eSPeeter Must evdev_revoke_client(struct evdev_client *client)
665d3d1dd3eSPeeter Must {
666d3d1dd3eSPeeter Must 
667d3d1dd3eSPeeter Must 	EVDEV_LOCK_ASSERT(client->ec_evdev);
668d3d1dd3eSPeeter Must 
669d3d1dd3eSPeeter Must 	client->ec_revoked = true;
670d3d1dd3eSPeeter Must }
671d3d1dd3eSPeeter Must 
672d3d1dd3eSPeeter Must void
evdev_notify_event(struct evdev_client * client)673d3d1dd3eSPeeter Must evdev_notify_event(struct evdev_client *client)
674d3d1dd3eSPeeter Must {
675d3d1dd3eSPeeter Must 
676d3d1dd3eSPeeter Must 	EVDEV_CLIENT_LOCKQ_ASSERT(client);
677d3d1dd3eSPeeter Must 
678d3d1dd3eSPeeter Must 	if (client->ec_blocked) {
679d3d1dd3eSPeeter Must 		client->ec_blocked = false;
680d3d1dd3eSPeeter Must 		wakeup(client);
681d3d1dd3eSPeeter Must 	}
682d3d1dd3eSPeeter Must 	if (client->ec_selected) {
683d3d1dd3eSPeeter Must 		client->ec_selected = false;
684d3d1dd3eSPeeter Must 		wakeup(&client->kqinfo);
685d3d1dd3eSPeeter Must 	}
686d3d1dd3eSPeeter Must 
687d3d1dd3eSPeeter Must 	KNOTE(&client->kqinfo.ki_note, 0);
688d3d1dd3eSPeeter Must 
689d3d1dd3eSPeeter Must 	if (client->ec_async && client->ec_sigio != NULL)
690d3d1dd3eSPeeter Must 		pgsigio(client->ec_sigio, SIGIO, 0);
691d3d1dd3eSPeeter Must }
692d3d1dd3eSPeeter Must 
693d3d1dd3eSPeeter Must int
evdev_cdev_create(struct evdev_dev * evdev)694d3d1dd3eSPeeter Must evdev_cdev_create(struct evdev_dev *evdev)
695d3d1dd3eSPeeter Must {
696d3d1dd3eSPeeter Must 	cdev_t dev;
697d3d1dd3eSPeeter Must 	int ret, unit;
698d3d1dd3eSPeeter Must 
699d3d1dd3eSPeeter Must 	/*
700d3d1dd3eSPeeter Must 	 * Iterate over devices input/eventX until we find a non-existing
701d3d1dd3eSPeeter Must 	 * one and record its number in unit.
702d3d1dd3eSPeeter Must 	 */
703d3d1dd3eSPeeter Must 	unit = 0;
704d3d1dd3eSPeeter Must 	while (devfs_find_device_by_name("input/event%d", unit) != NULL) {
705d3d1dd3eSPeeter Must 	    unit++;
706d3d1dd3eSPeeter Must 	}
707d3d1dd3eSPeeter Must 
708d3d1dd3eSPeeter Must 	/*
709d3d1dd3eSPeeter Must 	 * Put unit as minor. Minor and major will determine st_rdev of
710d3d1dd3eSPeeter Must 	 * eventX. Ensuring that all eventX have different major and minor
711d3d1dd3eSPeeter Must 	 * will make st_rdev unique. This is needed by libinput, which
712d3d1dd3eSPeeter Must 	 * determines eventX from st_rdev.
713d3d1dd3eSPeeter Must 	 */
714111eaeadSPeeter Must 	dev = make_dev(&evdev_cdevsw, unit, UID_ROOT, GID_WHEEL, 0600,
715111eaeadSPeeter Must 	    "input/event%d", unit);
716d3d1dd3eSPeeter Must 
717d3d1dd3eSPeeter Must 	if (dev != NULL) {
718d3d1dd3eSPeeter Must 		dev->si_drv1 = evdev;
719d3d1dd3eSPeeter Must 		evdev->ev_cdev = dev;
720d3d1dd3eSPeeter Must 		evdev->ev_unit = unit;
721d3d1dd3eSPeeter Must 		ret = 0;
722d3d1dd3eSPeeter Must 	} else {
723d3d1dd3eSPeeter Must 		ret = ENODEV;
724d3d1dd3eSPeeter Must 		goto err;
725d3d1dd3eSPeeter Must 	}
726d3d1dd3eSPeeter Must 
727d3d1dd3eSPeeter Must 	reference_dev(evdev->ev_cdev);
728d3d1dd3eSPeeter Must 
729d3d1dd3eSPeeter Must err:
730d3d1dd3eSPeeter Must 	return (ret);
731d3d1dd3eSPeeter Must }
732d3d1dd3eSPeeter Must 
733d3d1dd3eSPeeter Must int
evdev_cdev_destroy(struct evdev_dev * evdev)734d3d1dd3eSPeeter Must evdev_cdev_destroy(struct evdev_dev *evdev)
735d3d1dd3eSPeeter Must {
736d3d1dd3eSPeeter Must 
737d3d1dd3eSPeeter Must 	if (evdev->ev_cdev) {
738d3d1dd3eSPeeter Must 		dev_ops_remove_minor(&evdev_cdevsw, evdev->ev_unit);
739d3d1dd3eSPeeter Must 	}
740d3d1dd3eSPeeter Must 
741d3d1dd3eSPeeter Must 	return (0);
742d3d1dd3eSPeeter Must }
743d3d1dd3eSPeeter Must 
744d3d1dd3eSPeeter Must static void
evdev_client_gettime(struct evdev_client * client,struct timeval * tv)745d3d1dd3eSPeeter Must evdev_client_gettime(struct evdev_client *client, struct timeval *tv)
746d3d1dd3eSPeeter Must {
747d3d1dd3eSPeeter Must 
748d3d1dd3eSPeeter Must 	switch (client->ec_clock_id) {
749d3d1dd3eSPeeter Must 	case EV_CLOCK_BOOTTIME:
750d3d1dd3eSPeeter Must 		/*
751d3d1dd3eSPeeter Must 		 * XXX: FreeBSD does not support true POSIX monotonic clock.
752d3d1dd3eSPeeter Must 		 *      So aliase EV_CLOCK_BOOTTIME to EV_CLOCK_MONOTONIC.
753d3d1dd3eSPeeter Must 		 */
754d3d1dd3eSPeeter Must 	case EV_CLOCK_MONOTONIC:
755d3d1dd3eSPeeter Must 		microuptime(tv);
756d3d1dd3eSPeeter Must 		break;
757d3d1dd3eSPeeter Must 
758d3d1dd3eSPeeter Must 	case EV_CLOCK_REALTIME:
759d3d1dd3eSPeeter Must 	default:
760d3d1dd3eSPeeter Must 		microtime(tv);
761d3d1dd3eSPeeter Must 		break;
762d3d1dd3eSPeeter Must 	}
763d3d1dd3eSPeeter Must }
764d3d1dd3eSPeeter Must 
765d3d1dd3eSPeeter Must void
evdev_client_push(struct evdev_client * client,uint16_t type,uint16_t code,int32_t value)766d3d1dd3eSPeeter Must evdev_client_push(struct evdev_client *client, uint16_t type, uint16_t code,
767d3d1dd3eSPeeter Must     int32_t value)
768d3d1dd3eSPeeter Must {
769d3d1dd3eSPeeter Must 	struct timeval time;
770d3d1dd3eSPeeter Must 	size_t count, head, tail, ready;
771d3d1dd3eSPeeter Must 
772d3d1dd3eSPeeter Must 	EVDEV_CLIENT_LOCKQ_ASSERT(client);
773d3d1dd3eSPeeter Must 	head = client->ec_buffer_head;
774d3d1dd3eSPeeter Must 	tail = client->ec_buffer_tail;
775d3d1dd3eSPeeter Must 	ready = client->ec_buffer_ready;
776d3d1dd3eSPeeter Must 	count = client->ec_buffer_size;
777d3d1dd3eSPeeter Must 
778d3d1dd3eSPeeter Must 	/* If queue is full drop its content and place SYN_DROPPED event */
779d3d1dd3eSPeeter Must 	if ((tail + 1) % count == head) {
780d3d1dd3eSPeeter Must 		debugf(client, "client %p: buffer overflow", client);
781d3d1dd3eSPeeter Must 
782d3d1dd3eSPeeter Must 		head = (tail + count - 1) % count;
783d3d1dd3eSPeeter Must 		client->ec_buffer[head] = (struct input_event) {
784d3d1dd3eSPeeter Must 			.type = EV_SYN,
785d3d1dd3eSPeeter Must 			.code = SYN_DROPPED,
786d3d1dd3eSPeeter Must 			.value = 0
787d3d1dd3eSPeeter Must 		};
788d3d1dd3eSPeeter Must 		/*
789d3d1dd3eSPeeter Must 		 * XXX: Here is a small race window from now till the end of
790d3d1dd3eSPeeter Must 		 *      report. The queue is empty but client has been already
791d3d1dd3eSPeeter Must 		 *      notified of data readyness. Can be fixed in two ways:
792d3d1dd3eSPeeter Must 		 * 1. Implement bulk insert so queue lock would not be dropped
793d3d1dd3eSPeeter Must 		 *    till the SYN_REPORT event.
794d3d1dd3eSPeeter Must 		 * 2. Insert SYN_REPORT just now and skip remaining events
795d3d1dd3eSPeeter Must 		 */
796d3d1dd3eSPeeter Must 		client->ec_buffer_head = head;
797d3d1dd3eSPeeter Must 		client->ec_buffer_ready = head;
798d3d1dd3eSPeeter Must 	}
799d3d1dd3eSPeeter Must 
800d3d1dd3eSPeeter Must 	client->ec_buffer[tail].type = type;
801d3d1dd3eSPeeter Must 	client->ec_buffer[tail].code = code;
802d3d1dd3eSPeeter Must 	client->ec_buffer[tail].value = value;
803d3d1dd3eSPeeter Must 	client->ec_buffer_tail = (tail + 1) % count;
804d3d1dd3eSPeeter Must 
805d3d1dd3eSPeeter Must 	/* Allow users to read events only after report has been completed */
806d3d1dd3eSPeeter Must 	if (type == EV_SYN && code == SYN_REPORT) {
807d3d1dd3eSPeeter Must 		evdev_client_gettime(client, &time);
808d3d1dd3eSPeeter Must 		for (; ready != client->ec_buffer_tail;
809d3d1dd3eSPeeter Must 		    ready = (ready + 1) % count)
810d3d1dd3eSPeeter Must 			client->ec_buffer[ready].time = time;
811d3d1dd3eSPeeter Must 		client->ec_buffer_ready = client->ec_buffer_tail;
812d3d1dd3eSPeeter Must 	}
813d3d1dd3eSPeeter Must }
814d3d1dd3eSPeeter Must 
815d3d1dd3eSPeeter Must void
evdev_client_dumpqueue(struct evdev_client * client)816d3d1dd3eSPeeter Must evdev_client_dumpqueue(struct evdev_client *client)
817d3d1dd3eSPeeter Must {
818d3d1dd3eSPeeter Must 	struct input_event *event;
819d3d1dd3eSPeeter Must 	size_t i, head, tail, ready, size;
820d3d1dd3eSPeeter Must 
821d3d1dd3eSPeeter Must 	head = client->ec_buffer_head;
822d3d1dd3eSPeeter Must 	tail = client->ec_buffer_tail;
823d3d1dd3eSPeeter Must 	ready = client->ec_buffer_ready;
824d3d1dd3eSPeeter Must 	size = client->ec_buffer_size;
825d3d1dd3eSPeeter Must 
826d3d1dd3eSPeeter Must 	kprintf("evdev client: %p\n", client);
827d3d1dd3eSPeeter Must 	kprintf("event queue: head=%zu ready=%zu tail=%zu size=%zu\n",
828d3d1dd3eSPeeter Must 	    head, ready, tail, size);
829d3d1dd3eSPeeter Must 
830d3d1dd3eSPeeter Must 	kprintf("queue contents:\n");
831d3d1dd3eSPeeter Must 
832d3d1dd3eSPeeter Must 	for (i = 0; i < size; i++) {
833d3d1dd3eSPeeter Must 		event = &client->ec_buffer[i];
834d3d1dd3eSPeeter Must 		kprintf("%zu: ", i);
835d3d1dd3eSPeeter Must 
836d3d1dd3eSPeeter Must 		if (i < head || i > tail)
837d3d1dd3eSPeeter Must 			kprintf("unused\n");
838d3d1dd3eSPeeter Must 		else
839d3d1dd3eSPeeter Must 			kprintf("type=%d code=%d value=%d ", event->type,
840d3d1dd3eSPeeter Must 			    event->code, event->value);
841d3d1dd3eSPeeter Must 
842d3d1dd3eSPeeter Must 		if (i == head)
843d3d1dd3eSPeeter Must 			kprintf("<- head\n");
844d3d1dd3eSPeeter Must 		else if (i == tail)
845d3d1dd3eSPeeter Must 			kprintf("<- tail\n");
846d3d1dd3eSPeeter Must 		else if (i == ready)
847d3d1dd3eSPeeter Must 			kprintf("<- ready\n");
848d3d1dd3eSPeeter Must 		else
849d3d1dd3eSPeeter Must 			kprintf("\n");
850d3d1dd3eSPeeter Must 	}
851d3d1dd3eSPeeter Must }
852d3d1dd3eSPeeter Must 
853d3d1dd3eSPeeter Must static void
evdev_client_filter_queue(struct evdev_client * client,uint16_t type)854d3d1dd3eSPeeter Must evdev_client_filter_queue(struct evdev_client *client, uint16_t type)
855d3d1dd3eSPeeter Must {
856d3d1dd3eSPeeter Must 	struct input_event *event;
857d3d1dd3eSPeeter Must 	size_t head, tail, count, i;
858d3d1dd3eSPeeter Must 	bool last_was_syn = false;
859d3d1dd3eSPeeter Must 
860d3d1dd3eSPeeter Must 	EVDEV_CLIENT_LOCKQ(client);
861d3d1dd3eSPeeter Must 
862d3d1dd3eSPeeter Must 	i = head = client->ec_buffer_head;
863d3d1dd3eSPeeter Must 	tail = client->ec_buffer_tail;
864d3d1dd3eSPeeter Must 	count = client->ec_buffer_size;
865d3d1dd3eSPeeter Must 	client->ec_buffer_ready = client->ec_buffer_tail;
866d3d1dd3eSPeeter Must 
867d3d1dd3eSPeeter Must 	while (i != client->ec_buffer_tail) {
868d3d1dd3eSPeeter Must 		event = &client->ec_buffer[i];
869d3d1dd3eSPeeter Must 		i = (i + 1) % count;
870d3d1dd3eSPeeter Must 
871d3d1dd3eSPeeter Must 		/* Skip event of given type */
872d3d1dd3eSPeeter Must 		if (event->type == type)
873d3d1dd3eSPeeter Must 			continue;
874d3d1dd3eSPeeter Must 
875d3d1dd3eSPeeter Must 		/* Remove empty SYN_REPORT events */
876d3d1dd3eSPeeter Must 		if (event->type == EV_SYN && event->code == SYN_REPORT) {
877d3d1dd3eSPeeter Must 			if (last_was_syn)
878d3d1dd3eSPeeter Must 				continue;
879d3d1dd3eSPeeter Must 			else
880d3d1dd3eSPeeter Must 				client->ec_buffer_ready = (tail + 1) % count;
881d3d1dd3eSPeeter Must 		}
882d3d1dd3eSPeeter Must 
883d3d1dd3eSPeeter Must 		/* Rewrite entry */
884d3d1dd3eSPeeter Must 		memcpy(&client->ec_buffer[tail], event,
885d3d1dd3eSPeeter Must 		    sizeof(struct input_event));
886d3d1dd3eSPeeter Must 
887d3d1dd3eSPeeter Must 		last_was_syn = (event->type == EV_SYN &&
888d3d1dd3eSPeeter Must 		    event->code == SYN_REPORT);
889d3d1dd3eSPeeter Must 
890d3d1dd3eSPeeter Must 		tail = (tail + 1) % count;
891d3d1dd3eSPeeter Must 	}
892d3d1dd3eSPeeter Must 
893d3d1dd3eSPeeter Must 	client->ec_buffer_head = i;
894d3d1dd3eSPeeter Must 	client->ec_buffer_tail = tail;
895d3d1dd3eSPeeter Must 
896d3d1dd3eSPeeter Must 	EVDEV_CLIENT_UNLOCKQ(client);
897d3d1dd3eSPeeter Must }
898