Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 13 Apr 2020 22:18:50 +0000 (UTC)
From:      Vladimir Kondratyev <wulf@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-12@freebsd.org
Subject:   svn commit: r359906 - stable/12/sys/dev/evdev
Message-ID:  <202004132218.03DMIoOe010626@repo.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: wulf
Date: Mon Apr 13 22:18:49 2020
New Revision: 359906
URL: https://svnweb.freebsd.org/changeset/base/359906

Log:
  MFC r359428:
  evdev: Add COMPAT_FREEBSD32 support for amd64 arch
  
  Incompatibility between i386 and amd64 evdev ABIs was caused by presence of
  'struct timeval' in evdev protocol. Replace it with 'struct timeval32' for
  32 bit binaries.
  
  Big-endian platforms may require additional work due to bitstr_t (array of
  unsigned longs) usage in ioctl interface.
  
  MFC r359429:
  evdev: return error rather than zero-length data on blocked read()
  if blocked process has been woken up by evdev device destruction.

Modified:
  stable/12/sys/dev/evdev/cdev.c
Directory Properties:
  stable/12/   (props changed)

Modified: stable/12/sys/dev/evdev/cdev.c
==============================================================================
--- stable/12/sys/dev/evdev/cdev.c	Mon Apr 13 22:06:28 2020	(r359905)
+++ stable/12/sys/dev/evdev/cdev.c	Mon Apr 13 22:18:49 2020	(r359906)
@@ -47,6 +47,18 @@
 #include <dev/evdev/evdev_private.h>
 #include <dev/evdev/input.h>
 
+#ifdef COMPAT_FREEBSD32
+#include <sys/mount.h>
+#include <sys/sysent.h>
+#include <compat/freebsd32/freebsd32.h>
+struct input_event32 {
+	struct timeval32	time;
+	uint16_t		type;
+	uint16_t		code;
+	int32_t			value;
+};
+#endif
+
 #ifdef EVDEV_DEBUG
 #define	debugf(client, fmt, args...)	printf("evdev cdev: "fmt"\n", ##args)
 #else
@@ -161,7 +173,14 @@ static int
 evdev_read(struct cdev *dev, struct uio *uio, int ioflag)
 {
 	struct evdev_client *client;
-	struct input_event event;
+	union {
+		struct input_event t;
+#ifdef COMPAT_FREEBSD32
+		struct input_event32 t32;
+#endif
+	} event;
+	struct input_event *head;
+	size_t evsize;
 	int ret = 0;
 	int remaining;
 
@@ -175,11 +194,18 @@ evdev_read(struct cdev *dev, struct uio *uio, int iofl
 	if (client->ec_revoked)
 		return (ENODEV);
 
+#ifdef COMPAT_FREEBSD32
+	if (SV_CURPROC_FLAG(SV_ILP32))
+		evsize = sizeof(struct input_event32);
+	else
+#endif
+		evsize = sizeof(struct input_event);
+
 	/* Zero-sized reads are allowed for error checking */
-	if (uio->uio_resid != 0 && uio->uio_resid < sizeof(struct input_event))
+	if (uio->uio_resid != 0 && uio->uio_resid < evsize)
 		return (EINVAL);
 
-	remaining = uio->uio_resid / sizeof(struct input_event);
+	remaining = uio->uio_resid / evsize;
 
 	EVDEV_CLIENT_LOCKQ(client);
 
@@ -191,19 +217,31 @@ evdev_read(struct cdev *dev, struct uio *uio, int iofl
 				client->ec_blocked = true;
 				ret = mtx_sleep(client, &client->ec_buffer_mtx,
 				    PCATCH, "evread", 0);
+				if (ret == 0 && client->ec_revoked)
+					ret = ENODEV;
 			}
 		}
 	}
 
 	while (ret == 0 && !EVDEV_CLIENT_EMPTYQ(client) && remaining > 0) {
-		memcpy(&event, &client->ec_buffer[client->ec_buffer_head],
-		    sizeof(struct input_event));
+		head = client->ec_buffer + client->ec_buffer_head;
+#ifdef COMPAT_FREEBSD32
+		if (SV_CURPROC_FLAG(SV_ILP32)) {
+			bzero(&event.t32, sizeof(struct input_event32));
+			TV_CP(*head, event.t32, time);
+			CP(*head, event.t32, type);
+			CP(*head, event.t32, code);
+			CP(*head, event.t32, value);
+		} else
+#endif
+			bcopy(head, &event.t, evsize);
+
 		client->ec_buffer_head =
 		    (client->ec_buffer_head + 1) % client->ec_buffer_size;
 		remaining--;
 
 		EVDEV_CLIENT_UNLOCKQ(client);
-		ret = uiomove(&event, sizeof(struct input_event), uio);
+		ret = uiomove(&event, evsize, uio);
 		EVDEV_CLIENT_LOCKQ(client);
 	}
 
@@ -217,7 +255,13 @@ evdev_write(struct cdev *dev, struct uio *uio, int iof
 {
 	struct evdev_dev *evdev = dev->si_drv1;
 	struct evdev_client *client;
-	struct input_event event;
+	union {
+		struct input_event t;
+#ifdef COMPAT_FREEBSD32
+		struct input_event32 t32;
+#endif
+	} event;
+	size_t evsize;
 	int ret = 0;
 
 	ret = devfs_get_cdevpriv((void **)&client);
@@ -230,16 +274,30 @@ evdev_write(struct cdev *dev, struct uio *uio, int iof
 	if (client->ec_revoked || evdev == NULL)
 		return (ENODEV);
 
-	if (uio->uio_resid % sizeof(struct input_event) != 0) {
+#ifdef COMPAT_FREEBSD32
+	if (SV_CURPROC_FLAG(SV_ILP32))
+		evsize = sizeof(struct input_event32);
+	else
+#endif
+		evsize = sizeof(struct input_event);
+
+	if (uio->uio_resid % evsize != 0) {
 		debugf(client, "write size not multiple of input_event size");
 		return (EINVAL);
 	}
 
 	while (uio->uio_resid > 0 && ret == 0) {
-		ret = uiomove(&event, sizeof(struct input_event), uio);
-		if (ret == 0)
-			ret = evdev_inject_event(evdev, event.type, event.code,
-			    event.value);
+		ret = uiomove(&event, evsize, uio);
+		if (ret == 0) {
+#ifdef COMPAT_FREEBSD32
+			if (SV_CURPROC_FLAG(SV_ILP32))
+				ret = evdev_inject_event(evdev, event.t32.type,
+				    event.t32.code, event.t32.value);
+			else
+#endif
+				ret = evdev_inject_event(evdev, event.t.type,
+				    event.t.code, event.t.value);
+		}
 	}
 
 	return (ret);



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