---
 freebsd/sys/dev/evdev/cdev.c              | 863 +++++++++++++++++++++++++++
 freebsd/sys/dev/evdev/evdev.c             | 939 ++++++++++++++++++++++++++++++
 freebsd/sys/dev/evdev/evdev.h             | 210 +++++++
 freebsd/sys/dev/evdev/evdev_mt.c          | 294 ++++++++++
 freebsd/sys/dev/evdev/evdev_private.h     | 200 +++++++
 freebsd/sys/dev/evdev/evdev_utils.c       | 335 +++++++++++
 freebsd/sys/dev/evdev/input-event-codes.h | 819 ++++++++++++++++++++++++++
 freebsd/sys/dev/evdev/input.h             | 273 +++++++++
 freebsd/sys/dev/evdev/uinput.c            | 715 +++++++++++++++++++++++
 freebsd/sys/dev/evdev/uinput.h            | 107 ++++
 10 files changed, 4755 insertions(+)
 create mode 100644 freebsd/sys/dev/evdev/cdev.c
 create mode 100644 freebsd/sys/dev/evdev/evdev.c
 create mode 100644 freebsd/sys/dev/evdev/evdev.h
 create mode 100644 freebsd/sys/dev/evdev/evdev_mt.c
 create mode 100644 freebsd/sys/dev/evdev/evdev_private.h
 create mode 100644 freebsd/sys/dev/evdev/evdev_utils.c
 create mode 100644 freebsd/sys/dev/evdev/input-event-codes.h
 create mode 100644 freebsd/sys/dev/evdev/input.h
 create mode 100644 freebsd/sys/dev/evdev/uinput.c
 create mode 100644 freebsd/sys/dev/evdev/uinput.h

diff --git a/freebsd/sys/dev/evdev/cdev.c b/freebsd/sys/dev/evdev/cdev.c
new file mode 100644
index 0000000..b9cc4cd
--- /dev/null
+++ b/freebsd/sys/dev/evdev/cdev.c
@@ -0,0 +1,863 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2014 Jakub Wojciech Klama <jc...@freebsd.org>
+ * Copyright (c) 2015-2016 Vladimir Kondratyev <w...@cicgroup.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <rtems/bsd/local/opt_evdev.h>
+
+#include <sys/types.h>
+#include <sys/bitstring.h>
+#include <sys/systm.h>
+#include <rtems/bsd/sys/param.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/proc.h>
+#include <sys/poll.h>
+#include <sys/filio.h>
+#include <sys/fcntl.h>
+#include <sys/selinfo.h>
+#include <sys/malloc.h>
+#include <sys/time.h>
+
+#include <dev/evdev/input.h>
+#include <dev/evdev/evdev.h>
+#include <dev/evdev/evdev_private.h>
+
+#ifdef EVDEV_DEBUG
+#define        debugf(client, fmt, args...)    printf("evdev cdev: "fmt"\n", 
##args)
+#else
+#define        debugf(client, fmt, args...)
+#endif
+
+#define        DEF_RING_REPORTS        8
+
+static d_open_t                evdev_open;
+static d_read_t                evdev_read;
+static d_write_t       evdev_write;
+static d_ioctl_t       evdev_ioctl;
+static d_poll_t                evdev_poll;
+static d_kqfilter_t    evdev_kqfilter;
+
+static int evdev_kqread(struct knote *kn, long hint);
+static void evdev_kqdetach(struct knote *kn);
+static void evdev_dtor(void *);
+static int evdev_ioctl_eviocgbit(struct evdev_dev *, int, int, caddr_t);
+static void evdev_client_filter_queue(struct evdev_client *, uint16_t);
+
+static struct cdevsw evdev_cdevsw = {
+       .d_version = D_VERSION,
+       .d_open = evdev_open,
+       .d_read = evdev_read,
+       .d_write = evdev_write,
+       .d_ioctl = evdev_ioctl,
+       .d_poll = evdev_poll,
+       .d_kqfilter = evdev_kqfilter,
+       .d_name = "evdev",
+};
+
+static struct filterops evdev_cdev_filterops = {
+       .f_isfd = 1,
+       .f_attach = NULL,
+       .f_detach = evdev_kqdetach,
+       .f_event = evdev_kqread,
+};
+
+static int
+evdev_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
+{
+       struct evdev_dev *evdev = dev->si_drv1;
+       struct evdev_client *client;
+       size_t buffer_size;
+       int ret;
+
+       if (evdev == NULL)
+               return (ENODEV);
+
+       /* Initialize client structure */
+       buffer_size = evdev->ev_report_size * DEF_RING_REPORTS;
+       client = malloc(offsetof(struct evdev_client, ec_buffer) +
+           sizeof(struct input_event) * buffer_size,
+           M_EVDEV, M_WAITOK | M_ZERO);
+
+       /* Initialize ring buffer */
+       client->ec_buffer_size = buffer_size;
+       client->ec_buffer_head = 0;
+       client->ec_buffer_tail = 0;
+       client->ec_buffer_ready = 0;
+
+       client->ec_evdev = evdev;
+       mtx_init(&client->ec_buffer_mtx, "evclient", "evdev", MTX_DEF);
+       knlist_init_mtx(&client->ec_selp.si_note, &client->ec_buffer_mtx);
+
+       /* Avoid race with evdev_unregister */
+       EVDEV_LOCK(evdev);
+       if (dev->si_drv1 == NULL)
+               ret = ENODEV;
+       else
+               ret = evdev_register_client(evdev, client);
+
+       if (ret != 0)
+               evdev_revoke_client(client);
+       /*
+        * Unlock evdev here because non-sleepable lock held 
+        * while calling devfs_set_cdevpriv upsets WITNESS
+        */
+       EVDEV_UNLOCK(evdev);
+
+       if (!ret)
+               ret = devfs_set_cdevpriv(client, evdev_dtor);
+
+       if (ret != 0) {
+               debugf(client, "cannot register evdev client");
+               evdev_dtor(client);
+       }
+
+       return (ret);
+}
+
+static void
+evdev_dtor(void *data)
+{
+       struct evdev_client *client = (struct evdev_client *)data;
+
+       EVDEV_LOCK(client->ec_evdev);
+       if (!client->ec_revoked)
+               evdev_dispose_client(client->ec_evdev, client);
+       EVDEV_UNLOCK(client->ec_evdev);
+
+       knlist_clear(&client->ec_selp.si_note, 0);
+       seldrain(&client->ec_selp);
+       knlist_destroy(&client->ec_selp.si_note);
+       funsetown(&client->ec_sigio);
+       mtx_destroy(&client->ec_buffer_mtx);
+       free(client, M_EVDEV);
+}
+
+static int
+evdev_read(struct cdev *dev, struct uio *uio, int ioflag)
+{
+       struct evdev_client *client;
+       struct input_event event;
+       int ret = 0;
+       int remaining;
+
+       ret = devfs_get_cdevpriv((void **)&client);
+       if (ret != 0)
+               return (ret);
+
+       debugf(client, "read %zd bytes by thread %d", uio->uio_resid,
+           uio->uio_td->td_tid);
+
+       if (client->ec_revoked)
+               return (ENODEV);
+
+       /* Zero-sized reads are allowed for error checking */
+       if (uio->uio_resid != 0 && uio->uio_resid < sizeof(struct input_event))
+               return (EINVAL);
+
+       remaining = uio->uio_resid / sizeof(struct input_event);
+
+       EVDEV_CLIENT_LOCKQ(client);
+
+       if (EVDEV_CLIENT_EMPTYQ(client)) {
+               if (ioflag & O_NONBLOCK)
+                       ret = EWOULDBLOCK;
+               else {
+                       if (remaining != 0) {
+                               client->ec_blocked = true;
+                               ret = mtx_sleep(client, &client->ec_buffer_mtx,
+                                   PCATCH, "evread", 0);
+                       }
+               }
+       }
+
+       while (ret == 0 && !EVDEV_CLIENT_EMPTYQ(client) && remaining > 0) {
+               memcpy(&event, &client->ec_buffer[client->ec_buffer_head],
+                   sizeof(struct input_event));
+               client->ec_buffer_head =
+                   (client->ec_buffer_head + 1) % client->ec_buffer_size;
+               remaining--;
+
+               EVDEV_CLIENT_UNLOCKQ(client);
+               ret = uiomove(&event, sizeof(struct input_event), uio);
+               EVDEV_CLIENT_LOCKQ(client);
+       }
+
+       EVDEV_CLIENT_UNLOCKQ(client);
+
+       return (ret);
+}
+
+static int
+evdev_write(struct cdev *dev, struct uio *uio, int ioflag)
+{
+       struct evdev_dev *evdev = dev->si_drv1;
+       struct evdev_client *client;
+       struct input_event event;
+       int ret = 0;
+
+       ret = devfs_get_cdevpriv((void **)&client);
+       if (ret != 0)
+               return (ret);
+
+       debugf(client, "write %zd bytes by thread %d", uio->uio_resid,
+           uio->uio_td->td_tid);
+
+       if (client->ec_revoked || evdev == NULL)
+               return (ENODEV);
+
+       if (uio->uio_resid % sizeof(struct input_event) != 0) {
+               debugf(client, "write size not multiple of input_event size");
+               return (EINVAL);
+       }
+
+       while (uio->uio_resid > 0 && ret == 0) {
+               ret = uiomove(&event, sizeof(struct input_event), uio);
+               if (ret == 0)
+                       ret = evdev_inject_event(evdev, event.type, event.code,
+                           event.value);
+       }
+
+       return (ret);
+}
+
+static int
+evdev_poll(struct cdev *dev, int events, struct thread *td)
+{
+       struct evdev_client *client;
+       int ret;
+       int revents = 0;
+
+       ret = devfs_get_cdevpriv((void **)&client);
+       if (ret != 0)
+               return (POLLNVAL);
+
+       debugf(client, "poll by thread %d", td->td_tid);
+
+       if (client->ec_revoked)
+               return (POLLHUP);
+
+       if (events & (POLLIN | POLLRDNORM)) {
+               EVDEV_CLIENT_LOCKQ(client);
+               if (!EVDEV_CLIENT_EMPTYQ(client))
+                       revents = events & (POLLIN | POLLRDNORM);
+               else {
+                       client->ec_selected = true;
+                       selrecord(td, &client->ec_selp);
+               }
+               EVDEV_CLIENT_UNLOCKQ(client);
+       }
+
+       return (revents);
+}
+
+static int
+evdev_kqfilter(struct cdev *dev, struct knote *kn)
+{
+       struct evdev_client *client;
+       int ret;
+
+       ret = devfs_get_cdevpriv((void **)&client);
+       if (ret != 0)
+               return (ret);
+
+       if (client->ec_revoked)
+               return (ENODEV);
+
+       switch(kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &evdev_cdev_filterops;
+               break;
+       default:
+               return(EINVAL);
+       }
+       kn->kn_hook = (caddr_t)client;
+
+       knlist_add(&client->ec_selp.si_note, kn, 0);
+       return (0);
+}
+
+static int
+evdev_kqread(struct knote *kn, long hint)
+{
+       struct evdev_client *client;
+       int ret;
+
+       client = (struct evdev_client *)kn->kn_hook;
+
+       EVDEV_CLIENT_LOCKQ_ASSERT(client);
+
+       if (client->ec_revoked) {
+               kn->kn_flags |= EV_EOF;
+               ret = 1;
+       } else {
+               kn->kn_data = EVDEV_CLIENT_SIZEQ(client) *
+                   sizeof(struct input_event);
+               ret = !EVDEV_CLIENT_EMPTYQ(client);
+       }
+       return (ret);
+}
+
+static void
+evdev_kqdetach(struct knote *kn)
+{
+       struct evdev_client *client;
+
+       client = (struct evdev_client *)kn->kn_hook;
+       knlist_remove(&client->ec_selp.si_note, kn, 0);
+}
+
+static int
+evdev_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
+    struct thread *td)
+{
+       struct evdev_dev *evdev = dev->si_drv1;
+       struct evdev_client *client;
+       struct input_keymap_entry *ke;
+       int ret, len, limit, type_num;
+       uint32_t code;
+       size_t nvalues;
+
+       ret = devfs_get_cdevpriv((void **)&client);
+       if (ret != 0)
+               return (ret);
+
+       if (client->ec_revoked || evdev == NULL)
+               return (ENODEV);
+
+       /* file I/O ioctl handling */
+       switch (cmd) {
+       case FIOSETOWN:
+               return (fsetown(*(int *)data, &client->ec_sigio));
+
+       case FIOGETOWN:
+               *(int *)data = fgetown(&client->ec_sigio);
+               return (0);
+
+       case FIONBIO:
+               return (0);
+
+       case FIOASYNC:
+               if (*(int *)data)
+                       client->ec_async = true;
+               else
+                       client->ec_async = false;
+
+               return (0);
+
+       case FIONREAD:
+               EVDEV_CLIENT_LOCKQ(client);
+               *(int *)data =
+                   EVDEV_CLIENT_SIZEQ(client) * sizeof(struct input_event);
+               EVDEV_CLIENT_UNLOCKQ(client);
+               return (0);
+       }
+
+       len = IOCPARM_LEN(cmd);
+       debugf(client, "ioctl called: cmd=0x%08lx, data=%p", cmd, data);
+
+       /* evdev fixed-length ioctls handling */
+       switch (cmd) {
+       case EVIOCGVERSION:
+               *(int *)data = EV_VERSION;
+               return (0);
+
+       case EVIOCGID:
+               debugf(client, "EVIOCGID: bus=%d vendor=0x%04x product=0x%04x",
+                   evdev->ev_id.bustype, evdev->ev_id.vendor,
+                   evdev->ev_id.product);
+               memcpy(data, &evdev->ev_id, sizeof(struct input_id));
+               return (0);
+
+       case EVIOCGREP:
+               if (!evdev_event_supported(evdev, EV_REP))
+                       return (ENOTSUP);
+
+               memcpy(data, evdev->ev_rep, sizeof(evdev->ev_rep));
+               return (0);
+
+       case EVIOCSREP:
+               if (!evdev_event_supported(evdev, EV_REP))
+                       return (ENOTSUP);
+
+               evdev_inject_event(evdev, EV_REP, REP_DELAY, ((int *)data)[0]);
+               evdev_inject_event(evdev, EV_REP, REP_PERIOD,
+                   ((int *)data)[1]);
+               return (0);
+
+       case EVIOCGKEYCODE:
+               /* Fake unsupported ioctl */
+               return (0);
+
+       case EVIOCGKEYCODE_V2:
+               if (evdev->ev_methods == NULL ||
+                   evdev->ev_methods->ev_get_keycode == NULL)
+                       return (ENOTSUP);
+
+               ke = (struct input_keymap_entry *)data;
+               evdev->ev_methods->ev_get_keycode(evdev, evdev->ev_softc, ke);
+               return (0);
+
+       case EVIOCSKEYCODE:
+               /* Fake unsupported ioctl */
+               return (0);
+
+       case EVIOCSKEYCODE_V2:
+               if (evdev->ev_methods == NULL ||
+                   evdev->ev_methods->ev_set_keycode == NULL)
+                       return (ENOTSUP);
+
+               ke = (struct input_keymap_entry *)data;
+               evdev->ev_methods->ev_set_keycode(evdev, evdev->ev_softc, ke);
+               return (0);
+
+       case EVIOCGABS(0) ... EVIOCGABS(ABS_MAX):
+               if (evdev->ev_absinfo == NULL)
+                       return (EINVAL);
+
+               memcpy(data, &evdev->ev_absinfo[cmd - EVIOCGABS(0)],
+                   sizeof(struct input_absinfo));
+               return (0);
+
+       case EVIOCSABS(0) ... EVIOCSABS(ABS_MAX):
+               if (evdev->ev_absinfo == NULL)
+                       return (EINVAL);
+
+               code = cmd - EVIOCSABS(0);
+               /* mt-slot number can not be changed */
+               if (code == ABS_MT_SLOT)
+                       return (EINVAL);
+
+               EVDEV_LOCK(evdev);
+               evdev_set_absinfo(evdev, code, (struct input_absinfo *)data);
+               EVDEV_UNLOCK(evdev);
+               return (0);
+
+       case EVIOCSFF:
+       case EVIOCRMFF:
+       case EVIOCGEFFECTS:
+               /* Fake unsupported ioctls */
+               return (0);
+
+       case EVIOCGRAB:
+               EVDEV_LOCK(evdev);
+               if (*(int *)data)
+                       ret = evdev_grab_client(evdev, client);
+               else
+                       ret = evdev_release_client(evdev, client);
+               EVDEV_UNLOCK(evdev);
+               return (ret);
+
+       case EVIOCREVOKE:
+               if (*(int *)data != 0)
+                       return (EINVAL);
+
+               EVDEV_LOCK(evdev);
+               if (dev->si_drv1 != NULL && !client->ec_revoked) {
+                       evdev_dispose_client(evdev, client);
+                       evdev_revoke_client(client);
+               }
+               EVDEV_UNLOCK(evdev);
+               return (0);
+
+       case EVIOCSCLOCKID:
+               switch (*(int *)data) {
+               case CLOCK_REALTIME:
+                       client->ec_clock_id = EV_CLOCK_REALTIME;
+                       return (0);
+               case CLOCK_MONOTONIC:
+                       client->ec_clock_id = EV_CLOCK_MONOTONIC;
+                       return (0);
+               default:
+                       return (EINVAL);
+               }
+       }
+
+       /* evdev variable-length ioctls handling */
+       switch (IOCBASECMD(cmd)) {
+       case EVIOCGNAME(0):
+               strlcpy(data, evdev->ev_name, len);
+               return (0);
+
+       case EVIOCGPHYS(0):
+               if (evdev->ev_shortname[0] == 0)
+                       return (ENOENT);
+
+               strlcpy(data, evdev->ev_shortname, len);
+               return (0);
+
+       case EVIOCGUNIQ(0):
+               if (evdev->ev_serial[0] == 0)
+                       return (ENOENT);
+
+               strlcpy(data, evdev->ev_serial, len);
+               return (0);
+
+       case EVIOCGPROP(0):
+               limit = MIN(len, bitstr_size(INPUT_PROP_CNT));
+               memcpy(data, evdev->ev_prop_flags, limit);
+               return (0);
+
+       case EVIOCGMTSLOTS(0):
+               if (evdev->ev_mt == NULL)
+                       return (EINVAL);
+               if (len < sizeof(uint32_t))
+                       return (EINVAL);
+               code = *(uint32_t *)data;
+               if (!ABS_IS_MT(code))
+                       return (EINVAL);
+
+               nvalues =
+                   MIN(len / sizeof(int32_t) - 1, MAXIMAL_MT_SLOT(evdev) + 1);
+               for (int i = 0; i < nvalues; i++)
+                       ((int32_t *)data)[i + 1] =
+                           evdev_get_mt_value(evdev, i, code);
+               return (0);
+
+       case EVIOCGKEY(0):
+               limit = MIN(len, bitstr_size(KEY_CNT));
+               EVDEV_LOCK(evdev);
+               evdev_client_filter_queue(client, EV_KEY);
+               memcpy(data, evdev->ev_key_states, limit);
+               EVDEV_UNLOCK(evdev);
+               return (0);
+
+       case EVIOCGLED(0):
+               limit = MIN(len, bitstr_size(LED_CNT));
+               EVDEV_LOCK(evdev);
+               evdev_client_filter_queue(client, EV_LED);
+               memcpy(data, evdev->ev_led_states, limit);
+               EVDEV_UNLOCK(evdev);
+               return (0);
+
+       case EVIOCGSND(0):
+               limit = MIN(len, bitstr_size(SND_CNT));
+               EVDEV_LOCK(evdev);
+               evdev_client_filter_queue(client, EV_SND);
+               memcpy(data, evdev->ev_snd_states, limit);
+               EVDEV_UNLOCK(evdev);
+               return (0);
+
+       case EVIOCGSW(0):
+               limit = MIN(len, bitstr_size(SW_CNT));
+               EVDEV_LOCK(evdev);
+               evdev_client_filter_queue(client, EV_SW);
+               memcpy(data, evdev->ev_sw_states, limit);
+               EVDEV_UNLOCK(evdev);
+               return (0);
+
+       case EVIOCGBIT(0, 0) ... EVIOCGBIT(EV_MAX, 0):
+               type_num = IOCBASECMD(cmd) - EVIOCGBIT(0, 0);
+               debugf(client, "EVIOCGBIT(%d): data=%p, len=%d", type_num,
+                   data, len);
+               return (evdev_ioctl_eviocgbit(evdev, type_num, len, data));
+       }
+
+       return (EINVAL);
+}
+
+static int
+evdev_ioctl_eviocgbit(struct evdev_dev *evdev, int type, int len, caddr_t data)
+{
+       unsigned long *bitmap;
+       int limit;
+
+       switch (type) {
+       case 0:
+               bitmap = evdev->ev_type_flags;
+               limit = EV_CNT;
+               break;
+       case EV_KEY:
+               bitmap = evdev->ev_key_flags;
+               limit = KEY_CNT;
+               break;
+       case EV_REL:
+               bitmap = evdev->ev_rel_flags;
+               limit = REL_CNT;
+               break;
+       case EV_ABS:
+               bitmap = evdev->ev_abs_flags;
+               limit = ABS_CNT;
+               break;
+       case EV_MSC:
+               bitmap = evdev->ev_msc_flags;
+               limit = MSC_CNT;
+               break;
+       case EV_LED:
+               bitmap = evdev->ev_led_flags;
+               limit = LED_CNT;
+               break;
+       case EV_SND:
+               bitmap = evdev->ev_snd_flags;
+               limit = SND_CNT;
+               break;
+       case EV_SW:
+               bitmap = evdev->ev_sw_flags;
+               limit = SW_CNT;
+               break;
+       case EV_FF:
+               /*
+                * We don't support EV_FF now, so let's
+                * just fake it returning only zeros.
+                */
+               bzero(data, len);
+               return (0);
+       default:
+               return (ENOTTY);
+       }
+
+       /*
+        * Clear ioctl data buffer in case it's bigger than
+        * bitmap size
+        */
+       bzero(data, len);
+
+       limit = bitstr_size(limit);
+       len = MIN(limit, len);
+       memcpy(data, bitmap, len);
+       return (0);
+}
+
+void
+evdev_revoke_client(struct evdev_client *client)
+{
+
+       EVDEV_LOCK_ASSERT(client->ec_evdev);
+
+       client->ec_revoked = true;
+}
+
+void
+evdev_notify_event(struct evdev_client *client)
+{
+
+       EVDEV_CLIENT_LOCKQ_ASSERT(client);
+
+       if (client->ec_blocked) {
+               client->ec_blocked = false;
+               wakeup(client);
+       }
+       if (client->ec_selected) {
+               client->ec_selected = false;
+               selwakeup(&client->ec_selp);
+       }
+       KNOTE_LOCKED(&client->ec_selp.si_note, 0);
+
+       if (client->ec_async && client->ec_sigio != NULL)
+               pgsigio(&client->ec_sigio, SIGIO, 0);
+}
+
+int
+evdev_cdev_create(struct evdev_dev *evdev)
+{
+       struct make_dev_args mda;
+       int ret, unit = 0;
+
+       make_dev_args_init(&mda);
+       mda.mda_flags = MAKEDEV_WAITOK | MAKEDEV_CHECKNAME;
+       mda.mda_devsw = &evdev_cdevsw;
+       mda.mda_uid = UID_ROOT;
+       mda.mda_gid = GID_WHEEL;
+       mda.mda_mode = 0600;
+       mda.mda_si_drv1 = evdev;
+
+       /* Try to coexist with cuse-backed input/event devices */
+       while ((ret = make_dev_s(&mda, &evdev->ev_cdev, "input/event%d", unit))
+           == EEXIST)
+               unit++;
+
+       if (ret == 0)
+               evdev->ev_unit = unit;
+
+       return (ret);
+}
+
+int
+evdev_cdev_destroy(struct evdev_dev *evdev)
+{
+
+       destroy_dev(evdev->ev_cdev);
+       return (0);
+}
+
+static void
+evdev_client_gettime(struct evdev_client *client, struct timeval *tv)
+{
+
+       switch (client->ec_clock_id) {
+       case EV_CLOCK_BOOTTIME:
+               /*
+                * XXX: FreeBSD does not support true POSIX monotonic clock.
+                *      So aliase EV_CLOCK_BOOTTIME to EV_CLOCK_MONOTONIC.
+                */
+       case EV_CLOCK_MONOTONIC:
+               microuptime(tv);
+               break;
+
+       case EV_CLOCK_REALTIME:
+       default:
+               microtime(tv);
+               break;
+       }
+}
+
+void
+evdev_client_push(struct evdev_client *client, uint16_t type, uint16_t code,
+    int32_t value)
+{
+       struct timeval time;
+       size_t count, head, tail, ready;
+
+       EVDEV_CLIENT_LOCKQ_ASSERT(client);
+       head = client->ec_buffer_head;
+       tail = client->ec_buffer_tail;
+       ready = client->ec_buffer_ready;
+       count = client->ec_buffer_size;
+
+       /* If queue is full drop its content and place SYN_DROPPED event */
+       if ((tail + 1) % count == head) {
+               debugf(client, "client %p: buffer overflow", client);
+
+               head = (tail + count - 1) % count;
+               client->ec_buffer[head] = (struct input_event) {
+                       .type = EV_SYN,
+                       .code = SYN_DROPPED,
+                       .value = 0
+               };
+               /*
+                * XXX: Here is a small race window from now till the end of
+                *      report. The queue is empty but client has been already
+                *      notified of data readyness. Can be fixed in two ways:
+                * 1. Implement bulk insert so queue lock would not be dropped
+                *    till the SYN_REPORT event.
+                * 2. Insert SYN_REPORT just now and skip remaining events
+                */
+               client->ec_buffer_head = head;
+               client->ec_buffer_ready = head;
+       }
+
+       client->ec_buffer[tail].type = type;
+       client->ec_buffer[tail].code = code;
+       client->ec_buffer[tail].value = value;
+       client->ec_buffer_tail = (tail + 1) % count;
+
+       /* Allow users to read events only after report has been completed */
+       if (type == EV_SYN && code == SYN_REPORT) {
+               evdev_client_gettime(client, &time);
+               for (; ready != client->ec_buffer_tail;
+                   ready = (ready + 1) % count)
+                       client->ec_buffer[ready].time = time;
+               client->ec_buffer_ready = client->ec_buffer_tail;
+       }
+}
+
+void
+evdev_client_dumpqueue(struct evdev_client *client)
+{
+       struct input_event *event;
+       size_t i, head, tail, ready, size;
+
+       head = client->ec_buffer_head;
+       tail = client->ec_buffer_tail;
+       ready = client->ec_buffer_ready;
+       size = client->ec_buffer_size;
+
+       printf("evdev client: %p\n", client);
+       printf("event queue: head=%zu ready=%zu tail=%zu size=%zu\n",
+           head, ready, tail, size);
+
+       printf("queue contents:\n");
+
+       for (i = 0; i < size; i++) {
+               event = &client->ec_buffer[i];
+               printf("%zu: ", i);
+
+               if (i < head || i > tail)
+                       printf("unused\n");
+               else
+                       printf("type=%d code=%d value=%d ", event->type,
+                           event->code, event->value);
+
+               if (i == head)
+                       printf("<- head\n");
+               else if (i == tail)
+                       printf("<- tail\n");
+               else if (i == ready)
+                       printf("<- ready\n");
+               else
+                       printf("\n");
+       }
+}
+
+static void
+evdev_client_filter_queue(struct evdev_client *client, uint16_t type)
+{
+       struct input_event *event;
+       size_t head, tail, count, i;
+       bool last_was_syn = false;
+
+       EVDEV_CLIENT_LOCKQ(client);
+
+       i = head = client->ec_buffer_head;
+       tail = client->ec_buffer_tail;
+       count = client->ec_buffer_size;
+       client->ec_buffer_ready = client->ec_buffer_tail;
+
+       while (i != client->ec_buffer_tail) {
+               event = &client->ec_buffer[i];
+               i = (i + 1) % count;
+
+               /* Skip event of given type */
+               if (event->type == type)
+                       continue;
+
+               /* Remove empty SYN_REPORT events */
+               if (event->type == EV_SYN && event->code == SYN_REPORT) {
+                       if (last_was_syn)
+                               continue;
+                       else
+                               client->ec_buffer_ready = (tail + 1) % count;
+               }
+
+               /* Rewrite entry */
+               memcpy(&client->ec_buffer[tail], event,
+                   sizeof(struct input_event));
+
+               last_was_syn = (event->type == EV_SYN &&
+                   event->code == SYN_REPORT);
+
+               tail = (tail + 1) % count;
+       }
+
+       client->ec_buffer_head = i;
+       client->ec_buffer_tail = tail;
+
+       EVDEV_CLIENT_UNLOCKQ(client);
+}
diff --git a/freebsd/sys/dev/evdev/evdev.c b/freebsd/sys/dev/evdev/evdev.c
new file mode 100644
index 0000000..e7575d5
--- /dev/null
+++ b/freebsd/sys/dev/evdev/evdev.c
@@ -0,0 +1,939 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2014 Jakub Wojciech Klama <jc...@freebsd.org>
+ * Copyright (c) 2015-2016 Vladimir Kondratyev <w...@cicgroup.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <rtems/bsd/local/opt_evdev.h>
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <rtems/bsd/sys/param.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/conf.h>
+#include <sys/malloc.h>
+#include <sys/bitstring.h>
+#include <sys/sysctl.h>
+
+#include <dev/evdev/input.h>
+#include <dev/evdev/evdev.h>
+#include <dev/evdev/evdev_private.h>
+
+#ifdef EVDEV_DEBUG
+#define        debugf(evdev, fmt, args...)     printf("evdev: " fmt "\n", 
##args)
+#else
+#define        debugf(evdev, fmt, args...)
+#endif
+
+#ifdef FEATURE
+FEATURE(evdev, "Input event devices support");
+#endif
+
+enum evdev_sparse_result
+{
+       EV_SKIP_EVENT,          /* Event value not changed */
+       EV_REPORT_EVENT,        /* Event value changed */
+       EV_REPORT_MT_SLOT,      /* Event value and MT slot number changed */
+};
+
+MALLOC_DEFINE(M_EVDEV, "evdev", "evdev memory");
+
+int evdev_rcpt_mask = EVDEV_RCPT_SYSMOUSE | EVDEV_RCPT_KBDMUX;
+int evdev_sysmouse_t_axis = 0;
+
+SYSCTL_NODE(_kern, OID_AUTO, evdev, CTLFLAG_RW, 0, "Evdev args");
+SYSCTL_INT(_kern_evdev, OID_AUTO, rcpt_mask, CTLFLAG_RW, &evdev_rcpt_mask, 0,
+    "Who is receiving events: bit0 - sysmouse, bit1 - kbdmux, "
+    "bit2 - mouse hardware, bit3 - keyboard hardware");
+SYSCTL_INT(_kern_evdev, OID_AUTO, sysmouse_t_axis, CTLFLAG_RW,
+    &evdev_sysmouse_t_axis, 0, "Extract T-axis from 0-none, 1-ums, 2-psm");
+
+static void evdev_start_repeat(struct evdev_dev *, uint16_t);
+static void evdev_stop_repeat(struct evdev_dev *);
+static int evdev_check_event(struct evdev_dev *, uint16_t, uint16_t, int32_t);
+
+static inline void
+bit_change(bitstr_t *bitstr, int bit, int value)
+{
+       if (value)
+               bit_set(bitstr, bit);
+       else
+               bit_clear(bitstr, bit);
+}
+
+struct evdev_dev *
+evdev_alloc(void)
+{
+
+       return malloc(sizeof(struct evdev_dev), M_EVDEV, M_WAITOK | M_ZERO);
+}
+
+void
+evdev_free(struct evdev_dev *evdev)
+{
+
+       if (evdev != NULL && evdev->ev_cdev != NULL &&
+           evdev->ev_cdev->si_drv1 != NULL)
+               evdev_unregister(evdev);
+
+       free(evdev, M_EVDEV);
+}
+
+static struct input_absinfo *
+evdev_alloc_absinfo(void)
+{
+
+       return (malloc(sizeof(struct input_absinfo) * ABS_CNT, M_EVDEV,
+           M_WAITOK | M_ZERO));
+}
+
+static void
+evdev_free_absinfo(struct input_absinfo *absinfo)
+{
+
+       free(absinfo, M_EVDEV);
+}
+
+int
+evdev_set_report_size(struct evdev_dev *evdev, size_t report_size)
+{
+       if (report_size > KEY_CNT + REL_CNT + ABS_CNT + MAX_MT_SLOTS * MT_CNT +
+           MSC_CNT + LED_CNT + SND_CNT + SW_CNT + FF_CNT)
+               return (EINVAL);
+
+       evdev->ev_report_size = report_size;
+       return (0);
+}
+
+static size_t
+evdev_estimate_report_size(struct evdev_dev *evdev)
+{
+       size_t size = 0;
+       int res;
+
+       /*
+        * Keyboards generate one event per report but other devices with
+        * buttons like mouses can report events simultaneously
+        */
+       bit_ffs_at(evdev->ev_key_flags, KEY_OK, KEY_CNT - KEY_OK, &res);
+       if (res == -1)
+               bit_ffs(evdev->ev_key_flags, BTN_MISC, &res);
+       size += (res != -1);
+       bit_count(evdev->ev_key_flags, BTN_MISC, KEY_OK - BTN_MISC, &res);
+       size += res;
+
+       /* All relative axes can be reported simultaneously */
+       bit_count(evdev->ev_rel_flags, 0, REL_CNT, &res);
+       size += res;
+
+       /*
+        * All absolute axes can be reported simultaneously.
+        * Multitouch axes can be reported ABS_MT_SLOT times
+        */
+       if (evdev->ev_absinfo != NULL) {
+               bit_count(evdev->ev_abs_flags, 0, ABS_CNT, &res);
+               size += res;
+               bit_count(evdev->ev_abs_flags, ABS_MT_FIRST, MT_CNT, &res);
+               if (res > 0) {
+                       res++;  /* ABS_MT_SLOT or SYN_MT_REPORT */
+                       if (bit_test(evdev->ev_abs_flags, ABS_MT_SLOT))
+                               /* MT type B */
+                               size += res * MAXIMAL_MT_SLOT(evdev);
+                       else
+                               /* MT type A */
+                               size += res * (MAX_MT_REPORTS - 1);
+               }
+       }
+
+       /* All misc events can be reported simultaneously */
+       bit_count(evdev->ev_msc_flags, 0, MSC_CNT, &res);
+       size += res;
+
+       /* All leds can be reported simultaneously */
+       bit_count(evdev->ev_led_flags, 0, LED_CNT, &res);
+       size += res;
+
+       /* Assume other events are generated once per report */
+       bit_ffs(evdev->ev_snd_flags, SND_CNT, &res);
+       size += (res != -1);
+
+       bit_ffs(evdev->ev_sw_flags, SW_CNT, &res);
+       size += (res != -1);
+
+       /* XXX: FF part is not implemented yet */
+
+       size++;         /* SYN_REPORT */
+       return (size);
+}
+
+static int
+evdev_register_common(struct evdev_dev *evdev)
+{
+       int ret;
+
+       debugf(evdev, "%s: registered evdev provider: %s <%s>\n",
+           evdev->ev_shortname, evdev->ev_name, evdev->ev_serial);
+
+       /* Initialize internal structures */
+       LIST_INIT(&evdev->ev_clients);
+
+       if (evdev_event_supported(evdev, EV_REP) &&
+           bit_test(evdev->ev_flags, EVDEV_FLAG_SOFTREPEAT)) {
+               /* Initialize callout */
+               callout_init_mtx(&evdev->ev_rep_callout, &evdev->ev_mtx, 0);
+
+               if (evdev->ev_rep[REP_DELAY] == 0 &&
+                   evdev->ev_rep[REP_PERIOD] == 0) {
+                       /* Supply default values */
+                       evdev->ev_rep[REP_DELAY] = 250;
+                       evdev->ev_rep[REP_PERIOD] = 33;
+               }
+       }
+
+       /* Initialize multitouch protocol type B states */
+       if (bit_test(evdev->ev_abs_flags, ABS_MT_SLOT) &&
+           evdev->ev_absinfo != NULL && MAXIMAL_MT_SLOT(evdev) > 0)
+               evdev_mt_init(evdev);
+
+       /* Estimate maximum report size */
+       if (evdev->ev_report_size == 0) {
+               ret = evdev_set_report_size(evdev,
+                   evdev_estimate_report_size(evdev));
+               if (ret != 0)
+                       goto bail_out;
+       }
+
+       /* Create char device node */
+       ret = evdev_cdev_create(evdev);
+bail_out:
+       return (ret);
+}
+
+int
+evdev_register(struct evdev_dev *evdev)
+{
+       int ret;
+
+       evdev->ev_lock_type = EV_LOCK_INTERNAL;
+       evdev->ev_lock = &evdev->ev_mtx;
+       mtx_init(&evdev->ev_mtx, "evmtx", NULL, MTX_DEF);
+
+       ret = evdev_register_common(evdev);
+       if (ret != 0)
+               mtx_destroy(&evdev->ev_mtx);
+
+       return (ret);
+}
+
+int
+evdev_register_mtx(struct evdev_dev *evdev, struct mtx *mtx)
+{
+
+       evdev->ev_lock_type = EV_LOCK_MTX;
+       evdev->ev_lock = mtx;
+       return (evdev_register_common(evdev));
+}
+
+int
+evdev_unregister(struct evdev_dev *evdev)
+{
+       struct evdev_client *client;
+       int ret;
+       debugf(evdev, "%s: unregistered evdev provider: %s\n",
+           evdev->ev_shortname, evdev->ev_name);
+
+       EVDEV_LOCK(evdev);
+       evdev->ev_cdev->si_drv1 = NULL;
+       /* Wake up sleepers */
+       LIST_FOREACH(client, &evdev->ev_clients, ec_link) {
+               evdev_revoke_client(client);
+               evdev_dispose_client(evdev, client);
+               EVDEV_CLIENT_LOCKQ(client);
+               evdev_notify_event(client);
+               EVDEV_CLIENT_UNLOCKQ(client);
+       }
+       EVDEV_UNLOCK(evdev);
+
+       /* destroy_dev can sleep so release lock */
+       ret = evdev_cdev_destroy(evdev);
+       evdev->ev_cdev = NULL;
+       if (ret == 0 && evdev->ev_lock_type == EV_LOCK_INTERNAL)
+               mtx_destroy(&evdev->ev_mtx);
+
+       evdev_free_absinfo(evdev->ev_absinfo);
+       evdev_mt_free(evdev);
+
+       return (ret);
+}
+
+inline void
+evdev_set_name(struct evdev_dev *evdev, const char *name)
+{
+
+       snprintf(evdev->ev_name, NAMELEN, "%s", name);
+}
+
+inline void
+evdev_set_id(struct evdev_dev *evdev, uint16_t bustype, uint16_t vendor,
+    uint16_t product, uint16_t version)
+{
+
+       evdev->ev_id = (struct input_id) {
+               .bustype = bustype,
+               .vendor = vendor,
+               .product = product,
+               .version = version
+       };
+}
+
+inline void
+evdev_set_phys(struct evdev_dev *evdev, const char *name)
+{
+
+       snprintf(evdev->ev_shortname, NAMELEN, "%s", name);
+}
+
+inline void
+evdev_set_serial(struct evdev_dev *evdev, const char *serial)
+{
+
+       snprintf(evdev->ev_serial, NAMELEN, "%s", serial);
+}
+
+inline void
+evdev_set_methods(struct evdev_dev *evdev, void *softc,
+    const struct evdev_methods *methods)
+{
+
+       evdev->ev_methods = methods;
+       evdev->ev_softc = softc;
+}
+
+inline void
+evdev_support_prop(struct evdev_dev *evdev, uint16_t prop)
+{
+
+       KASSERT(prop < INPUT_PROP_CNT, ("invalid evdev input property"));
+       bit_set(evdev->ev_prop_flags, prop);
+}
+
+inline void
+evdev_support_event(struct evdev_dev *evdev, uint16_t type)
+{
+
+       KASSERT(type < EV_CNT, ("invalid evdev event property"));
+       bit_set(evdev->ev_type_flags, type);
+}
+
+inline void
+evdev_support_key(struct evdev_dev *evdev, uint16_t code)
+{
+
+       KASSERT(code < KEY_CNT, ("invalid evdev key property"));
+       bit_set(evdev->ev_key_flags, code);
+}
+
+inline void
+evdev_support_rel(struct evdev_dev *evdev, uint16_t code)
+{
+
+       KASSERT(code < REL_CNT, ("invalid evdev rel property"));
+       bit_set(evdev->ev_rel_flags, code);
+}
+
+inline void
+evdev_support_abs(struct evdev_dev *evdev, uint16_t code, int32_t value,
+    int32_t minimum, int32_t maximum, int32_t fuzz, int32_t flat,
+    int32_t resolution)
+{
+       struct input_absinfo absinfo;
+
+       KASSERT(code < ABS_CNT, ("invalid evdev abs property"));
+
+       absinfo = (struct input_absinfo) {
+               .value = value,
+               .minimum = minimum,
+               .maximum = maximum,
+               .fuzz = fuzz,
+               .flat = flat,
+               .resolution = resolution,
+       };
+       evdev_set_abs_bit(evdev, code);
+       evdev_set_absinfo(evdev, code, &absinfo);
+}
+
+inline void
+evdev_set_abs_bit(struct evdev_dev *evdev, uint16_t code)
+{
+
+       KASSERT(code < ABS_CNT, ("invalid evdev abs property"));
+       if (evdev->ev_absinfo == NULL)
+               evdev->ev_absinfo = evdev_alloc_absinfo();
+       bit_set(evdev->ev_abs_flags, code);
+}
+
+inline void
+evdev_support_msc(struct evdev_dev *evdev, uint16_t code)
+{
+
+       KASSERT(code < MSC_CNT, ("invalid evdev msc property"));
+       bit_set(evdev->ev_msc_flags, code);
+}
+
+
+inline void
+evdev_support_led(struct evdev_dev *evdev, uint16_t code)
+{
+
+       KASSERT(code < LED_CNT, ("invalid evdev led property"));
+       bit_set(evdev->ev_led_flags, code);
+}
+
+inline void
+evdev_support_snd(struct evdev_dev *evdev, uint16_t code)
+{
+
+       KASSERT(code < SND_CNT, ("invalid evdev snd property"));
+       bit_set(evdev->ev_snd_flags, code);
+}
+
+inline void
+evdev_support_sw(struct evdev_dev *evdev, uint16_t code)
+{
+
+       KASSERT(code < SW_CNT, ("invalid evdev sw property"));
+       bit_set(evdev->ev_sw_flags, code);
+}
+
+bool
+evdev_event_supported(struct evdev_dev *evdev, uint16_t type)
+{
+
+       KASSERT(type < EV_CNT, ("invalid evdev event property"));
+       return (bit_test(evdev->ev_type_flags, type));
+}
+
+inline void
+evdev_set_absinfo(struct evdev_dev *evdev, uint16_t axis,
+    struct input_absinfo *absinfo)
+{
+
+       KASSERT(axis < ABS_CNT, ("invalid evdev abs property"));
+
+       if (axis == ABS_MT_SLOT &&
+           (absinfo->maximum < 1 || absinfo->maximum >= MAX_MT_SLOTS))
+               return;
+
+       if (evdev->ev_absinfo == NULL)
+               evdev->ev_absinfo = evdev_alloc_absinfo();
+
+       if (axis == ABS_MT_SLOT)
+               evdev->ev_absinfo[ABS_MT_SLOT].maximum = absinfo->maximum;
+       else
+               memcpy(&evdev->ev_absinfo[axis], absinfo,
+                   sizeof(struct input_absinfo));
+}
+
+inline void
+evdev_set_repeat_params(struct evdev_dev *evdev, uint16_t property, int value)
+{
+
+       KASSERT(property < REP_CNT, ("invalid evdev repeat property"));
+       evdev->ev_rep[property] = value;
+}
+
+inline void
+evdev_set_flag(struct evdev_dev *evdev, uint16_t flag)
+{
+
+       KASSERT(flag < EVDEV_FLAG_CNT, ("invalid evdev flag property"));
+       bit_set(evdev->ev_flags, flag);
+}
+
+static int
+evdev_check_event(struct evdev_dev *evdev, uint16_t type, uint16_t code,
+    int32_t value)
+{
+
+       if (type >= EV_CNT)
+               return (EINVAL);
+
+       /* Allow SYN events implicitly */
+       if (type != EV_SYN && !evdev_event_supported(evdev, type))
+               return (EINVAL);
+
+       switch (type) {
+       case EV_SYN:
+               if (code >= SYN_CNT)
+                       return (EINVAL);
+               break;
+
+       case EV_KEY:
+               if (code >= KEY_CNT)
+                       return (EINVAL);
+               if (!bit_test(evdev->ev_key_flags, code))
+                       return (EINVAL);
+               break;
+
+       case EV_REL:
+               if (code >= REL_CNT)
+                       return (EINVAL);
+               if (!bit_test(evdev->ev_rel_flags, code))
+                       return (EINVAL);
+               break;
+
+       case EV_ABS:
+               if (code >= ABS_CNT)
+                       return (EINVAL);
+               if (!bit_test(evdev->ev_abs_flags, code))
+                       return (EINVAL);
+               if (code == ABS_MT_SLOT &&
+                   (value < 0 || value > MAXIMAL_MT_SLOT(evdev)))
+                       return (EINVAL);
+               if (ABS_IS_MT(code) && evdev->ev_mt == NULL &&
+                   bit_test(evdev->ev_abs_flags, ABS_MT_SLOT))
+                       return (EINVAL);
+               break;
+
+       case EV_MSC:
+               if (code >= MSC_CNT)
+                       return (EINVAL);
+               if (!bit_test(evdev->ev_msc_flags, code))
+                       return (EINVAL);
+               break;
+
+       case EV_LED:
+               if (code >= LED_CNT)
+                       return (EINVAL);
+               if (!bit_test(evdev->ev_led_flags, code))
+                       return (EINVAL);
+               break;
+
+       case EV_SND:
+               if (code >= SND_CNT)
+                       return (EINVAL);
+               if (!bit_test(evdev->ev_snd_flags, code))
+                       return (EINVAL);
+               break;
+
+       case EV_SW:
+               if (code >= SW_CNT)
+                       return (EINVAL);
+               if (!bit_test(evdev->ev_sw_flags, code))
+                       return (EINVAL);
+               break;
+
+       case EV_REP:
+               if (code >= REP_CNT)
+                       return (EINVAL);
+               break;
+
+       default:
+               return (EINVAL);
+       }
+
+       return (0);
+}
+
+static void
+evdev_modify_event(struct evdev_dev *evdev, uint16_t type, uint16_t code,
+    int32_t *value)
+{
+
+       EVDEV_LOCK_ASSERT(evdev);
+
+       switch (type) {
+       case EV_KEY:
+               if (!evdev_event_supported(evdev, EV_REP))
+                       break;
+
+               if (!bit_test(evdev->ev_flags, EVDEV_FLAG_SOFTREPEAT)) {
+                       /* Detect driver key repeats. */
+                       if (bit_test(evdev->ev_key_states, code) &&
+                           *value == KEY_EVENT_DOWN)
+                               *value = KEY_EVENT_REPEAT;
+               } else {
+                       /* Start/stop callout for evdev repeats */
+                       if (bit_test(evdev->ev_key_states, code) == !*value) {
+                               if (*value == KEY_EVENT_DOWN)
+                                       evdev_start_repeat(evdev, code);
+                               else
+                                       evdev_stop_repeat(evdev);
+                       }
+               }
+               break;
+
+       case EV_ABS:
+               /* TBD: implement fuzz */
+               break;
+       }
+}
+
+static enum evdev_sparse_result
+evdev_sparse_event(struct evdev_dev *evdev, uint16_t type, uint16_t code,
+    int32_t value)
+{
+       int32_t last_mt_slot;
+
+       EVDEV_LOCK_ASSERT(evdev);
+
+       /*
+        * For certain event types, update device state bits
+        * and convert level reporting to edge reporting
+        */
+       switch (type) {
+       case EV_KEY:
+               switch (value) {
+               case KEY_EVENT_UP:
+               case KEY_EVENT_DOWN:
+                       if (bit_test(evdev->ev_key_states, code) == value)
+                               return (EV_SKIP_EVENT);
+                       bit_change(evdev->ev_key_states, code, value);
+                       break;
+
+               case KEY_EVENT_REPEAT:
+                       if (bit_test(evdev->ev_key_states, code) == 0 ||
+                           !evdev_event_supported(evdev, EV_REP))
+                               return (EV_SKIP_EVENT);
+                       break;
+
+               default:
+                        return (EV_SKIP_EVENT);
+               }
+               break;
+
+       case EV_LED:
+               if (bit_test(evdev->ev_led_states, code) == value)
+                       return (EV_SKIP_EVENT);
+               bit_change(evdev->ev_led_states, code, value);
+               break;
+
+       case EV_SND:
+               if (bit_test(evdev->ev_snd_states, code) == value)
+                       return (EV_SKIP_EVENT);
+               bit_change(evdev->ev_snd_states, code, value);
+               break;
+
+       case EV_SW:
+               if (bit_test(evdev->ev_sw_states, code) == value)
+                       return (EV_SKIP_EVENT);
+               bit_change(evdev->ev_sw_states, code, value);
+               break;
+
+       case EV_REP:
+               if (evdev->ev_rep[code] == value)
+                       return (EV_SKIP_EVENT);
+               evdev_set_repeat_params(evdev, code, value);
+               break;
+
+       case EV_REL:
+               if (value == 0)
+                       return (EV_SKIP_EVENT);
+               break;
+
+       /* For EV_ABS, save last value in absinfo and ev_mt_states */
+       case EV_ABS:
+               switch (code) {
+               case ABS_MT_SLOT:
+                       /* Postpone ABS_MT_SLOT till next event */
+                       evdev_set_last_mt_slot(evdev, value);
+                       return (EV_SKIP_EVENT);
+
+               case ABS_MT_FIRST ... ABS_MT_LAST:
+                       /* Pass MT protocol type A events as is */
+                       if (!bit_test(evdev->ev_abs_flags, ABS_MT_SLOT))
+                               break;
+                       /* Don`t repeat MT protocol type B events */
+                       last_mt_slot = evdev_get_last_mt_slot(evdev);
+                       if (evdev_get_mt_value(evdev, last_mt_slot, code)
+                            == value)
+                               return (EV_SKIP_EVENT);
+                       evdev_set_mt_value(evdev, last_mt_slot, code, value);
+                       if (last_mt_slot != CURRENT_MT_SLOT(evdev)) {
+                               CURRENT_MT_SLOT(evdev) = last_mt_slot;
+                               evdev->ev_report_opened = true;
+                               return (EV_REPORT_MT_SLOT);
+                       }
+                       break;
+
+               default:
+                       if (evdev->ev_absinfo[code].value == value)
+                               return (EV_SKIP_EVENT);
+                       evdev->ev_absinfo[code].value = value;
+               }
+               break;
+
+       case EV_SYN:
+               if (code == SYN_REPORT) {
+                       /* Count empty reports as well as non empty */
+                       evdev->ev_report_count++;
+                       /* Skip empty reports */
+                       if (!evdev->ev_report_opened)
+                               return (EV_SKIP_EVENT);
+                       evdev->ev_report_opened = false;
+                       return (EV_REPORT_EVENT);
+               }
+               break;
+       }
+
+       evdev->ev_report_opened = true;
+       return (EV_REPORT_EVENT);
+}
+
+static void
+evdev_propagate_event(struct evdev_dev *evdev, uint16_t type, uint16_t code,
+    int32_t value)
+{
+       struct evdev_client *client;
+
+       debugf(evdev, "%s pushed event %d/%d/%d",
+           evdev->ev_shortname, type, code, value);
+
+       EVDEV_LOCK_ASSERT(evdev);
+
+       /* Propagate event through all clients */
+       LIST_FOREACH(client, &evdev->ev_clients, ec_link) {
+               if (evdev->ev_grabber != NULL && evdev->ev_grabber != client)
+                       continue;
+
+               EVDEV_CLIENT_LOCKQ(client);
+               evdev_client_push(client, type, code, value);
+               if (type == EV_SYN && code == SYN_REPORT)
+                       evdev_notify_event(client);
+               EVDEV_CLIENT_UNLOCKQ(client);
+       }
+
+       evdev->ev_event_count++;
+}
+
+void
+evdev_send_event(struct evdev_dev *evdev, uint16_t type, uint16_t code,
+    int32_t value)
+{
+       enum evdev_sparse_result sparse;
+
+       EVDEV_LOCK_ASSERT(evdev);
+
+       sparse =  evdev_sparse_event(evdev, type, code, value);
+       switch (sparse) {
+       case EV_REPORT_MT_SLOT:
+               /* report postponed ABS_MT_SLOT */
+               evdev_propagate_event(evdev, EV_ABS, ABS_MT_SLOT,
+                   CURRENT_MT_SLOT(evdev));
+               /* FALLTHROUGH */
+       case EV_REPORT_EVENT:
+               evdev_propagate_event(evdev, type, code, value);
+               /* FALLTHROUGH */
+       case EV_SKIP_EVENT:
+               break;
+       }
+}
+
+int
+evdev_push_event(struct evdev_dev *evdev, uint16_t type, uint16_t code,
+    int32_t value)
+{
+
+       if (evdev->ev_lock_type != EV_LOCK_INTERNAL)
+               EVDEV_LOCK_ASSERT(evdev);
+
+       if (evdev_check_event(evdev, type, code, value) != 0)
+               return (EINVAL);
+
+       if (evdev->ev_lock_type == EV_LOCK_INTERNAL)
+               EVDEV_LOCK(evdev);
+       evdev_modify_event(evdev, type, code, &value);
+       if (type == EV_SYN && code == SYN_REPORT &&
+            bit_test(evdev->ev_flags, EVDEV_FLAG_MT_AUTOREL))
+               evdev_send_mt_autorel(evdev);
+       if (type == EV_SYN && code == SYN_REPORT && evdev->ev_report_opened &&
+           bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT))
+               evdev_send_mt_compat(evdev);
+       evdev_send_event(evdev, type, code, value);
+       if (evdev->ev_lock_type == EV_LOCK_INTERNAL)
+               EVDEV_UNLOCK(evdev);
+
+       return (0);
+}
+
+int
+evdev_inject_event(struct evdev_dev *evdev, uint16_t type, uint16_t code,
+    int32_t value)
+{
+       int ret = 0;
+
+       switch (type) {
+       case EV_REP:
+               /* evdev repeats should not be processed by hardware driver */
+               if (bit_test(evdev->ev_flags, EVDEV_FLAG_SOFTREPEAT))
+                       goto push;
+               /* FALLTHROUGH */
+       case EV_LED:
+       case EV_MSC:
+       case EV_SND:
+       case EV_FF:
+               if (evdev->ev_methods != NULL &&
+                   evdev->ev_methods->ev_event != NULL)
+                       evdev->ev_methods->ev_event(evdev, evdev->ev_softc,
+                           type, code, value);
+               /*
+                * Leds and driver repeats should be reported in ev_event
+                * method body to interoperate with kbdmux states and rates
+                * propagation so both ways (ioctl and evdev) of changing it
+                * will produce only one evdev event report to client.
+                */
+               if (type == EV_LED || type == EV_REP)
+                       break;
+               /* FALLTHROUGH */
+       case EV_SYN:
+       case EV_KEY:
+       case EV_REL:
+       case EV_ABS:
+       case EV_SW:
+push:
+               ret = evdev_push_event(evdev, type,  code, value);
+               break;
+
+       default:
+               ret = EINVAL;
+       }
+
+       return (ret);
+}
+
+int
+evdev_register_client(struct evdev_dev *evdev, struct evdev_client *client)
+{
+       int ret = 0;
+
+       debugf(evdev, "adding new client for device %s", evdev->ev_shortname);
+
+       EVDEV_LOCK_ASSERT(evdev);
+
+       if (LIST_EMPTY(&evdev->ev_clients) && evdev->ev_methods != NULL &&
+           evdev->ev_methods->ev_open != NULL) {
+               debugf(evdev, "calling ev_open() on device %s",
+                   evdev->ev_shortname);
+               ret = evdev->ev_methods->ev_open(evdev, evdev->ev_softc);
+       }
+       if (ret == 0)
+               LIST_INSERT_HEAD(&evdev->ev_clients, client, ec_link);
+       return (ret);
+}
+
+void
+evdev_dispose_client(struct evdev_dev *evdev, struct evdev_client *client)
+{
+       debugf(evdev, "removing client for device %s", evdev->ev_shortname);
+
+       EVDEV_LOCK_ASSERT(evdev);
+
+       LIST_REMOVE(client, ec_link);
+       if (LIST_EMPTY(&evdev->ev_clients)) {
+               if (evdev->ev_methods != NULL &&
+                   evdev->ev_methods->ev_close != NULL)
+                       evdev->ev_methods->ev_close(evdev, evdev->ev_softc);
+               if (evdev_event_supported(evdev, EV_REP) &&
+                   bit_test(evdev->ev_flags, EVDEV_FLAG_SOFTREPEAT))
+                       evdev_stop_repeat(evdev);
+       }
+       evdev_release_client(evdev, client);
+}
+
+int
+evdev_grab_client(struct evdev_dev *evdev, struct evdev_client *client)
+{
+
+       EVDEV_LOCK_ASSERT(evdev);
+
+       if (evdev->ev_grabber != NULL)
+               return (EBUSY);
+
+       evdev->ev_grabber = client;
+
+       return (0);
+}
+
+int
+evdev_release_client(struct evdev_dev *evdev, struct evdev_client *client)
+{
+
+       EVDEV_LOCK_ASSERT(evdev);
+
+       if (evdev->ev_grabber != client)
+               return (EINVAL);
+
+       evdev->ev_grabber = NULL;
+
+       return (0);
+}
+
+static void
+evdev_repeat_callout(void *arg)
+{
+       struct evdev_dev *evdev = (struct evdev_dev *)arg;
+
+       evdev_send_event(evdev, EV_KEY, evdev->ev_rep_key, KEY_EVENT_REPEAT);
+       evdev_send_event(evdev, EV_SYN, SYN_REPORT, 1);
+
+       if (evdev->ev_rep[REP_PERIOD])
+               callout_reset(&evdev->ev_rep_callout,
+                   evdev->ev_rep[REP_PERIOD] * hz / 1000,
+                   evdev_repeat_callout, evdev);
+       else
+               evdev->ev_rep_key = KEY_RESERVED;
+}
+
+static void
+evdev_start_repeat(struct evdev_dev *evdev, uint16_t key)
+{
+
+       EVDEV_LOCK_ASSERT(evdev);
+
+       if (evdev->ev_rep[REP_DELAY]) {
+               evdev->ev_rep_key = key;
+               callout_reset(&evdev->ev_rep_callout,
+                   evdev->ev_rep[REP_DELAY] * hz / 1000,
+                   evdev_repeat_callout, evdev);
+       }
+}
+
+static void
+evdev_stop_repeat(struct evdev_dev *evdev)
+{
+
+       EVDEV_LOCK_ASSERT(evdev);
+
+       if (evdev->ev_rep_key != KEY_RESERVED) {
+               callout_stop(&evdev->ev_rep_callout);
+               evdev->ev_rep_key = KEY_RESERVED;
+       }
+}
+
+MODULE_VERSION(evdev, 1);
diff --git a/freebsd/sys/dev/evdev/evdev.h b/freebsd/sys/dev/evdev/evdev.h
new file mode 100644
index 0000000..946913c
--- /dev/null
+++ b/freebsd/sys/dev/evdev/evdev.h
@@ -0,0 +1,210 @@
+/*-
+ * Copyright (c) 2014 Jakub Wojciech Klama <jc...@freebsd.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef        _DEV_EVDEV_EVDEV_H
+#define        _DEV_EVDEV_EVDEV_H
+
+#include <sys/types.h>
+#include <sys/kbio.h>
+#include <dev/evdev/input.h>
+#include <dev/kbd/kbdreg.h>
+
+#define        NAMELEN         80
+
+struct evdev_dev;
+
+typedef int (evdev_open_t)(struct evdev_dev *, void *);
+typedef void (evdev_close_t)(struct evdev_dev *, void *);
+typedef void (evdev_event_t)(struct evdev_dev *, void *, uint16_t,
+    uint16_t, int32_t);
+typedef void (evdev_keycode_t)(struct evdev_dev *, void *,
+    struct input_keymap_entry *);
+
+/*
+ * Keyboard and mouse events recipient mask.
+ * evdev_rcpt_mask variable should be respected by keyboard and mouse drivers
+ * that are able to send events through both evdev and sysmouse/kbdmux
+ * interfaces so user can choose prefered one to not receive one event twice.
+ */
+#define        EVDEV_RCPT_SYSMOUSE     (1<<0)
+#define        EVDEV_RCPT_KBDMUX       (1<<1)
+#define        EVDEV_RCPT_HW_MOUSE     (1<<2)
+#define        EVDEV_RCPT_HW_KBD       (1<<3)
+extern int evdev_rcpt_mask;
+/*
+ * Sysmouse protocol does not support horizontal wheel movement reporting.
+ * To overcome this limitation different drivers use different sysmouse proto
+ * extensions. Set kern.evdev.sysmouse_t_axis to tell sysmouse evdev driver
+ * which protocol extension is used.
+ * 0 - do not extract horizontal wheel movement (default).
+ * 1 - ums(4) horizontal wheel encoding. T-axis is mapped to buttons 6 and 7
+ * 2 - psm(4) wheels encoding: z = 1,-1 - vert. wheel, z = 2,-2 - horiz. wheel
+ */
+enum
+{
+       EVDEV_SYSMOUSE_T_AXIS_NONE = 0,
+       EVDEV_SYSMOUSE_T_AXIS_UMS = 1,
+       EVDEV_SYSMOUSE_T_AXIS_PSM = 2,
+};
+extern int evdev_sysmouse_t_axis;
+
+#define        ABS_MT_FIRST    ABS_MT_TOUCH_MAJOR
+#define        ABS_MT_LAST     ABS_MT_TOOL_Y
+#define        ABS_IS_MT(x)    ((x) >= ABS_MT_FIRST && (x) <= ABS_MT_LAST)
+#define        ABS_MT_INDEX(x) ((x) - ABS_MT_FIRST)
+#define        MT_CNT          (ABS_MT_INDEX(ABS_MT_LAST) + 1)
+/* Multitouch protocol type A */
+#define        MAX_MT_REPORTS  5
+/* Multitouch protocol type B interface */
+#define        MAX_MT_SLOTS    16
+
+#define        EVDEV_FLAG_SOFTREPEAT   0x00    /* use evdev to repeat keys */
+#define        EVDEV_FLAG_MT_STCOMPAT  0x01    /* autogenerate ST-compatible 
events
+                                        * for MT protocol type B reports */
+#define        EVDEV_FLAG_MT_AUTOREL   0x02    /* Autorelease MT-slots not 
listed in
+                                        * current MT protocol type B report */
+#define        EVDEV_FLAG_MAX          0x1F
+#define        EVDEV_FLAG_CNT          (EVDEV_FLAG_MAX + 1)
+
+struct evdev_methods
+{
+       evdev_open_t            *ev_open;
+       evdev_close_t           *ev_close;
+       evdev_event_t           *ev_event;
+       evdev_keycode_t         *ev_get_keycode;
+       evdev_keycode_t         *ev_set_keycode;
+};
+
+/* Input device interface: */
+struct evdev_dev *evdev_alloc(void);
+void evdev_free(struct evdev_dev *);
+void evdev_set_name(struct evdev_dev *, const char *);
+void evdev_set_id(struct evdev_dev *, uint16_t, uint16_t, uint16_t, uint16_t);
+void evdev_set_phys(struct evdev_dev *, const char *);
+void evdev_set_serial(struct evdev_dev *, const char *);
+void evdev_set_methods(struct evdev_dev *, void *,
+    const struct evdev_methods *);
+int evdev_register(struct evdev_dev *);
+int evdev_register_mtx(struct evdev_dev *, struct mtx *);
+int evdev_unregister(struct evdev_dev *);
+int evdev_push_event(struct evdev_dev *, uint16_t, uint16_t, int32_t);
+void evdev_support_prop(struct evdev_dev *, uint16_t);
+void evdev_support_event(struct evdev_dev *, uint16_t);
+void evdev_support_key(struct evdev_dev *, uint16_t);
+void evdev_support_rel(struct evdev_dev *, uint16_t);
+void evdev_support_abs(struct evdev_dev *, uint16_t, int32_t, int32_t, int32_t,
+   int32_t, int32_t, int32_t);
+void evdev_support_msc(struct evdev_dev *, uint16_t);
+void evdev_support_led(struct evdev_dev *, uint16_t);
+void evdev_support_snd(struct evdev_dev *, uint16_t);
+void evdev_support_sw(struct evdev_dev *, uint16_t);
+void evdev_set_repeat_params(struct evdev_dev *, uint16_t, int);
+int evdev_set_report_size(struct evdev_dev *, size_t);
+void evdev_set_flag(struct evdev_dev *, uint16_t);
+
+/* Multitouch related functions: */
+int32_t evdev_get_mt_slot_by_tracking_id(struct evdev_dev *, int32_t);
+void evdev_support_nfingers(struct evdev_dev *, int32_t);
+void evdev_support_mt_compat(struct evdev_dev *);
+void evdev_push_nfingers(struct evdev_dev *, int32_t);
+void evdev_push_mt_compat(struct evdev_dev *);
+
+/* Utility functions: */
+uint16_t evdev_hid2key(int);
+void evdev_support_all_known_keys(struct evdev_dev *);
+uint16_t evdev_scancode2key(int *, int);
+void evdev_push_mouse_btn(struct evdev_dev *, int);
+void evdev_push_leds(struct evdev_dev *, int);
+void evdev_push_repeats(struct evdev_dev *, keyboard_t *);
+evdev_event_t evdev_ev_kbd_event;
+
+/* Event reporting shortcuts: */
+static __inline int
+evdev_sync(struct evdev_dev *evdev)
+{
+
+       return (evdev_push_event(evdev, EV_SYN, SYN_REPORT, 1));
+}
+
+static __inline int
+evdev_mt_sync(struct evdev_dev *evdev)
+{
+
+       return (evdev_push_event(evdev, EV_SYN, SYN_MT_REPORT, 1));
+}
+
+static __inline int
+evdev_push_key(struct evdev_dev *evdev, uint16_t code, int32_t value)
+{
+
+       return (evdev_push_event(evdev, EV_KEY, code, value != 0));
+}
+
+static __inline int
+evdev_push_rel(struct evdev_dev *evdev, uint16_t code, int32_t value)
+{
+
+       return (evdev_push_event(evdev, EV_REL, code, value));
+}
+
+static __inline int
+evdev_push_abs(struct evdev_dev *evdev, uint16_t code, int32_t value)
+{
+
+       return (evdev_push_event(evdev, EV_ABS, code, value));
+}
+
+static __inline int
+evdev_push_msc(struct evdev_dev *evdev, uint16_t code, int32_t value)
+{
+
+       return (evdev_push_event(evdev, EV_MSC, code, value));
+}
+
+static __inline int
+evdev_push_led(struct evdev_dev *evdev, uint16_t code, int32_t value)
+{
+
+       return (evdev_push_event(evdev, EV_LED, code, value != 0));
+}
+
+static __inline int
+evdev_push_snd(struct evdev_dev *evdev, uint16_t code, int32_t value)
+{
+
+       return (evdev_push_event(evdev, EV_SND, code, value != 0));
+}
+
+static __inline int
+evdev_push_sw(struct evdev_dev *evdev, uint16_t code, int32_t value)
+{
+
+       return (evdev_push_event(evdev, EV_SW, code, value != 0));
+}
+
+#endif /* _DEV_EVDEV_EVDEV_H */
diff --git a/freebsd/sys/dev/evdev/evdev_mt.c b/freebsd/sys/dev/evdev/evdev_mt.c
new file mode 100644
index 0000000..9eb8a54
--- /dev/null
+++ b/freebsd/sys/dev/evdev/evdev_mt.c
@@ -0,0 +1,294 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2016 Vladimir Kondratyev <w...@cicgroup.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <rtems/bsd/sys/param.h>
+#include <sys/malloc.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/mutex.h>
+#include <sys/systm.h>
+
+#include <dev/evdev/input.h>
+#include <dev/evdev/evdev.h>
+#include <dev/evdev/evdev_private.h>
+
+#ifdef DEBUG
+#define        debugf(fmt, args...)    printf("evdev: " fmt "\n", ##args)
+#else
+#define        debugf(fmt, args...)
+#endif
+
+static uint16_t evdev_fngmap[] = {
+       BTN_TOOL_FINGER,
+       BTN_TOOL_DOUBLETAP,
+       BTN_TOOL_TRIPLETAP,
+       BTN_TOOL_QUADTAP,
+       BTN_TOOL_QUINTTAP,
+};
+
+static uint16_t evdev_mtstmap[][2] = {
+       { ABS_MT_POSITION_X, ABS_X },
+       { ABS_MT_POSITION_Y, ABS_Y },
+       { ABS_MT_PRESSURE, ABS_PRESSURE },
+       { ABS_MT_TOUCH_MAJOR, ABS_TOOL_WIDTH },
+};
+
+struct evdev_mt_slot {
+       uint64_t ev_report;
+       int32_t ev_mt_states[MT_CNT];
+};
+
+struct evdev_mt {
+       int32_t ev_mt_last_reported_slot;
+       struct evdev_mt_slot ev_mt_slots[];
+};
+
+void
+evdev_mt_init(struct evdev_dev *evdev)
+{
+       int32_t slot, slots;
+
+       slots = MAXIMAL_MT_SLOT(evdev) + 1;
+
+       evdev->ev_mt = malloc(offsetof(struct evdev_mt, ev_mt_slots) +
+            sizeof(struct evdev_mt_slot) * slots, M_EVDEV, M_WAITOK | M_ZERO);
+
+       /* Initialize multitouch protocol type B states */
+       for (slot = 0; slot < slots; slot++) {
+               /*
+                * .ev_report should not be initialized to initial value of
+                * report counter (0) as it brokes free slot detection in
+                * evdev_get_mt_slot_by_tracking_id. So initialize it to -1
+                */
+               evdev->ev_mt->ev_mt_slots[slot] = (struct evdev_mt_slot) {
+                       .ev_report = 0xFFFFFFFFFFFFFFFFULL,
+                       .ev_mt_states[ABS_MT_INDEX(ABS_MT_TRACKING_ID)] = -1,
+               };
+       }
+
+       if (bit_test(evdev->ev_flags, EVDEV_FLAG_MT_STCOMPAT))
+               evdev_support_mt_compat(evdev);
+}
+
+void
+evdev_mt_free(struct evdev_dev *evdev)
+{
+
+       free(evdev->ev_mt, M_EVDEV);
+}
+
+int32_t
+evdev_get_last_mt_slot(struct evdev_dev *evdev)
+{
+
+       return (evdev->ev_mt->ev_mt_last_reported_slot);
+}
+
+void
+evdev_set_last_mt_slot(struct evdev_dev *evdev, int32_t slot)
+{
+
+       evdev->ev_mt->ev_mt_slots[slot].ev_report = evdev->ev_report_count;
+       evdev->ev_mt->ev_mt_last_reported_slot = slot;
+}
+
+inline int32_t
+evdev_get_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code)
+{
+
+       return (evdev->ev_mt->
+           ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)]);
+}
+
+inline void
+evdev_set_mt_value(struct evdev_dev *evdev, int32_t slot, int16_t code,
+    int32_t value)
+{
+
+       evdev->ev_mt->ev_mt_slots[slot].ev_mt_states[ABS_MT_INDEX(code)] =
+           value;
+}
+
+int32_t
+evdev_get_mt_slot_by_tracking_id(struct evdev_dev *evdev, int32_t tracking_id)
+{
+       int32_t tr_id, slot, free_slot = -1;
+
+       for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) {
+               tr_id = evdev_get_mt_value(evdev, slot, ABS_MT_TRACKING_ID);
+               if (tr_id == tracking_id)
+                       return (slot);
+               /*
+                * Its possible that slot will be reassigned in a place of just
+                * released one within the same report. To avoid this compare
+                * report counter with slot`s report number updated with each
+                * ABS_MT_TRACKING_ID change.
+                */
+               if (free_slot == -1 && tr_id == -1 &&
+                   evdev->ev_mt->ev_mt_slots[slot].ev_report !=
+                   evdev->ev_report_count)
+                       free_slot = slot;
+       }
+
+       return (free_slot);
+}
+
+void
+evdev_support_nfingers(struct evdev_dev *evdev, int32_t nfingers)
+{
+       int32_t i;
+
+       for (i = 0; i < MIN(nitems(evdev_fngmap), nfingers); i++)
+               evdev_support_key(evdev, evdev_fngmap[i]);
+}
+
+void
+evdev_support_mt_compat(struct evdev_dev *evdev)
+{
+       int32_t i;
+
+       if (evdev->ev_absinfo == NULL)
+               return;
+
+       evdev_support_event(evdev, EV_KEY);
+       evdev_support_key(evdev, BTN_TOUCH);
+
+       /* Touchscreens should not advertise tap tool capabilities */
+       if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
+               evdev_support_nfingers(evdev, MAXIMAL_MT_SLOT(evdev) + 1);
+
+       /* Echo 0-th MT-slot as ST-slot */
+       for (i = 0; i < nitems(evdev_mtstmap); i++)
+               if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][0]))
+                       evdev_support_abs(evdev, evdev_mtstmap[i][1],
+                           evdev->ev_absinfo[evdev_mtstmap[i][0]].value,
+                           evdev->ev_absinfo[evdev_mtstmap[i][0]].minimum,
+                           evdev->ev_absinfo[evdev_mtstmap[i][0]].maximum,
+                           evdev->ev_absinfo[evdev_mtstmap[i][0]].fuzz,
+                           evdev->ev_absinfo[evdev_mtstmap[i][0]].flat,
+                           evdev->ev_absinfo[evdev_mtstmap[i][0]].resolution);
+}
+
+static int32_t
+evdev_count_fingers(struct evdev_dev *evdev)
+{
+       int32_t nfingers = 0, i;
+
+       for (i = 0; i <= MAXIMAL_MT_SLOT(evdev); i++)
+               if (evdev_get_mt_value(evdev, i, ABS_MT_TRACKING_ID) != -1)
+                       nfingers++;
+
+       return (nfingers);
+}
+
+static void
+evdev_send_nfingers(struct evdev_dev *evdev, int32_t nfingers)
+{
+       int32_t i;
+
+       EVDEV_LOCK_ASSERT(evdev);
+
+       if (nfingers > nitems(evdev_fngmap))
+               nfingers = nitems(evdev_fngmap);
+
+       for (i = 0; i < nitems(evdev_fngmap); i++)
+               evdev_send_event(evdev, EV_KEY, evdev_fngmap[i],
+                   nfingers == i + 1);
+}
+
+void
+evdev_push_nfingers(struct evdev_dev *evdev, int32_t nfingers)
+{
+
+       if (evdev->ev_lock_type == EV_LOCK_INTERNAL)
+               EVDEV_LOCK(evdev);
+       else
+               EVDEV_LOCK_ASSERT(evdev);
+       evdev_send_nfingers(evdev, nfingers);
+       if (evdev->ev_lock_type == EV_LOCK_INTERNAL)
+               EVDEV_UNLOCK(evdev);
+}
+
+void
+evdev_send_mt_compat(struct evdev_dev *evdev)
+{
+       int32_t nfingers, i;
+
+       EVDEV_LOCK_ASSERT(evdev);
+
+       nfingers = evdev_count_fingers(evdev);
+       evdev_send_event(evdev, EV_KEY, BTN_TOUCH, nfingers > 0);
+
+       if (evdev_get_mt_value(evdev, 0, ABS_MT_TRACKING_ID) != -1)
+               /* Echo 0-th MT-slot as ST-slot */
+               for (i = 0; i < nitems(evdev_mtstmap); i++)
+                       if (bit_test(evdev->ev_abs_flags, evdev_mtstmap[i][1]))
+                               evdev_send_event(evdev, EV_ABS,
+                                   evdev_mtstmap[i][1],
+                                   evdev_get_mt_value(evdev, 0,
+                                   evdev_mtstmap[i][0]));
+
+       /* Touchscreens should not report tool taps */
+       if (!bit_test(evdev->ev_prop_flags, INPUT_PROP_DIRECT))
+               evdev_send_nfingers(evdev, nfingers);
+
+       if (nfingers == 0)
+               evdev_send_event(evdev, EV_ABS, ABS_PRESSURE, 0);
+}
+
+void
+evdev_push_mt_compat(struct evdev_dev *evdev)
+{
+
+       if (evdev->ev_lock_type == EV_LOCK_INTERNAL)
+               EVDEV_LOCK(evdev);
+       else
+               EVDEV_LOCK_ASSERT(evdev);
+       evdev_send_mt_compat(evdev);
+       if (evdev->ev_lock_type == EV_LOCK_INTERNAL)
+               EVDEV_UNLOCK(evdev);
+}
+
+void
+evdev_send_mt_autorel(struct evdev_dev *evdev)
+{
+       int32_t slot;
+
+       EVDEV_LOCK_ASSERT(evdev);
+
+       for (slot = 0; slot <= MAXIMAL_MT_SLOT(evdev); slot++) {
+               if (evdev->ev_mt->ev_mt_slots[slot].ev_report !=
+                   evdev->ev_report_count &&
+                   evdev_get_mt_value(evdev, slot, ABS_MT_TRACKING_ID) != -1){
+                       evdev_send_event(evdev, EV_ABS, ABS_MT_SLOT, slot);
+                       evdev_send_event(evdev, EV_ABS, ABS_MT_TRACKING_ID,
+                           -1);
+               }
+       }
+}
diff --git a/freebsd/sys/dev/evdev/evdev_private.h 
b/freebsd/sys/dev/evdev/evdev_private.h
new file mode 100644
index 0000000..b3de1bf
--- /dev/null
+++ b/freebsd/sys/dev/evdev/evdev_private.h
@@ -0,0 +1,200 @@
+/*-
+ * Copyright (c) 2014 Jakub Wojciech Klama <jc...@freebsd.org>
+ * Copyright (c) 2015-2016 Vladimir Kondratyev <w...@cicgroup.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef        _DEV_EVDEV_EVDEV_PRIVATE_H
+#define        _DEV_EVDEV_EVDEV_PRIVATE_H
+
+#include <sys/bitstring.h>
+#include <sys/queue.h>
+#include <sys/malloc.h>
+#include <sys/kbio.h>
+#include <sys/selinfo.h>
+#include <dev/evdev/evdev.h>
+#include <dev/evdev/input.h>
+#include <dev/kbd/kbdreg.h>
+
+#define        NAMELEN         80
+
+/*
+ * bitstr_t implementation must be identical to one found in EVIOCG*
+ * libevdev ioctls. Our bitstring(3) API is compatible since r299090.
+ */
+_Static_assert(sizeof(bitstr_t) == sizeof(unsigned long),
+    "bitstr_t size mismatch");
+
+MALLOC_DECLARE(M_EVDEV);
+
+struct evdev_client;
+struct evdev_mt;
+
+#define        CURRENT_MT_SLOT(evdev)  ((evdev)->ev_absinfo[ABS_MT_SLOT].value)
+#define        MAXIMAL_MT_SLOT(evdev)  
((evdev)->ev_absinfo[ABS_MT_SLOT].maximum)
+
+enum evdev_key_events
+{
+       KEY_EVENT_UP,
+       KEY_EVENT_DOWN,
+       KEY_EVENT_REPEAT
+};
+
+/* evdev clock IDs in Linux semantic */
+enum evdev_clock_id
+{
+       EV_CLOCK_REALTIME = 0,  /* UTC clock */
+       EV_CLOCK_MONOTONIC,     /* monotonic, stops on suspend */
+       EV_CLOCK_BOOTTIME       /* monotonic, suspend-awared */
+};
+
+enum evdev_lock_type
+{
+       EV_LOCK_INTERNAL = 0,   /* Internal evdev mutex */
+       EV_LOCK_MTX,            /* Driver`s mutex */
+};
+
+struct evdev_dev
+{
+       char                    ev_name[NAMELEN];
+       char                    ev_shortname[NAMELEN];
+       char                    ev_serial[NAMELEN];
+       struct cdev *           ev_cdev;
+       int                     ev_unit;
+       enum evdev_lock_type    ev_lock_type;
+       struct mtx *            ev_lock;
+       struct mtx              ev_mtx;
+       struct input_id         ev_id;
+       struct evdev_client *   ev_grabber;
+       size_t                  ev_report_size;
+
+       /* Supported features: */
+       bitstr_t                bit_decl(ev_prop_flags, INPUT_PROP_CNT);
+       bitstr_t                bit_decl(ev_type_flags, EV_CNT);
+       bitstr_t                bit_decl(ev_key_flags, KEY_CNT);
+       bitstr_t                bit_decl(ev_rel_flags, REL_CNT);
+       bitstr_t                bit_decl(ev_abs_flags, ABS_CNT);
+       bitstr_t                bit_decl(ev_msc_flags, MSC_CNT);
+       bitstr_t                bit_decl(ev_led_flags, LED_CNT);
+       bitstr_t                bit_decl(ev_snd_flags, SND_CNT);
+       bitstr_t                bit_decl(ev_sw_flags, SW_CNT);
+       struct input_absinfo *  ev_absinfo;
+       bitstr_t                bit_decl(ev_flags, EVDEV_FLAG_CNT);
+
+       /* Repeat parameters & callout: */
+       int                     ev_rep[REP_CNT];
+       struct callout          ev_rep_callout;
+       uint16_t                ev_rep_key;
+
+       /* State: */
+       bitstr_t                bit_decl(ev_key_states, KEY_CNT);
+       bitstr_t                bit_decl(ev_led_states, LED_CNT);
+       bitstr_t                bit_decl(ev_snd_states, SND_CNT);
+       bitstr_t                bit_decl(ev_sw_states, SW_CNT);
+       bool                    ev_report_opened;
+
+       /* Multitouch protocol type B state: */
+       struct evdev_mt *       ev_mt;
+
+       /* Counters: */
+       uint64_t                ev_event_count;
+       uint64_t                ev_report_count;
+
+       /* Parent driver callbacks: */
+       const struct evdev_methods * ev_methods;
+       void *                  ev_softc;
+
+       LIST_ENTRY(evdev_dev) ev_link;
+       LIST_HEAD(, evdev_client) ev_clients;
+};
+
+#define        EVDEV_LOCK(evdev)               mtx_lock((evdev)->ev_lock)
+#define        EVDEV_UNLOCK(evdev)             mtx_unlock((evdev)->ev_lock)
+#define        EVDEV_LOCK_ASSERT(evdev)        mtx_assert((evdev)->ev_lock, 
MA_OWNED)
+
+struct evdev_client
+{
+       struct evdev_dev *      ec_evdev;
+       struct mtx              ec_buffer_mtx;
+       size_t                  ec_buffer_size;
+       size_t                  ec_buffer_head;
+       size_t                  ec_buffer_tail;
+       size_t                  ec_buffer_ready;
+       enum evdev_clock_id     ec_clock_id;
+       struct selinfo          ec_selp;
+       struct sigio *          ec_sigio;
+       bool                    ec_async;
+       bool                    ec_revoked;
+       bool                    ec_blocked;
+       bool                    ec_selected;
+
+       LIST_ENTRY(evdev_client) ec_link;
+
+       struct input_event      ec_buffer[];
+};
+
+#define        EVDEV_CLIENT_LOCKQ(client)      
mtx_lock(&(client)->ec_buffer_mtx)
+#define        EVDEV_CLIENT_UNLOCKQ(client)    
mtx_unlock(&(client)->ec_buffer_mtx)
+#define EVDEV_CLIENT_LOCKQ_ASSERT(client) \
+    mtx_assert(&(client)->ec_buffer_mtx, MA_OWNED)
+#define        EVDEV_CLIENT_EMPTYQ(client) \
+    ((client)->ec_buffer_head == (client)->ec_buffer_ready)
+#define        EVDEV_CLIENT_SIZEQ(client) \
+    (((client)->ec_buffer_ready + (client)->ec_buffer_size - \
+      (client)->ec_buffer_head) % (client)->ec_buffer_size)
+
+/* Input device interface: */
+void evdev_send_event(struct evdev_dev *, uint16_t, uint16_t, int32_t);
+int evdev_inject_event(struct evdev_dev *, uint16_t, uint16_t, int32_t);
+int evdev_cdev_create(struct evdev_dev *);
+int evdev_cdev_destroy(struct evdev_dev *);
+bool evdev_event_supported(struct evdev_dev *, uint16_t);
+void evdev_set_abs_bit(struct evdev_dev *, uint16_t);
+void evdev_set_absinfo(struct evdev_dev *, uint16_t, struct input_absinfo *);
+
+/* Client interface: */
+int evdev_register_client(struct evdev_dev *, struct evdev_client *);
+void evdev_dispose_client(struct evdev_dev *, struct evdev_client *);
+int evdev_grab_client(struct evdev_dev *, struct evdev_client *);
+int evdev_release_client(struct evdev_dev *, struct evdev_client *);
+void evdev_client_push(struct evdev_client *, uint16_t, uint16_t, int32_t);
+void evdev_notify_event(struct evdev_client *);
+void evdev_revoke_client(struct evdev_client *);
+
+/* Multitouch related functions: */
+void evdev_mt_init(struct evdev_dev *);
+void evdev_mt_free(struct evdev_dev *);
+int32_t evdev_get_last_mt_slot(struct evdev_dev *);
+void evdev_set_last_mt_slot(struct evdev_dev *, int32_t);
+int32_t evdev_get_mt_value(struct evdev_dev *, int32_t, int16_t);
+void evdev_set_mt_value(struct evdev_dev *, int32_t, int16_t, int32_t);
+void evdev_send_mt_compat(struct evdev_dev *);
+void evdev_send_mt_autorel(struct evdev_dev *);
+
+/* Utility functions: */
+void evdev_client_dumpqueue(struct evdev_client *);
+
+#endif /* _DEV_EVDEV_EVDEV_PRIVATE_H */
diff --git a/freebsd/sys/dev/evdev/evdev_utils.c 
b/freebsd/sys/dev/evdev/evdev_utils.c
new file mode 100644
index 0000000..787cc2d
--- /dev/null
+++ b/freebsd/sys/dev/evdev/evdev_utils.c
@@ -0,0 +1,335 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2014 Jakub Wojciech Klama <jc...@freebsd.org>
+ * Copyright (c) 2015-2016 Vladimir Kondratyev <w...@cicgroup.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <rtems/bsd/sys/param.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/conf.h>
+#include <sys/malloc.h>
+#include <sys/kbio.h>
+
+#include <dev/evdev/input.h>
+#include <dev/evdev/evdev.h>
+
+#include <dev/kbd/kbdreg.h>
+
+#define        NONE    KEY_RESERVED
+
+static uint16_t evdev_usb_scancodes[256] = {
+       /* 0x00 - 0x27 */
+       NONE,   NONE,   NONE,   NONE,   KEY_A,  KEY_B,  KEY_C,  KEY_D,
+       KEY_E,  KEY_F,  KEY_G,  KEY_H,  KEY_I,  KEY_J,  KEY_K,  KEY_L,
+       KEY_M,  KEY_N,  KEY_O,  KEY_P,  KEY_Q,  KEY_R,  KEY_S,  KEY_T,
+       KEY_U,  KEY_V,  KEY_W,  KEY_X,  KEY_Y,  KEY_Z,  KEY_1,  KEY_2,
+       KEY_3,  KEY_4,  KEY_5,  KEY_6,  KEY_7,  KEY_8,  KEY_9,  KEY_0,
+       /* 0x28 - 0x3f */
+       KEY_ENTER,      KEY_ESC,        KEY_BACKSPACE,  KEY_TAB,
+       KEY_SPACE,      KEY_MINUS,      KEY_EQUAL,      KEY_LEFTBRACE,
+       KEY_RIGHTBRACE, KEY_BACKSLASH,  KEY_BACKSLASH,  KEY_SEMICOLON,
+       KEY_APOSTROPHE, KEY_GRAVE,      KEY_COMMA,      KEY_DOT,
+       KEY_SLASH,      KEY_CAPSLOCK,   KEY_F1,         KEY_F2,
+       KEY_F3,         KEY_F4,         KEY_F5,         KEY_F6,
+       /* 0x40 - 0x5f */
+       KEY_F7,         KEY_F8,         KEY_F9,         KEY_F10,
+       KEY_F11,        KEY_F12,        KEY_SYSRQ,      KEY_SCROLLLOCK,
+       KEY_PAUSE,      KEY_INSERT,     KEY_HOME,       KEY_PAGEUP,
+       KEY_DELETE,     KEY_END,        KEY_PAGEDOWN,   KEY_RIGHT,
+       KEY_LEFT,       KEY_DOWN,       KEY_UP,         KEY_NUMLOCK,
+       KEY_SLASH,      KEY_KPASTERISK, KEY_KPMINUS,    KEY_KPPLUS,
+       KEY_KPENTER,    KEY_KP1,        KEY_KP2,        KEY_KP3,
+       KEY_KP4,        KEY_KP5,        KEY_KP6,        KEY_KP7,
+       /* 0x60 - 0x7f */
+       KEY_KP8,        KEY_KP9,        KEY_KP0,        KEY_KPDOT,
+       KEY_102ND,      KEY_COMPOSE,    KEY_POWER,      KEY_KPEQUAL,
+       KEY_F13,        KEY_F14,        KEY_F15,        KEY_F16,
+       KEY_F17,        KEY_F18,        KEY_F19,        KEY_F20,
+       KEY_F21,        KEY_F22,        KEY_F23,        KEY_F24,
+       KEY_OPEN,       KEY_HELP,       KEY_PROPS,      KEY_FRONT,
+       KEY_STOP,       KEY_AGAIN,      KEY_UNDO,       KEY_CUT,
+       KEY_COPY,       KEY_PASTE,      KEY_FIND,       KEY_MUTE,
+       /* 0x80 - 0x9f */
+       KEY_VOLUMEUP,   KEY_VOLUMEDOWN, NONE,           NONE,
+       NONE,           KEY_KPCOMMA,    NONE,           KEY_RO,
+       KEY_KATAKANAHIRAGANA,   KEY_YEN,KEY_HENKAN,     KEY_MUHENKAN,
+       KEY_KPJPCOMMA,  NONE,           NONE,           NONE,
+       KEY_HANGEUL,    KEY_HANJA,      KEY_KATAKANA,   KEY_HIRAGANA,
+       KEY_ZENKAKUHANKAKU,     NONE,   NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       /* 0xa0 - 0xbf */
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       /* 0xc0 - 0xdf */
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       /* 0xe0 - 0xff */
+       KEY_LEFTCTRL,   KEY_LEFTSHIFT,  KEY_LEFTALT,    KEY_LEFTMETA,
+       KEY_RIGHTCTRL,  KEY_RIGHTSHIFT, KEY_RIGHTALT,   KEY_RIGHTMETA,
+       KEY_PLAYPAUSE,  KEY_STOPCD,     KEY_PREVIOUSSONG,KEY_NEXTSONG,
+       KEY_EJECTCD,    KEY_VOLUMEUP,   KEY_VOLUMEDOWN, KEY_MUTE,
+       KEY_WWW,        KEY_BACK,       KEY_FORWARD,    KEY_STOP,
+       KEY_FIND,       KEY_SCROLLUP,   KEY_SCROLLDOWN, KEY_EDIT,
+       KEY_SLEEP,      KEY_COFFEE,     KEY_REFRESH,    KEY_CALC,
+       NONE,           NONE,           NONE,           NONE,
+
+};
+
+static uint16_t evdev_at_set1_scancodes[] = {
+       /* 0x00 - 0x1f */
+       NONE,           KEY_ESC,        KEY_1,          KEY_2,
+       KEY_3,          KEY_4,          KEY_5,          KEY_6,
+       KEY_7,          KEY_8,          KEY_9,          KEY_0,
+       KEY_MINUS,      KEY_EQUAL,      KEY_BACKSPACE,  KEY_TAB,
+       KEY_Q,          KEY_W,          KEY_E,          KEY_R,
+       KEY_T,          KEY_Y,          KEY_U,          KEY_I,
+       KEY_O,          KEY_P,          KEY_LEFTBRACE,  KEY_RIGHTBRACE,
+       KEY_ENTER,      KEY_LEFTCTRL,   KEY_A,          KEY_S,
+       /* 0x20 - 0x3f */
+       KEY_D,          KEY_F,          KEY_G,          KEY_H,
+       KEY_J,          KEY_K,          KEY_L,          KEY_SEMICOLON,
+       KEY_APOSTROPHE, KEY_GRAVE,      KEY_LEFTSHIFT,  KEY_BACKSLASH,
+       KEY_Z,          KEY_X,          KEY_C,          KEY_V,
+       KEY_B,          KEY_N,          KEY_M,          KEY_COMMA,
+       KEY_DOT,        KEY_SLASH,      KEY_RIGHTSHIFT, NONE,
+       KEY_LEFTALT,    KEY_SPACE,      KEY_CAPSLOCK,   KEY_F1,
+       KEY_F2,         KEY_F3,         KEY_F4,         KEY_F5,
+       /* 0x40 - 0x5f */
+       KEY_F6,         KEY_F7,         KEY_F8,         KEY_F9,
+       KEY_F10,        KEY_NUMLOCK,    KEY_SCROLLLOCK, KEY_KP7,
+       KEY_KP8,        KEY_KP9,        KEY_KPMINUS,    KEY_KP4,
+       KEY_KP5,        KEY_KP6,        KEY_KPPLUS,     KEY_KP1,
+       KEY_KP2,        KEY_KP3,        KEY_KP0,        KEY_KPDOT,
+       NONE,           NONE,           NONE,           KEY_F11,
+       KEY_F12,        NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       /* 0x60 - 0x7f */
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       KEY_KATAKANAHIRAGANA,   NONE,   NONE,           KEY_RO,
+       NONE,           NONE,   KEY_ZENKAKUHANKAKU,     KEY_HIRAGANA,
+       KEY_KATAKANA,   KEY_HENKAN,     NONE,           KEY_MUHENKAN,
+       NONE,           KEY_YEN,        KEY_KPCOMMA,    NONE,
+       /* 0x00 - 0x1f. 0xE0 prefixed */
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       KEY_PREVIOUSSONG,       NONE,   NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           KEY_NEXTSONG,   NONE,           NONE,
+       KEY_KPENTER,    KEY_RIGHTCTRL,  NONE,           NONE,
+       /* 0x20 - 0x3f. 0xE0 prefixed */
+       KEY_MUTE,       KEY_CALC,       KEY_PLAYPAUSE,  NONE,
+       KEY_STOPCD,     NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           KEY_VOLUMEDOWN, NONE,
+       KEY_VOLUMEUP,   NONE,           KEY_HOMEPAGE,   NONE,
+       NONE,           KEY_KPASTERISK, NONE,           KEY_SYSRQ,
+       KEY_RIGHTALT,   NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       /* 0x40 - 0x5f. 0xE0 prefixed */
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           KEY_PAUSE,      KEY_HOME,
+       KEY_UP,         KEY_PAGEUP,     NONE,           KEY_LEFT,
+       NONE,           KEY_RIGHT,      NONE,           KEY_END,
+       KEY_DOWN,       KEY_PAGEDOWN,   KEY_INSERT,     KEY_DELETE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           KEY_LEFTMETA,
+       KEY_RIGHTMETA,  KEY_MENU,       KEY_POWER,      KEY_SLEEP,
+       /* 0x60 - 0x7f. 0xE0 prefixed */
+       NONE,           NONE,           NONE,           KEY_WAKEUP,
+       NONE,           KEY_SEARCH,     KEY_BOOKMARKS,  KEY_REFRESH,
+       KEY_STOP,       KEY_FORWARD,    KEY_BACK,       KEY_COMPUTER,
+       KEY_MAIL,       KEY_MEDIA,      NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+       NONE,           NONE,           NONE,           NONE,
+};
+
+static uint16_t evdev_mouse_button_codes[] = {
+       BTN_LEFT,
+       BTN_MIDDLE,
+       BTN_RIGHT,
+       BTN_SIDE,
+       BTN_EXTRA,
+       BTN_FORWARD,
+       BTN_BACK,
+       BTN_TASK,
+};
+
+static uint16_t evdev_led_codes[] = {
+       LED_CAPSL,      /* CLKED */
+       LED_NUML,       /* NLKED */
+       LED_SCROLLL,    /* SLKED */
+};
+
+uint16_t
+evdev_hid2key(int scancode)
+{
+       return evdev_usb_scancodes[scancode];
+}
+
+void
+evdev_support_all_known_keys(struct evdev_dev *evdev)
+{
+       size_t i;
+
+       for (i = KEY_RESERVED; i < nitems(evdev_at_set1_scancodes); i++)
+               if (evdev_at_set1_scancodes[i] != NONE)
+                       evdev_support_key(evdev, evdev_at_set1_scancodes[i]);
+}
+
+uint16_t
+evdev_scancode2key(int *state, int scancode)
+{
+       uint16_t keycode;
+
+       /* translate the scan code into a keycode */
+       keycode = evdev_at_set1_scancodes[scancode & 0x7f];
+       switch (*state) {
+       case 0x00:      /* normal scancode */
+               switch(scancode) {
+               case 0xE0:
+               case 0xE1:
+                       *state = scancode;
+                       return (NONE);
+               }
+               break;
+       case 0xE0:              /* 0xE0 prefix */
+               *state = 0;
+               keycode = evdev_at_set1_scancodes[0x80 + (scancode & 0x7f)];
+               break;
+       case 0xE1:      /* 0xE1 prefix */
+               /*
+                * The pause/break key on the 101 keyboard produces:
+                * E1-1D-45 E1-9D-C5
+                * Ctrl-pause/break produces:
+                * E0-46 E0-C6 (See above.)
+                */
+               *state = 0;
+               if ((scancode & 0x7f) == 0x1D)
+                       *state = 0x1D;
+               return (NONE);
+               /* NOT REACHED */
+       case 0x1D:      /* pause / break */
+               *state = 0;
+               if (scancode != 0x45)
+                       return (NONE);
+               keycode = KEY_PAUSE;
+               break;
+       }
+
+       return (keycode);
+}
+
+void
+evdev_push_mouse_btn(struct evdev_dev *evdev, int buttons)
+{
+       size_t i;
+
+       for (i = 0; i < nitems(evdev_mouse_button_codes); i++)
+               evdev_push_key(evdev, evdev_mouse_button_codes[i],
+                   buttons & (1 << i));
+}
+
+void
+evdev_push_leds(struct evdev_dev *evdev, int leds)
+{
+       size_t i;
+
+       /* Some drivers initialize leds before evdev */
+       if (evdev == NULL)
+               return;
+
+       for (i = 0; i < nitems(evdev_led_codes); i++)
+               evdev_push_led(evdev, evdev_led_codes[i], leds & (1 << i));
+}
+
+void
+evdev_push_repeats(struct evdev_dev *evdev, keyboard_t *kbd)
+{
+       /* Some drivers initialize typematics before evdev */
+       if (evdev == NULL)
+               return;
+
+       evdev_push_event(evdev, EV_REP, REP_DELAY, kbd->kb_delay1);
+       evdev_push_event(evdev, EV_REP, REP_PERIOD, kbd->kb_delay2);
+}
+
+void
+evdev_ev_kbd_event(struct evdev_dev *evdev, void *softc, uint16_t type,
+    uint16_t code, int32_t value)
+{
+       keyboard_t *kbd = (keyboard_t *)softc;
+       int delay[2], leds, oleds;
+       size_t i;
+
+       if (type == EV_LED) {
+               leds = oleds = KBD_LED_VAL(kbd);
+               for (i = 0; i < nitems(evdev_led_codes); i++) {
+                       if (evdev_led_codes[i] == code) {
+                               if (value)
+                                       leds |= 1 << i;
+                               else
+                                       leds &= ~(1 << i);
+                               if (leds != oleds)
+                                       kbdd_ioctl(kbd, KDSETLED,
+                                           (caddr_t)&leds);
+                               break;
+                       }
+               }
+       } else if (type == EV_REP && code == REP_DELAY) {
+               delay[0] = value;
+               delay[1] = kbd->kb_delay2;
+               kbdd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
+       } else if (type == EV_REP && code == REP_PERIOD) {
+               delay[0] = kbd->kb_delay1;
+               delay[1] = value;
+               kbdd_ioctl(kbd, KDSETREPEAT, (caddr_t)delay);
+       }
+}
diff --git a/freebsd/sys/dev/evdev/input-event-codes.h 
b/freebsd/sys/dev/evdev/input-event-codes.h
new file mode 100644
index 0000000..78ba7d2
--- /dev/null
+++ b/freebsd/sys/dev/evdev/input-event-codes.h
@@ -0,0 +1,819 @@
+/*-
+ * Copyright (c) 2016 Oleksandr Tymoshenko <go...@freebsd.org>
+ * Copyright (c) 2015-2016 Vladimir Kondratyev <w...@cicgroup.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef        _EVDEV_INPUT_EVENT_CODES_H
+#define        _EVDEV_INPUT_EVENT_CODES_H
+
+/*
+ * Device properties and quirks
+ */
+
+#define        INPUT_PROP_POINTER              0x00    /* needs a pointer */
+#define        INPUT_PROP_DIRECT               0x01    /* direct input devices 
*/
+#define        INPUT_PROP_BUTTONPAD            0x02    /* has button(s) under 
pad */
+#define        INPUT_PROP_SEMI_MT              0x03    /* touch rectangle only 
*/
+#define        INPUT_PROP_TOPBUTTONPAD         0x04    /* softbuttons at top 
of pad */
+#define        INPUT_PROP_POINTING_STICK       0x05    /* is a pointing stick 
*/
+#define        INPUT_PROP_ACCELEROMETER        0x06    /* has accelerometer */
+
+#define        INPUT_PROP_MAX                  0x1f
+#define        INPUT_PROP_CNT                  (INPUT_PROP_MAX + 1)
+
+/*
+ * Event types
+ */
+
+#define        EV_SYN                  0x00
+#define        EV_KEY                  0x01
+#define        EV_REL                  0x02
+#define        EV_ABS                  0x03
+#define        EV_MSC                  0x04
+#define        EV_SW                   0x05
+#define        EV_LED                  0x11
+#define        EV_SND                  0x12
+#define        EV_REP                  0x14
+#define        EV_FF                   0x15
+#define        EV_PWR                  0x16
+#define        EV_FF_STATUS            0x17
+#define        EV_MAX                  0x1f
+#define        EV_CNT                  (EV_MAX+1)
+
+/*
+ * Synchronization events.
+ */
+
+#define        SYN_REPORT              0
+#define        SYN_CONFIG              1
+#define        SYN_MT_REPORT           2
+#define        SYN_DROPPED             3
+#define        SYN_MAX                 0xf
+#define        SYN_CNT                 (SYN_MAX+1)
+
+/*
+ * Keys and buttons
+ */
+
+/*
+ * Abbreviations in the comments:
+ * AC - Application Control
+ * AL - Application Launch Button
+ * SC - System Control
+ */
+
+#define        KEY_RESERVED            0
+#define        KEY_ESC                 1
+#define        KEY_1                   2
+#define        KEY_2                   3
+#define        KEY_3                   4
+#define        KEY_4                   5
+#define        KEY_5                   6
+#define        KEY_6                   7
+#define        KEY_7                   8
+#define        KEY_8                   9
+#define        KEY_9                   10
+#define        KEY_0                   11
+#define        KEY_MINUS               12
+#define        KEY_EQUAL               13
+#define        KEY_BACKSPACE           14
+#define        KEY_TAB                 15
+#define        KEY_Q                   16
+#define        KEY_W                   17
+#define        KEY_E                   18
+#define        KEY_R                   19
+#define        KEY_T                   20
+#define        KEY_Y                   21
+#define        KEY_U                   22
+#define        KEY_I                   23
+#define        KEY_O                   24
+#define        KEY_P                   25
+#define        KEY_LEFTBRACE           26
+#define        KEY_RIGHTBRACE          27
+#define        KEY_ENTER               28
+#define        KEY_LEFTCTRL            29
+#define        KEY_A                   30
+#define        KEY_S                   31
+#define        KEY_D                   32
+#define        KEY_F                   33
+#define        KEY_G                   34
+#define        KEY_H                   35
+#define        KEY_J                   36
+#define        KEY_K                   37
+#define        KEY_L                   38
+#define        KEY_SEMICOLON           39
+#define        KEY_APOSTROPHE          40
+#define        KEY_GRAVE               41
+#define        KEY_LEFTSHIFT           42
+#define        KEY_BACKSLASH           43
+#define        KEY_Z                   44
+#define        KEY_X                   45
+#define        KEY_C                   46
+#define        KEY_V                   47
+#define        KEY_B                   48
+#define        KEY_N                   49
+#define        KEY_M                   50
+#define        KEY_COMMA               51
+#define        KEY_DOT                 52
+#define        KEY_SLASH               53
+#define        KEY_RIGHTSHIFT          54
+#define        KEY_KPASTERISK          55
+#define        KEY_LEFTALT             56
+#define        KEY_SPACE               57
+#define        KEY_CAPSLOCK            58
+#define        KEY_F1                  59
+#define        KEY_F2                  60
+#define        KEY_F3                  61
+#define        KEY_F4                  62
+#define        KEY_F5                  63
+#define        KEY_F6                  64
+#define        KEY_F7                  65
+#define        KEY_F8                  66
+#define        KEY_F9                  67
+#define        KEY_F10                 68
+#define        KEY_NUMLOCK             69
+#define        KEY_SCROLLLOCK          70
+#define        KEY_KP7                 71
+#define        KEY_KP8                 72
+#define        KEY_KP9                 73
+#define        KEY_KPMINUS             74
+#define        KEY_KP4                 75
+#define        KEY_KP5                 76
+#define        KEY_KP6                 77
+#define        KEY_KPPLUS              78
+#define        KEY_KP1                 79
+#define        KEY_KP2                 80
+#define        KEY_KP3                 81
+#define        KEY_KP0                 82
+#define        KEY_KPDOT               83
+
+#define        KEY_ZENKAKUHANKAKU      85
+#define        KEY_102ND               86
+#define        KEY_F11                 87
+#define        KEY_F12                 88
+#define        KEY_RO                  89
+#define        KEY_KATAKANA            90
+#define        KEY_HIRAGANA            91
+#define        KEY_HENKAN              92
+#define        KEY_KATAKANAHIRAGANA    93
+#define        KEY_MUHENKAN            94
+#define        KEY_KPJPCOMMA           95
+#define        KEY_KPENTER             96
+#define        KEY_RIGHTCTRL           97
+#define        KEY_KPSLASH             98
+#define        KEY_SYSRQ               99
+#define        KEY_RIGHTALT            100
+#define        KEY_LINEFEED            101
+#define        KEY_HOME                102
+#define        KEY_UP                  103
+#define        KEY_PAGEUP              104
+#define        KEY_LEFT                105
+#define        KEY_RIGHT               106
+#define        KEY_END                 107
+#define        KEY_DOWN                108
+#define        KEY_PAGEDOWN            109
+#define        KEY_INSERT              110
+#define        KEY_DELETE              111
+#define        KEY_MACRO               112
+#define        KEY_MUTE                113
+#define        KEY_VOLUMEDOWN          114
+#define        KEY_VOLUMEUP            115
+#define        KEY_POWER               116     /* SC System Power Down */
+#define        KEY_KPEQUAL             117
+#define        KEY_KPPLUSMINUS         118
+#define        KEY_PAUSE               119
+#define        KEY_SCALE               120     /* AL Compiz Scale (Expose) */
+
+#define        KEY_KPCOMMA             121
+#define        KEY_HANGEUL             122
+#define        KEY_HANGUEL             KEY_HANGEUL
+#define        KEY_HANJA               123
+#define        KEY_YEN                 124
+#define        KEY_LEFTMETA            125
+#define        KEY_RIGHTMETA           126
+#define        KEY_COMPOSE             127
+
+#define        KEY_STOP                128     /* AC Stop */
+#define        KEY_AGAIN               129
+#define        KEY_PROPS               130     /* AC Properties */
+#define        KEY_UNDO                131     /* AC Undo */
+#define        KEY_FRONT               132
+#define        KEY_COPY                133     /* AC Copy */
+#define        KEY_OPEN                134     /* AC Open */
+#define        KEY_PASTE               135     /* AC Paste */
+#define        KEY_FIND                136     /* AC Search */
+#define        KEY_CUT                 137     /* AC Cut */
+#define        KEY_HELP                138     /* AL Integrated Help Center */
+#define        KEY_MENU                139     /* Menu (show menu) */
+#define        KEY_CALC                140     /* AL Calculator */
+#define        KEY_SETUP               141
+#define        KEY_SLEEP               142     /* SC System Sleep */
+#define        KEY_WAKEUP              143     /* System Wake Up */
+#define        KEY_FILE                144     /* AL Local Machine Browser */
+#define        KEY_SENDFILE            145
+#define        KEY_DELETEFILE          146
+#define        KEY_XFER                147
+#define        KEY_PROG1               148
+#define        KEY_PROG2               149
+#define        KEY_WWW                 150     /* AL Internet Browser */
+#define        KEY_MSDOS               151
+#define        KEY_COFFEE              152     /* AL Terminal Lock/Screensaver 
*/
+#define        KEY_SCREENLOCK          KEY_COFFEE
+#define        KEY_ROTATE_DISPLAY      153     /* Display orientation for e.g. 
tablets */
+#define        KEY_DIRECTION           KEY_ROTATE_DISPLAY
+#define        KEY_CYCLEWINDOWS        154
+#define        KEY_MAIL                155
+#define        KEY_BOOKMARKS           156     /* AC Bookmarks */
+#define        KEY_COMPUTER            157
+#define        KEY_BACK                158     /* AC Back */
+#define        KEY_FORWARD             159     /* AC Forward */
+#define        KEY_CLOSECD             160
+#define        KEY_EJECTCD             161
+#define        KEY_EJECTCLOSECD        162
+#define        KEY_NEXTSONG            163
+#define        KEY_PLAYPAUSE           164
+#define        KEY_PREVIOUSSONG        165
+#define        KEY_STOPCD              166
+#define        KEY_RECORD              167
+#define        KEY_REWIND              168
+#define        KEY_PHONE               169     /* Media Select Telephone */
+#define        KEY_ISO                 170
+#define        KEY_CONFIG              171     /* AL Consumer Control 
Configuration */
+#define        KEY_HOMEPAGE            172     /* AC Home */
+#define        KEY_REFRESH             173     /* AC Refresh */
+#define        KEY_EXIT                174     /* AC Exit */
+#define        KEY_MOVE                175
+#define        KEY_EDIT                176
+#define        KEY_SCROLLUP            177
+#define        KEY_SCROLLDOWN          178
+#define        KEY_KPLEFTPAREN         179
+#define        KEY_KPRIGHTPAREN        180
+#define        KEY_NEW                 181     /* AC New */
+#define        KEY_REDO                182     /* AC Redo/Repeat */
+
+#define        KEY_F13                 183
+#define        KEY_F14                 184
+#define        KEY_F15                 185
+#define        KEY_F16                 186
+#define        KEY_F17                 187
+#define        KEY_F18                 188
+#define        KEY_F19                 189
+#define        KEY_F20                 190
+#define        KEY_F21                 191
+#define        KEY_F22                 192
+#define        KEY_F23                 193
+#define        KEY_F24                 194
+
+#define        KEY_PLAYCD              200
+#define        KEY_PAUSECD             201
+#define        KEY_PROG3               202
+#define        KEY_PROG4               203
+#define        KEY_DASHBOARD           204     /* AL Dashboard */
+#define        KEY_SUSPEND             205
+#define        KEY_CLOSE               206     /* AC Close */
+#define        KEY_PLAY                207
+#define        KEY_FASTFORWARD         208
+#define        KEY_BASSBOOST           209
+#define        KEY_PRINT               210     /* AC Print */
+#define        KEY_HP                  211
+#define        KEY_CAMERA              212
+#define        KEY_SOUND               213
+#define        KEY_QUESTION            214
+#define        KEY_EMAIL               215
+#define        KEY_CHAT                216
+#define        KEY_SEARCH              217
+#define        KEY_CONNECT             218
+#define        KEY_FINANCE             219     /* AL Checkbook/Finance */
+#define        KEY_SPORT               220
+#define        KEY_SHOP                221
+#define        KEY_ALTERASE            222
+#define        KEY_CANCEL              223     /* AC Cancel */
+#define        KEY_BRIGHTNESSDOWN      224
+#define        KEY_BRIGHTNESSUP        225
+#define        KEY_MEDIA               226
+
+#define        KEY_SWITCHVIDEOMODE     227     /* Cycle between available video
+                                          outputs (Monitor/LCD/TV-out/etc) */
+#define        KEY_KBDILLUMTOGGLE      228
+#define        KEY_KBDILLUMDOWN        229
+#define        KEY_KBDILLUMUP          230
+
+#define        KEY_SEND                231     /* AC Send */
+#define        KEY_REPLY               232     /* AC Reply */
+#define        KEY_FORWARDMAIL         233     /* AC Forward Msg */
+#define        KEY_SAVE                234     /* AC Save */
+#define        KEY_DOCUMENTS           235
+
+#define        KEY_BATTERY             236
+
+#define        KEY_BLUETOOTH           237
+#define        KEY_WLAN                238
+#define        KEY_UWB                 239
+
+#define        KEY_UNKNOWN             240
+
+#define        KEY_VIDEO_NEXT          241     /* drive next video source */
+#define        KEY_VIDEO_PREV          242     /* drive previous video source 
*/
+#define        KEY_BRIGHTNESS_CYCLE    243     /* brightness up, after max is 
min */
+#define        KEY_BRIGHTNESS_AUTO     244     /* Set Auto Brightness: manual
+                                         brightness control is off,
+                                         rely on ambient */
+#define        KEY_BRIGHTNESS_ZERO     KEY_BRIGHTNESS_AUTO
+#define        KEY_DISPLAY_OFF         245     /* display device to off state 
*/
+
+#define        KEY_WWAN                246     /* Wireless WAN (LTE, UMTS, 
GSM, etc.) */
+#define        KEY_WIMAX               KEY_WWAN
+#define        KEY_RFKILL              247     /* Key that controls all radios 
*/
+
+#define        KEY_MICMUTE             248     /* Mute / unmute the microphone 
*/
+
+/* Code 255 is reserved for special needs of AT keyboard driver */
+
+#define        BTN_MISC                0x100
+#define        BTN_0                   0x100
+#define        BTN_1                   0x101
+#define        BTN_2                   0x102
+#define        BTN_3                   0x103
+#define        BTN_4                   0x104
+#define        BTN_5                   0x105
+#define        BTN_6                   0x106
+#define        BTN_7                   0x107
+#define        BTN_8                   0x108
+#define        BTN_9                   0x109
+
+#define        BTN_MOUSE               0x110
+#define        BTN_LEFT                0x110
+#define        BTN_RIGHT               0x111
+#define        BTN_MIDDLE              0x112
+#define        BTN_SIDE                0x113
+#define        BTN_EXTRA               0x114
+#define        BTN_FORWARD             0x115
+#define        BTN_BACK                0x116
+#define        BTN_TASK                0x117
+
+#define        BTN_JOYSTICK            0x120
+#define        BTN_TRIGGER             0x120
+#define        BTN_THUMB               0x121
+#define        BTN_THUMB2              0x122
+#define        BTN_TOP                 0x123
+#define        BTN_TOP2                0x124
+#define        BTN_PINKIE              0x125
+#define        BTN_BASE                0x126
+#define        BTN_BASE2               0x127
+#define        BTN_BASE3               0x128
+#define        BTN_BASE4               0x129
+#define        BTN_BASE5               0x12a
+#define        BTN_BASE6               0x12b
+#define        BTN_DEAD                0x12f
+
+#define        BTN_GAMEPAD             0x130
+#define        BTN_SOUTH               0x130
+#define        BTN_A                   BTN_SOUTH
+#define        BTN_EAST                0x131
+#define        BTN_B                   BTN_EAST
+#define        BTN_C                   0x132
+#define        BTN_NORTH               0x133
+#define        BTN_X                   BTN_NORTH
+#define        BTN_WEST                0x134
+#define        BTN_Y                   BTN_WEST
+#define        BTN_Z                   0x135
+#define        BTN_TL                  0x136
+#define        BTN_TR                  0x137
+#define        BTN_TL2                 0x138
+#define        BTN_TR2                 0x139
+#define        BTN_SELECT              0x13a
+#define        BTN_START               0x13b
+#define        BTN_MODE                0x13c
+#define        BTN_THUMBL              0x13d
+#define        BTN_THUMBR              0x13e
+
+#define        BTN_DIGI                0x140
+#define        BTN_TOOL_PEN            0x140
+#define        BTN_TOOL_RUBBER         0x141
+#define        BTN_TOOL_BRUSH          0x142
+#define        BTN_TOOL_PENCIL         0x143
+#define        BTN_TOOL_AIRBRUSH       0x144
+#define        BTN_TOOL_FINGER         0x145
+#define        BTN_TOOL_MOUSE          0x146
+#define        BTN_TOOL_LENS           0x147
+#define        BTN_TOOL_QUINTTAP       0x148   /* Five fingers on trackpad */
+#define        BTN_TOUCH               0x14a
+#define        BTN_STYLUS              0x14b
+#define        BTN_STYLUS2             0x14c
+#define        BTN_TOOL_DOUBLETAP      0x14d
+#define        BTN_TOOL_TRIPLETAP      0x14e
+#define        BTN_TOOL_QUADTAP        0x14f   /* Four fingers on trackpad */
+
+#define        BTN_WHEEL               0x150
+#define        BTN_GEAR_DOWN           0x150
+#define        BTN_GEAR_UP             0x151
+
+#define        KEY_OK                  0x160
+#define        KEY_SELECT              0x161
+#define        KEY_GOTO                0x162
+#define        KEY_CLEAR               0x163
+#define        KEY_POWER2              0x164
+#define        KEY_OPTION              0x165
+#define        KEY_INFO                0x166   /* AL OEM 
Features/Tips/Tutorial */
+#define        KEY_TIME                0x167
+#define        KEY_VENDOR              0x168
+#define        KEY_ARCHIVE             0x169
+#define        KEY_PROGRAM             0x16a   /* Media Select Program Guide */
+#define        KEY_CHANNEL             0x16b
+#define        KEY_FAVORITES           0x16c
+#define        KEY_EPG                 0x16d
+#define        KEY_PVR                 0x16e   /* Media Select Home */
+#define        KEY_MHP                 0x16f
+#define        KEY_LANGUAGE            0x170
+#define        KEY_TITLE               0x171
+#define        KEY_SUBTITLE            0x172
+#define        KEY_ANGLE               0x173
+#define        KEY_ZOOM                0x174
+#define        KEY_MODE                0x175
+#define        KEY_KEYBOARD            0x176
+#define        KEY_SCREEN              0x177
+#define        KEY_PC                  0x178   /* Media Select Computer */
+#define        KEY_TV                  0x179   /* Media Select TV */
+#define        KEY_TV2                 0x17a   /* Media Select Cable */
+#define        KEY_VCR                 0x17b   /* Media Select VCR */
+#define        KEY_VCR2                0x17c   /* VCR Plus */
+#define        KEY_SAT                 0x17d   /* Media Select Satellite */
+#define        KEY_SAT2                0x17e
+#define        KEY_CD                  0x17f   /* Media Select CD */
+#define        KEY_TAPE                0x180   /* Media Select Tape */
+#define        KEY_RADIO               0x181
+#define        KEY_TUNER               0x182   /* Media Select Tuner */
+#define        KEY_PLAYER              0x183
+#define        KEY_TEXT                0x184
+#define        KEY_DVD                 0x185   /* Media Select DVD */
+#define        KEY_AUX                 0x186
+#define        KEY_MP3                 0x187
+#define        KEY_AUDIO               0x188   /* AL Audio Browser */
+#define        KEY_VIDEO               0x189   /* AL Movie Browser */
+#define        KEY_DIRECTORY           0x18a
+#define        KEY_LIST                0x18b
+#define        KEY_MEMO                0x18c   /* Media Select Messages */
+#define        KEY_CALENDAR            0x18d
+#define        KEY_RED                 0x18e
+#define        KEY_GREEN               0x18f
+#define        KEY_YELLOW              0x190
+#define        KEY_BLUE                0x191
+#define        KEY_CHANNELUP           0x192   /* Channel Increment */
+#define        KEY_CHANNELDOWN         0x193   /* Channel Decrement */
+#define        KEY_FIRST               0x194
+#define        KEY_LAST                0x195   /* Recall Last */
+#define        KEY_AB                  0x196
+#define        KEY_NEXT                0x197
+#define        KEY_RESTART             0x198
+#define        KEY_SLOW                0x199
+#define        KEY_SHUFFLE             0x19a
+#define        KEY_BREAK               0x19b
+#define        KEY_PREVIOUS            0x19c
+#define        KEY_DIGITS              0x19d
+#define        KEY_TEEN                0x19e
+#define        KEY_TWEN                0x19f
+#define        KEY_VIDEOPHONE          0x1a0   /* Media Select Video Phone */
+#define        KEY_GAMES               0x1a1   /* Media Select Games */
+#define        KEY_ZOOMIN              0x1a2   /* AC Zoom In */
+#define        KEY_ZOOMOUT             0x1a3   /* AC Zoom Out */
+#define        KEY_ZOOMRESET           0x1a4   /* AC Zoom */
+#define        KEY_WORDPROCESSOR       0x1a5   /* AL Word Processor */
+#define        KEY_EDITOR              0x1a6   /* AL Text Editor */
+#define        KEY_SPREADSHEET         0x1a7   /* AL Spreadsheet */
+#define        KEY_GRAPHICSEDITOR      0x1a8   /* AL Graphics Editor */
+#define        KEY_PRESENTATION        0x1a9   /* AL Presentation App */
+#define        KEY_DATABASE            0x1aa   /* AL Database App */
+#define        KEY_NEWS                0x1ab   /* AL Newsreader */
+#define        KEY_VOICEMAIL           0x1ac   /* AL Voicemail */
+#define        KEY_ADDRESSBOOK         0x1ad   /* AL Contacts/Address Book */
+#define        KEY_MESSENGER           0x1ae   /* AL Instant Messaging */
+#define        KEY_DISPLAYTOGGLE       0x1af   /* Turn display (LCD) on and 
off */
+#define        KEY_BRIGHTNESS_TOGGLE   KEY_DISPLAYTOGGLE
+#define        KEY_SPELLCHECK          0x1b0   /* AL Spell Check */
+#define        KEY_LOGOFF              0x1b1   /* AL Logoff */
+
+#define        KEY_DOLLAR              0x1b2
+#define        KEY_EURO                0x1b3
+
+#define        KEY_FRAMEBACK           0x1b4   /* Consumer - transport 
controls */
+#define        KEY_FRAMEFORWARD        0x1b5
+#define        KEY_CONTEXT_MENU        0x1b6   /* GenDesc - system context 
menu */
+#define        KEY_MEDIA_REPEAT        0x1b7   /* Consumer - transport control 
*/
+#define        KEY_10CHANNELSUP        0x1b8   /* 10 channels up (10+) */
+#define        KEY_10CHANNELSDOWN      0x1b9   /* 10 channels down (10-) */
+#define        KEY_IMAGES              0x1ba   /* AL Image Browser */
+
+#define        KEY_DEL_EOL             0x1c0
+#define        KEY_DEL_EOS             0x1c1
+#define        KEY_INS_LINE            0x1c2
+#define        KEY_DEL_LINE            0x1c3
+
+#define        KEY_FN                  0x1d0
+#define        KEY_FN_ESC              0x1d1
+#define        KEY_FN_F1               0x1d2
+#define        KEY_FN_F2               0x1d3
+#define        KEY_FN_F3               0x1d4
+#define        KEY_FN_F4               0x1d5
+#define        KEY_FN_F5               0x1d6
+#define        KEY_FN_F6               0x1d7
+#define        KEY_FN_F7               0x1d8
+#define        KEY_FN_F8               0x1d9
+#define        KEY_FN_F9               0x1da
+#define        KEY_FN_F10              0x1db
+#define        KEY_FN_F11              0x1dc
+#define        KEY_FN_F12              0x1dd
+#define        KEY_FN_1                0x1de
+#define        KEY_FN_2                0x1df
+#define        KEY_FN_D                0x1e0
+#define        KEY_FN_E                0x1e1
+#define        KEY_FN_F                0x1e2
+#define        KEY_FN_S                0x1e3
+#define        KEY_FN_B                0x1e4
+
+#define        KEY_BRL_DOT1            0x1f1
+#define        KEY_BRL_DOT2            0x1f2
+#define        KEY_BRL_DOT3            0x1f3
+#define        KEY_BRL_DOT4            0x1f4
+#define        KEY_BRL_DOT5            0x1f5
+#define        KEY_BRL_DOT6            0x1f6
+#define        KEY_BRL_DOT7            0x1f7
+#define        KEY_BRL_DOT8            0x1f8
+#define        KEY_BRL_DOT9            0x1f9
+#define        KEY_BRL_DOT10           0x1fa
+
+#define        KEY_NUMERIC_0           0x200   /* used by phones, remote 
controls, */
+#define        KEY_NUMERIC_1           0x201   /* and other keypads */
+#define        KEY_NUMERIC_2           0x202
+#define        KEY_NUMERIC_3           0x203
+#define        KEY_NUMERIC_4           0x204
+#define        KEY_NUMERIC_5           0x205
+#define        KEY_NUMERIC_6           0x206
+#define        KEY_NUMERIC_7           0x207
+#define        KEY_NUMERIC_8           0x208
+#define        KEY_NUMERIC_9           0x209
+#define        KEY_NUMERIC_STAR        0x20a
+#define        KEY_NUMERIC_POUND       0x20b
+#define        KEY_NUMERIC_A           0x20c   /* Phone key A - HUT Telephony 
0xb9 */
+#define        KEY_NUMERIC_B           0x20d
+#define        KEY_NUMERIC_C           0x20e
+#define        KEY_NUMERIC_D           0x20f
+
+#define        KEY_CAMERA_FOCUS        0x210
+#define        KEY_WPS_BUTTON          0x211   /* WiFi Protected Setup key */
+
+#define        KEY_TOUCHPAD_TOGGLE     0x212   /* Request switch touchpad on 
or off */
+#define        KEY_TOUCHPAD_ON         0x213
+#define        KEY_TOUCHPAD_OFF        0x214
+
+#define        KEY_CAMERA_ZOOMIN       0x215
+#define        KEY_CAMERA_ZOOMOUT      0x216
+#define        KEY_CAMERA_UP           0x217
+#define        KEY_CAMERA_DOWN         0x218
+#define        KEY_CAMERA_LEFT         0x219
+#define        KEY_CAMERA_RIGHT        0x21a
+
+#define        KEY_ATTENDANT_ON        0x21b
+#define        KEY_ATTENDANT_OFF       0x21c
+#define        KEY_ATTENDANT_TOGGLE    0x21d   /* Attendant call on or off */
+#define        KEY_LIGHTS_TOGGLE       0x21e   /* Reading light on or off */
+
+#define        BTN_DPAD_UP             0x220
+#define        BTN_DPAD_DOWN           0x221
+#define        BTN_DPAD_LEFT           0x222
+#define        BTN_DPAD_RIGHT          0x223
+
+#define        KEY_ALS_TOGGLE          0x230   /* Ambient light sensor */
+
+#define        KEY_BUTTONCONFIG                0x240   /* AL Button 
Configuration */
+#define        KEY_TASKMANAGER         0x241   /* AL Task/Project Manager */
+#define        KEY_JOURNAL             0x242   /* AL Log/Journal/Timecard */
+#define        KEY_CONTROLPANEL                0x243   /* AL Control Panel */
+#define        KEY_APPSELECT           0x244   /* AL Select Task/Application */
+#define        KEY_SCREENSAVER         0x245   /* AL Screen Saver */
+#define        KEY_VOICECOMMAND                0x246   /* Listening Voice 
Command */
+
+#define        KEY_BRIGHTNESS_MIN              0x250   /* Set Brightness to 
Minimum */
+#define        KEY_BRIGHTNESS_MAX              0x251   /* Set Brightness to 
Maximum */
+
+#define        KEY_KBDINPUTASSIST_PREV         0x260
+#define        KEY_KBDINPUTASSIST_NEXT         0x261
+#define        KEY_KBDINPUTASSIST_PREVGROUP            0x262
+#define        KEY_KBDINPUTASSIST_NEXTGROUP            0x263
+#define        KEY_KBDINPUTASSIST_ACCEPT               0x264
+#define        KEY_KBDINPUTASSIST_CANCEL               0x265
+
+#define        BTN_TRIGGER_HAPPY               0x2c0
+#define        BTN_TRIGGER_HAPPY1              0x2c0
+#define        BTN_TRIGGER_HAPPY2              0x2c1
+#define        BTN_TRIGGER_HAPPY3              0x2c2
+#define        BTN_TRIGGER_HAPPY4              0x2c3
+#define        BTN_TRIGGER_HAPPY5              0x2c4
+#define        BTN_TRIGGER_HAPPY6              0x2c5
+#define        BTN_TRIGGER_HAPPY7              0x2c6
+#define        BTN_TRIGGER_HAPPY8              0x2c7
+#define        BTN_TRIGGER_HAPPY9              0x2c8
+#define        BTN_TRIGGER_HAPPY10             0x2c9
+#define        BTN_TRIGGER_HAPPY11             0x2ca
+#define        BTN_TRIGGER_HAPPY12             0x2cb
+#define        BTN_TRIGGER_HAPPY13             0x2cc
+#define        BTN_TRIGGER_HAPPY14             0x2cd
+#define        BTN_TRIGGER_HAPPY15             0x2ce
+#define        BTN_TRIGGER_HAPPY16             0x2cf
+#define        BTN_TRIGGER_HAPPY17             0x2d0
+#define        BTN_TRIGGER_HAPPY18             0x2d1
+#define        BTN_TRIGGER_HAPPY19             0x2d2
+#define        BTN_TRIGGER_HAPPY20             0x2d3
+#define        BTN_TRIGGER_HAPPY21             0x2d4
+#define        BTN_TRIGGER_HAPPY22             0x2d5
+#define        BTN_TRIGGER_HAPPY23             0x2d6
+#define        BTN_TRIGGER_HAPPY24             0x2d7
+#define        BTN_TRIGGER_HAPPY25             0x2d8
+#define        BTN_TRIGGER_HAPPY26             0x2d9
+#define        BTN_TRIGGER_HAPPY27             0x2da
+#define        BTN_TRIGGER_HAPPY28             0x2db
+#define        BTN_TRIGGER_HAPPY29             0x2dc
+#define        BTN_TRIGGER_HAPPY30             0x2dd
+#define        BTN_TRIGGER_HAPPY31             0x2de
+#define        BTN_TRIGGER_HAPPY32             0x2df
+#define        BTN_TRIGGER_HAPPY33             0x2e0
+#define        BTN_TRIGGER_HAPPY34             0x2e1
+#define        BTN_TRIGGER_HAPPY35             0x2e2
+#define        BTN_TRIGGER_HAPPY36             0x2e3
+#define        BTN_TRIGGER_HAPPY37             0x2e4
+#define        BTN_TRIGGER_HAPPY38             0x2e5
+#define        BTN_TRIGGER_HAPPY39             0x2e6
+#define        BTN_TRIGGER_HAPPY40             0x2e7
+
+/* We avoid low common keys in module aliases so they don't get huge. */
+#define        KEY_MIN_INTERESTING     KEY_MUTE
+#define        KEY_MAX                 0x2ff
+#define        KEY_CNT                 (KEY_MAX+1)
+
+/*
+ * Relative axes
+ */
+
+#define        REL_X                   0x00
+#define        REL_Y                   0x01
+#define        REL_Z                   0x02
+#define        REL_RX                  0x03
+#define        REL_RY                  0x04
+#define        REL_RZ                  0x05
+#define        REL_HWHEEL              0x06
+#define        REL_DIAL                0x07
+#define        REL_WHEEL               0x08
+#define        REL_MISC                0x09
+#define        REL_MAX                 0x0f
+#define        REL_CNT                 (REL_MAX+1)
+
+/*
+ * Absolute axes
+ */
+
+#define        ABS_X                   0x00
+#define        ABS_Y                   0x01
+#define        ABS_Z                   0x02
+#define        ABS_RX                  0x03
+#define        ABS_RY                  0x04
+#define        ABS_RZ                  0x05
+#define        ABS_THROTTLE            0x06
+#define        ABS_RUDDER              0x07
+#define        ABS_WHEEL               0x08
+#define        ABS_GAS                 0x09
+#define        ABS_BRAKE               0x0a
+#define        ABS_HAT0X               0x10
+#define        ABS_HAT0Y               0x11
+#define        ABS_HAT1X               0x12
+#define        ABS_HAT1Y               0x13
+#define        ABS_HAT2X               0x14
+#define        ABS_HAT2Y               0x15
+#define        ABS_HAT3X               0x16
+#define        ABS_HAT3Y               0x17
+#define        ABS_PRESSURE            0x18
+#define        ABS_DISTANCE            0x19
+#define        ABS_TILT_X              0x1a
+#define        ABS_TILT_Y              0x1b
+#define        ABS_TOOL_WIDTH          0x1c
+
+#define        ABS_VOLUME              0x20
+
+#define        ABS_MISC                0x28
+
+#define        ABS_MT_SLOT             0x2f    /* MT slot being modified */
+#define        ABS_MT_TOUCH_MAJOR      0x30    /* Major axis of touching 
ellipse */
+#define        ABS_MT_TOUCH_MINOR      0x31    /* Minor axis (omit if 
circular) */
+#define        ABS_MT_WIDTH_MAJOR      0x32    /* Major axis of approaching 
ellipse */
+#define        ABS_MT_WIDTH_MINOR      0x33    /* Minor axis (omit if 
circular) */
+#define        ABS_MT_ORIENTATION      0x34    /* Ellipse orientation */
+#define        ABS_MT_POSITION_X       0x35    /* Center X touch position */
+#define        ABS_MT_POSITION_Y       0x36    /* Center Y touch position */
+#define        ABS_MT_TOOL_TYPE        0x37    /* Type of touching device */
+#define        ABS_MT_BLOB_ID          0x38    /* Group a set of packets as a 
blob */
+#define        ABS_MT_TRACKING_ID      0x39    /* Unique ID of initiated 
contact */
+#define        ABS_MT_PRESSURE         0x3a    /* Pressure on contact area */
+#define        ABS_MT_DISTANCE         0x3b    /* Contact hover distance */
+#define        ABS_MT_TOOL_X           0x3c    /* Center X tool position */
+#define        ABS_MT_TOOL_Y           0x3d    /* Center Y tool position */
+
+#define        ABS_MAX                 0x3f
+#define        ABS_CNT                 (ABS_MAX+1)
+
+/*
+ * Switch events
+ */
+
+#define        SW_LID                  0x00  /* set = lid shut */
+#define        SW_TABLET_MODE          0x01  /* set = tablet mode */
+#define        SW_HEADPHONE_INSERT     0x02  /* set = inserted */
+#define        SW_RFKILL_ALL           0x03  /* rfkill master switch, type 
"any"
+                                        set = radio enabled */
+#define        SW_RADIO                SW_RFKILL_ALL   /* deprecated */
+#define        SW_MICROPHONE_INSERT    0x04  /* set = inserted */
+#define        SW_DOCK                 0x05  /* set = plugged into dock */
+#define        SW_LINEOUT_INSERT       0x06  /* set = inserted */
+#define        SW_JACK_PHYSICAL_INSERT 0x07  /* set = mechanical switch set */
+#define        SW_VIDEOOUT_INSERT      0x08  /* set = inserted */
+#define        SW_CAMERA_LENS_COVER    0x09  /* set = lens covered */
+#define        SW_KEYPAD_SLIDE         0x0a  /* set = keypad slide out */
+#define        SW_FRONT_PROXIMITY      0x0b  /* set = front proximity sensor 
active */
+#define        SW_ROTATE_LOCK          0x0c  /* set = rotate locked/disabled */
+#define        SW_LINEIN_INSERT        0x0d  /* set = inserted */
+#define        SW_MUTE_DEVICE          0x0e  /* set = device disabled */
+#define        SW_MAX                  0x0f
+#define        SW_CNT                  (SW_MAX+1)
+
+/*
+ * Misc events
+ */
+
+#define        MSC_SERIAL              0x00
+#define        MSC_PULSELED            0x01
+#define        MSC_GESTURE             0x02
+#define        MSC_RAW                 0x03
+#define        MSC_SCAN                0x04
+#define        MSC_TIMESTAMP           0x05
+#define        MSC_MAX                 0x07
+#define        MSC_CNT                 (MSC_MAX+1)
+
+/*
+ * LEDs
+ */
+
+#define        LED_NUML                0x00
+#define        LED_CAPSL               0x01
+#define        LED_SCROLLL             0x02
+#define        LED_COMPOSE             0x03
+#define        LED_KANA                0x04
+#define        LED_SLEEP               0x05
+#define        LED_SUSPEND             0x06
+#define        LED_MUTE                0x07
+#define        LED_MISC                0x08
+#define        LED_MAIL                0x09
+#define        LED_CHARGING            0x0a
+#define        LED_MAX                 0x0f
+#define        LED_CNT                 (LED_MAX+1)
+
+/*
+ * Autorepeat values
+ */
+
+#define        REP_DELAY               0x00
+#define        REP_PERIOD              0x01
+#define        REP_MAX                 0x01
+#define        REP_CNT                 (REP_MAX+1)
+
+/*
+ * Sounds
+ */
+
+#define        SND_CLICK               0x00
+#define        SND_BELL                0x01
+#define        SND_TONE                0x02
+#define        SND_MAX                 0x07
+#define        SND_CNT                 (SND_MAX+1)
+
+#endif /* _EVDEV_INPUT_EVENT_CODES_H */
diff --git a/freebsd/sys/dev/evdev/input.h b/freebsd/sys/dev/evdev/input.h
new file mode 100644
index 0000000..0463844
--- /dev/null
+++ b/freebsd/sys/dev/evdev/input.h
@@ -0,0 +1,273 @@
+/*-
+ * Copyright (c) 2016 Oleksandr Tymoshenko <go...@freebsd.org>
+ * Copyright (c) 2015-2016 Vladimir Kondratyev <w...@cicgroup.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef        _EVDEV_INPUT_H
+#define        _EVDEV_INPUT_H
+
+#ifndef __KERNEL__
+#include <sys/time.h>
+#include <sys/ioccom.h>
+#include <sys/types.h>
+#endif
+
+#include "input-event-codes.h"
+
+struct input_event {
+       struct timeval  time;
+       uint16_t        type;
+       uint16_t        code;
+       int32_t         value;
+};
+
+#define        EV_VERSION              0x010001
+
+struct input_id {
+       uint16_t        bustype;
+       uint16_t        vendor;
+       uint16_t        product;
+       uint16_t        version;
+};
+
+struct input_absinfo {
+       int32_t         value;
+       int32_t         minimum;
+       int32_t         maximum;
+       int32_t         fuzz;
+       int32_t         flat;
+       int32_t         resolution;
+};
+
+#define        INPUT_KEYMAP_BY_INDEX   (1 << 0)
+
+struct input_keymap_entry {
+       uint8_t         flags;
+       uint8_t         len;
+       uint16_t        index;
+       uint32_t        keycode;
+       uint8_t         scancode[32];
+};
+
+#define        EVDEV_IOC_MAGIC 'E'
+#define        EVIOCGVERSION           _IOR(EVDEV_IOC_MAGIC, 0x01, int)        
        /* get driver version */
+#define        EVIOCGID                _IOR(EVDEV_IOC_MAGIC, 0x02, struct 
input_id)    /* get device ID */
+#define        EVIOCGREP               _IOR(EVDEV_IOC_MAGIC, 0x03, unsigned 
int[2])    /* get repeat settings */
+#define        EVIOCSREP               _IOW(EVDEV_IOC_MAGIC, 0x03, unsigned 
int[2])    /* set repeat settings */
+
+#define        EVIOCGKEYCODE           _IOWR(EVDEV_IOC_MAGIC, 0x04, unsigned 
int[2])   /* get keycode */
+#define        EVIOCGKEYCODE_V2        _IOWR(EVDEV_IOC_MAGIC, 0x04, struct 
input_keymap_entry)
+#define        EVIOCSKEYCODE           _IOW(EVDEV_IOC_MAGIC, 0x04, unsigned 
int[2])    /* set keycode */
+#define        EVIOCSKEYCODE_V2        _IOW(EVDEV_IOC_MAGIC, 0x04, struct 
input_keymap_entry)
+
+#define        EVIOCGNAME(len)         _IOC(IOC_OUT, EVDEV_IOC_MAGIC, 0x06, 
len)       /* get device name */
+#define        EVIOCGPHYS(len)         _IOC(IOC_OUT, EVDEV_IOC_MAGIC, 0x07, 
len)       /* get physical location */
+#define        EVIOCGUNIQ(len)         _IOC(IOC_OUT, EVDEV_IOC_MAGIC, 0x08, 
len)       /* get unique identifier */
+#define        EVIOCGPROP(len)         _IOC(IOC_OUT, EVDEV_IOC_MAGIC, 0x09, 
len)       /* get device properties */
+
+#define        EVIOCGMTSLOTS(len)      _IOC(IOC_INOUT, EVDEV_IOC_MAGIC, 0x0a, 
len)     /* get MT slots values */
+
+#define        EVIOCGKEY(len)          _IOC(IOC_OUT, EVDEV_IOC_MAGIC, 0x18, 
len)       /* get global key state */
+#define        EVIOCGLED(len)          _IOC(IOC_OUT, EVDEV_IOC_MAGIC, 0x19, 
len)       /* get all LEDs */
+#define        EVIOCGSND(len)          _IOC(IOC_OUT, EVDEV_IOC_MAGIC, 0x1a, 
len)       /* get all sounds status */
+#define        EVIOCGSW(len)           _IOC(IOC_OUT, EVDEV_IOC_MAGIC, 0x1b, 
len)       /* get all switch states */
+
+#define        EVIOCGBIT(ev,len)       _IOC(IOC_OUT, EVDEV_IOC_MAGIC, 0x20 + 
(ev), len)        /* get event bits */
+#define        EVIOCGABS(abs)          _IOR(EVDEV_IOC_MAGIC, 0x40 + (abs), 
struct input_absinfo)       /* get abs value/limits */
+#define        EVIOCSABS(abs)          _IOW(EVDEV_IOC_MAGIC, 0xc0 + (abs), 
struct input_absinfo)       /* set abs value/limits */
+
+#define        EVIOCSFF                _IOW(EVDEV_IOC_MAGIC, 0x80, struct 
ff_effect)   /* send a force effect to a force feedback device */
+#define        EVIOCRMFF               _IOWINT(EVDEV_IOC_MAGIC, 0x81)          
        /* Erase a force effect */
+#define        EVIOCGEFFECTS           _IOR(EVDEV_IOC_MAGIC, 0x84, int)        
        /* Report number of effects playable at the same time */
+
+#define        EVIOCGRAB               _IOWINT(EVDEV_IOC_MAGIC, 0x90)          
        /* Grab/Release device */
+#define        EVIOCREVOKE             _IOWINT(EVDEV_IOC_MAGIC, 0x91)          
        /* Revoke device access */
+
+#define        EVIOCSCLOCKID           _IOW(EVDEV_IOC_MAGIC, 0xa0, int)        
        /* Set clockid to be used for timestamps */
+
+/*
+ * IDs.
+ */
+
+#define        ID_BUS                  0
+#define        ID_VENDOR               1
+#define        ID_PRODUCT              2
+#define        ID_VERSION              3
+
+#define        BUS_PCI                 0x01
+#define        BUS_ISAPNP              0x02
+#define        BUS_USB                 0x03
+#define        BUS_HIL                 0x04
+#define        BUS_BLUETOOTH           0x05
+#define        BUS_VIRTUAL             0x06
+
+#define        BUS_ISA                 0x10
+#define        BUS_I8042               0x11
+#define        BUS_XTKBD               0x12
+#define        BUS_RS232               0x13
+#define        BUS_GAMEPORT            0x14
+#define        BUS_PARPORT             0x15
+#define        BUS_AMIGA               0x16
+#define        BUS_ADB                 0x17
+#define        BUS_I2C                 0x18
+#define        BUS_HOST                0x19
+#define        BUS_GSC                 0x1A
+#define        BUS_ATARI               0x1B
+#define        BUS_SPI                 0x1C
+
+/*
+ * MT_TOOL types
+ */
+#define        MT_TOOL_FINGER          0
+#define        MT_TOOL_PEN             1
+#define        MT_TOOL_PALM            2
+#define        MT_TOOL_MAX             2
+
+/*
+ * Values describing the status of a force-feedback effect
+ */
+#define        FF_STATUS_STOPPED       0x00
+#define        FF_STATUS_PLAYING       0x01
+#define        FF_STATUS_MAX           0x01
+
+/* scheduling info for force feedback effect */
+struct ff_replay {
+       uint16_t        length;         /* length of the effect (ms) */
+       uint16_t        delay;          /* delay before effect starts (ms) */
+};
+
+/* trigger for force feedback effect */
+struct ff_trigger {
+       uint16_t        button;         /* trigger button number */
+       uint16_t        interval;       /* delay between re-triggers */
+};
+
+/* force feedback effect envelop */
+struct ff_envelope {
+       uint16_t        attack_length;  /* duration of the attach (ms) */
+       uint16_t        attack_level;   /* level at the beginning (0x0000 - 
0x7fff) */
+       uint16_t        fade_length;    /* duratin of fade (ms) */
+       uint16_t        fade_level;     /* level at the end of fade */
+};
+
+struct ff_constant_effect {
+       int16_t                 level;
+       struct ff_envelope      envelope;
+};
+
+struct ff_ramp_effect {
+       int16_t                 start_level;
+       int16_t                 end_level;
+       struct ff_envelope      envelope;
+};
+
+struct ff_condition_effect {
+       /* maximum level when joystick moved to respective side */
+       uint16_t        right_saturation;
+
+       uint16_t        left_saturation;
+       /* how fast force grows when joystick move to the respective side */
+       int16_t         right_coeff;
+       int16_t         left_coeff;
+
+       uint16_t        deadband;       /* size of dead zone when no force is 
produced */
+       int16_t         center;         /* center of dead zone */
+};
+
+/*
+ * Force feedback periodic effect types
+ */
+
+#define        FF_SQUARE       0x58
+#define        FF_TRIANGLE     0x59
+#define        FF_SINE         0x5a
+#define        FF_SAW_UP       0x5b
+#define        FF_SAW_DOWN     0x5c
+#define        FF_CUSTOM       0x5d
+
+#define        FF_WAVEFORM_MIN FF_SQUARE
+#define        FF_WAVEFORM_MAX FF_CUSTOM
+
+struct ff_periodic_effect {
+       uint16_t                waveform;
+       uint16_t                period;         /* ms */
+       int16_t                 magnitude;      /* peak */
+       int16_t                 offset;         /* mean, roughly */
+       uint16_t                phase;          /* horizontal shift */
+       struct ff_envelope      envelope;
+       uint32_t                custom_len;     /* FF_CUSTOM waveform only */
+       int16_t                 *custom_data;   /* FF_CUSTOM waveform only */
+};
+
+struct ff_rumble_effect {
+       uint16_t        strong_magnitude;       /* magnitude of the heavy motor 
*/
+       uint16_t        weak_magnitude;         /* magnitude of the light motor 
*/
+};
+
+/*
+ * Force feedback effect types
+ */
+
+#define        FF_RUMBLE       0x50
+#define        FF_PERIODIC     0x51
+#define        FF_CONSTANT     0x52
+#define        FF_SPRING       0x53
+#define        FF_FRICTION     0x54
+#define        FF_DAMPER       0x55
+#define        FF_INERTIA      0x56
+#define        FF_RAMP         0x57
+
+#define        FF_EFFECT_MIN   FF_RUMBLE
+#define        FF_EFFECT_MAX   FF_RAMP
+
+struct ff_effect {
+       uint16_t                type;
+       int16_t                 id;
+       uint16_t                direction;      /* [0 .. 360) degrees -> [0 .. 
0x10000) */
+       struct ff_trigger       trigger;
+       struct ff_replay        replay;
+
+       union {
+               struct ff_constant_effect       constant;
+               struct ff_ramp_effect           ramp;
+               struct ff_periodic_effect       periodic;
+               struct ff_condition_effect      condition[2]; /* One for each 
axis */
+               struct ff_rumble_effect         rumble;
+       } u;
+};
+
+/*
+ * force feedback device properties
+ */
+
+#define        FF_GAIN         0x60
+#define        FF_AUTOCENTER   0x61
+
+#define        FF_MAX          0x7f
+#define        FF_CNT          (FF_MAX+1)
+
+#endif /* _EVDEV_INPUT_H */
diff --git a/freebsd/sys/dev/evdev/uinput.c b/freebsd/sys/dev/evdev/uinput.c
new file mode 100644
index 0000000..c66afe6
--- /dev/null
+++ b/freebsd/sys/dev/evdev/uinput.c
@@ -0,0 +1,715 @@
+#include <machine/rtems-bsd-kernel-space.h>
+
+/*-
+ * Copyright (c) 2014 Jakub Wojciech Klama <jc...@freebsd.org>
+ * Copyright (c) 2015-2016 Vladimir Kondratyev <w...@cicgroup.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#include <rtems/bsd/local/opt_evdev.h>
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <rtems/bsd/sys/param.h>
+#include <sys/fcntl.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/proc.h>
+#include <sys/poll.h>
+#include <sys/selinfo.h>
+#include <sys/malloc.h>
+#include <rtems/bsd/sys/lock.h>
+#include <sys/sx.h>
+
+#include <dev/evdev/input.h>
+#include <dev/evdev/uinput.h>
+#include <dev/evdev/evdev.h>
+#include <dev/evdev/evdev_private.h>
+
+#ifdef UINPUT_DEBUG
+#define        debugf(state, fmt, args...)     printf("uinput: " fmt "\n", 
##args)
+#else
+#define        debugf(state, fmt, args...)
+#endif
+
+#define        UINPUT_BUFFER_SIZE      16
+
+#define        UINPUT_LOCK(state)              sx_xlock(&(state)->ucs_lock)
+#define        UINPUT_UNLOCK(state)            sx_unlock(&(state)->ucs_lock)
+#define        UINPUT_LOCK_ASSERT(state)       sx_assert(&(state)->ucs_lock, 
SA_LOCKED)
+#define UINPUT_EMPTYQ(state) \
+    ((state)->ucs_buffer_head == (state)->ucs_buffer_tail)
+
+enum uinput_state
+{
+       UINPUT_NEW = 0,
+       UINPUT_CONFIGURED,
+       UINPUT_RUNNING
+};
+
+static evdev_event_t   uinput_ev_event;
+
+static d_open_t                uinput_open;
+static d_read_t                uinput_read;
+static d_write_t       uinput_write;
+static d_ioctl_t       uinput_ioctl;
+static d_poll_t                uinput_poll;
+static d_kqfilter_t    uinput_kqfilter;
+static void uinput_dtor(void *);
+
+static int uinput_kqread(struct knote *kn, long hint);
+static void uinput_kqdetach(struct knote *kn);
+
+static struct cdevsw uinput_cdevsw = {
+       .d_version = D_VERSION,
+       .d_open = uinput_open,
+       .d_read = uinput_read,
+       .d_write = uinput_write,
+       .d_ioctl = uinput_ioctl,
+       .d_poll = uinput_poll,
+       .d_kqfilter = uinput_kqfilter,
+       .d_name = "uinput",
+};
+
+static struct cdev *uinput_cdev;
+
+static struct evdev_methods uinput_ev_methods = {
+       .ev_open = NULL,
+       .ev_close = NULL,
+       .ev_event = uinput_ev_event,
+};
+
+static struct filterops uinput_filterops = {
+       .f_isfd = 1,
+       .f_attach = NULL,
+       .f_detach = uinput_kqdetach,
+       .f_event = uinput_kqread,
+};
+
+struct uinput_cdev_state
+{
+       enum uinput_state       ucs_state;
+       struct evdev_dev *      ucs_evdev;
+       struct sx               ucs_lock;
+       size_t                  ucs_buffer_head;
+       size_t                  ucs_buffer_tail;
+       struct selinfo          ucs_selp;
+       bool                    ucs_blocked;
+       bool                    ucs_selected;
+       struct input_event      ucs_buffer[UINPUT_BUFFER_SIZE];
+};
+
+static void uinput_enqueue_event(struct uinput_cdev_state *, uint16_t,
+    uint16_t, int32_t);
+static int uinput_setup_provider(struct uinput_cdev_state *,
+    struct uinput_user_dev *);
+static int uinput_cdev_create(void);
+static void uinput_notify(struct uinput_cdev_state *);
+
+static void
+uinput_knllock(void *arg)
+{
+       struct sx *sx = arg;
+
+       sx_xlock(sx);
+}
+
+static void
+uinput_knlunlock(void *arg)
+{
+       struct sx *sx = arg;
+
+       sx_unlock(sx);
+}
+
+static void
+uinput_knl_assert_locked(void *arg)
+{
+
+       sx_assert((struct sx*)arg, SA_XLOCKED);
+}
+
+static void
+uinput_knl_assert_unlocked(void *arg)
+{
+
+       sx_assert((struct sx*)arg, SA_UNLOCKED);
+}
+
+static void
+uinput_ev_event(struct evdev_dev *evdev, void *softc, uint16_t type,
+    uint16_t code, int32_t value)
+{
+       struct uinput_cdev_state *state = softc;
+
+       if (type == EV_LED)
+               evdev_push_event(evdev, type, code, value);
+
+       UINPUT_LOCK(state);
+       if (state->ucs_state == UINPUT_RUNNING) {
+               uinput_enqueue_event(state, type, code, value);
+               uinput_notify(state);
+       }
+       UINPUT_UNLOCK(state);
+}
+
+static void
+uinput_enqueue_event(struct uinput_cdev_state *state, uint16_t type,
+    uint16_t code, int32_t value)
+{
+       size_t head, tail;
+
+       UINPUT_LOCK_ASSERT(state);
+
+       head = state->ucs_buffer_head;
+       tail = (state->ucs_buffer_tail + 1) % UINPUT_BUFFER_SIZE;
+
+       microtime(&state->ucs_buffer[tail].time);
+       state->ucs_buffer[tail].type = type;
+       state->ucs_buffer[tail].code = code;
+       state->ucs_buffer[tail].value = value;
+       state->ucs_buffer_tail = tail;
+
+       /* If queue is full remove oldest event */
+       if (tail == head) {
+               debugf(state, "state %p: buffer overflow", state);
+
+               head = (head + 1) % UINPUT_BUFFER_SIZE;
+               state->ucs_buffer_head = head;
+       }
+}
+
+static int
+uinput_open(struct cdev *dev, int oflags, int devtype, struct thread *td)
+{
+       struct uinput_cdev_state *state;
+
+       state = malloc(sizeof(struct uinput_cdev_state), M_EVDEV,
+           M_WAITOK | M_ZERO);
+       state->ucs_evdev = evdev_alloc();
+
+       sx_init(&state->ucs_lock, "uinput");
+       knlist_init(&state->ucs_selp.si_note, &state->ucs_lock, uinput_knllock,
+           uinput_knlunlock, uinput_knl_assert_locked,
+           uinput_knl_assert_unlocked);
+
+       devfs_set_cdevpriv(state, uinput_dtor);
+       return (0);
+}
+
+static void
+uinput_dtor(void *data)
+{
+       struct uinput_cdev_state *state = (struct uinput_cdev_state *)data;
+
+       evdev_free(state->ucs_evdev);
+
+       knlist_clear(&state->ucs_selp.si_note, 0);
+       seldrain(&state->ucs_selp);
+       knlist_destroy(&state->ucs_selp.si_note);
+       sx_destroy(&state->ucs_lock);
+       free(data, M_EVDEV);
+}
+
+static int
+uinput_read(struct cdev *dev, struct uio *uio, int ioflag)
+{
+       struct uinput_cdev_state *state;
+       struct input_event *event;
+       int remaining, ret;
+
+       ret = devfs_get_cdevpriv((void **)&state);
+       if (ret != 0)
+               return (ret);
+
+       debugf(state, "read %zd bytes by thread %d", uio->uio_resid,
+           uio->uio_td->td_tid);
+
+       /* Zero-sized reads are allowed for error checking */
+       if (uio->uio_resid != 0 && uio->uio_resid < sizeof(struct input_event))
+               return (EINVAL);
+
+       remaining = uio->uio_resid / sizeof(struct input_event);
+
+       UINPUT_LOCK(state);
+
+       if (state->ucs_state != UINPUT_RUNNING)
+               ret = EINVAL;
+
+       if (ret == 0 && UINPUT_EMPTYQ(state)) {
+               if (ioflag & O_NONBLOCK)
+                       ret = EWOULDBLOCK;
+               else {
+                       if (remaining != 0) {
+                               state->ucs_blocked = true;
+                               ret = sx_sleep(state, &state->ucs_lock,
+                                   PCATCH, "uiread", 0);
+                       }
+               }
+       }
+
+       while (ret == 0 && !UINPUT_EMPTYQ(state) && remaining > 0) {
+               event = &state->ucs_buffer[state->ucs_buffer_head];
+               state->ucs_buffer_head = (state->ucs_buffer_head + 1) %
+                   UINPUT_BUFFER_SIZE;
+               remaining--;
+               ret = uiomove(event, sizeof(struct input_event), uio);
+       }
+
+       UINPUT_UNLOCK(state);
+
+       return (ret);
+}
+
+static int
+uinput_write(struct cdev *dev, struct uio *uio, int ioflag)
+{
+       struct uinput_cdev_state *state;
+       struct uinput_user_dev userdev;
+       struct input_event event;
+       int ret = 0;
+
+       ret = devfs_get_cdevpriv((void **)&state);
+       if (ret != 0)
+               return (ret);
+
+       debugf(state, "write %zd bytes by thread %d", uio->uio_resid,
+           uio->uio_td->td_tid);
+
+       UINPUT_LOCK(state);
+
+       if (state->ucs_state != UINPUT_RUNNING) {
+               /* Process written struct uinput_user_dev */
+               if (uio->uio_resid != sizeof(struct uinput_user_dev)) {
+                       debugf(state, "write size not multiple of "
+                           "struct uinput_user_dev size");
+                       ret = EINVAL;
+               } else {
+                       ret = uiomove(&userdev, sizeof(struct uinput_user_dev),
+                           uio);
+                       if (ret == 0)
+                               uinput_setup_provider(state, &userdev);
+               }
+       } else {
+               /* Process written event */
+               if (uio->uio_resid % sizeof(struct input_event) != 0) {
+                       debugf(state, "write size not multiple of "
+                           "struct input_event size");
+                       ret = EINVAL;
+               }
+
+               while (ret == 0 && uio->uio_resid > 0) {
+                       uiomove(&event, sizeof(struct input_event), uio);
+                       ret = evdev_push_event(state->ucs_evdev, event.type,
+                           event.code, event.value);
+               }
+       }
+
+       UINPUT_UNLOCK(state);
+
+       return (ret);
+}
+
+static int
+uinput_setup_dev(struct uinput_cdev_state *state, struct input_id *id,
+    char *name, uint32_t ff_effects_max)
+{
+
+       if (name[0] == 0)
+               return (EINVAL);
+
+       evdev_set_name(state->ucs_evdev, name);
+       evdev_set_id(state->ucs_evdev, id->bustype, id->vendor, id->product,
+           id->version);
+       state->ucs_state = UINPUT_CONFIGURED;
+
+       return (0);
+}
+
+static int
+uinput_setup_provider(struct uinput_cdev_state *state,
+    struct uinput_user_dev *udev)
+{
+       struct input_absinfo absinfo;
+       int i, ret;
+
+       debugf(state, "setup_provider called, udev=%p", udev);
+
+       ret = uinput_setup_dev(state, &udev->id, udev->name,
+           udev->ff_effects_max);
+       if (ret)
+               return (ret);
+
+       bzero(&absinfo, sizeof(struct input_absinfo));
+       for (i = 0; i < ABS_CNT; i++) {
+               if (!bit_test(state->ucs_evdev->ev_abs_flags, i))
+                       continue;
+
+               absinfo.minimum = udev->absmin[i];
+               absinfo.maximum = udev->absmax[i];
+               absinfo.fuzz = udev->absfuzz[i];
+               absinfo.flat = udev->absflat[i];
+               evdev_set_absinfo(state->ucs_evdev, i, &absinfo);
+       }
+
+       return (0);
+}
+
+static int
+uinput_poll(struct cdev *dev, int events, struct thread *td)
+{
+       struct uinput_cdev_state *state;
+       int revents = 0;
+
+       if (devfs_get_cdevpriv((void **)&state) != 0)
+               return (POLLNVAL);
+
+       debugf(state, "poll by thread %d", td->td_tid);
+
+       /* Always allow write */
+       if (events & (POLLOUT | POLLWRNORM))
+               revents |= (events & (POLLOUT | POLLWRNORM));
+
+       if (events & (POLLIN | POLLRDNORM)) {
+               UINPUT_LOCK(state);
+               if (!UINPUT_EMPTYQ(state))
+                       revents = events & (POLLIN | POLLRDNORM);
+               else {
+                       state->ucs_selected = true;
+                       selrecord(td, &state->ucs_selp);
+               }
+               UINPUT_UNLOCK(state);
+       }
+
+       return (revents);
+}
+
+static int
+uinput_kqfilter(struct cdev *dev, struct knote *kn)
+{
+       struct uinput_cdev_state *state;
+       int ret;
+
+       ret = devfs_get_cdevpriv((void **)&state);
+       if (ret != 0)
+               return (ret);
+
+       switch(kn->kn_filter) {
+       case EVFILT_READ:
+               kn->kn_fop = &uinput_filterops;
+               break;
+       default:
+               return(EINVAL);
+       }
+       kn->kn_hook = (caddr_t)state;
+
+       knlist_add(&state->ucs_selp.si_note, kn, 0);
+       return (0);
+}
+
+static int
+uinput_kqread(struct knote *kn, long hint)
+{
+       struct uinput_cdev_state *state;
+       int ret;
+
+       state = (struct uinput_cdev_state *)kn->kn_hook;
+
+       UINPUT_LOCK_ASSERT(state);
+
+       ret = !UINPUT_EMPTYQ(state);
+       return (ret);
+}
+
+static void
+uinput_kqdetach(struct knote *kn)
+{
+       struct uinput_cdev_state *state;
+
+       state = (struct uinput_cdev_state *)kn->kn_hook;
+       knlist_remove(&state->ucs_selp.si_note, kn, 0);
+}
+
+static void
+uinput_notify(struct uinput_cdev_state *state)
+{
+
+       UINPUT_LOCK_ASSERT(state);
+
+       if (state->ucs_blocked) {
+               state->ucs_blocked = false;
+               wakeup(state);
+       }
+       if (state->ucs_selected) {
+               state->ucs_selected = false;
+               selwakeup(&state->ucs_selp);
+       }
+       KNOTE_LOCKED(&state->ucs_selp.si_note, 0);
+}
+
+static int
+uinput_ioctl_sub(struct uinput_cdev_state *state, u_long cmd, caddr_t data)
+{
+       struct uinput_setup *us;
+       struct uinput_abs_setup *uabs;
+       int ret, len, intdata;
+       char buf[NAMELEN];
+
+       UINPUT_LOCK_ASSERT(state);
+
+       len = IOCPARM_LEN(cmd);
+       if ((cmd & IOC_DIRMASK) == IOC_VOID && len == sizeof(int))
+               intdata = *(int *)data;
+
+       switch (IOCBASECMD(cmd)) {
+       case UI_GET_SYSNAME(0):
+               if (state->ucs_state != UINPUT_RUNNING)
+                       return (ENOENT);
+               if (len == 0)
+                       return (EINVAL);
+               snprintf(data, len, "event%d", state->ucs_evdev->ev_unit);
+               return (0);
+       }
+
+       switch (cmd) {
+       case UI_DEV_CREATE:
+               if (state->ucs_state != UINPUT_CONFIGURED)
+                       return (EINVAL);
+
+               evdev_set_methods(state->ucs_evdev, state, &uinput_ev_methods);
+               evdev_set_flag(state->ucs_evdev, EVDEV_FLAG_SOFTREPEAT);
+               ret = evdev_register(state->ucs_evdev);
+               if (ret == 0)
+                       state->ucs_state = UINPUT_RUNNING;
+               return (ret);
+
+       case UI_DEV_DESTROY:
+               if (state->ucs_state != UINPUT_RUNNING)
+                       return (0);
+
+               evdev_unregister(state->ucs_evdev);
+               bzero(state->ucs_evdev, sizeof(struct evdev_dev));
+               state->ucs_state = UINPUT_NEW;
+               return (0);
+
+       case UI_DEV_SETUP:
+               if (state->ucs_state == UINPUT_RUNNING)
+                       return (EINVAL);
+
+               us = (struct uinput_setup *)data;
+               return (uinput_setup_dev(state, &us->id, us->name,
+                   us->ff_effects_max));
+
+       case UI_ABS_SETUP:
+               if (state->ucs_state == UINPUT_RUNNING)
+                       return (EINVAL);
+
+               uabs = (struct uinput_abs_setup *)data;
+               if (uabs->code > ABS_MAX)
+                       return (EINVAL);
+
+               evdev_support_abs(state->ucs_evdev, uabs->code,
+                   uabs->absinfo.value, uabs->absinfo.minimum,
+                   uabs->absinfo.maximum, uabs->absinfo.fuzz,
+                   uabs->absinfo.flat, uabs->absinfo.resolution);
+               return (0);
+
+       case UI_SET_EVBIT:
+               if (state->ucs_state == UINPUT_RUNNING ||
+                   intdata > EV_MAX || intdata < 0)
+                       return (EINVAL);
+               evdev_support_event(state->ucs_evdev, intdata);
+               return (0);
+
+       case UI_SET_KEYBIT:
+               if (state->ucs_state == UINPUT_RUNNING ||
+                   intdata > KEY_MAX || intdata < 0)
+                       return (EINVAL);
+               evdev_support_key(state->ucs_evdev, intdata);
+               return (0);
+
+       case UI_SET_RELBIT:
+               if (state->ucs_state == UINPUT_RUNNING ||
+                   intdata > REL_MAX || intdata < 0)
+                       return (EINVAL);
+               evdev_support_rel(state->ucs_evdev, intdata);
+               return (0);
+
+       case UI_SET_ABSBIT:
+               if (state->ucs_state == UINPUT_RUNNING ||
+                   intdata > ABS_MAX || intdata < 0)
+                       return (EINVAL);
+               evdev_set_abs_bit(state->ucs_evdev, intdata);
+               return (0);
+
+       case UI_SET_MSCBIT:
+               if (state->ucs_state == UINPUT_RUNNING ||
+                   intdata > MSC_MAX || intdata < 0)
+                       return (EINVAL);
+               evdev_support_msc(state->ucs_evdev, intdata);
+               return (0);
+
+       case UI_SET_LEDBIT:
+               if (state->ucs_state == UINPUT_RUNNING ||
+                   intdata > LED_MAX || intdata < 0)
+                       return (EINVAL);
+               evdev_support_led(state->ucs_evdev, intdata);
+               return (0);
+
+       case UI_SET_SNDBIT:
+               if (state->ucs_state == UINPUT_RUNNING ||
+                   intdata > SND_MAX || intdata < 0)
+                       return (EINVAL);
+               evdev_support_snd(state->ucs_evdev, intdata);
+               return (0);
+
+       case UI_SET_FFBIT:
+               if (state->ucs_state == UINPUT_RUNNING ||
+                   intdata > FF_MAX || intdata < 0)
+                       return (EINVAL);
+               /* Fake unsupported ioctl */
+               return (0);
+
+       case UI_SET_PHYS:
+               if (state->ucs_state == UINPUT_RUNNING)
+                       return (EINVAL);
+               ret = copyinstr(*(void **)data, buf, sizeof(buf), NULL);
+               /* Linux returns EINVAL when string does not fit the buffer */
+               if (ret == ENAMETOOLONG)
+                       ret = EINVAL;
+               if (ret != 0)
+                       return (ret);
+               evdev_set_phys(state->ucs_evdev, buf);
+               return (0);
+
+       case UI_SET_SWBIT:
+               if (state->ucs_state == UINPUT_RUNNING ||
+                   intdata > SW_MAX || intdata < 0)
+                       return (EINVAL);
+               evdev_support_sw(state->ucs_evdev, intdata);
+               return (0);
+
+       case UI_SET_PROPBIT:
+               if (state->ucs_state == UINPUT_RUNNING ||
+                   intdata > INPUT_PROP_MAX || intdata < 0)
+                       return (EINVAL);
+               evdev_support_prop(state->ucs_evdev, intdata);
+               return (0);
+
+       case UI_BEGIN_FF_UPLOAD:
+       case UI_END_FF_UPLOAD:
+       case UI_BEGIN_FF_ERASE:
+       case UI_END_FF_ERASE:
+               if (state->ucs_state == UINPUT_RUNNING)
+                       return (EINVAL);
+               /* Fake unsupported ioctl */
+               return (0);
+
+       case UI_GET_VERSION:
+               *(unsigned int *)data = UINPUT_VERSION;
+               return (0);
+       }
+
+       return (EINVAL);
+}
+
+static int
+uinput_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
+    struct thread *td)
+{
+       struct uinput_cdev_state *state;
+       int ret;
+
+       ret = devfs_get_cdevpriv((void **)&state);
+       if (ret != 0)
+               return (ret);
+
+       debugf(state, "ioctl called: cmd=0x%08lx, data=%p", cmd, data);
+
+       UINPUT_LOCK(state);
+       ret = uinput_ioctl_sub(state, cmd, data);
+       UINPUT_UNLOCK(state);
+
+       return (ret);
+}
+
+static int
+uinput_cdev_create(void)
+{
+       struct make_dev_args mda;
+       int ret;
+
+       make_dev_args_init(&mda);
+       mda.mda_flags = MAKEDEV_WAITOK | MAKEDEV_CHECKNAME;
+       mda.mda_devsw = &uinput_cdevsw;
+       mda.mda_uid = UID_ROOT;
+       mda.mda_gid = GID_WHEEL;
+       mda.mda_mode = 0600;
+
+       ret = make_dev_s(&mda, &uinput_cdev, "uinput");
+
+       return (ret);
+}
+
+static int
+uinput_cdev_destroy(void)
+{
+
+       destroy_dev(uinput_cdev);
+
+       return (0);
+}
+
+static int
+uinput_modevent(module_t mod __unused, int cmd, void *data)
+{
+       int ret = 0;
+
+       switch (cmd) {
+       case MOD_LOAD:
+               ret = uinput_cdev_create();
+               break;
+
+       case MOD_UNLOAD:
+               ret = uinput_cdev_destroy();
+               break;
+
+       case MOD_SHUTDOWN:
+               break;
+
+       default:
+               ret = EINVAL;
+               break;
+       }
+
+       return (ret);
+}
+
+DEV_MODULE(uinput, uinput_modevent, NULL);
+MODULE_VERSION(uinput, 1);
+MODULE_DEPEND(uinput, evdev, 1, 1, 1);
diff --git a/freebsd/sys/dev/evdev/uinput.h b/freebsd/sys/dev/evdev/uinput.h
new file mode 100644
index 0000000..f1721e1
--- /dev/null
+++ b/freebsd/sys/dev/evdev/uinput.h
@@ -0,0 +1,107 @@
+/*-
+ * Copyright (c) 2016 Oleksandr Tymoshenko <go...@freebsd.org>
+ * Copyright (c) 2015-2016 Vladimir Kondratyev <w...@cicgroup.ru>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $FreeBSD$
+ */
+
+#ifndef _EVDEV_UINPUT_H_
+#define        _EVDEV_UINPUT_H_
+
+#include <sys/types.h>
+#include <dev/evdev/input.h>
+
+#define UINPUT_VERSION         5
+#define        UINPUT_MAX_NAME_SIZE    80
+
+struct uinput_ff_upload {
+       uint32_t                request_id;
+       int32_t                 retval;
+       struct ff_effect        effect;
+       struct ff_effect        old;
+};
+
+struct uinput_ff_erase {
+       uint32_t                request_id;
+       int32_t                 retval;
+       uint32_t                effect_id;
+};
+
+/* ioctl */
+#define UINPUT_IOCTL_BASE      'U'
+
+#define UI_DEV_CREATE          _IO(UINPUT_IOCTL_BASE, 1)
+#define UI_DEV_DESTROY         _IO(UINPUT_IOCTL_BASE, 2)
+
+struct uinput_setup {
+       struct input_id id;
+       char            name[UINPUT_MAX_NAME_SIZE];
+       uint32_t        ff_effects_max;
+};
+
+#define UI_DEV_SETUP _IOW(UINPUT_IOCTL_BASE, 3, struct uinput_setup)
+
+struct uinput_abs_setup {
+       uint16_t                code; /* axis code */
+       struct input_absinfo    absinfo;
+};
+
+#define UI_ABS_SETUP           _IOW(UINPUT_IOCTL_BASE, 4, struct 
uinput_abs_setup)
+
+#define UI_GET_SYSNAME(len)    _IOC(IOC_OUT, UINPUT_IOCTL_BASE, 44, len)
+#define UI_GET_VERSION         _IOR(UINPUT_IOCTL_BASE, 45, unsigned int)
+
+#define UI_SET_EVBIT           _IOWINT(UINPUT_IOCTL_BASE, 100)
+#define UI_SET_KEYBIT          _IOWINT(UINPUT_IOCTL_BASE, 101)
+#define UI_SET_RELBIT          _IOWINT(UINPUT_IOCTL_BASE, 102)
+#define UI_SET_ABSBIT          _IOWINT(UINPUT_IOCTL_BASE, 103)
+#define UI_SET_MSCBIT          _IOWINT(UINPUT_IOCTL_BASE, 104)
+#define UI_SET_LEDBIT          _IOWINT(UINPUT_IOCTL_BASE, 105)
+#define UI_SET_SNDBIT          _IOWINT(UINPUT_IOCTL_BASE, 106)
+#define UI_SET_FFBIT           _IOWINT(UINPUT_IOCTL_BASE, 107)
+#define UI_SET_PHYS            _IO(UINPUT_IOCTL_BASE, 108)
+#define UI_SET_SWBIT           _IOWINT(UINPUT_IOCTL_BASE, 109)
+#define UI_SET_PROPBIT         _IOWINT(UINPUT_IOCTL_BASE, 110)
+
+#define UI_BEGIN_FF_UPLOAD     _IOWR(UINPUT_IOCTL_BASE, 200, struct 
uinput_ff_upload)
+#define UI_END_FF_UPLOAD       _IOW(UINPUT_IOCTL_BASE, 201, struct 
uinput_ff_upload)
+#define UI_BEGIN_FF_ERASE      _IOWR(UINPUT_IOCTL_BASE, 202, struct 
uinput_ff_erase)
+#define UI_END_FF_ERASE                _IOW(UINPUT_IOCTL_BASE, 203, struct 
uinput_ff_erase)
+
+#define EV_UINPUT              0x0101
+#define UI_FF_UPLOAD           1
+#define UI_FF_ERASE            2
+
+struct uinput_user_dev {
+       char            name[UINPUT_MAX_NAME_SIZE];
+       struct input_id id;
+       uint32_t        ff_effects_max;
+       int32_t         absmax[ABS_CNT];
+       int32_t         absmin[ABS_CNT];
+       int32_t         absfuzz[ABS_CNT];
+       int32_t         absflat[ABS_CNT];
+};
+
+#endif /* _EVDEV_UINPUT_H_ */
-- 
1.9.1

_______________________________________________
devel mailing list
devel@rtems.org
http://lists.rtems.org/mailman/listinfo/devel

Reply via email to