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/cdev.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/bitstring.h>
   34 #include <sys/conf.h>
   35 #include <sys/filio.h>
   36 #include <sys/fcntl.h>
   37 #include <sys/kernel.h>
   38 #include <sys/malloc.h>
   39 #include <sys/poll.h>
   40 #include <sys/proc.h>
   41 #include <sys/selinfo.h>
   42 #include <sys/systm.h>
   43 #include <sys/time.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 
   50 #ifdef COMPAT_FREEBSD32
   51 #include <sys/mount.h>
   52 #include <sys/sysent.h>
   53 #include <compat/freebsd32/freebsd32.h>
   54 struct input_event32 {
   55         struct timeval32        time;
   56         uint16_t                type;
   57         uint16_t                code;
   58         int32_t                 value;
   59 };
   60 #endif
   61 
   62 #ifdef EVDEV_DEBUG
   63 #define debugf(client, fmt, args...)    printf("evdev cdev: "fmt"\n", ##args)
   64 #else
   65 #define debugf(client, fmt, args...)
   66 #endif
   67 
   68 #define DEF_RING_REPORTS        8
   69 
   70 static d_open_t         evdev_open;
   71 static d_read_t         evdev_read;
   72 static d_write_t        evdev_write;
   73 static d_ioctl_t        evdev_ioctl;
   74 static d_poll_t         evdev_poll;
   75 static d_kqfilter_t     evdev_kqfilter;
   76 
   77 static int evdev_kqread(struct knote *kn, long hint);
   78 static void evdev_kqdetach(struct knote *kn);
   79 static void evdev_dtor(void *);
   80 static int evdev_ioctl_eviocgbit(struct evdev_dev *, int, int, caddr_t);
   81 static void evdev_client_filter_queue(struct evdev_client *, uint16_t);
   82 
   83 static struct cdevsw evdev_cdevsw = {
   84         .d_version = D_VERSION,
   85         .d_open = evdev_open,
   86         .d_read = evdev_read,
   87         .d_write = evdev_write,
   88         .d_ioctl = evdev_ioctl,
   89         .d_poll = evdev_poll,
   90         .d_kqfilter = evdev_kqfilter,
   91         .d_name = "evdev",
   92 };
   93 
   94 static struct filterops evdev_cdev_filterops = {
   95         .f_isfd = 1,
   96         .f_attach = NULL,
   97         .f_detach = evdev_kqdetach,
   98         .f_event = evdev_kqread,
   99 };
  100 
  101 static int
  102 evdev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
  103 {
  104         struct evdev_dev *evdev = dev->si_drv1;
  105         struct evdev_client *client;
  106         size_t buffer_size;
  107         int ret;
  108 
  109         if (evdev == NULL)
  110                 return (ENODEV);
  111 
  112         /* Initialize client structure */
  113         buffer_size = evdev->ev_report_size * DEF_RING_REPORTS;
  114         client = malloc(offsetof(struct evdev_client, ec_buffer) +
  115             sizeof(struct input_event) * buffer_size,
  116             M_EVDEV, M_WAITOK | M_ZERO);
  117 
  118         /* Initialize ring buffer */
  119         client->ec_buffer_size = buffer_size;
  120         client->ec_buffer_head = 0;
  121         client->ec_buffer_tail = 0;
  122         client->ec_buffer_ready = 0;
  123 
  124         client->ec_evdev = evdev;
  125         mtx_init(&client->ec_buffer_mtx, "evclient", "evdev", MTX_DEF);
  126         knlist_init_mtx(&client->ec_selp.si_note, &client->ec_buffer_mtx);
  127 
  128         /* Avoid race with evdev_unregister */
  129         EVDEV_LOCK(evdev);
  130         if (dev->si_drv1 == NULL)
  131                 ret = ENODEV;
  132         else
  133                 ret = evdev_register_client(evdev, client);
  134 
  135         if (ret != 0)
  136                 evdev_revoke_client(client);
  137         /*
  138          * Unlock evdev here because non-sleepable lock held 
  139          * while calling devfs_set_cdevpriv upsets WITNESS
  140          */
  141         EVDEV_UNLOCK(evdev);
  142 
  143         if (!ret)
  144                 ret = devfs_set_cdevpriv(client, evdev_dtor);
  145 
  146         if (ret != 0) {
  147                 debugf(client, "cannot register evdev client");
  148                 evdev_dtor(client);
  149         }
  150 
  151         return (ret);
  152 }
  153 
  154 static void
  155 evdev_dtor(void *data)
  156 {
  157         struct evdev_client *client = (struct evdev_client *)data;
  158 
  159         EVDEV_LOCK(client->ec_evdev);
  160         if (!client->ec_revoked)
  161                 evdev_dispose_client(client->ec_evdev, client);
  162         EVDEV_UNLOCK(client->ec_evdev);
  163 
  164         knlist_clear(&client->ec_selp.si_note, 0);
  165         seldrain(&client->ec_selp);
  166         knlist_destroy(&client->ec_selp.si_note);
  167         funsetown(&client->ec_sigio);
  168         mtx_destroy(&client->ec_buffer_mtx);
  169         free(client, M_EVDEV);
  170 }
  171 
  172 static int
  173 evdev_read(struct cdev *dev, struct uio *uio, int ioflag)
  174 {
  175         struct evdev_client *client;
  176         union {
  177                 struct input_event t;
  178 #ifdef COMPAT_FREEBSD32
  179                 struct input_event32 t32;
  180 #endif
  181         } event;
  182         struct input_event *head;
  183         size_t evsize;
  184         int ret = 0;
  185         int remaining;
  186 
  187         ret = devfs_get_cdevpriv((void **)&client);
  188         if (ret != 0)
  189                 return (ret);
  190 
  191         debugf(client, "read %zd bytes by thread %d", uio->uio_resid,
  192             uio->uio_td->td_tid);
  193 
  194         if (client->ec_revoked)
  195                 return (ENODEV);
  196 
  197 #ifdef COMPAT_FREEBSD32
  198         if (SV_CURPROC_FLAG(SV_ILP32))
  199                 evsize = sizeof(struct input_event32);
  200         else
  201 #endif
  202                 evsize = sizeof(struct input_event);
  203 
  204         /* Zero-sized reads are allowed for error checking */
  205         if (uio->uio_resid != 0 && uio->uio_resid < evsize)
  206                 return (EINVAL);
  207 
  208         remaining = uio->uio_resid / evsize;
  209 
  210         EVDEV_CLIENT_LOCKQ(client);
  211 
  212         if (EVDEV_CLIENT_EMPTYQ(client)) {
  213                 if (ioflag & O_NONBLOCK)
  214                         ret = EWOULDBLOCK;
  215                 else {
  216                         if (remaining != 0) {
  217                                 client->ec_blocked = true;
  218                                 ret = mtx_sleep(client, &client->ec_buffer_mtx,
  219                                     PCATCH, "evread", 0);
  220                                 if (ret == 0 && client->ec_revoked)
  221                                         ret = ENODEV;
  222                         }
  223                 }
  224         }
  225 
  226         while (ret == 0 && !EVDEV_CLIENT_EMPTYQ(client) && remaining > 0) {
  227                 head = client->ec_buffer + client->ec_buffer_head;
  228 #ifdef COMPAT_FREEBSD32
  229                 if (SV_CURPROC_FLAG(SV_ILP32)) {
  230                         bzero(&event.t32, sizeof(struct input_event32));
  231                         TV_CP(*head, event.t32, time);
  232                         CP(*head, event.t32, type);
  233                         CP(*head, event.t32, code);
  234                         CP(*head, event.t32, value);
  235                 } else
  236 #endif
  237                         bcopy(head, &event.t, evsize);
  238 
  239                 client->ec_buffer_head =
  240                     (client->ec_buffer_head + 1) % client->ec_buffer_size;
  241                 remaining--;
  242 
  243                 EVDEV_CLIENT_UNLOCKQ(client);
  244                 ret = uiomove(&event, evsize, uio);
  245                 EVDEV_CLIENT_LOCKQ(client);
  246         }
  247 
  248         EVDEV_CLIENT_UNLOCKQ(client);
  249 
  250         return (ret);
  251 }
  252 
  253 static int
  254 evdev_write(struct cdev *dev, struct uio *uio, int ioflag)
  255 {
  256         struct evdev_dev *evdev = dev->si_drv1;
  257         struct evdev_client *client;
  258         union {
  259                 struct input_event t;
  260 #ifdef COMPAT_FREEBSD32
  261                 struct input_event32 t32;
  262 #endif
  263         } event;
  264         size_t evsize;
  265         int ret = 0;
  266 
  267         ret = devfs_get_cdevpriv((void **)&client);
  268         if (ret != 0)
  269                 return (ret);
  270 
  271         debugf(client, "write %zd bytes by thread %d", uio->uio_resid,
  272             uio->uio_td->td_tid);
  273 
  274         if (client->ec_revoked || evdev == NULL)
  275                 return (ENODEV);
  276 
  277 #ifdef COMPAT_FREEBSD32
  278         if (SV_CURPROC_FLAG(SV_ILP32))
  279                 evsize = sizeof(struct input_event32);
  280         else
  281 #endif
  282                 evsize = sizeof(struct input_event);
  283 
  284         if (uio->uio_resid % evsize != 0) {
  285                 debugf(client, "write size not multiple of input_event size");
  286                 return (EINVAL);
  287         }
  288 
  289         while (uio->uio_resid > 0 && ret == 0) {
  290                 ret = uiomove(&event, evsize, uio);
  291                 if (ret == 0) {
  292 #ifdef COMPAT_FREEBSD32
  293                         if (SV_CURPROC_FLAG(SV_ILP32))
  294                                 ret = evdev_inject_event(evdev, event.t32.type,
  295                                     event.t32.code, event.t32.value);
  296                         else
  297 #endif
  298                                 ret = evdev_inject_event(evdev, event.t.type,
  299                                     event.t.code, event.t.value);
  300                 }
  301         }
  302 
  303         return (ret);
  304 }
  305 
  306 static int
  307 evdev_poll(struct cdev *dev, int events, struct thread *td)
  308 {
  309         struct evdev_client *client;
  310         int ret;
  311         int revents = 0;
  312 
  313         ret = devfs_get_cdevpriv((void **)&client);
  314         if (ret != 0)
  315                 return (POLLNVAL);
  316 
  317         debugf(client, "poll by thread %d", td->td_tid);
  318 
  319         if (client->ec_revoked)
  320                 return (POLLHUP);
  321 
  322         if (events & (POLLIN | POLLRDNORM)) {
  323                 EVDEV_CLIENT_LOCKQ(client);
  324                 if (!EVDEV_CLIENT_EMPTYQ(client))
  325                         revents = events & (POLLIN | POLLRDNORM);
  326                 else {
  327                         client->ec_selected = true;
  328                         selrecord(td, &client->ec_selp);
  329                 }
  330                 EVDEV_CLIENT_UNLOCKQ(client);
  331         }
  332 
  333         return (revents);
  334 }
  335 
  336 static int
  337 evdev_kqfilter(struct cdev *dev, struct knote *kn)
  338 {
  339         struct evdev_client *client;
  340         int ret;
  341 
  342         ret = devfs_get_cdevpriv((void **)&client);
  343         if (ret != 0)
  344                 return (ret);
  345 
  346         if (client->ec_revoked)
  347                 return (ENODEV);
  348 
  349         switch(kn->kn_filter) {
  350         case EVFILT_READ:
  351                 kn->kn_fop = &evdev_cdev_filterops;
  352                 break;
  353         default:
  354                 return(EINVAL);
  355         }
  356         kn->kn_hook = (caddr_t)client;
  357 
  358         knlist_add(&client->ec_selp.si_note, kn, 0);
  359         return (0);
  360 }
  361 
  362 static int
  363 evdev_kqread(struct knote *kn, long hint)
  364 {
  365         struct evdev_client *client;
  366         int ret;
  367 
  368         client = (struct evdev_client *)kn->kn_hook;
  369 
  370         EVDEV_CLIENT_LOCKQ_ASSERT(client);
  371 
  372         if (client->ec_revoked) {
  373                 kn->kn_flags |= EV_EOF;
  374                 ret = 1;
  375         } else {
  376                 kn->kn_data = EVDEV_CLIENT_SIZEQ(client) *
  377                     sizeof(struct input_event);
  378                 ret = !EVDEV_CLIENT_EMPTYQ(client);
  379         }
  380         return (ret);
  381 }
  382 
  383 static void
  384 evdev_kqdetach(struct knote *kn)
  385 {
  386         struct evdev_client *client;
  387 
  388         client = (struct evdev_client *)kn->kn_hook;
  389         knlist_remove(&client->ec_selp.si_note, kn, 0);
  390 }
  391 
  392 static int
  393 evdev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
  394     struct thread *td)
  395 {
  396         struct evdev_dev *evdev = dev->si_drv1;
  397         struct evdev_client *client;
  398         struct input_keymap_entry *ke;
  399         int ret, len, limit, type_num;
  400         uint32_t code;
  401         size_t nvalues;
  402 
  403         ret = devfs_get_cdevpriv((void **)&client);
  404         if (ret != 0)
  405                 return (ret);
  406 
  407         if (client->ec_revoked || evdev == NULL)
  408                 return (ENODEV);
  409 
  410         /*
  411          * Fix evdev state corrupted with discarding of kdb events.
  412          * EVIOCGKEY and EVIOCGLED ioctls can suffer from this.
  413          */
  414         if (evdev->ev_kdb_active) {
  415                 EVDEV_LOCK(evdev);
  416                 if (evdev->ev_kdb_active) {
  417                         evdev->ev_kdb_active = false;
  418                         evdev_restore_after_kdb(evdev);
  419                 }
  420                 EVDEV_UNLOCK(evdev);
  421         }
  422 
  423         /* file I/O ioctl handling */
  424         switch (cmd) {
  425         case FIOSETOWN:
  426                 return (fsetown(*(int *)data, &client->ec_sigio));
  427 
  428         case FIOGETOWN:
  429                 *(int *)data = fgetown(&client->ec_sigio);
  430                 return (0);
  431 
  432         case FIONBIO:
  433                 return (0);
  434 
  435         case FIOASYNC:
  436                 if (*(int *)data)
  437                         client->ec_async = true;
  438                 else
  439                         client->ec_async = false;
  440 
  441                 return (0);
  442 
  443         case FIONREAD:
  444                 EVDEV_CLIENT_LOCKQ(client);
  445                 *(int *)data =
  446                     EVDEV_CLIENT_SIZEQ(client) * sizeof(struct input_event);
  447                 EVDEV_CLIENT_UNLOCKQ(client);
  448                 return (0);
  449         }
  450 
  451         len = IOCPARM_LEN(cmd);
  452         debugf(client, "ioctl called: cmd=0x%08lx, data=%p", cmd, data);
  453 
  454         /* evdev fixed-length ioctls handling */
  455         switch (cmd) {
  456         case EVIOCGVERSION:
  457                 *(int *)data = EV_VERSION;
  458                 return (0);
  459 
  460         case EVIOCGID:
  461                 debugf(client, "EVIOCGID: bus=%d vendor=0x%04x product=0x%04x",
  462                     evdev->ev_id.bustype, evdev->ev_id.vendor,
  463                     evdev->ev_id.product);
  464                 memcpy(data, &evdev->ev_id, sizeof(struct input_id));
  465                 return (0);
  466 
  467         case EVIOCGREP:
  468                 if (!evdev_event_supported(evdev, EV_REP))
  469                         return (ENOTSUP);
  470 
  471                 memcpy(data, evdev->ev_rep, sizeof(evdev->ev_rep));
  472                 return (0);
  473 
  474         case EVIOCSREP:
  475                 if (!evdev_event_supported(evdev, EV_REP))
  476                         return (ENOTSUP);
  477 
  478                 evdev_inject_event(evdev, EV_REP, REP_DELAY, ((int *)data)[0]);
  479                 evdev_inject_event(evdev, EV_REP, REP_PERIOD,
  480                     ((int *)data)[1]);
  481                 return (0);
  482 
  483         case EVIOCGKEYCODE:
  484                 /* Fake unsupported ioctl */
  485                 return (0);
  486 
  487         case EVIOCGKEYCODE_V2:
  488                 if (evdev->ev_methods == NULL ||
  489                     evdev->ev_methods->ev_get_keycode == NULL)
  490                         return (ENOTSUP);
  491 
  492                 ke = (struct input_keymap_entry *)data;
  493                 evdev->ev_methods->ev_get_keycode(evdev, ke);
  494                 return (0);
  495 
  496         case EVIOCSKEYCODE:
  497                 /* Fake unsupported ioctl */
  498                 return (0);
  499 
  500         case EVIOCSKEYCODE_V2:
  501                 if (evdev->ev_methods == NULL ||
  502                     evdev->ev_methods->ev_set_keycode == NULL)
  503                         return (ENOTSUP);
  504 
  505                 ke = (struct input_keymap_entry *)data;
  506                 evdev->ev_methods->ev_set_keycode(evdev, ke);
  507                 return (0);
  508 
  509         case EVIOCGABS(0) ... EVIOCGABS(ABS_MAX):
  510                 if (evdev->ev_absinfo == NULL)
  511                         return (EINVAL);
  512 
  513                 memcpy(data, &evdev->ev_absinfo[cmd - EVIOCGABS(0)],
  514                     sizeof(struct input_absinfo));
  515                 return (0);
  516 
  517         case EVIOCSABS(0) ... EVIOCSABS(ABS_MAX):
  518                 if (evdev->ev_absinfo == NULL)
  519                         return (EINVAL);
  520 
  521                 code = cmd - EVIOCSABS(0);
  522                 /* mt-slot number can not be changed */
  523                 if (code == ABS_MT_SLOT)
  524                         return (EINVAL);
  525 
  526                 EVDEV_LOCK(evdev);
  527                 evdev_set_absinfo(evdev, code, (struct input_absinfo *)data);
  528                 EVDEV_UNLOCK(evdev);
  529                 return (0);
  530 
  531         case EVIOCSFF:
  532         case EVIOCRMFF:
  533         case EVIOCGEFFECTS:
  534                 /* Fake unsupported ioctls */
  535                 return (0);
  536 
  537         case EVIOCGRAB:
  538                 EVDEV_LOCK(evdev);
  539                 if (*(int *)data)
  540                         ret = evdev_grab_client(evdev, client);
  541                 else
  542                         ret = evdev_release_client(evdev, client);
  543                 EVDEV_UNLOCK(evdev);
  544                 return (ret);
  545 
  546         case EVIOCREVOKE:
  547                 if (*(int *)data != 0)
  548                         return (EINVAL);
  549 
  550                 EVDEV_LOCK(evdev);
  551                 if (dev->si_drv1 != NULL && !client->ec_revoked) {
  552                         evdev_dispose_client(evdev, client);
  553                         evdev_revoke_client(client);
  554                 }
  555                 EVDEV_UNLOCK(evdev);
  556                 return (0);
  557 
  558         case EVIOCSCLOCKID:
  559                 switch (*(int *)data) {
  560                 case CLOCK_REALTIME:
  561                         client->ec_clock_id = EV_CLOCK_REALTIME;
  562                         return (0);
  563                 case CLOCK_MONOTONIC:
  564                         client->ec_clock_id = EV_CLOCK_MONOTONIC;
  565                         return (0);
  566                 default:
  567                         return (EINVAL);
  568                 }
  569         }
  570 
  571         /* evdev variable-length ioctls handling */
  572         switch (IOCBASECMD(cmd)) {
  573         case EVIOCGNAME(0):
  574                 strlcpy(data, evdev->ev_name, len);
  575                 return (0);
  576 
  577         case EVIOCGPHYS(0):
  578                 if (evdev->ev_shortname[0] == 0)
  579                         return (ENOENT);
  580 
  581                 strlcpy(data, evdev->ev_shortname, len);
  582                 return (0);
  583 
  584         case EVIOCGUNIQ(0):
  585                 if (evdev->ev_serial[0] == 0)
  586                         return (ENOENT);
  587 
  588                 strlcpy(data, evdev->ev_serial, len);
  589                 return (0);
  590 
  591         case EVIOCGPROP(0):
  592                 limit = MIN(len, bitstr_size(INPUT_PROP_CNT));
  593                 memcpy(data, evdev->ev_prop_flags, limit);
  594                 return (0);
  595 
  596         case EVIOCGMTSLOTS(0):
  597                 if (evdev->ev_mt == NULL)
  598                         return (EINVAL);
  599                 if (len < sizeof(uint32_t))
  600                         return (EINVAL);
  601                 code = *(uint32_t *)data;
  602                 if (!ABS_IS_MT(code))
  603                         return (EINVAL);
  604 
  605                 nvalues =
  606                     MIN(len / sizeof(int32_t) - 1, MAXIMAL_MT_SLOT(evdev) + 1);
  607                 for (int i = 0; i < nvalues; i++)
  608                         ((int32_t *)data)[i + 1] =
  609                             evdev_get_mt_value(evdev, i, code);
  610                 return (0);
  611 
  612         case EVIOCGKEY(0):
  613                 limit = MIN(len, bitstr_size(KEY_CNT));
  614                 EVDEV_LOCK(evdev);
  615                 evdev_client_filter_queue(client, EV_KEY);
  616                 memcpy(data, evdev->ev_key_states, limit);
  617                 EVDEV_UNLOCK(evdev);
  618                 return (0);
  619 
  620         case EVIOCGLED(0):
  621                 limit = MIN(len, bitstr_size(LED_CNT));
  622                 EVDEV_LOCK(evdev);
  623                 evdev_client_filter_queue(client, EV_LED);
  624                 memcpy(data, evdev->ev_led_states, limit);
  625                 EVDEV_UNLOCK(evdev);
  626                 return (0);
  627 
  628         case EVIOCGSND(0):
  629                 limit = MIN(len, bitstr_size(SND_CNT));
  630                 EVDEV_LOCK(evdev);
  631                 evdev_client_filter_queue(client, EV_SND);
  632                 memcpy(data, evdev->ev_snd_states, limit);
  633                 EVDEV_UNLOCK(evdev);
  634                 return (0);
  635 
  636         case EVIOCGSW(0):
  637                 limit = MIN(len, bitstr_size(SW_CNT));
  638                 EVDEV_LOCK(evdev);
  639                 evdev_client_filter_queue(client, EV_SW);
  640                 memcpy(data, evdev->ev_sw_states, limit);
  641                 EVDEV_UNLOCK(evdev);
  642                 return (0);
  643 
  644         case EVIOCGBIT(0, 0) ... EVIOCGBIT(EV_MAX, 0):
  645                 type_num = IOCBASECMD(cmd) - EVIOCGBIT(0, 0);
  646                 debugf(client, "EVIOCGBIT(%d): data=%p, len=%d", type_num,
  647                     data, len);
  648                 return (evdev_ioctl_eviocgbit(evdev, type_num, len, data));
  649         }
  650 
  651         return (EINVAL);
  652 }
  653 
  654 static int
  655 evdev_ioctl_eviocgbit(struct evdev_dev *evdev, int type, int len, caddr_t data)
  656 {
  657         unsigned long *bitmap;
  658         int limit;
  659 
  660         switch (type) {
  661         case 0:
  662                 bitmap = evdev->ev_type_flags;
  663                 limit = EV_CNT;
  664                 break;
  665         case EV_KEY:
  666                 bitmap = evdev->ev_key_flags;
  667                 limit = KEY_CNT;
  668                 break;
  669         case EV_REL:
  670                 bitmap = evdev->ev_rel_flags;
  671                 limit = REL_CNT;
  672                 break;
  673         case EV_ABS:
  674                 bitmap = evdev->ev_abs_flags;
  675                 limit = ABS_CNT;
  676                 break;
  677         case EV_MSC:
  678                 bitmap = evdev->ev_msc_flags;
  679                 limit = MSC_CNT;
  680                 break;
  681         case EV_LED:
  682                 bitmap = evdev->ev_led_flags;
  683                 limit = LED_CNT;
  684                 break;
  685         case EV_SND:
  686                 bitmap = evdev->ev_snd_flags;
  687                 limit = SND_CNT;
  688                 break;
  689         case EV_SW:
  690                 bitmap = evdev->ev_sw_flags;
  691                 limit = SW_CNT;
  692                 break;
  693         case EV_FF:
  694                 /*
  695                  * We don't support EV_FF now, so let's
  696                  * just fake it returning only zeros.
  697                  */
  698                 bzero(data, len);
  699                 return (0);
  700         default:
  701                 return (ENOTTY);
  702         }
  703 
  704         /*
  705          * Clear ioctl data buffer in case it's bigger than
  706          * bitmap size
  707          */
  708         bzero(data, len);
  709 
  710         limit = bitstr_size(limit);
  711         len = MIN(limit, len);
  712         memcpy(data, bitmap, len);
  713         return (0);
  714 }
  715 
  716 void
  717 evdev_revoke_client(struct evdev_client *client)
  718 {
  719 
  720         EVDEV_LOCK_ASSERT(client->ec_evdev);
  721 
  722         client->ec_revoked = true;
  723 }
  724 
  725 void
  726 evdev_notify_event(struct evdev_client *client)
  727 {
  728 
  729         EVDEV_CLIENT_LOCKQ_ASSERT(client);
  730 
  731         if (client->ec_blocked) {
  732                 client->ec_blocked = false;
  733                 wakeup(client);
  734         }
  735         if (client->ec_selected) {
  736                 client->ec_selected = false;
  737                 selwakeup(&client->ec_selp);
  738         }
  739         KNOTE_LOCKED(&client->ec_selp.si_note, 0);
  740 
  741         if (client->ec_async && client->ec_sigio != NULL)
  742                 pgsigio(&client->ec_sigio, SIGIO, 0);
  743 }
  744 
  745 int
  746 evdev_cdev_create(struct evdev_dev *evdev)
  747 {
  748         struct make_dev_args mda;
  749         int ret, unit = 0;
  750 
  751         make_dev_args_init(&mda);
  752         mda.mda_flags = MAKEDEV_WAITOK | MAKEDEV_CHECKNAME;
  753         mda.mda_devsw = &evdev_cdevsw;
  754         mda.mda_uid = UID_ROOT;
  755         mda.mda_gid = GID_WHEEL;
  756         mda.mda_mode = 0600;
  757         mda.mda_si_drv1 = evdev;
  758 
  759         /* Try to coexist with cuse-backed input/event devices */
  760         while ((ret = make_dev_s(&mda, &evdev->ev_cdev, "input/event%d", unit))
  761             == EEXIST)
  762                 unit++;
  763 
  764         if (ret == 0)
  765                 evdev->ev_unit = unit;
  766 
  767         return (ret);
  768 }
  769 
  770 int
  771 evdev_cdev_destroy(struct evdev_dev *evdev)
  772 {
  773 
  774         destroy_dev(evdev->ev_cdev);
  775         return (0);
  776 }
  777 
  778 static void
  779 evdev_client_gettime(struct evdev_client *client, struct timeval *tv)
  780 {
  781 
  782         switch (client->ec_clock_id) {
  783         case EV_CLOCK_BOOTTIME:
  784                 /*
  785                  * XXX: FreeBSD does not support true POSIX monotonic clock.
  786                  *      So aliase EV_CLOCK_BOOTTIME to EV_CLOCK_MONOTONIC.
  787                  */
  788         case EV_CLOCK_MONOTONIC:
  789                 microuptime(tv);
  790                 break;
  791 
  792         case EV_CLOCK_REALTIME:
  793         default:
  794                 microtime(tv);
  795                 break;
  796         }
  797 }
  798 
  799 void
  800 evdev_client_push(struct evdev_client *client, uint16_t type, uint16_t code,
  801     int32_t value)
  802 {
  803         struct timeval time;
  804         size_t count, head, tail, ready;
  805 
  806         EVDEV_CLIENT_LOCKQ_ASSERT(client);
  807         head = client->ec_buffer_head;
  808         tail = client->ec_buffer_tail;
  809         ready = client->ec_buffer_ready;
  810         count = client->ec_buffer_size;
  811 
  812         /* If queue is full drop its content and place SYN_DROPPED event */
  813         if ((tail + 1) % count == head) {
  814                 debugf(client, "client %p: buffer overflow", client);
  815 
  816                 head = (tail + count - 1) % count;
  817                 client->ec_buffer[head] = (struct input_event) {
  818                         .type = EV_SYN,
  819                         .code = SYN_DROPPED,
  820                         .value = 0
  821                 };
  822                 /*
  823                  * XXX: Here is a small race window from now till the end of
  824                  *      report. The queue is empty but client has been already
  825                  *      notified of data readyness. Can be fixed in two ways:
  826                  * 1. Implement bulk insert so queue lock would not be dropped
  827                  *    till the SYN_REPORT event.
  828                  * 2. Insert SYN_REPORT just now and skip remaining events
  829                  */
  830                 client->ec_buffer_head = head;
  831                 client->ec_buffer_ready = head;
  832         }
  833 
  834         client->ec_buffer[tail].type = type;
  835         client->ec_buffer[tail].code = code;
  836         client->ec_buffer[tail].value = value;
  837         client->ec_buffer_tail = (tail + 1) % count;
  838 
  839         /* Allow users to read events only after report has been completed */
  840         if (type == EV_SYN && code == SYN_REPORT) {
  841                 evdev_client_gettime(client, &time);
  842                 for (; ready != client->ec_buffer_tail;
  843                     ready = (ready + 1) % count)
  844                         client->ec_buffer[ready].time = time;
  845                 client->ec_buffer_ready = client->ec_buffer_tail;
  846         }
  847 }
  848 
  849 void
  850 evdev_client_dumpqueue(struct evdev_client *client)
  851 {
  852         struct input_event *event;
  853         size_t i, head, tail, ready, size;
  854 
  855         head = client->ec_buffer_head;
  856         tail = client->ec_buffer_tail;
  857         ready = client->ec_buffer_ready;
  858         size = client->ec_buffer_size;
  859 
  860         printf("evdev client: %p\n", client);
  861         printf("event queue: head=%zu ready=%zu tail=%zu size=%zu\n",
  862             head, ready, tail, size);
  863 
  864         printf("queue contents:\n");
  865 
  866         for (i = 0; i < size; i++) {
  867                 event = &client->ec_buffer[i];
  868                 printf("%zu: ", i);
  869 
  870                 if (i < head || i > tail)
  871                         printf("unused\n");
  872                 else
  873                         printf("type=%d code=%d value=%d ", event->type,
  874                             event->code, event->value);
  875 
  876                 if (i == head)
  877                         printf("<- head\n");
  878                 else if (i == tail)
  879                         printf("<- tail\n");
  880                 else if (i == ready)
  881                         printf("<- ready\n");
  882                 else
  883                         printf("\n");
  884         }
  885 }
  886 
  887 static void
  888 evdev_client_filter_queue(struct evdev_client *client, uint16_t type)
  889 {
  890         struct input_event *event;
  891         size_t head, tail, count, i;
  892         bool last_was_syn = false;
  893 
  894         EVDEV_CLIENT_LOCKQ(client);
  895 
  896         i = head = client->ec_buffer_head;
  897         tail = client->ec_buffer_tail;
  898         count = client->ec_buffer_size;
  899         client->ec_buffer_ready = client->ec_buffer_tail;
  900 
  901         while (i != client->ec_buffer_tail) {
  902                 event = &client->ec_buffer[i];
  903                 i = (i + 1) % count;
  904 
  905                 /* Skip event of given type */
  906                 if (event->type == type)
  907                         continue;
  908 
  909                 /* Remove empty SYN_REPORT events */
  910                 if (event->type == EV_SYN && event->code == SYN_REPORT) {
  911                         if (last_was_syn)
  912                                 continue;
  913                         else
  914                                 client->ec_buffer_ready = (tail + 1) % count;
  915                 }
  916 
  917                 /* Rewrite entry */
  918                 memcpy(&client->ec_buffer[tail], event,
  919                     sizeof(struct input_event));
  920 
  921                 last_was_syn = (event->type == EV_SYN &&
  922                     event->code == SYN_REPORT);
  923 
  924                 tail = (tail + 1) % count;
  925         }
  926 
  927         client->ec_buffer_head = i;
  928         client->ec_buffer_tail = tail;
  929 
  930         EVDEV_CLIENT_UNLOCKQ(client);
  931 }

Cache object: f424dc780e92d3e0754988c7968967e2


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