svn commit: r268163 - in user/jceel/soc2014_evdev/head/sys: conf dev/evdev
Jakub Wojciech Klama
jceel at FreeBSD.org
Wed Jul 2 15:40:26 UTC 2014
Author: jceel
Date: Wed Jul 2 15:40:25 2014
New Revision: 268163
URL: http://svnweb.freebsd.org/changeset/base/268163
Log:
Adding initial uinput support, adapting uinput.h to FreeBSD ioctl specifics.
Added:
user/jceel/soc2014_evdev/head/sys/dev/evdev/uinput.c (contents, props changed)
Modified:
user/jceel/soc2014_evdev/head/sys/conf/files
user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.c
user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.h
user/jceel/soc2014_evdev/head/sys/dev/evdev/uinput.h
Modified: user/jceel/soc2014_evdev/head/sys/conf/files
==============================================================================
--- user/jceel/soc2014_evdev/head/sys/conf/files Wed Jul 2 15:23:13 2014 (r268162)
+++ user/jceel/soc2014_evdev/head/sys/conf/files Wed Jul 2 15:40:25 2014 (r268163)
@@ -1364,6 +1364,7 @@ dev/etherswitch/ukswitch/ukswitch.c opti
dev/evdev/evdev.c optional evdev
dev/evdev/cdev.c optional evdev
dev/evdev/evdev_utils.c optional evdev
+dev/evdev/uinput.c optional evdev
dev/ex/if_ex.c optional ex
dev/ex/if_ex_isa.c optional ex isa
dev/ex/if_ex_pccard.c optional ex pccard
Modified: user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.c
==============================================================================
--- user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.c Wed Jul 2 15:23:13 2014 (r268162)
+++ user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.c Wed Jul 2 15:40:25 2014 (r268163)
@@ -77,6 +77,13 @@ evdev_alloc(void)
return malloc(sizeof(struct evdev_dev), M_EVDEV, M_WAITOK | M_ZERO);
}
+void
+evdev_free(struct evdev_dev *evdev)
+{
+
+ free(evdev, M_EVDEV);
+}
+
int
evdev_register(device_t dev, struct evdev_dev *evdev)
{
@@ -88,9 +95,13 @@ evdev_register(device_t dev, struct evde
/* Initialize internal structures */
evdev->ev_dev = dev;
mtx_init(&evdev->ev_mtx, "evmtx", "evdev", MTX_DEF);
- strlcpy(evdev->ev_shortname, device_get_nameunit(dev), NAMELEN);
LIST_INIT(&evdev->ev_clients);
+ if (dev != NULL)
+ strlcpy(evdev->ev_shortname, device_get_nameunit(dev), NAMELEN);
+ else
+ strlcpy(evdev->ev_shortname, "uinput", NAMELEN);
+
if (evdev->ev_repeat_mode == EVDEV_REPEAT) {
/* Initialize callout */
callout_init(&evdev->ev_rep_callout, 1);
@@ -214,7 +225,7 @@ evdev_support_repeat(struct evdev_dev *e
{
if (mode != NO_REPEAT)
- setbit(&evdev->ev_type_flags, EV_REP)
+ setbit(&evdev->ev_type_flags, EV_REP);
evdev->ev_repeat_mode = mode;
}
Modified: user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.h
==============================================================================
--- user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.h Wed Jul 2 15:23:13 2014 (r268162)
+++ user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.h Wed Jul 2 15:40:25 2014 (r268163)
@@ -135,6 +135,7 @@ struct evdev_client
/* 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_serial(struct evdev_dev *, const char *);
void evdev_set_methods(struct evdev_dev *, struct evdev_methods *);
Added: user/jceel/soc2014_evdev/head/sys/dev/evdev/uinput.c
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ user/jceel/soc2014_evdev/head/sys/dev/evdev/uinput.c Wed Jul 2 15:40:25 2014 (r268163)
@@ -0,0 +1,406 @@
+/*-
+ * Copyright (c) 2014 Jakub Wojciech Klama <jceel at 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$
+ */
+
+#include <sys/types.h>
+#include <sys/systm.h>
+#include <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/selinfo.h>
+#include <sys/malloc.h>
+
+#include <dev/evdev/input.h>
+#include <dev/evdev/uinput.h>
+#include <dev/evdev/evdev.h>
+
+#define DEBUG
+#ifdef DEBUG
+#define debugf(fmt, args...) printf("evdev: " fmt "\n", ##args);
+#else
+#define debugf(fmt, args...)
+#endif
+
+static int uinput_open(struct cdev *, int, int, struct thread *);
+static int uinput_close(struct cdev *, int, int, struct thread *);
+static int uinput_read(struct cdev *, struct uio *, int);
+static int uinput_write(struct cdev *, struct uio *, int);
+static int uinput_ioctl(struct cdev *, u_long, caddr_t, int, struct thread *);
+static int uinput_poll(struct cdev *, int, struct thread *);
+static int uinput_kqfilter(struct cdev *, struct knote *);
+static int uinput_kqread(struct knote *kn, long hint);
+static void uinput_kqdetach(struct knote *kn);
+static void uinput_dtor(void *);
+
+static int uinput_setup_provider(struct evdev_dev *, struct uinput_user_dev *);
+
+static evdev_open_t uinput_ev_open;
+static evdev_close_t uinput_ev_close;
+static evdev_event_t uinput_ev_event;
+
+static int uinput_cdev_create(void);
+
+static struct cdevsw uinput_cdevsw = {
+ .d_version = D_VERSION,
+ .d_open = uinput_open,
+ .d_close = uinput_close,
+ .d_read = uinput_read,
+ .d_write = uinput_write,
+ .d_ioctl = uinput_ioctl,
+ .d_poll = uinput_poll,
+ .d_kqfilter = uinput_kqfilter,
+ .d_name = "uinput",
+ .d_flags = D_TRACKCLOSE,
+};
+
+static struct filterops uinput_cdev_filterops = {
+ .f_isfd = 1,
+ .f_attach = NULL,
+ .f_detach = uinput_kqdetach,
+ .f_event = uinput_kqread,
+};
+
+static struct evdev_methods uinput_ev_methods = {
+ .ev_open = uinput_ev_open,
+ .ev_close = uinput_ev_close,
+ .ev_event = uinput_ev_event,
+};
+
+struct uinput_cdev_softc
+{
+ int ucs_open_count;
+
+ LIST_ENTRY(uinput_cdev_softc) ucs_link;
+};
+
+struct uinput_cdev_state
+{
+ bool ucs_connected;
+ struct evdev_dev * ucs_evdev;
+ struct evdev_dev ucs_state;
+ struct mtx ucs_mtx;
+ struct selinfo ucs_selp;
+ struct sigio * ucs_sigio;
+};
+
+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();
+
+ knlist_init_mtx(&state->ucs_selp.si_note, NULL);
+
+ devfs_set_cdevpriv(state, uinput_dtor);
+ return (0);
+}
+
+static int
+uinput_close(struct cdev *dev, int fflag, int devtype, struct thread *td)
+{
+ struct uinput_cdev_softc *sc = dev->si_drv1;
+
+ sc->ucs_open_count--;
+ return (0);
+}
+
+static void
+uinput_dtor(void *data)
+{
+ struct uinput_cdev_state *state = (struct uinput_cdev_state *)data;
+
+ evdev_unregister(NULL, state->ucs_evdev);
+ evdev_free(state->ucs_evdev);
+
+ seldrain(&state->ucs_selp);
+ free(data, M_EVDEV);
+}
+
+static int
+uinput_read(struct cdev *dev, struct uio *uio, int ioflag)
+{
+ struct uinput_cdev_state *state;
+ struct evdev_dev *evdev;
+ int ret = 0;
+
+ debugf("uinput: read %ld bytes by thread %d", uio->uio_resid,
+ uio->uio_td->td_tid);
+
+ ret = devfs_get_cdevpriv((void **)&state);
+ if (ret != 0)
+ return (ret);
+
+ evdev = state->ucs_evdev;
+
+ if (uio->uio_resid % sizeof(struct input_event) != 0) {
+ debugf("read size not multiple of struct input_event size");
+ return (EINVAL);
+ }
+
+ return (0);
+}
+
+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;
+
+ debugf("uinput: write %ld bytes by thread %d", uio->uio_resid,
+ uio->uio_td->td_tid);
+
+ ret = devfs_get_cdevpriv((void **)&state);
+ if (ret != 0)
+ return (ret);
+
+ if (!state->ucs_connected) {
+ /* Process written struct uinput_user_dev */
+ if (uio->uio_resid != sizeof(struct uinput_user_dev)) {
+ debugf("write size not multiple of struct uinput_user_dev size");
+ return (EINVAL);
+ }
+
+ uiomove(&userdev, sizeof(struct uinput_user_dev), uio);
+ uinput_setup_provider(state->ucs_evdev, &userdev);
+ } else {
+ /* Process written event */
+ if (uio->uio_resid % sizeof(struct input_event) != 0) {
+ debugf("write size not multiple of struct input_event size");
+ return (EINVAL);
+ }
+
+ while (uio->uio_resid > 0) {
+ uiomove(&event, sizeof(struct input_event), uio);
+ evdev_push_event(state->ucs_evdev, event.type, event.code,
+ event.value);
+ }
+ }
+
+ return (0);
+}
+
+static int
+uinput_setup_provider(struct evdev_dev *evdev, struct uinput_user_dev *udev)
+{
+ struct input_absinfo absinfo;
+ int i;
+
+ debugf("uinput: setup_provider called, udev=%p", udev);
+
+ evdev_set_name(evdev, udev->name);
+ memcpy(&evdev->ev_id, &udev->id, sizeof(struct input_id));
+
+ for (i = 0; i < ABS_CNT; i++) {
+ if (!isset(&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(evdev, i, &absinfo);
+ }
+
+ return (0);
+}
+
+static int
+uinput_poll(struct cdev *dev, int events, struct thread *td)
+{
+ struct uinput_cdev_state *state;
+ int ret;
+ int revents = 0;
+
+ debugf("cdev: poll by thread %d", td->td_tid);
+
+ ret = devfs_get_cdevpriv((void **)&state);
+ if (ret != 0)
+ return (ret);
+
+ 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);
+
+ kn->kn_hook = (caddr_t)state;
+ kn->kn_fop = &uinput_cdev_filterops;
+
+ 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;
+
+ state = (struct uinput_cdev_state *)kn->kn_hook;
+ return (0);
+}
+
+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 int
+uinput_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
+ struct thread *td)
+{
+ struct uinput_cdev_state *state;
+ int ret, len;
+
+ len = IOCPARM_LEN(cmd);
+
+ debugf("uinput: ioctl called: cmd=0x%08lx, data=%p", cmd, data);
+
+
+ ret = devfs_get_cdevpriv((void **)&state);
+ if (ret != 0)
+ return (ret);
+
+ switch (cmd) {
+ case UI_DEV_CREATE:
+ evdev_set_methods(state->ucs_evdev, &uinput_ev_methods);
+ evdev_set_softc(state->ucs_evdev, state);
+ evdev_register(NULL, state->ucs_evdev);
+ state->ucs_connected = true;
+ break;
+
+ case UI_DEV_DESTROY:
+ if (!state->ucs_connected)
+ return (0);
+
+ evdev_unregister(NULL, state->ucs_evdev);
+ evdev_free(state->ucs_evdev);
+ state->ucs_evdev = NULL;
+ state->ucs_connected = false;
+ break;
+
+ case UI_SET_EVBIT:
+ evdev_support_event(state->ucs_evdev, (uint16_t)data);
+ break;
+
+ case UI_SET_KEYBIT:
+ evdev_support_key(state->ucs_evdev, (uint16_t)data);
+ break;
+
+ case UI_SET_RELBIT:
+ evdev_support_rel(state->ucs_evdev, (uint16_t)data);
+ break;
+
+ case UI_SET_ABSBIT:
+ evdev_support_abs(state->ucs_evdev, (uint16_t)data);
+ break;
+
+ case UI_SET_MSCBIT:
+ evdev_support_msc(state->ucs_evdev, (uint16_t)data);
+ break;
+
+ case UI_SET_LEDBIT:
+ evdev_support_led(state->ucs_evdev, (uint16_t)data);
+ break;
+
+ case UI_SET_SNDBIT:
+ evdev_support_snd(state->ucs_evdev, (uint16_t)data);
+ break;
+
+ case UI_SET_PHYS:
+ break;
+
+ case UI_SET_SWBIT:
+ evdev_support_sw(state->ucs_evdev, (uint16_t)data);
+ break;
+
+ case UI_SET_PROPBIT:
+ break;
+ }
+
+ return (0);
+}
+
+static void
+uinput_notify_event(struct evdev_client *client, void *data)
+{
+ struct uinput_cdev_state *state = (struct uinput_cdev_state *)data;
+
+ selwakeup(&state->ucs_selp);
+}
+
+static int uinput_ev_open(struct evdev_dev *dev, void *softc)
+{
+
+ return (0);
+}
+
+
+static void uinput_ev_close(struct evdev_dev *dev, void *softc)
+{
+
+}
+
+static void uinput_ev_event(struct evdev_dev *dev, void *softc, uint16_t type,
+ uint16_t code, int32_t value)
+{
+
+}
+
+static int
+uinput_cdev_create(void)
+{
+ struct uinput_cdev_softc *sc;
+ struct cdev *cdev;
+
+ cdev = make_dev(&uinput_cdevsw, 0, UID_ROOT, GID_WHEEL, 0600,
+ "uinput");
+
+ sc = malloc(sizeof(struct uinput_cdev_softc), M_EVDEV, M_WAITOK | M_ZERO);
+
+ cdev->si_drv1 = sc;
+ return (0);
+}
+
+SYSINIT(uinput, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, uinput_cdev_create, NULL);
Modified: user/jceel/soc2014_evdev/head/sys/dev/evdev/uinput.h
==============================================================================
--- user/jceel/soc2014_evdev/head/sys/dev/evdev/uinput.h Wed Jul 2 15:23:13 2014 (r268162)
+++ user/jceel/soc2014_evdev/head/sys/dev/evdev/uinput.h Wed Jul 2 15:40:25 2014 (r268163)
@@ -56,17 +56,17 @@ struct uinput_ff_erase {
#define UI_DEV_CREATE _IO(UINPUT_IOCTL_BASE, 1)
#define UI_DEV_DESTROY _IO(UINPUT_IOCTL_BASE, 2)
-#define UI_SET_EVBIT _IOW(UINPUT_IOCTL_BASE, 100, int)
-#define UI_SET_KEYBIT _IOW(UINPUT_IOCTL_BASE, 101, int)
-#define UI_SET_RELBIT _IOW(UINPUT_IOCTL_BASE, 102, int)
-#define UI_SET_ABSBIT _IOW(UINPUT_IOCTL_BASE, 103, int)
-#define UI_SET_MSCBIT _IOW(UINPUT_IOCTL_BASE, 104, int)
-#define UI_SET_LEDBIT _IOW(UINPUT_IOCTL_BASE, 105, int)
-#define UI_SET_SNDBIT _IOW(UINPUT_IOCTL_BASE, 106, int)
-#define UI_SET_FFBIT _IOW(UINPUT_IOCTL_BASE, 107, 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 _IOW(UINPUT_IOCTL_BASE, 108, char*)
-#define UI_SET_SWBIT _IOW(UINPUT_IOCTL_BASE, 109, int)
-#define UI_SET_PROPBIT _IOW(UINPUT_IOCTL_BASE, 110, int)
+#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)
More information about the svn-src-user
mailing list