From owner-svn-src-user@FreeBSD.ORG Wed Jun 11 18:45:48 2014 Return-Path: Delivered-To: svn-src-user@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) (using TLSv1 with cipher ADH-AES256-SHA (256/256 bits)) (No client certificate requested) by hub.freebsd.org (Postfix) with ESMTPS id 5D0EF341; Wed, 11 Jun 2014 18:45:48 +0000 (UTC) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id 49ABF2761; Wed, 11 Jun 2014 18:45:48 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.8/8.14.8) with ESMTP id s5BIjmVV032160; Wed, 11 Jun 2014 18:45:48 GMT (envelope-from jceel@svn.freebsd.org) Received: (from jceel@localhost) by svn.freebsd.org (8.14.8/8.14.8/Submit) id s5BIjl2f032157; Wed, 11 Jun 2014 18:45:47 GMT (envelope-from jceel@svn.freebsd.org) Message-Id: <201406111845.s5BIjl2f032157@svn.freebsd.org> From: Jakub Wojciech Klama Date: Wed, 11 Jun 2014 18:45:47 +0000 (UTC) To: src-committers@freebsd.org, svn-src-user@freebsd.org Subject: svn commit: r267369 - user/jceel/soc2014_evdev/head/sys/dev/evdev X-SVN-Group: user MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-user@freebsd.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: "SVN commit messages for the experimental " user" src tree" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 11 Jun 2014 18:45:48 -0000 Author: jceel Date: Wed Jun 11 18:45:47 2014 New Revision: 267369 URL: http://svnweb.freebsd.org/changeset/base/267369 Log: Add support for more ioctls and change behavior of EVIOCG(LED|KEY|SW|SND) so when called, events of corresponding type are removed from the input queue. Modified: user/jceel/soc2014_evdev/head/sys/dev/evdev/cdev.c user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.c user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.h Modified: user/jceel/soc2014_evdev/head/sys/dev/evdev/cdev.c ============================================================================== --- user/jceel/soc2014_evdev/head/sys/dev/evdev/cdev.c Wed Jun 11 18:24:51 2014 (r267368) +++ user/jceel/soc2014_evdev/head/sys/dev/evdev/cdev.c Wed Jun 11 18:45:47 2014 (r267369) @@ -294,13 +294,18 @@ evdev_ioctl(struct cdev *dev, u_long cmd { struct evdev_cdev_softc *sc = dev->si_drv1; struct evdev_dev *evdev = sc->ecs_evdev; - //struct input_id id; - int len, num, limit; + struct evdev_cdev_state *state; + struct input_keymap_entry *ke; + int ret, len, num, limit; len = IOCPARM_LEN(cmd); cmd = IOCBASECMD(cmd); num = IOCNUM(cmd); + ret = devfs_get_cdevpriv((void **)&state); + if (ret != 0) + return (ret); + debugf("cdev: ioctl called: cmd=0x%08lx, data=%p", cmd, data); switch (cmd) { @@ -309,28 +314,38 @@ evdev_ioctl(struct cdev *dev, u_long cmd break; case EVIOCGID: + memcpy(data, &evdev->ev_id, sizeof(struct input_id)); break; case EVIOCGREP: - break; + return ENOTSUP; case EVIOCSREP: - break; + return ENOTSUP; case EVIOCGKEYCODE: - break; + return ENOTSUP; case EVIOCGKEYCODE_V2: + if (evdev->ev_methods->ev_get_keycode == NULL) + return ENOTSUP; + + ke = (struct keymap_entry *)data; + evdev->ev_methods->ev_get_keycode(evdev, evdev->ev_softc, ke); break; case EVIOCSKEYCODE: - break; + return ENOTSUP; case EVIOCSKEYCODE_V2: + if (evdev->ev_methods->ev_set_keycode == NULL) + return ENOTSUP; + + ke = (struct keymap_entry *)data; + evdev->ev_methods->ev_set_keycode(evdev, evdev->ev_softc, ke); break; case EVIOCGNAME(0): - debugf("EVIOCGNAME: data=%p, ev_name=%s, len=%d", data, evdev->ev_name, len); strlcpy(data, evdev->ev_name, len); break; @@ -348,26 +363,40 @@ evdev_ioctl(struct cdev *dev, u_long cmd break; case EVIOCGKEY(0): + evdev_client_filter_queue(state->ecs_client, EV_KEY); limit = MIN(len, howmany(KEY_CNT, 8)); memcpy(data, evdev->ev_key_states, limit); break; case EVIOCGLED(0): + evdev_client_filter_queue(state->ecs_client, EV_LED); limit = MIN(len, howmany(LED_CNT, 8)); memcpy(data, evdev->ev_led_states, limit); break; case EVIOCGSND(0): + evdev_client_filter_queue(state->ecs_client, EV_SND); limit = MIN(len, howmany(SND_CNT, 8)); memcpy(data, evdev->ev_snd_states, limit); break; case EVIOCGSW(0): + evdev_client_filter_queue(state->ecs_client, EV_SW); limit = MIN(len, howmany(SW_CNT, 8)); memcpy(data, evdev->ev_sw_states, limit); break; + + case EVIOCGRAB: + if (data) + evdev_grab_client(state->ecs_client); + else + evdev_release_client(state->ecs_client); + break; + + case EVIOCREVOKE: + break; } if (IOCGROUP(cmd) != 'E') @@ -390,7 +419,9 @@ evdev_ioctl(struct cdev *dev, u_long cmd /* Handle EVIOCSABS variants */ if (num >= IOCNUM(EVIOCSABS(0)) && num < IOCNUM(EVIOCSABS(ABS_CNT))) { int index = num - IOCNUM(EVIOCSABS(0)); + EVDEV_LOCK(evdev); memcpy(&evdev->ev_absinfo[index], data, len); + EVDEV_UNLOCK(evdev); } return (0); Modified: user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.c ============================================================================== --- user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.c Wed Jun 11 18:24:51 2014 (r267368) +++ user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.c Wed Jun 11 18:45:47 2014 (r267369) @@ -44,6 +44,8 @@ #define debugf(fmt, args...) #endif +#define DEF_RING_SIZE 16 + MALLOC_DEFINE(M_EVDEV, "evdev", "evdev memory"); static inline void changebit(uint32_t *array, int, int); @@ -76,6 +78,7 @@ 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); @@ -228,6 +231,19 @@ evdev_push_event(struct evdev_dev *evdev } int +evdev_inject_event(struct evdev_dev *evdev, uint16_t type, uint16_t code, + int32_t value) +{ + + if (evdev->ev_methods->ev_event != NULL) { + evdev->ev_methods->ev_event(evdev, evdev->ev_softc, type, + code, value); + } + + return (0); +} + +int evdev_sync(struct evdev_dev *evdev) { @@ -241,14 +257,16 @@ evdev_register_client(struct evdev_dev * /* Initialize client structure */ client = malloc(sizeof(struct evdev_client), M_EVDEV, M_WAITOK | M_ZERO); - mtx_init(&client->ec_buffer_mtx, "evmtx", "evdev", MTX_DEF); + mtx_init(&client->ec_buffer_mtx, "evclient", "evdev", MTX_DEF); client->ec_evdev = evdev; /* Initialize ring buffer */ - client->ec_buffer = malloc(sizeof(struct input_event) * 10, M_EVDEV, M_WAITOK | M_ZERO); - client->ec_buffer_size = 10; + client->ec_buffer = malloc(sizeof(struct input_event) * DEF_RING_SIZE, + M_EVDEV, M_WAITOK | M_ZERO); + client->ec_buffer_size = DEF_RING_SIZE; client->ec_buffer_head = 0; client->ec_buffer_tail = 0; + client->ec_enabled = true; debugf("adding new client for device %s", evdev->ev_shortname); @@ -283,15 +301,68 @@ evdev_dispose_client(struct evdev_client return (0); } +int +evdev_grab_client(struct evdev_client *client) +{ + struct evdev_dev *evdev = client->ec_evdev; + struct evdev_client *iter; + + EVDEV_LOCK(evdev); + if (evdev->ev_grabbed) { + EVDEV_UNLOCK(evdev); + return (EBUSY); + } + + evdev->ev_grabbed = true; + + /* Disable all other clients */ + LIST_FOREACH(iter, &evdev->ev_clients, ec_link) { + if (iter != client) + iter->ec_enabled = false; + } + + EVDEV_UNLOCK(evdev); + return (0); +} + +int +evdev_release_client(struct evdev_client *client) +{ + struct evdev_dev *evdev = client->ec_evdev; + struct evdev_client *iter; + + EVDEV_LOCK(evdev); + if (!evdev->ev_grabbed) { + EVDEV_UNLOCK(evdev); + return (EINVAL); + } + + evdev->ev_grabbed = false; + + /* Enable all other clients */ + LIST_FOREACH(iter, &evdev->ev_clients, ec_link) { + iter->ec_enabled = true; + } + + EVDEV_UNLOCK(evdev); + return (0); +} + static void evdev_client_push(struct evdev_client *client, uint16_t type, uint16_t code, int32_t value) { int count, head, tail; - mtx_lock(&client->ec_buffer_mtx); + + EVDEV_CLIENT_LOCKQ(client); head = client->ec_buffer_head; tail = client->ec_buffer_tail; count = client->ec_buffer_size; + + if (!client->ec_enabled) { + EVDEV_CLIENT_UNLOCKQ(client); + return; + } /* If queue is full, overwrite last element with SYN_DROPPED event */ if ((tail + 1) % count == head) { @@ -303,7 +374,7 @@ evdev_client_push(struct evdev_client *c client->ec_buffer[tail].code = SYN_DROPPED; wakeup(client); - mtx_unlock(&client->ec_buffer_mtx); + EVDEV_CLIENT_UNLOCKQ(client); return; } @@ -314,6 +385,82 @@ evdev_client_push(struct evdev_client *c client->ec_buffer_tail = (tail + 1) % count; wakeup(client); - mtx_unlock(&client->ec_buffer_mtx); + EVDEV_CLIENT_UNLOCKQ(client); } +void +evdev_client_dumpqueue(struct evdev_client *client) +{ + struct input_event *event; + int i, head, tail, size; + + head = client->ec_buffer_head; + tail = client->ec_buffer_tail; + size = client->ec_buffer_size; + + printf("evdev client: %p\n", client); + printf("evdev provider name: %s\n", client->ec_evdev->ev_name); + printf("event queue: head=%d tail=%d size=%d\n", tail, head, size); + + printf("queue contents:\n"); + + for (i = 0; i < size; i++) { + event = &client->ec_buffer[i]; + printf("%d: ", 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 + printf("\n"); + } +} + +void +evdev_client_filter_queue(struct evdev_client *client, uint16_t type) +{ + struct input_event *event; + int 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; + + 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 && + last_was_syn) + continue; + + /* 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); +} Modified: user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.h ============================================================================== --- user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.h Wed Jun 11 18:24:51 2014 (r267368) +++ user/jceel/soc2014_evdev/head/sys/dev/evdev/evdev.h Wed Jun 11 18:45:47 2014 (r267369) @@ -42,7 +42,10 @@ struct evdev_client; 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_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 *); typedef void (evdev_client_event_t)(struct evdev_client *, void *); struct evdev_methods @@ -50,6 +53,8 @@ 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; }; struct evdev_dev @@ -60,6 +65,9 @@ struct evdev_dev device_t ev_dev; void * ev_softc; struct cdev * ev_cdev; + struct mtx ev_mtx; + struct input_id ev_id; + bool ev_grabbed; /* Supported features: */ uint32_t ev_type_flags[howmany(EV_CNT, 32)]; @@ -78,6 +86,10 @@ struct evdev_dev uint32_t ev_snd_states[howmany(SND_CNT, 32)]; uint32_t ev_sw_states[howmany(SW_CNT, 32)]; + /* Keyboard delay/repeat: */ + int ev_kbd_delay; + int ev_kbd_repeat; + /* Counters: */ uint64_t ev_event_count; int ev_clients_count; @@ -88,6 +100,9 @@ struct evdev_dev LIST_HEAD(, evdev_client) ev_clients; }; +#define EVDEV_LOCK(evdev) mtx_lock(&(evdev)->ev_mtx) +#define EVDEV_UNLOCK(evdev) mtx_unlock(&(evdev)->ev_mtx) + struct evdev_client { struct evdev_dev * ec_evdev; @@ -118,8 +133,8 @@ void evdev_set_methods(struct evdev_dev void evdev_set_softc(struct evdev_dev *, void *); int evdev_register(device_t, struct evdev_dev *); int evdev_unregister(device_t, struct evdev_dev *); -int evdev_push_event(struct evdev_dev *, uint16_t type, uint16_t code, - int32_t value); +int evdev_push_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_sync(struct evdev_dev *); int evdev_cdev_create(struct evdev_dev *); int evdev_cdev_destroy(struct evdev_dev *); @@ -136,9 +151,13 @@ void evdev_set_absinfo(struct evdev_dev /* Client interface: */ int evdev_register_client(struct evdev_dev *, struct evdev_client **); int evdev_dispose_client(struct evdev_client *); +int evdev_grab_client(struct evdev_client *); +int evdev_release_client(struct evdev_client *); +void evdev_client_filter_queue(struct evdev_client *, uint16_t); /* Utility functions: */ uint16_t evdev_hid2key(int); uint16_t evdev_at2key(int); +void evdev_client_dumpqueue(struct evdev_client *); #endif /* _DEV_EVDEV_EVDEV_H */