1305706Sgonzo/*-
2305706Sgonzo * Copyright (c) 2014 Jakub Wojciech Klama <jceel@FreeBSD.org>
3324768Swulf * Copyright (c) 2015-2016 Vladimir Kondratyev <wulf@FreeBSD.org>
4305706Sgonzo * All rights reserved.
5305706Sgonzo *
6305706Sgonzo * Redistribution and use in source and binary forms, with or without
7305706Sgonzo * modification, are permitted provided that the following conditions
8305706Sgonzo * are met:
9305706Sgonzo * 1. Redistributions of source code must retain the above copyright
10305706Sgonzo *    notice, this list of conditions and the following disclaimer.
11305706Sgonzo * 2. Redistributions in binary form must reproduce the above copyright
12305706Sgonzo *    notice, this list of conditions and the following disclaimer in the
13305706Sgonzo *    documentation and/or other materials provided with the distribution.
14305706Sgonzo *
15305706Sgonzo * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16305706Sgonzo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17305706Sgonzo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18305706Sgonzo * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19305706Sgonzo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20305706Sgonzo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21305706Sgonzo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22305706Sgonzo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23305706Sgonzo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24305706Sgonzo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25305706Sgonzo * SUCH DAMAGE.
26305706Sgonzo *
27305706Sgonzo * $FreeBSD: stable/11/sys/dev/evdev/cdev.c 359907 2020-04-13 22:21:01Z wulf $
28305706Sgonzo */
29305706Sgonzo
30305706Sgonzo#include "opt_evdev.h"
31305706Sgonzo
32324768Swulf#include <sys/param.h>
33305706Sgonzo#include <sys/bitstring.h>
34305706Sgonzo#include <sys/conf.h>
35305706Sgonzo#include <sys/filio.h>
36305706Sgonzo#include <sys/fcntl.h>
37324768Swulf#include <sys/kernel.h>
38324768Swulf#include <sys/malloc.h>
39324768Swulf#include <sys/poll.h>
40324768Swulf#include <sys/proc.h>
41305706Sgonzo#include <sys/selinfo.h>
42324768Swulf#include <sys/systm.h>
43305706Sgonzo#include <sys/time.h>
44324768Swulf#include <sys/uio.h>
45305706Sgonzo
46305706Sgonzo#include <dev/evdev/evdev.h>
47305706Sgonzo#include <dev/evdev/evdev_private.h>
48324768Swulf#include <dev/evdev/input.h>
49305706Sgonzo
50359907Swulf#ifdef COMPAT_FREEBSD32
51359907Swulf#include <sys/mount.h>
52359907Swulf#include <sys/sysent.h>
53359907Swulf#include <compat/freebsd32/freebsd32.h>
54359907Swulfstruct input_event32 {
55359907Swulf	struct timeval32	time;
56359907Swulf	uint16_t		type;
57359907Swulf	uint16_t		code;
58359907Swulf	int32_t			value;
59359907Swulf};
60359907Swulf#endif
61359907Swulf
62305706Sgonzo#ifdef EVDEV_DEBUG
63307760Sgonzo#define	debugf(client, fmt, args...)	printf("evdev cdev: "fmt"\n", ##args)
64305706Sgonzo#else
65305706Sgonzo#define	debugf(client, fmt, args...)
66305706Sgonzo#endif
67305706Sgonzo
68305706Sgonzo#define	DEF_RING_REPORTS	8
69305706Sgonzo
70305706Sgonzostatic d_open_t		evdev_open;
71305706Sgonzostatic d_read_t		evdev_read;
72305706Sgonzostatic d_write_t	evdev_write;
73305706Sgonzostatic d_ioctl_t	evdev_ioctl;
74305706Sgonzostatic d_poll_t		evdev_poll;
75305706Sgonzostatic d_kqfilter_t	evdev_kqfilter;
76305706Sgonzo
77305706Sgonzostatic int evdev_kqread(struct knote *kn, long hint);
78305706Sgonzostatic void evdev_kqdetach(struct knote *kn);
79305706Sgonzostatic void evdev_dtor(void *);
80305706Sgonzostatic int evdev_ioctl_eviocgbit(struct evdev_dev *, int, int, caddr_t);
81305706Sgonzostatic void evdev_client_filter_queue(struct evdev_client *, uint16_t);
82305706Sgonzo
83305706Sgonzostatic struct cdevsw evdev_cdevsw = {
84305706Sgonzo	.d_version = D_VERSION,
85305706Sgonzo	.d_open = evdev_open,
86305706Sgonzo	.d_read = evdev_read,
87305706Sgonzo	.d_write = evdev_write,
88305706Sgonzo	.d_ioctl = evdev_ioctl,
89305706Sgonzo	.d_poll = evdev_poll,
90305706Sgonzo	.d_kqfilter = evdev_kqfilter,
91305706Sgonzo	.d_name = "evdev",
92305706Sgonzo};
93305706Sgonzo
94305706Sgonzostatic struct filterops evdev_cdev_filterops = {
95305706Sgonzo	.f_isfd = 1,
96305706Sgonzo	.f_attach = NULL,
97305706Sgonzo	.f_detach = evdev_kqdetach,
98305706Sgonzo	.f_event = evdev_kqread,
99305706Sgonzo};
100305706Sgonzo
101305706Sgonzostatic int
102305706Sgonzoevdev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
103305706Sgonzo{
104305706Sgonzo	struct evdev_dev *evdev = dev->si_drv1;
105305706Sgonzo	struct evdev_client *client;
106305706Sgonzo	size_t buffer_size;
107305706Sgonzo	int ret;
108305706Sgonzo
109305706Sgonzo	if (evdev == NULL)
110305706Sgonzo		return (ENODEV);
111305706Sgonzo
112305706Sgonzo	/* Initialize client structure */
113305706Sgonzo	buffer_size = evdev->ev_report_size * DEF_RING_REPORTS;
114305706Sgonzo	client = malloc(offsetof(struct evdev_client, ec_buffer) +
115305706Sgonzo	    sizeof(struct input_event) * buffer_size,
116305706Sgonzo	    M_EVDEV, M_WAITOK | M_ZERO);
117305706Sgonzo
118305706Sgonzo	/* Initialize ring buffer */
119305706Sgonzo	client->ec_buffer_size = buffer_size;
120305706Sgonzo	client->ec_buffer_head = 0;
121305706Sgonzo	client->ec_buffer_tail = 0;
122305706Sgonzo	client->ec_buffer_ready = 0;
123305706Sgonzo
124305706Sgonzo	client->ec_evdev = evdev;
125305706Sgonzo	mtx_init(&client->ec_buffer_mtx, "evclient", "evdev", MTX_DEF);
126305706Sgonzo	knlist_init_mtx(&client->ec_selp.si_note, &client->ec_buffer_mtx);
127305706Sgonzo
128305706Sgonzo	/* Avoid race with evdev_unregister */
129305706Sgonzo	EVDEV_LOCK(evdev);
130305706Sgonzo	if (dev->si_drv1 == NULL)
131305706Sgonzo		ret = ENODEV;
132305706Sgonzo	else
133305706Sgonzo		ret = evdev_register_client(evdev, client);
134305706Sgonzo
135305706Sgonzo	if (ret != 0)
136305706Sgonzo		evdev_revoke_client(client);
137305706Sgonzo	/*
138305706Sgonzo	 * Unlock evdev here because non-sleepable lock held
139305706Sgonzo	 * while calling devfs_set_cdevpriv upsets WITNESS
140305706Sgonzo	 */
141305706Sgonzo	EVDEV_UNLOCK(evdev);
142305706Sgonzo
143305706Sgonzo	if (!ret)
144305706Sgonzo		ret = devfs_set_cdevpriv(client, evdev_dtor);
145305706Sgonzo
146305706Sgonzo	if (ret != 0) {
147305706Sgonzo		debugf(client, "cannot register evdev client");
148305706Sgonzo		evdev_dtor(client);
149305706Sgonzo	}
150305706Sgonzo
151305706Sgonzo	return (ret);
152305706Sgonzo}
153305706Sgonzo
154305706Sgonzostatic void
155305706Sgonzoevdev_dtor(void *data)
156305706Sgonzo{
157305706Sgonzo	struct evdev_client *client = (struct evdev_client *)data;
158305706Sgonzo
159305706Sgonzo	EVDEV_LOCK(client->ec_evdev);
160305706Sgonzo	if (!client->ec_revoked)
161305706Sgonzo		evdev_dispose_client(client->ec_evdev, client);
162305706Sgonzo	EVDEV_UNLOCK(client->ec_evdev);
163305706Sgonzo
164305706Sgonzo	knlist_clear(&client->ec_selp.si_note, 0);
165305706Sgonzo	seldrain(&client->ec_selp);
166305706Sgonzo	knlist_destroy(&client->ec_selp.si_note);
167305706Sgonzo	funsetown(&client->ec_sigio);
168305706Sgonzo	mtx_destroy(&client->ec_buffer_mtx);
169305706Sgonzo	free(client, M_EVDEV);
170305706Sgonzo}
171305706Sgonzo
172305706Sgonzostatic int
173305706Sgonzoevdev_read(struct cdev *dev, struct uio *uio, int ioflag)
174305706Sgonzo{
175305706Sgonzo	struct evdev_client *client;
176359907Swulf	union {
177359907Swulf		struct input_event t;
178359907Swulf#ifdef COMPAT_FREEBSD32
179359907Swulf		struct input_event32 t32;
180359907Swulf#endif
181359907Swulf	} event;
182359907Swulf	struct input_event *head;
183359907Swulf	size_t evsize;
184305706Sgonzo	int ret = 0;
185305706Sgonzo	int remaining;
186305706Sgonzo
187305706Sgonzo	ret = devfs_get_cdevpriv((void **)&client);
188305706Sgonzo	if (ret != 0)
189305706Sgonzo		return (ret);
190305706Sgonzo
191305706Sgonzo	debugf(client, "read %zd bytes by thread %d", uio->uio_resid,
192305706Sgonzo	    uio->uio_td->td_tid);
193305706Sgonzo
194305706Sgonzo	if (client->ec_revoked)
195305706Sgonzo		return (ENODEV);
196305706Sgonzo
197359907Swulf#ifdef COMPAT_FREEBSD32
198359907Swulf	if (SV_CURPROC_FLAG(SV_ILP32))
199359907Swulf		evsize = sizeof(struct input_event32);
200359907Swulf	else
201359907Swulf#endif
202359907Swulf		evsize = sizeof(struct input_event);
203359907Swulf
204305706Sgonzo	/* Zero-sized reads are allowed for error checking */
205359907Swulf	if (uio->uio_resid != 0 && uio->uio_resid < evsize)
206305706Sgonzo		return (EINVAL);
207305706Sgonzo
208359907Swulf	remaining = uio->uio_resid / evsize;
209305706Sgonzo
210305706Sgonzo	EVDEV_CLIENT_LOCKQ(client);
211305706Sgonzo
212305706Sgonzo	if (EVDEV_CLIENT_EMPTYQ(client)) {
213305706Sgonzo		if (ioflag & O_NONBLOCK)
214305706Sgonzo			ret = EWOULDBLOCK;
215305706Sgonzo		else {
216305706Sgonzo			if (remaining != 0) {
217305706Sgonzo				client->ec_blocked = true;
218305706Sgonzo				ret = mtx_sleep(client, &client->ec_buffer_mtx,
219305706Sgonzo				    PCATCH, "evread", 0);
220359907Swulf				if (ret == 0 && client->ec_revoked)
221359907Swulf					ret = ENODEV;
222305706Sgonzo			}
223305706Sgonzo		}
224305706Sgonzo	}
225305706Sgonzo
226305706Sgonzo	while (ret == 0 && !EVDEV_CLIENT_EMPTYQ(client) && remaining > 0) {
227359907Swulf		head = client->ec_buffer + client->ec_buffer_head;
228359907Swulf#ifdef COMPAT_FREEBSD32
229359907Swulf		if (SV_CURPROC_FLAG(SV_ILP32)) {
230359907Swulf			bzero(&event.t32, sizeof(struct input_event32));
231359907Swulf			TV_CP(*head, event.t32, time);
232359907Swulf			CP(*head, event.t32, type);
233359907Swulf			CP(*head, event.t32, code);
234359907Swulf			CP(*head, event.t32, value);
235359907Swulf		} else
236359907Swulf#endif
237359907Swulf			bcopy(head, &event.t, evsize);
238359907Swulf
239305706Sgonzo		client->ec_buffer_head =
240305706Sgonzo		    (client->ec_buffer_head + 1) % client->ec_buffer_size;
241305706Sgonzo		remaining--;
242305706Sgonzo
243305706Sgonzo		EVDEV_CLIENT_UNLOCKQ(client);
244359907Swulf		ret = uiomove(&event, evsize, uio);
245305706Sgonzo		EVDEV_CLIENT_LOCKQ(client);
246305706Sgonzo	}
247305706Sgonzo
248305706Sgonzo	EVDEV_CLIENT_UNLOCKQ(client);
249305706Sgonzo
250305706Sgonzo	return (ret);
251305706Sgonzo}
252305706Sgonzo
253305706Sgonzostatic int
254305706Sgonzoevdev_write(struct cdev *dev, struct uio *uio, int ioflag)
255305706Sgonzo{
256305706Sgonzo	struct evdev_dev *evdev = dev->si_drv1;
257305706Sgonzo	struct evdev_client *client;
258359907Swulf	union {
259359907Swulf		struct input_event t;
260359907Swulf#ifdef COMPAT_FREEBSD32
261359907Swulf		struct input_event32 t32;
262359907Swulf#endif
263359907Swulf	} event;
264359907Swulf	size_t evsize;
265305706Sgonzo	int ret = 0;
266305706Sgonzo
267305706Sgonzo	ret = devfs_get_cdevpriv((void **)&client);
268305706Sgonzo	if (ret != 0)
269305706Sgonzo		return (ret);
270305706Sgonzo
271305706Sgonzo	debugf(client, "write %zd bytes by thread %d", uio->uio_resid,
272305706Sgonzo	    uio->uio_td->td_tid);
273305706Sgonzo
274305706Sgonzo	if (client->ec_revoked || evdev == NULL)
275305706Sgonzo		return (ENODEV);
276305706Sgonzo
277359907Swulf#ifdef COMPAT_FREEBSD32
278359907Swulf	if (SV_CURPROC_FLAG(SV_ILP32))
279359907Swulf		evsize = sizeof(struct input_event32);
280359907Swulf	else
281359907Swulf#endif
282359907Swulf		evsize = sizeof(struct input_event);
283359907Swulf
284359907Swulf	if (uio->uio_resid % evsize != 0) {
285305706Sgonzo		debugf(client, "write size not multiple of input_event size");
286305706Sgonzo		return (EINVAL);
287305706Sgonzo	}
288305706Sgonzo
289305706Sgonzo	while (uio->uio_resid > 0 && ret == 0) {
290359907Swulf		ret = uiomove(&event, evsize, uio);
291359907Swulf		if (ret == 0) {
292359907Swulf#ifdef COMPAT_FREEBSD32
293359907Swulf			if (SV_CURPROC_FLAG(SV_ILP32))
294359907Swulf				ret = evdev_inject_event(evdev, event.t32.type,
295359907Swulf				    event.t32.code, event.t32.value);
296359907Swulf			else
297359907Swulf#endif
298359907Swulf				ret = evdev_inject_event(evdev, event.t.type,
299359907Swulf				    event.t.code, event.t.value);
300359907Swulf		}
301305706Sgonzo	}
302305706Sgonzo
303305706Sgonzo	return (ret);
304305706Sgonzo}
305305706Sgonzo
306305706Sgonzostatic int
307305706Sgonzoevdev_poll(struct cdev *dev, int events, struct thread *td)
308305706Sgonzo{
309305706Sgonzo	struct evdev_client *client;
310305706Sgonzo	int ret;
311305706Sgonzo	int revents = 0;
312305706Sgonzo
313305706Sgonzo	ret = devfs_get_cdevpriv((void **)&client);
314305706Sgonzo	if (ret != 0)
315305706Sgonzo		return (POLLNVAL);
316305706Sgonzo
317305706Sgonzo	debugf(client, "poll by thread %d", td->td_tid);
318305706Sgonzo
319305706Sgonzo	if (client->ec_revoked)
320305706Sgonzo		return (POLLHUP);
321305706Sgonzo
322305706Sgonzo	if (events & (POLLIN | POLLRDNORM)) {
323305706Sgonzo		EVDEV_CLIENT_LOCKQ(client);
324305706Sgonzo		if (!EVDEV_CLIENT_EMPTYQ(client))
325305706Sgonzo			revents = events & (POLLIN | POLLRDNORM);
326305706Sgonzo		else {
327305706Sgonzo			client->ec_selected = true;
328305706Sgonzo			selrecord(td, &client->ec_selp);
329305706Sgonzo		}
330305706Sgonzo		EVDEV_CLIENT_UNLOCKQ(client);
331305706Sgonzo	}
332305706Sgonzo
333305706Sgonzo	return (revents);
334305706Sgonzo}
335305706Sgonzo
336305706Sgonzostatic int
337305706Sgonzoevdev_kqfilter(struct cdev *dev, struct knote *kn)
338305706Sgonzo{
339305706Sgonzo	struct evdev_client *client;
340305706Sgonzo	int ret;
341305706Sgonzo
342305706Sgonzo	ret = devfs_get_cdevpriv((void **)&client);
343305706Sgonzo	if (ret != 0)
344305706Sgonzo		return (ret);
345305706Sgonzo
346305706Sgonzo	if (client->ec_revoked)
347305706Sgonzo		return (ENODEV);
348305706Sgonzo
349305706Sgonzo	switch(kn->kn_filter) {
350305706Sgonzo	case EVFILT_READ:
351305706Sgonzo		kn->kn_fop = &evdev_cdev_filterops;
352305706Sgonzo		break;
353305706Sgonzo	default:
354305706Sgonzo		return(EINVAL);
355305706Sgonzo	}
356305706Sgonzo	kn->kn_hook = (caddr_t)client;
357305706Sgonzo
358305706Sgonzo	knlist_add(&client->ec_selp.si_note, kn, 0);
359305706Sgonzo	return (0);
360305706Sgonzo}
361305706Sgonzo
362305706Sgonzostatic int
363305706Sgonzoevdev_kqread(struct knote *kn, long hint)
364305706Sgonzo{
365305706Sgonzo	struct evdev_client *client;
366305706Sgonzo	int ret;
367305706Sgonzo
368305706Sgonzo	client = (struct evdev_client *)kn->kn_hook;
369305706Sgonzo
370305706Sgonzo	EVDEV_CLIENT_LOCKQ_ASSERT(client);
371305706Sgonzo
372305706Sgonzo	if (client->ec_revoked) {
373305706Sgonzo		kn->kn_flags |= EV_EOF;
374305706Sgonzo		ret = 1;
375305706Sgonzo	} else {
376305706Sgonzo		kn->kn_data = EVDEV_CLIENT_SIZEQ(client) *
377305706Sgonzo		    sizeof(struct input_event);
378305706Sgonzo		ret = !EVDEV_CLIENT_EMPTYQ(client);
379305706Sgonzo	}
380305706Sgonzo	return (ret);
381305706Sgonzo}
382305706Sgonzo
383305706Sgonzostatic void
384305706Sgonzoevdev_kqdetach(struct knote *kn)
385305706Sgonzo{
386305706Sgonzo	struct evdev_client *client;
387305706Sgonzo
388305706Sgonzo	client = (struct evdev_client *)kn->kn_hook;
389305706Sgonzo	knlist_remove(&client->ec_selp.si_note, kn, 0);
390305706Sgonzo}
391305706Sgonzo
392305706Sgonzostatic int
393305706Sgonzoevdev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
394305706Sgonzo    struct thread *td)
395305706Sgonzo{
396305706Sgonzo	struct evdev_dev *evdev = dev->si_drv1;
397305706Sgonzo	struct evdev_client *client;
398305706Sgonzo	struct input_keymap_entry *ke;
399305706Sgonzo	int ret, len, limit, type_num;
400305706Sgonzo	uint32_t code;
401305706Sgonzo	size_t nvalues;
402305706Sgonzo
403305706Sgonzo	ret = devfs_get_cdevpriv((void **)&client);
404305706Sgonzo	if (ret != 0)
405305706Sgonzo		return (ret);
406305706Sgonzo
407305706Sgonzo	if (client->ec_revoked || evdev == NULL)
408305706Sgonzo		return (ENODEV);
409305706Sgonzo
410305706Sgonzo	/* file I/O ioctl handling */
411305706Sgonzo	switch (cmd) {
412305706Sgonzo	case FIOSETOWN:
413305706Sgonzo		return (fsetown(*(int *)data, &client->ec_sigio));
414305706Sgonzo
415305706Sgonzo	case FIOGETOWN:
416305706Sgonzo		*(int *)data = fgetown(&client->ec_sigio);
417305706Sgonzo		return (0);
418305706Sgonzo
419305706Sgonzo	case FIONBIO:
420305706Sgonzo		return (0);
421305706Sgonzo
422305706Sgonzo	case FIOASYNC:
423305706Sgonzo		if (*(int *)data)
424305706Sgonzo			client->ec_async = true;
425305706Sgonzo		else
426305706Sgonzo			client->ec_async = false;
427305706Sgonzo
428305706Sgonzo		return (0);
429305706Sgonzo
430305706Sgonzo	case FIONREAD:
431305706Sgonzo		EVDEV_CLIENT_LOCKQ(client);
432305706Sgonzo		*(int *)data =
433305706Sgonzo		    EVDEV_CLIENT_SIZEQ(client) * sizeof(struct input_event);
434305706Sgonzo		EVDEV_CLIENT_UNLOCKQ(client);
435305706Sgonzo		return (0);
436305706Sgonzo	}
437305706Sgonzo
438305706Sgonzo	len = IOCPARM_LEN(cmd);
439305706Sgonzo	debugf(client, "ioctl called: cmd=0x%08lx, data=%p", cmd, data);
440305706Sgonzo
441305706Sgonzo	/* evdev fixed-length ioctls handling */
442305706Sgonzo	switch (cmd) {
443305706Sgonzo	case EVIOCGVERSION:
444305706Sgonzo		*(int *)data = EV_VERSION;
445305706Sgonzo		return (0);
446305706Sgonzo
447305706Sgonzo	case EVIOCGID:
448305706Sgonzo		debugf(client, "EVIOCGID: bus=%d vendor=0x%04x product=0x%04x",
449305706Sgonzo		    evdev->ev_id.bustype, evdev->ev_id.vendor,
450305706Sgonzo		    evdev->ev_id.product);
451305706Sgonzo		memcpy(data, &evdev->ev_id, sizeof(struct input_id));
452305706Sgonzo		return (0);
453305706Sgonzo
454305706Sgonzo	case EVIOCGREP:
455305706Sgonzo		if (!evdev_event_supported(evdev, EV_REP))
456305706Sgonzo			return (ENOTSUP);
457305706Sgonzo
458305706Sgonzo		memcpy(data, evdev->ev_rep, sizeof(evdev->ev_rep));
459305706Sgonzo		return (0);
460305706Sgonzo
461305706Sgonzo	case EVIOCSREP:
462305706Sgonzo		if (!evdev_event_supported(evdev, EV_REP))
463305706Sgonzo			return (ENOTSUP);
464305706Sgonzo
465305706Sgonzo		evdev_inject_event(evdev, EV_REP, REP_DELAY, ((int *)data)[0]);
466305706Sgonzo		evdev_inject_event(evdev, EV_REP, REP_PERIOD,
467305706Sgonzo		    ((int *)data)[1]);
468305706Sgonzo		return (0);
469305706Sgonzo
470305706Sgonzo	case EVIOCGKEYCODE:
471305706Sgonzo		/* Fake unsupported ioctl */
472305706Sgonzo		return (0);
473305706Sgonzo
474305706Sgonzo	case EVIOCGKEYCODE_V2:
475305706Sgonzo		if (evdev->ev_methods == NULL ||
476305706Sgonzo		    evdev->ev_methods->ev_get_keycode == NULL)
477305706Sgonzo			return (ENOTSUP);
478305706Sgonzo
479305706Sgonzo		ke = (struct input_keymap_entry *)data;
480305706Sgonzo		evdev->ev_methods->ev_get_keycode(evdev, evdev->ev_softc, ke);
481305706Sgonzo		return (0);
482305706Sgonzo
483305706Sgonzo	case EVIOCSKEYCODE:
484305706Sgonzo		/* Fake unsupported ioctl */
485305706Sgonzo		return (0);
486305706Sgonzo
487305706Sgonzo	case EVIOCSKEYCODE_V2:
488305706Sgonzo		if (evdev->ev_methods == NULL ||
489305706Sgonzo		    evdev->ev_methods->ev_set_keycode == NULL)
490305706Sgonzo			return (ENOTSUP);
491305706Sgonzo
492305706Sgonzo		ke = (struct input_keymap_entry *)data;
493305706Sgonzo		evdev->ev_methods->ev_set_keycode(evdev, evdev->ev_softc, ke);
494305706Sgonzo		return (0);
495305706Sgonzo
496305706Sgonzo	case EVIOCGABS(0) ... EVIOCGABS(ABS_MAX):
497305706Sgonzo		if (evdev->ev_absinfo == NULL)
498305706Sgonzo			return (EINVAL);
499305706Sgonzo
500305706Sgonzo		memcpy(data, &evdev->ev_absinfo[cmd - EVIOCGABS(0)],
501305706Sgonzo		    sizeof(struct input_absinfo));
502305706Sgonzo		return (0);
503305706Sgonzo
504305706Sgonzo	case EVIOCSABS(0) ... EVIOCSABS(ABS_MAX):
505305706Sgonzo		if (evdev->ev_absinfo == NULL)
506305706Sgonzo			return (EINVAL);
507305706Sgonzo
508305706Sgonzo		code = cmd - EVIOCSABS(0);
509305706Sgonzo		/* mt-slot number can not be changed */
510305706Sgonzo		if (code == ABS_MT_SLOT)
511305706Sgonzo			return (EINVAL);
512305706Sgonzo
513305706Sgonzo		EVDEV_LOCK(evdev);
514305706Sgonzo		evdev_set_absinfo(evdev, code, (struct input_absinfo *)data);
515305706Sgonzo		EVDEV_UNLOCK(evdev);
516305706Sgonzo		return (0);
517305706Sgonzo
518305706Sgonzo	case EVIOCSFF:
519305706Sgonzo	case EVIOCRMFF:
520305706Sgonzo	case EVIOCGEFFECTS:
521305706Sgonzo		/* Fake unsupported ioctls */
522305706Sgonzo		return (0);
523305706Sgonzo
524305706Sgonzo	case EVIOCGRAB:
525305706Sgonzo		EVDEV_LOCK(evdev);
526305706Sgonzo		if (*(int *)data)
527305706Sgonzo			ret = evdev_grab_client(evdev, client);
528305706Sgonzo		else
529305706Sgonzo			ret = evdev_release_client(evdev, client);
530305706Sgonzo		EVDEV_UNLOCK(evdev);
531305706Sgonzo		return (ret);
532305706Sgonzo
533305706Sgonzo	case EVIOCREVOKE:
534305706Sgonzo		if (*(int *)data != 0)
535305706Sgonzo			return (EINVAL);
536305706Sgonzo
537305706Sgonzo		EVDEV_LOCK(evdev);
538305706Sgonzo		if (dev->si_drv1 != NULL && !client->ec_revoked) {
539305706Sgonzo			evdev_dispose_client(evdev, client);
540305706Sgonzo			evdev_revoke_client(client);
541305706Sgonzo		}
542305706Sgonzo		EVDEV_UNLOCK(evdev);
543305706Sgonzo		return (0);
544305706Sgonzo
545305706Sgonzo	case EVIOCSCLOCKID:
546305706Sgonzo		switch (*(int *)data) {
547305706Sgonzo		case CLOCK_REALTIME:
548305706Sgonzo			client->ec_clock_id = EV_CLOCK_REALTIME;
549305706Sgonzo			return (0);
550305706Sgonzo		case CLOCK_MONOTONIC:
551305706Sgonzo			client->ec_clock_id = EV_CLOCK_MONOTONIC;
552305706Sgonzo			return (0);
553305706Sgonzo		default:
554305706Sgonzo			return (EINVAL);
555305706Sgonzo		}
556305706Sgonzo	}
557305706Sgonzo
558305706Sgonzo	/* evdev variable-length ioctls handling */
559305706Sgonzo	switch (IOCBASECMD(cmd)) {
560305706Sgonzo	case EVIOCGNAME(0):
561305706Sgonzo		strlcpy(data, evdev->ev_name, len);
562305706Sgonzo		return (0);
563305706Sgonzo
564305706Sgonzo	case EVIOCGPHYS(0):
565305706Sgonzo		if (evdev->ev_shortname[0] == 0)
566305706Sgonzo			return (ENOENT);
567305706Sgonzo
568305706Sgonzo		strlcpy(data, evdev->ev_shortname, len);
569305706Sgonzo		return (0);
570305706Sgonzo
571305706Sgonzo	case EVIOCGUNIQ(0):
572305706Sgonzo		if (evdev->ev_serial[0] == 0)
573305706Sgonzo			return (ENOENT);
574305706Sgonzo
575305706Sgonzo		strlcpy(data, evdev->ev_serial, len);
576305706Sgonzo		return (0);
577305706Sgonzo
578305706Sgonzo	case EVIOCGPROP(0):
579305706Sgonzo		limit = MIN(len, bitstr_size(INPUT_PROP_CNT));
580305706Sgonzo		memcpy(data, evdev->ev_prop_flags, limit);
581305706Sgonzo		return (0);
582305706Sgonzo
583305706Sgonzo	case EVIOCGMTSLOTS(0):
584305706Sgonzo		if (evdev->ev_mt == NULL)
585305706Sgonzo			return (EINVAL);
586305706Sgonzo		if (len < sizeof(uint32_t))
587305706Sgonzo			return (EINVAL);
588305706Sgonzo		code = *(uint32_t *)data;
589305706Sgonzo		if (!ABS_IS_MT(code))
590305706Sgonzo			return (EINVAL);
591305706Sgonzo
592305706Sgonzo		nvalues =
593305706Sgonzo		    MIN(len / sizeof(int32_t) - 1, MAXIMAL_MT_SLOT(evdev) + 1);
594305706Sgonzo		for (int i = 0; i < nvalues; i++)
595305706Sgonzo			((int32_t *)data)[i + 1] =
596305706Sgonzo			    evdev_get_mt_value(evdev, i, code);
597305706Sgonzo		return (0);
598305706Sgonzo
599305706Sgonzo	case EVIOCGKEY(0):
600305706Sgonzo		limit = MIN(len, bitstr_size(KEY_CNT));
601305706Sgonzo		EVDEV_LOCK(evdev);
602305706Sgonzo		evdev_client_filter_queue(client, EV_KEY);
603305706Sgonzo		memcpy(data, evdev->ev_key_states, limit);
604305706Sgonzo		EVDEV_UNLOCK(evdev);
605305706Sgonzo		return (0);
606305706Sgonzo
607305706Sgonzo	case EVIOCGLED(0):
608305706Sgonzo		limit = MIN(len, bitstr_size(LED_CNT));
609305706Sgonzo		EVDEV_LOCK(evdev);
610305706Sgonzo		evdev_client_filter_queue(client, EV_LED);
611305706Sgonzo		memcpy(data, evdev->ev_led_states, limit);
612305706Sgonzo		EVDEV_UNLOCK(evdev);
613305706Sgonzo		return (0);
614305706Sgonzo
615305706Sgonzo	case EVIOCGSND(0):
616305706Sgonzo		limit = MIN(len, bitstr_size(SND_CNT));
617305706Sgonzo		EVDEV_LOCK(evdev);
618305706Sgonzo		evdev_client_filter_queue(client, EV_SND);
619305706Sgonzo		memcpy(data, evdev->ev_snd_states, limit);
620305706Sgonzo		EVDEV_UNLOCK(evdev);
621305706Sgonzo		return (0);
622305706Sgonzo
623305706Sgonzo	case EVIOCGSW(0):
624305706Sgonzo		limit = MIN(len, bitstr_size(SW_CNT));
625305706Sgonzo		EVDEV_LOCK(evdev);
626305706Sgonzo		evdev_client_filter_queue(client, EV_SW);
627305706Sgonzo		memcpy(data, evdev->ev_sw_states, limit);
628305706Sgonzo		EVDEV_UNLOCK(evdev);
629305706Sgonzo		return (0);
630305706Sgonzo
631305706Sgonzo	case EVIOCGBIT(0, 0) ... EVIOCGBIT(EV_MAX, 0):
632305706Sgonzo		type_num = IOCBASECMD(cmd) - EVIOCGBIT(0, 0);
633305706Sgonzo		debugf(client, "EVIOCGBIT(%d): data=%p, len=%d", type_num,
634305706Sgonzo		    data, len);
635305706Sgonzo		return (evdev_ioctl_eviocgbit(evdev, type_num, len, data));
636305706Sgonzo	}
637305706Sgonzo
638305706Sgonzo	return (EINVAL);
639305706Sgonzo}
640305706Sgonzo
641305706Sgonzostatic int
642305706Sgonzoevdev_ioctl_eviocgbit(struct evdev_dev *evdev, int type, int len, caddr_t data)
643305706Sgonzo{
644305706Sgonzo	unsigned long *bitmap;
645305706Sgonzo	int limit;
646305706Sgonzo
647305706Sgonzo	switch (type) {
648305706Sgonzo	case 0:
649305706Sgonzo		bitmap = evdev->ev_type_flags;
650305706Sgonzo		limit = EV_CNT;
651305706Sgonzo		break;
652305706Sgonzo	case EV_KEY:
653305706Sgonzo		bitmap = evdev->ev_key_flags;
654305706Sgonzo		limit = KEY_CNT;
655305706Sgonzo		break;
656305706Sgonzo	case EV_REL:
657305706Sgonzo		bitmap = evdev->ev_rel_flags;
658305706Sgonzo		limit = REL_CNT;
659305706Sgonzo		break;
660305706Sgonzo	case EV_ABS:
661305706Sgonzo		bitmap = evdev->ev_abs_flags;
662305706Sgonzo		limit = ABS_CNT;
663305706Sgonzo		break;
664305706Sgonzo	case EV_MSC:
665305706Sgonzo		bitmap = evdev->ev_msc_flags;
666305706Sgonzo		limit = MSC_CNT;
667305706Sgonzo		break;
668305706Sgonzo	case EV_LED:
669305706Sgonzo		bitmap = evdev->ev_led_flags;
670305706Sgonzo		limit = LED_CNT;
671305706Sgonzo		break;
672305706Sgonzo	case EV_SND:
673305706Sgonzo		bitmap = evdev->ev_snd_flags;
674305706Sgonzo		limit = SND_CNT;
675305706Sgonzo		break;
676305706Sgonzo	case EV_SW:
677305706Sgonzo		bitmap = evdev->ev_sw_flags;
678305706Sgonzo		limit = SW_CNT;
679305706Sgonzo		break;
680305706Sgonzo	case EV_FF:
681305706Sgonzo		/*
682305706Sgonzo		 * We don't support EV_FF now, so let's
683305706Sgonzo		 * just fake it returning only zeros.
684305706Sgonzo		 */
685305706Sgonzo		bzero(data, len);
686305706Sgonzo		return (0);
687305706Sgonzo	default:
688305706Sgonzo		return (ENOTTY);
689305706Sgonzo	}
690305706Sgonzo
691305706Sgonzo	/*
692305706Sgonzo	 * Clear ioctl data buffer in case it's bigger than
693305706Sgonzo	 * bitmap size
694305706Sgonzo	 */
695305706Sgonzo	bzero(data, len);
696305706Sgonzo
697305706Sgonzo	limit = bitstr_size(limit);
698305706Sgonzo	len = MIN(limit, len);
699305706Sgonzo	memcpy(data, bitmap, len);
700305706Sgonzo	return (0);
701305706Sgonzo}
702305706Sgonzo
703305706Sgonzovoid
704305706Sgonzoevdev_revoke_client(struct evdev_client *client)
705305706Sgonzo{
706305706Sgonzo
707305706Sgonzo	EVDEV_LOCK_ASSERT(client->ec_evdev);
708305706Sgonzo
709305706Sgonzo	client->ec_revoked = true;
710305706Sgonzo}
711305706Sgonzo
712305706Sgonzovoid
713305706Sgonzoevdev_notify_event(struct evdev_client *client)
714305706Sgonzo{
715305706Sgonzo
716305706Sgonzo	EVDEV_CLIENT_LOCKQ_ASSERT(client);
717305706Sgonzo
718305706Sgonzo	if (client->ec_blocked) {
719305706Sgonzo		client->ec_blocked = false;
720305706Sgonzo		wakeup(client);
721305706Sgonzo	}
722305706Sgonzo	if (client->ec_selected) {
723305706Sgonzo		client->ec_selected = false;
724305706Sgonzo		selwakeup(&client->ec_selp);
725305706Sgonzo	}
726305706Sgonzo	KNOTE_LOCKED(&client->ec_selp.si_note, 0);
727305706Sgonzo
728305706Sgonzo	if (client->ec_async && client->ec_sigio != NULL)
729305706Sgonzo		pgsigio(&client->ec_sigio, SIGIO, 0);
730305706Sgonzo}
731305706Sgonzo
732305706Sgonzoint
733305706Sgonzoevdev_cdev_create(struct evdev_dev *evdev)
734305706Sgonzo{
735305706Sgonzo	struct make_dev_args mda;
736305706Sgonzo	int ret, unit = 0;
737305706Sgonzo
738305706Sgonzo	make_dev_args_init(&mda);
739305706Sgonzo	mda.mda_flags = MAKEDEV_WAITOK | MAKEDEV_CHECKNAME;
740305706Sgonzo	mda.mda_devsw = &evdev_cdevsw;
741305706Sgonzo	mda.mda_uid = UID_ROOT;
742305706Sgonzo	mda.mda_gid = GID_WHEEL;
743305706Sgonzo	mda.mda_mode = 0600;
744305706Sgonzo	mda.mda_si_drv1 = evdev;
745305706Sgonzo
746305706Sgonzo	/* Try to coexist with cuse-backed input/event devices */
747305706Sgonzo	while ((ret = make_dev_s(&mda, &evdev->ev_cdev, "input/event%d", unit))
748305706Sgonzo	    == EEXIST)
749305706Sgonzo		unit++;
750305706Sgonzo
751305706Sgonzo	if (ret == 0)
752305706Sgonzo		evdev->ev_unit = unit;
753305706Sgonzo
754305706Sgonzo	return (ret);
755305706Sgonzo}
756305706Sgonzo
757305706Sgonzoint
758305706Sgonzoevdev_cdev_destroy(struct evdev_dev *evdev)
759305706Sgonzo{
760305706Sgonzo
761305706Sgonzo	destroy_dev(evdev->ev_cdev);
762305706Sgonzo	return (0);
763305706Sgonzo}
764305706Sgonzo
765305706Sgonzostatic void
766305706Sgonzoevdev_client_gettime(struct evdev_client *client, struct timeval *tv)
767305706Sgonzo{
768305706Sgonzo
769305706Sgonzo	switch (client->ec_clock_id) {
770305706Sgonzo	case EV_CLOCK_BOOTTIME:
771305706Sgonzo		/*
772305706Sgonzo		 * XXX: FreeBSD does not support true POSIX monotonic clock.
773305706Sgonzo		 *      So aliase EV_CLOCK_BOOTTIME to EV_CLOCK_MONOTONIC.
774305706Sgonzo		 */
775305706Sgonzo	case EV_CLOCK_MONOTONIC:
776305706Sgonzo		microuptime(tv);
777305706Sgonzo		break;
778305706Sgonzo
779305706Sgonzo	case EV_CLOCK_REALTIME:
780305706Sgonzo	default:
781305706Sgonzo		microtime(tv);
782305706Sgonzo		break;
783305706Sgonzo	}
784305706Sgonzo}
785305706Sgonzo
786305706Sgonzovoid
787305706Sgonzoevdev_client_push(struct evdev_client *client, uint16_t type, uint16_t code,
788305706Sgonzo    int32_t value)
789305706Sgonzo{
790305706Sgonzo	struct timeval time;
791305706Sgonzo	size_t count, head, tail, ready;
792305706Sgonzo
793305706Sgonzo	EVDEV_CLIENT_LOCKQ_ASSERT(client);
794305706Sgonzo	head = client->ec_buffer_head;
795305706Sgonzo	tail = client->ec_buffer_tail;
796305706Sgonzo	ready = client->ec_buffer_ready;
797305706Sgonzo	count = client->ec_buffer_size;
798305706Sgonzo
799305706Sgonzo	/* If queue is full drop its content and place SYN_DROPPED event */
800305706Sgonzo	if ((tail + 1) % count == head) {
801305706Sgonzo		debugf(client, "client %p: buffer overflow", client);
802305706Sgonzo
803305706Sgonzo		head = (tail + count - 1) % count;
804305706Sgonzo		client->ec_buffer[head] = (struct input_event) {
805305706Sgonzo			.type = EV_SYN,
806305706Sgonzo			.code = SYN_DROPPED,
807305706Sgonzo			.value = 0
808305706Sgonzo		};
809305706Sgonzo		/*
810305706Sgonzo		 * XXX: Here is a small race window from now till the end of
811305706Sgonzo		 *      report. The queue is empty but client has been already
812305706Sgonzo		 *      notified of data readyness. Can be fixed in two ways:
813305706Sgonzo		 * 1. Implement bulk insert so queue lock would not be dropped
814305706Sgonzo		 *    till the SYN_REPORT event.
815305706Sgonzo		 * 2. Insert SYN_REPORT just now and skip remaining events
816305706Sgonzo		 */
817305706Sgonzo		client->ec_buffer_head = head;
818305706Sgonzo		client->ec_buffer_ready = head;
819305706Sgonzo	}
820305706Sgonzo
821305706Sgonzo	client->ec_buffer[tail].type = type;
822305706Sgonzo	client->ec_buffer[tail].code = code;
823305706Sgonzo	client->ec_buffer[tail].value = value;
824305706Sgonzo	client->ec_buffer_tail = (tail + 1) % count;
825305706Sgonzo
826305706Sgonzo	/* Allow users to read events only after report has been completed */
827305706Sgonzo	if (type == EV_SYN && code == SYN_REPORT) {
828305706Sgonzo		evdev_client_gettime(client, &time);
829305706Sgonzo		for (; ready != client->ec_buffer_tail;
830305706Sgonzo		    ready = (ready + 1) % count)
831305706Sgonzo			client->ec_buffer[ready].time = time;
832305706Sgonzo		client->ec_buffer_ready = client->ec_buffer_tail;
833305706Sgonzo	}
834305706Sgonzo}
835305706Sgonzo
836305706Sgonzovoid
837305706Sgonzoevdev_client_dumpqueue(struct evdev_client *client)
838305706Sgonzo{
839305706Sgonzo	struct input_event *event;
840305706Sgonzo	size_t i, head, tail, ready, size;
841305706Sgonzo
842305706Sgonzo	head = client->ec_buffer_head;
843305706Sgonzo	tail = client->ec_buffer_tail;
844305706Sgonzo	ready = client->ec_buffer_ready;
845305706Sgonzo	size = client->ec_buffer_size;
846305706Sgonzo
847305706Sgonzo	printf("evdev client: %p\n", client);
848305706Sgonzo	printf("event queue: head=%zu ready=%zu tail=%zu size=%zu\n",
849305706Sgonzo	    head, ready, tail, size);
850305706Sgonzo
851305706Sgonzo	printf("queue contents:\n");
852305706Sgonzo
853305706Sgonzo	for (i = 0; i < size; i++) {
854305706Sgonzo		event = &client->ec_buffer[i];
855305706Sgonzo		printf("%zu: ", i);
856305706Sgonzo
857305706Sgonzo		if (i < head || i > tail)
858305706Sgonzo			printf("unused\n");
859305706Sgonzo		else
860305706Sgonzo			printf("type=%d code=%d value=%d ", event->type,
861305706Sgonzo			    event->code, event->value);
862305706Sgonzo
863305706Sgonzo		if (i == head)
864305706Sgonzo			printf("<- head\n");
865305706Sgonzo		else if (i == tail)
866305706Sgonzo			printf("<- tail\n");
867305706Sgonzo		else if (i == ready)
868305706Sgonzo			printf("<- ready\n");
869305706Sgonzo		else
870305706Sgonzo			printf("\n");
871305706Sgonzo	}
872305706Sgonzo}
873305706Sgonzo
874305706Sgonzostatic void
875305706Sgonzoevdev_client_filter_queue(struct evdev_client *client, uint16_t type)
876305706Sgonzo{
877305706Sgonzo	struct input_event *event;
878305706Sgonzo	size_t head, tail, count, i;
879305706Sgonzo	bool last_was_syn = false;
880305706Sgonzo
881305706Sgonzo	EVDEV_CLIENT_LOCKQ(client);
882305706Sgonzo
883305706Sgonzo	i = head = client->ec_buffer_head;
884305706Sgonzo	tail = client->ec_buffer_tail;
885305706Sgonzo	count = client->ec_buffer_size;
886305706Sgonzo	client->ec_buffer_ready = client->ec_buffer_tail;
887305706Sgonzo
888305706Sgonzo	while (i != client->ec_buffer_tail) {
889305706Sgonzo		event = &client->ec_buffer[i];
890305706Sgonzo		i = (i + 1) % count;
891305706Sgonzo
892305706Sgonzo		/* Skip event of given type */
893305706Sgonzo		if (event->type == type)
894305706Sgonzo			continue;
895305706Sgonzo
896305706Sgonzo		/* Remove empty SYN_REPORT events */
897305706Sgonzo		if (event->type == EV_SYN && event->code == SYN_REPORT) {
898305706Sgonzo			if (last_was_syn)
899305706Sgonzo				continue;
900305706Sgonzo			else
901305706Sgonzo				client->ec_buffer_ready = (tail + 1) % count;
902305706Sgonzo		}
903305706Sgonzo
904305706Sgonzo		/* Rewrite entry */
905305706Sgonzo		memcpy(&client->ec_buffer[tail], event,
906305706Sgonzo		    sizeof(struct input_event));
907305706Sgonzo
908305706Sgonzo		last_was_syn = (event->type == EV_SYN &&
909305706Sgonzo		    event->code == SYN_REPORT);
910305706Sgonzo
911305706Sgonzo		tail = (tail + 1) % count;
912305706Sgonzo	}
913305706Sgonzo
914305706Sgonzo	client->ec_buffer_head = i;
915305706Sgonzo	client->ec_buffer_tail = tail;
916305706Sgonzo
917305706Sgonzo	EVDEV_CLIENT_UNLOCKQ(client);
918305706Sgonzo}
919