Skip site navigation (1)Skip section navigation (2)
Date:      Wed, 11 Jun 2014 18:45:47 +0000 (UTC)
From:      Jakub Wojciech Klama <jceel@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-user@freebsd.org
Subject:   svn commit: r267369 - user/jceel/soc2014_evdev/head/sys/dev/evdev
Message-ID:  <201406111845.s5BIjl2f032157@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
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 */



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201406111845.s5BIjl2f032157>