The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/evdev/uinput.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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_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
  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
  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
  680 uinput_cdev_destroy(void)
  681 {
  682 
  683         destroy_dev(uinput_cdev);
  684 
  685         return (0);
  686 }
  687 
  688 static int
  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);

Cache object: a66efe3b0e246a8b0e8115d59805e31b


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.