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