xref: /freebsd/sys/dev/evdev/uinput.c (revision 8ddb146abcdf061be9f2c0db7e391697dafad85c)
1 /*-
2  * Copyright (c) 2014 Jakub Wojciech Klama <jceel@FreeBSD.org>
3  * Copyright (c) 2015-2016 Vladimir Kondratyev <wulf@FreeBSD.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  *
27  * $FreeBSD$
28  */
29 
30 #include "opt_evdev.h"
31 
32 #include <sys/param.h>
33 #include <sys/conf.h>
34 #include <sys/fcntl.h>
35 #include <sys/kernel.h>
36 #include <sys/lock.h>
37 #include <sys/malloc.h>
38 #include <sys/module.h>
39 #include <sys/poll.h>
40 #include <sys/proc.h>
41 #include <sys/selinfo.h>
42 #include <sys/systm.h>
43 #include <sys/sx.h>
44 #include <sys/uio.h>
45 
46 #include <dev/evdev/evdev.h>
47 #include <dev/evdev/evdev_private.h>
48 #include <dev/evdev/input.h>
49 #include <dev/evdev/uinput.h>
50 
51 #ifdef UINPUT_DEBUG
52 #define	debugf(state, fmt, args...)	printf("uinput: " fmt "\n", ##args)
53 #else
54 #define	debugf(state, fmt, args...)
55 #endif
56 
57 #define	UINPUT_BUFFER_SIZE	16
58 
59 #define	UINPUT_LOCK(state)		sx_xlock(&(state)->ucs_lock)
60 #define	UINPUT_UNLOCK(state)		sx_unlock(&(state)->ucs_lock)
61 #define	UINPUT_LOCK_ASSERT(state)	sx_assert(&(state)->ucs_lock, SA_LOCKED)
62 #define UINPUT_EMPTYQ(state) \
63     ((state)->ucs_buffer_head == (state)->ucs_buffer_tail)
64 
65 enum uinput_state
66 {
67 	UINPUT_NEW = 0,
68 	UINPUT_CONFIGURED,
69 	UINPUT_RUNNING
70 };
71 
72 static evdev_event_t	uinput_ev_event;
73 
74 static d_open_t		uinput_open;
75 static d_read_t		uinput_read;
76 static d_write_t	uinput_write;
77 static d_ioctl_t	uinput_ioctl;
78 static d_poll_t		uinput_poll;
79 static d_kqfilter_t	uinput_kqfilter;
80 static void uinput_dtor(void *);
81 
82 static int uinput_kqread(struct knote *kn, long hint);
83 static void uinput_kqdetach(struct knote *kn);
84 
85 static struct cdevsw uinput_cdevsw = {
86 	.d_version = D_VERSION,
87 	.d_open = uinput_open,
88 	.d_read = uinput_read,
89 	.d_write = uinput_write,
90 	.d_ioctl = uinput_ioctl,
91 	.d_poll = uinput_poll,
92 	.d_kqfilter = uinput_kqfilter,
93 	.d_name = "uinput",
94 };
95 
96 static struct cdev *uinput_cdev;
97 
98 static struct evdev_methods uinput_ev_methods = {
99 	.ev_open = NULL,
100 	.ev_close = NULL,
101 	.ev_event = uinput_ev_event,
102 };
103 
104 static struct filterops uinput_filterops = {
105 	.f_isfd = 1,
106 	.f_attach = NULL,
107 	.f_detach = uinput_kqdetach,
108 	.f_event = uinput_kqread,
109 };
110 
111 struct uinput_cdev_state
112 {
113 	enum uinput_state	ucs_state;
114 	struct evdev_dev *	ucs_evdev;
115 	struct sx		ucs_lock;
116 	size_t			ucs_buffer_head;
117 	size_t			ucs_buffer_tail;
118 	struct selinfo		ucs_selp;
119 	bool			ucs_blocked;
120 	bool			ucs_selected;
121 	struct input_event      ucs_buffer[UINPUT_BUFFER_SIZE];
122 };
123 
124 static void uinput_enqueue_event(struct uinput_cdev_state *, uint16_t,
125     uint16_t, int32_t);
126 static int uinput_setup_provider(struct uinput_cdev_state *,
127     struct uinput_user_dev *);
128 static int uinput_cdev_create(void);
129 static void uinput_notify(struct uinput_cdev_state *);
130 
131 static void
132 uinput_knllock(void *arg)
133 {
134 	struct sx *sx = arg;
135 
136 	sx_xlock(sx);
137 }
138 
139 static void
140 uinput_knlunlock(void *arg)
141 {
142 	struct sx *sx = arg;
143 
144 	sx_unlock(sx);
145 }
146 
147 static void
148 uinput_knl_assert_lock(void *arg, int what)
149 {
150 
151 	if (what == LA_LOCKED)
152 		sx_assert((struct sx*)arg, SA_XLOCKED);
153 	else
154 		sx_assert((struct sx*)arg, SA_UNLOCKED);
155 }
156 
157 static void
158 uinput_ev_event(struct evdev_dev *evdev, uint16_t type, uint16_t code,
159     int32_t value)
160 {
161 	struct uinput_cdev_state *state = evdev_get_softc(evdev);
162 
163 	if (type == EV_LED)
164 		evdev_push_event(evdev, type, code, value);
165 
166 	UINPUT_LOCK(state);
167 	if (state->ucs_state == UINPUT_RUNNING) {
168 		uinput_enqueue_event(state, type, code, value);
169 		uinput_notify(state);
170 	}
171 	UINPUT_UNLOCK(state);
172 }
173 
174 static void
175 uinput_enqueue_event(struct uinput_cdev_state *state, uint16_t type,
176     uint16_t code, int32_t value)
177 {
178 	size_t head, tail;
179 
180 	UINPUT_LOCK_ASSERT(state);
181 
182 	head = state->ucs_buffer_head;
183 	tail = (state->ucs_buffer_tail + 1) % UINPUT_BUFFER_SIZE;
184 
185 	microtime(&state->ucs_buffer[tail].time);
186 	state->ucs_buffer[tail].type = type;
187 	state->ucs_buffer[tail].code = code;
188 	state->ucs_buffer[tail].value = value;
189 	state->ucs_buffer_tail = tail;
190 
191 	/* If queue is full remove oldest event */
192 	if (tail == head) {
193 		debugf(state, "state %p: buffer overflow", state);
194 
195 		head = (head + 1) % UINPUT_BUFFER_SIZE;
196 		state->ucs_buffer_head = head;
197 	}
198 }
199 
200 static int
201 uinput_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
202 {
203 	struct uinput_cdev_state *state;
204 
205 	state = malloc(sizeof(struct uinput_cdev_state), M_EVDEV,
206 	    M_WAITOK | M_ZERO);
207 	state->ucs_evdev = evdev_alloc();
208 
209 	sx_init(&state->ucs_lock, "uinput");
210 	knlist_init(&state->ucs_selp.si_note, &state->ucs_lock, uinput_knllock,
211 	    uinput_knlunlock, uinput_knl_assert_lock);
212 
213 	devfs_set_cdevpriv(state, uinput_dtor);
214 	return (0);
215 }
216 
217 static void
218 uinput_dtor(void *data)
219 {
220 	struct uinput_cdev_state *state = (struct uinput_cdev_state *)data;
221 
222 	evdev_free(state->ucs_evdev);
223 
224 	knlist_clear(&state->ucs_selp.si_note, 0);
225 	seldrain(&state->ucs_selp);
226 	knlist_destroy(&state->ucs_selp.si_note);
227 	sx_destroy(&state->ucs_lock);
228 	free(data, M_EVDEV);
229 }
230 
231 static int
232 uinput_read(struct cdev *dev, struct uio *uio, int ioflag)
233 {
234 	struct uinput_cdev_state *state;
235 	struct input_event *event;
236 	int remaining, ret;
237 
238 	ret = devfs_get_cdevpriv((void **)&state);
239 	if (ret != 0)
240 		return (ret);
241 
242 	debugf(state, "read %zd bytes by thread %d", uio->uio_resid,
243 	    uio->uio_td->td_tid);
244 
245 	/* Zero-sized reads are allowed for error checking */
246 	if (uio->uio_resid != 0 && uio->uio_resid < sizeof(struct input_event))
247 		return (EINVAL);
248 
249 	remaining = uio->uio_resid / sizeof(struct input_event);
250 
251 	UINPUT_LOCK(state);
252 
253 	if (state->ucs_state != UINPUT_RUNNING)
254 		ret = EINVAL;
255 
256 	if (ret == 0 && UINPUT_EMPTYQ(state)) {
257 		if (ioflag & O_NONBLOCK)
258 			ret = EWOULDBLOCK;
259 		else {
260 			if (remaining != 0) {
261 				state->ucs_blocked = true;
262 				ret = sx_sleep(state, &state->ucs_lock,
263 				    PCATCH, "uiread", 0);
264 			}
265 		}
266 	}
267 
268 	while (ret == 0 && !UINPUT_EMPTYQ(state) && remaining > 0) {
269 		event = &state->ucs_buffer[state->ucs_buffer_head];
270 		state->ucs_buffer_head = (state->ucs_buffer_head + 1) %
271 		    UINPUT_BUFFER_SIZE;
272 		remaining--;
273 		ret = uiomove(event, sizeof(struct input_event), uio);
274 	}
275 
276 	UINPUT_UNLOCK(state);
277 
278 	return (ret);
279 }
280 
281 static int
282 uinput_write(struct cdev *dev, struct uio *uio, int ioflag)
283 {
284 	struct uinput_cdev_state *state;
285 	struct uinput_user_dev userdev;
286 	struct input_event event;
287 	int ret = 0;
288 
289 	ret = devfs_get_cdevpriv((void **)&state);
290 	if (ret != 0)
291 		return (ret);
292 
293 	debugf(state, "write %zd bytes by thread %d", uio->uio_resid,
294 	    uio->uio_td->td_tid);
295 
296 	UINPUT_LOCK(state);
297 
298 	if (state->ucs_state != UINPUT_RUNNING) {
299 		/* Process written struct uinput_user_dev */
300 		if (uio->uio_resid != sizeof(struct uinput_user_dev)) {
301 			debugf(state, "write size not multiple of "
302 			    "struct uinput_user_dev size");
303 			ret = EINVAL;
304 		} else {
305 			ret = uiomove(&userdev, sizeof(struct uinput_user_dev),
306 			    uio);
307 			if (ret == 0)
308 				uinput_setup_provider(state, &userdev);
309 		}
310 	} else {
311 		/* Process written event */
312 		if (uio->uio_resid % sizeof(struct input_event) != 0) {
313 			debugf(state, "write size not multiple of "
314 			    "struct input_event size");
315 			ret = EINVAL;
316 		}
317 
318 		while (ret == 0 && uio->uio_resid > 0) {
319 			uiomove(&event, sizeof(struct input_event), uio);
320 			ret = evdev_push_event(state->ucs_evdev, event.type,
321 			    event.code, event.value);
322 		}
323 	}
324 
325 	UINPUT_UNLOCK(state);
326 
327 	return (ret);
328 }
329 
330 static int
331 uinput_setup_dev(struct uinput_cdev_state *state, struct input_id *id,
332     char *name, uint32_t ff_effects_max)
333 {
334 
335 	if (name[0] == 0)
336 		return (EINVAL);
337 
338 	evdev_set_name(state->ucs_evdev, name);
339 	evdev_set_id(state->ucs_evdev, id->bustype, id->vendor, id->product,
340 	    id->version);
341 	state->ucs_state = UINPUT_CONFIGURED;
342 
343 	return (0);
344 }
345 
346 static int
347 uinput_setup_provider(struct uinput_cdev_state *state,
348     struct uinput_user_dev *udev)
349 {
350 	struct input_absinfo absinfo;
351 	int i, ret;
352 
353 	debugf(state, "setup_provider called, udev=%p", udev);
354 
355 	ret = uinput_setup_dev(state, &udev->id, udev->name,
356 	    udev->ff_effects_max);
357 	if (ret)
358 		return (ret);
359 
360 	bzero(&absinfo, sizeof(struct input_absinfo));
361 	for (i = 0; i < ABS_CNT; i++) {
362 		if (!bit_test(state->ucs_evdev->ev_abs_flags, i))
363 			continue;
364 
365 		absinfo.minimum = udev->absmin[i];
366 		absinfo.maximum = udev->absmax[i];
367 		absinfo.fuzz = udev->absfuzz[i];
368 		absinfo.flat = udev->absflat[i];
369 		evdev_set_absinfo(state->ucs_evdev, i, &absinfo);
370 	}
371 
372 	return (0);
373 }
374 
375 static int
376 uinput_poll(struct cdev *dev, int events, struct thread *td)
377 {
378 	struct uinput_cdev_state *state;
379 	int revents = 0;
380 
381 	if (devfs_get_cdevpriv((void **)&state) != 0)
382 		return (POLLNVAL);
383 
384 	debugf(state, "poll by thread %d", td->td_tid);
385 
386 	/* Always allow write */
387 	if (events & (POLLOUT | POLLWRNORM))
388 		revents |= (events & (POLLOUT | POLLWRNORM));
389 
390 	if (events & (POLLIN | POLLRDNORM)) {
391 		UINPUT_LOCK(state);
392 		if (!UINPUT_EMPTYQ(state))
393 			revents = events & (POLLIN | POLLRDNORM);
394 		else {
395 			state->ucs_selected = true;
396 			selrecord(td, &state->ucs_selp);
397 		}
398 		UINPUT_UNLOCK(state);
399 	}
400 
401 	return (revents);
402 }
403 
404 static int
405 uinput_kqfilter(struct cdev *dev, struct knote *kn)
406 {
407 	struct uinput_cdev_state *state;
408 	int ret;
409 
410 	ret = devfs_get_cdevpriv((void **)&state);
411 	if (ret != 0)
412 		return (ret);
413 
414 	switch(kn->kn_filter) {
415 	case EVFILT_READ:
416 		kn->kn_fop = &uinput_filterops;
417 		break;
418 	default:
419 		return(EINVAL);
420 	}
421 	kn->kn_hook = (caddr_t)state;
422 
423 	knlist_add(&state->ucs_selp.si_note, kn, 0);
424 	return (0);
425 }
426 
427 static int
428 uinput_kqread(struct knote *kn, long hint)
429 {
430 	struct uinput_cdev_state *state;
431 	int ret;
432 
433 	state = (struct uinput_cdev_state *)kn->kn_hook;
434 
435 	UINPUT_LOCK_ASSERT(state);
436 
437 	ret = !UINPUT_EMPTYQ(state);
438 	return (ret);
439 }
440 
441 static void
442 uinput_kqdetach(struct knote *kn)
443 {
444 	struct uinput_cdev_state *state;
445 
446 	state = (struct uinput_cdev_state *)kn->kn_hook;
447 	knlist_remove(&state->ucs_selp.si_note, kn, 0);
448 }
449 
450 static void
451 uinput_notify(struct uinput_cdev_state *state)
452 {
453 
454 	UINPUT_LOCK_ASSERT(state);
455 
456 	if (state->ucs_blocked) {
457 		state->ucs_blocked = false;
458 		wakeup(state);
459 	}
460 	if (state->ucs_selected) {
461 		state->ucs_selected = false;
462 		selwakeup(&state->ucs_selp);
463 	}
464 	KNOTE_LOCKED(&state->ucs_selp.si_note, 0);
465 }
466 
467 static int
468 uinput_ioctl_sub(struct uinput_cdev_state *state, u_long cmd, caddr_t data)
469 {
470 	struct uinput_setup *us;
471 	struct uinput_abs_setup *uabs;
472 	int ret, len, intdata;
473 	char buf[NAMELEN];
474 
475 	UINPUT_LOCK_ASSERT(state);
476 
477 	len = IOCPARM_LEN(cmd);
478 	if ((cmd & IOC_DIRMASK) == IOC_VOID && len == sizeof(int))
479 		intdata = *(int *)data;
480 
481 	switch (IOCBASECMD(cmd)) {
482 	case UI_GET_SYSNAME(0):
483 		if (state->ucs_state != UINPUT_RUNNING)
484 			return (ENOENT);
485 		if (len == 0)
486 			return (EINVAL);
487 		snprintf(data, len, "event%d", state->ucs_evdev->ev_unit);
488 		return (0);
489 	}
490 
491 	switch (cmd) {
492 	case UI_DEV_CREATE:
493 		if (state->ucs_state != UINPUT_CONFIGURED)
494 			return (EINVAL);
495 
496 		evdev_set_methods(state->ucs_evdev, state, &uinput_ev_methods);
497 		evdev_set_flag(state->ucs_evdev, EVDEV_FLAG_SOFTREPEAT);
498 		evdev_set_flag(state->ucs_evdev, EVDEV_FLAG_MT_KEEPID);
499 		ret = evdev_register(state->ucs_evdev);
500 		if (ret == 0)
501 			state->ucs_state = UINPUT_RUNNING;
502 		return (ret);
503 
504 	case UI_DEV_DESTROY:
505 		if (state->ucs_state != UINPUT_RUNNING)
506 			return (0);
507 
508 		evdev_unregister(state->ucs_evdev);
509 		bzero(state->ucs_evdev, sizeof(struct evdev_dev));
510 		state->ucs_state = UINPUT_NEW;
511 		return (0);
512 
513 	case UI_DEV_SETUP:
514 		if (state->ucs_state == UINPUT_RUNNING)
515 			return (EINVAL);
516 
517 		us = (struct uinput_setup *)data;
518 		return (uinput_setup_dev(state, &us->id, us->name,
519 		    us->ff_effects_max));
520 
521 	case UI_ABS_SETUP:
522 		if (state->ucs_state == UINPUT_RUNNING)
523 			return (EINVAL);
524 
525 		uabs = (struct uinput_abs_setup *)data;
526 		if (uabs->code > ABS_MAX)
527 			return (EINVAL);
528 
529 		evdev_set_abs_bit(state->ucs_evdev, uabs->code);
530 		evdev_set_absinfo(state->ucs_evdev, uabs->code,
531 		    &uabs->absinfo);
532 		return (0);
533 
534 	case UI_SET_EVBIT:
535 		if (state->ucs_state == UINPUT_RUNNING ||
536 		    intdata > EV_MAX || intdata < 0)
537 			return (EINVAL);
538 		evdev_support_event(state->ucs_evdev, intdata);
539 		return (0);
540 
541 	case UI_SET_KEYBIT:
542 		if (state->ucs_state == UINPUT_RUNNING ||
543 		    intdata > KEY_MAX || intdata < 0)
544 			return (EINVAL);
545 		evdev_support_key(state->ucs_evdev, intdata);
546 		return (0);
547 
548 	case UI_SET_RELBIT:
549 		if (state->ucs_state == UINPUT_RUNNING ||
550 		    intdata > REL_MAX || intdata < 0)
551 			return (EINVAL);
552 		evdev_support_rel(state->ucs_evdev, intdata);
553 		return (0);
554 
555 	case UI_SET_ABSBIT:
556 		if (state->ucs_state == UINPUT_RUNNING ||
557 		    intdata > ABS_MAX || intdata < 0)
558 			return (EINVAL);
559 		evdev_set_abs_bit(state->ucs_evdev, intdata);
560 		return (0);
561 
562 	case UI_SET_MSCBIT:
563 		if (state->ucs_state == UINPUT_RUNNING ||
564 		    intdata > MSC_MAX || intdata < 0)
565 			return (EINVAL);
566 		evdev_support_msc(state->ucs_evdev, intdata);
567 		return (0);
568 
569 	case UI_SET_LEDBIT:
570 		if (state->ucs_state == UINPUT_RUNNING ||
571 		    intdata > LED_MAX || intdata < 0)
572 			return (EINVAL);
573 		evdev_support_led(state->ucs_evdev, intdata);
574 		return (0);
575 
576 	case UI_SET_SNDBIT:
577 		if (state->ucs_state == UINPUT_RUNNING ||
578 		    intdata > SND_MAX || intdata < 0)
579 			return (EINVAL);
580 		evdev_support_snd(state->ucs_evdev, intdata);
581 		return (0);
582 
583 	case UI_SET_FFBIT:
584 		if (state->ucs_state == UINPUT_RUNNING ||
585 		    intdata > FF_MAX || intdata < 0)
586 			return (EINVAL);
587 		/* Fake unsupported ioctl */
588 		return (0);
589 
590 	case UI_SET_PHYS:
591 		if (state->ucs_state == UINPUT_RUNNING)
592 			return (EINVAL);
593 		ret = copyinstr(*(void **)data, buf, sizeof(buf), NULL);
594 		/* Linux returns EINVAL when string does not fit the buffer */
595 		if (ret == ENAMETOOLONG)
596 			ret = EINVAL;
597 		if (ret != 0)
598 			return (ret);
599 		evdev_set_phys(state->ucs_evdev, buf);
600 		return (0);
601 
602 	case UI_SET_BSDUNIQ:
603 		if (state->ucs_state == UINPUT_RUNNING)
604 			return (EINVAL);
605 		ret = copyinstr(*(void **)data, buf, sizeof(buf), NULL);
606 		if (ret != 0)
607 			return (ret);
608 		evdev_set_serial(state->ucs_evdev, buf);
609 		return (0);
610 
611 	case UI_SET_SWBIT:
612 		if (state->ucs_state == UINPUT_RUNNING ||
613 		    intdata > SW_MAX || intdata < 0)
614 			return (EINVAL);
615 		evdev_support_sw(state->ucs_evdev, intdata);
616 		return (0);
617 
618 	case UI_SET_PROPBIT:
619 		if (state->ucs_state == UINPUT_RUNNING ||
620 		    intdata > INPUT_PROP_MAX || intdata < 0)
621 			return (EINVAL);
622 		evdev_support_prop(state->ucs_evdev, intdata);
623 		return (0);
624 
625 	case UI_BEGIN_FF_UPLOAD:
626 	case UI_END_FF_UPLOAD:
627 	case UI_BEGIN_FF_ERASE:
628 	case UI_END_FF_ERASE:
629 		if (state->ucs_state == UINPUT_RUNNING)
630 			return (EINVAL);
631 		/* Fake unsupported ioctl */
632 		return (0);
633 
634 	case UI_GET_VERSION:
635 		*(unsigned int *)data = UINPUT_VERSION;
636 		return (0);
637 	}
638 
639 	return (EINVAL);
640 }
641 
642 static int
643 uinput_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
644     struct thread *td)
645 {
646 	struct uinput_cdev_state *state;
647 	int ret;
648 
649 	ret = devfs_get_cdevpriv((void **)&state);
650 	if (ret != 0)
651 		return (ret);
652 
653 	debugf(state, "ioctl called: cmd=0x%08lx, data=%p", cmd, data);
654 
655 	UINPUT_LOCK(state);
656 	ret = uinput_ioctl_sub(state, cmd, data);
657 	UINPUT_UNLOCK(state);
658 
659 	return (ret);
660 }
661 
662 static int
663 uinput_cdev_create(void)
664 {
665 	struct make_dev_args mda;
666 	int ret;
667 
668 	make_dev_args_init(&mda);
669 	mda.mda_flags = MAKEDEV_WAITOK | MAKEDEV_CHECKNAME;
670 	mda.mda_devsw = &uinput_cdevsw;
671 	mda.mda_uid = UID_ROOT;
672 	mda.mda_gid = GID_WHEEL;
673 	mda.mda_mode = 0600;
674 
675 	ret = make_dev_s(&mda, &uinput_cdev, "uinput");
676 
677 	return (ret);
678 }
679 
680 static int
681 uinput_cdev_destroy(void)
682 {
683 
684 	destroy_dev(uinput_cdev);
685 
686 	return (0);
687 }
688 
689 static int
690 uinput_modevent(module_t mod __unused, int cmd, void *data)
691 {
692 	int ret = 0;
693 
694 	switch (cmd) {
695 	case MOD_LOAD:
696 		ret = uinput_cdev_create();
697 		break;
698 
699 	case MOD_UNLOAD:
700 		ret = uinput_cdev_destroy();
701 		break;
702 
703 	case MOD_SHUTDOWN:
704 		break;
705 
706 	default:
707 		ret = EINVAL;
708 		break;
709 	}
710 
711 	return (ret);
712 }
713 
714 DEV_MODULE(uinput, uinput_modevent, NULL);
715 MODULE_VERSION(uinput, 1);
716 MODULE_DEPEND(uinput, evdev, 1, 1, 1);
717