blob: 09c058779b000cdac143d4c80e09075ed6c42279 [file] [log] [blame]
From b443a1863fb3349d8d1e599fdd5b5b4cefcb69f1 Mon Sep 17 00:00:00 2001
From: Michael Spang <spang@google.com>
Date: Mon, 13 Aug 2012 11:35:32 -0400
Subject: [PATCH] Add events debug log support
This adds a new xinput property "Dump Debug Logs" that dumps the last
64k input events to /var/log/evdev_input_events.dat for touchscreen
devices only.
---
src/Makefile.am | 3 +-
src/debug.c | 143 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
src/evdev.c | 15 +++++-
src/evdev.h | 14 ++++++
4 files changed, 173 insertions(+), 2 deletions(-)
create mode 100644 src/debug.c
diff --git a/src/Makefile.am b/src/Makefile.am
index 804ef73..0108bc9 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -39,5 +39,6 @@ AM_CPPFLAGS =-I$(top_srcdir)/include
emuThird.c \
emuWheel.c \
draglock.c \
- apple.c
+ apple.c \
+ debug.c
diff --git a/src/debug.c b/src/debug.c
new file mode 100644
index 0000000..493dec8
--- /dev/null
+++ b/src/debug.c
@@ -0,0 +1,143 @@
+// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <evdev.h>
+#include <evdev-properties.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <exevents.h>
+#include <xf86.h>
+#include <xf86Xinput.h>
+#include <X11/Xatom.h>
+
+#define XI_PROP_DUMP_DEBUG_LOG "Dump Debug Log"
+
+#define INPUT_EVENTS_LOG_FILE "/var/log/xorg/evdev_input_events.dat"
+
+static Atom dump_debug_log_prop;
+
+static void
+EvdevDumpLog(InputInfoPtr pInfo) {
+ EvdevPtr pEvdev = pInfo->private;
+ int i;
+ FILE *fp;
+
+ if (!pEvdev->debug_buf)
+ return;
+
+ fp = fopen(INPUT_EVENTS_LOG_FILE, "w");
+ if (!fp) {
+ xf86IDrvMsg(pInfo, X_ERROR, "fopen: %s: %s\n",
+ INPUT_EVENTS_LOG_FILE, strerror(errno));
+ return;
+ }
+
+ fprintf(fp, "# device: %s\n", pInfo->name);
+
+ for (i = ABS_X; i <= ABS_MAX; i++) {
+ if (EvdevBitIsSet(pEvdev->abs_bitmask, i)) {
+ fprintf(fp, "# absinfo: %d %d %d %d %d %d\n",
+ /* event code (axis) */ i,
+ pEvdev->absinfo[i].minimum,
+ pEvdev->absinfo[i].maximum,
+ pEvdev->absinfo[i].fuzz,
+ pEvdev->absinfo[i].flat,
+ pEvdev->absinfo[i].resolution);
+ }
+ }
+
+ for (i = 0; i < DEBUG_BUF_SIZE; ++i) {
+ struct debug_event *de =
+ &pEvdev->debug_buf[(pEvdev->debug_buf_tail + i) % DEBUG_BUF_SIZE];
+ if (de->ev.time.tv_sec == 0 && de->ev.time.tv_usec == 0)
+ continue;
+ fprintf(fp, "E: %ld.%06ld %04x %04x %d %d\n",
+ de->ev.time.tv_sec,
+ de->ev.time.tv_usec,
+ de->ev.type,
+ de->ev.code,
+ de->ev.value,
+ de->slot);
+ }
+
+ fclose(fp);
+}
+
+static int
+EvdevDebugGetProperty(DeviceIntPtr dev, Atom property)
+{
+ return Success;
+}
+
+static int
+EvdevDebugSetProperty(DeviceIntPtr dev, Atom atom,
+ XIPropertyValuePtr val, BOOL checkonly)
+{
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+ CARD32 data;
+
+ if (atom == dump_debug_log_prop) {
+ if (val->type != XA_INTEGER || val->format != 32 || val->size != 1)
+ return BadMatch;
+
+ data = *(CARD32 *)val->data;
+
+ if (data != 1)
+ return BadValue;
+
+ if (!checkonly)
+ EvdevDumpLog(pInfo);
+ }
+
+ return Success;
+}
+
+void
+EvdevDebugFreeBuffer(EvdevPtr pEvdev)
+{
+ if (pEvdev->debug_buf) {
+ free(pEvdev->debug_buf);
+ pEvdev->debug_buf = NULL;
+ }
+}
+
+void
+EvdevDebugAllocateBuffer(EvdevPtr pEvdev)
+{
+ if (pEvdev->flags & EVDEV_TOUCHSCREEN) {
+ pEvdev->debug_buf = (struct debug_event *)
+ malloc(sizeof(struct debug_event) * DEBUG_BUF_SIZE);
+ } else {
+ pEvdev->debug_buf = NULL;
+ }
+}
+
+void
+EvdevDebugInitProperty(DeviceIntPtr dev)
+{
+ InputInfoPtr pInfo = dev->public.devicePrivate;
+ EvdevPtr pEvdev = pInfo->private;
+
+ if (!(pEvdev->flags & EVDEV_TOUCHSCREEN))
+ return;
+
+ dump_debug_log_prop = MakeAtom(XI_PROP_DUMP_DEBUG_LOG,
+ strlen(XI_PROP_DUMP_DEBUG_LOG), TRUE);
+ CARD32 prop_dump_debug_log_init = 0;
+
+ XIChangeDeviceProperty(dev, dump_debug_log_prop, XA_INTEGER,
+ /* format */ 32, PropModeReplace, /* size */ 1,
+ &prop_dump_debug_log_init, FALSE);
+ XISetDevicePropertyDeletable(dev, dump_debug_log_prop, FALSE);
+ XIRegisterPropertyHandler(dev, EvdevDebugSetProperty,
+ EvdevDebugGetProperty, NULL);
+}
diff --git a/src/evdev.c b/src/evdev.c
index 2856e3b..84f5be6 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -219,7 +219,7 @@ static size_t EvdevCountBits(unsigned long *array, size_t nlongs)
return count;
}
-static inline int EvdevBitIsSet(const unsigned long *array, int bit)
+inline int EvdevBitIsSet(const unsigned long *array, int bit)
{
return !!(array[bit / LONG_BITS] & (1LL << (bit % LONG_BITS)));
}
@@ -1198,6 +1198,7 @@ static BOOL
EvdevProcessEvent(InputInfoPtr pInfo, struct input_event *ev)
{
BOOL syn_dropped = FALSE;
+ EvdevPtr pEvdev = pInfo->private;
switch (ev->type) {
case EV_REL:
EvdevProcessRelativeMotionEvent(pInfo, ev);
@@ -1212,6 +1213,15 @@ EvdevProcessEvent(InputInfoPtr pInfo, struct input_event *ev)
syn_dropped = EvdevProcessSyncEvent(pInfo, ev);
break;
}
+
+ // Add touch events to the debug log. Keypresses are not included.
+ if (pEvdev->debug_buf && (ev->type == EV_ABS || ev->type == EV_SYN ||
+ (ev->type == EV_KEY && ev->code == BTN_TOUCH))) {
+ pEvdev->debug_buf[pEvdev->debug_buf_tail].ev = *ev;
+ pEvdev->debug_buf[pEvdev->debug_buf_tail].slot = pEvdev->cur_slot;
+ pEvdev->debug_buf_tail++;
+ pEvdev->debug_buf_tail %= DEBUG_BUF_SIZE;
+ }
return syn_dropped;
}
@@ -2312,6 +2322,8 @@ EvdevInit(DeviceIntPtr device)
EvdevWheelEmuInitProperty(device);
EvdevDragLockInitProperty(device);
EvdevAppleInitProperty(device);
+ EvdevDebugAllocateBuffer(pEvdev);
+ EvdevDebugInitProperty(device);
return Success;
}
@@ -2395,6 +2407,7 @@ EvdevProc(DeviceIntPtr device, int what)
case DEVICE_CLOSE:
xf86IDrvMsg(pInfo, X_INFO, "Close\n");
EvdevCloseDevice(pInfo);
+ EvdevDebugFreeBuffer(pEvdev);
EvdevFreeMasks(pEvdev);
EvdevRemoveDevice(pInfo);
pEvdev->min_maj = 0;
diff --git a/src/evdev.h b/src/evdev.h
index 5d6045d..6f87326 100644
--- a/src/evdev.h
+++ b/src/evdev.h
@@ -101,6 +101,8 @@
/* Number of longs needed to hold the given number of bits */
#define NLONGS(x) (((x) + LONG_BITS - 1) / LONG_BITS)
+#define DEBUG_BUF_SIZE 65536
+
#define _ABS_MT_FIRST ABS_MT_TOUCH_MAJOR
#define _ABS_MT_LAST ABS_MT_DISTANCE
#define _ABS_MT_CNT (_ABS_MT_LAST - _ABS_MT_FIRST + 1)
@@ -268,6 +270,12 @@ typedef struct {
int num_queue;
EventQueueRec queue[EVDEV_MAXQUEUE];
+ struct debug_event {
+ struct input_event ev;
+ int slot;
+ } *debug_buf;
+ size_t debug_buf_tail;
+
enum fkeymode fkeymode;
/* Sync timestamps */
@@ -329,9 +337,15 @@ BOOL EvdevWheelEmuFilterMotion(InputInfoPtr pInfo, struct input_event *pEv);
void EvdevDragLockPreInit(InputInfoPtr pInfo);
BOOL EvdevDragLockFilterEvent(InputInfoPtr pInfo, unsigned int button, int value);
+int EvdevBitIsSet(const unsigned long *array, int bit);
+
void EvdevMBEmuInitProperty(DeviceIntPtr);
void Evdev3BEmuInitProperty(DeviceIntPtr);
void EvdevWheelEmuInitProperty(DeviceIntPtr);
void EvdevDragLockInitProperty(DeviceIntPtr);
void EvdevAppleInitProperty(DeviceIntPtr);
+void EvdevDebugInitProperty(DeviceIntPtr);
+void EvdevDebugAllocateBuffer(EvdevPtr);
+void EvdevDebugFreeBuffer(EvdevPtr);
+
#endif
--
1.8.1.5