]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/dev/evdev/uinput.c
kqueue: save space by using only one func pointer for assertions
[FreeBSD/FreeBSD.git] / sys / dev / evdev / uinput.c
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                 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_support_abs(state->ucs_evdev, uabs->code,
529                     uabs->absinfo.value, uabs->absinfo.minimum,
530                     uabs->absinfo.maximum, uabs->absinfo.fuzz,
531                     uabs->absinfo.flat, uabs->absinfo.resolution);
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);