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