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