Date: Wed, 2 Jul 2014 15:40:25 +0000 (UTC) From: Jakub Wojciech Klama <jceel@FreeBSD.org> To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r268163 - in user/jceel/soc2014_evdev/head/sys: conf dev/evdev Message-ID: <201407021540.s62FePTQ029148@svn.freebsd.org>
next in thread | raw e-mail | index | archive | help
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@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)
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201407021540.s62FePTQ029148>