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

Cache object: 02f9eea8a8b44f1643220db56d2bffea


[ 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.