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