summaryrefslogtreecommitdiff
path: root/utils
diff options
context:
space:
mode:
Diffstat (limited to 'utils')
-rw-r--r--utils/CMakeLists.txt8
-rw-r--r--utils/kmstouch.cpp297
2 files changed, 305 insertions, 0 deletions
diff --git a/utils/CMakeLists.txt b/utils/CMakeLists.txt
index f79b207..25216f2 100644
--- a/utils/CMakeLists.txt
+++ b/utils/CMakeLists.txt
@@ -1,6 +1,9 @@
include_directories(${LIBDRM_INCLUDE_DIRS})
link_directories(${LIBDRM_LIBRARY_DIRS})
+include_directories(${LIBEVDEV_INCLUDE_DIRS})
+link_directories(${LIBEVDEV_LIBRARY_DIRS})
+
add_executable (kmstest kmstest.cpp)
target_link_libraries(kmstest kms++ kms++util ${LIBDRM_LIBRARIES})
@@ -19,6 +22,11 @@ target_link_libraries(kmscapture kms++ kms++util ${LIBDRM_LIBRARIES})
add_executable (kmsblank kmsblank.cpp)
target_link_libraries(kmsblank kms++ kms++util ${LIBDRM_LIBRARIES})
+if(LIBEVDEV_FOUND)
+ add_executable (kmstouch kmstouch.cpp)
+ target_link_libraries(kmstouch kms++ kms++util ${LIBDRM_LIBRARIES} ${LIBEVDEV_LIBRARIES})
+endif()
+
add_executable (wbcap wbcap.cpp)
target_link_libraries(wbcap kms++ kms++util ${LIBDRM_LIBRARIES})
diff --git a/utils/kmstouch.cpp b/utils/kmstouch.cpp
new file mode 100644
index 0000000..b7ac420
--- /dev/null
+++ b/utils/kmstouch.cpp
@@ -0,0 +1,297 @@
+#include <cstdio>
+#include <unistd.h>
+#include <algorithm>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <cstring>
+
+#include <libevdev/libevdev.h>
+#include <libevdev/libevdev-uinput.h>
+
+#include <kms++/kms++.h>
+#include <kms++util/kms++util.h>
+
+using namespace std;
+using namespace kms;
+
+static const char* usage_str =
+ "Usage: kmstouch [OPTION]...\n\n"
+ "Simple touchscreen tester\n\n"
+ "Options:\n"
+ " --input=DEVICE DEVICE is the path to input device to open\n"
+ " --device=DEVICE DEVICE is the path to DRM card to open\n"
+ " -c, --connector=CONN CONN is <connector>\n"
+ "\n"
+ ;
+
+static void usage()
+{
+ puts(usage_str);
+}
+
+static bool s_print_ev = false;
+
+static vector<pair<int32_t, int32_t>> s_coords;
+
+// axis -> min,max
+static map<int, pair<int32_t, int32_t>> s_abs_map;
+// axis -> value
+static map<int, int32_t> s_abs_vals;
+
+static void print_abs_bits(struct libevdev *dev, int axis)
+{
+ const struct input_absinfo *abs;
+
+ if (!libevdev_has_event_code(dev, EV_ABS, axis))
+ return;
+
+ abs = libevdev_get_abs_info(dev, axis);
+
+ printf(" Value %6d\n", abs->value);
+ printf(" Min %6d\n", abs->minimum);
+ printf(" Max %6d\n", abs->maximum);
+ if (abs->fuzz)
+ printf(" Fuzz %6d\n", abs->fuzz);
+ if (abs->flat)
+ printf(" Flat %6d\n", abs->flat);
+ if (abs->resolution)
+ printf(" Resolution %6d\n", abs->resolution);
+}
+
+static void print_code_bits(struct libevdev *dev, unsigned int type, unsigned int max)
+{
+ for (uint32_t i = 0; i <= max; i++) {
+ if (!libevdev_has_event_code(dev, type, i))
+ continue;
+
+ printf(" Event code %i (%s)\n", i, libevdev_event_code_get_name(type, i));
+ if (type == EV_ABS)
+ print_abs_bits(dev, i);
+ }
+}
+
+static void print_bits(struct libevdev *dev)
+{
+ printf("Supported events:\n");
+
+ for (uint32_t i = 0; i <= EV_MAX; i++) {
+ if (!libevdev_has_event_type(dev, i))
+ continue;
+
+ printf(" Event type %d (%s)\n", i, libevdev_event_type_get_name(i));
+
+ switch(i) {
+ case EV_KEY:
+ print_code_bits(dev, EV_KEY, KEY_MAX);
+ break;
+ case EV_REL:
+ print_code_bits(dev, EV_REL, REL_MAX);
+ break;
+ case EV_ABS:
+ print_code_bits(dev, EV_ABS, ABS_MAX);
+ break;
+ case EV_LED:
+ print_code_bits(dev, EV_LED, LED_MAX);
+ break;
+ }
+ }
+}
+
+static void collect_current(struct libevdev* dev)
+{
+ for (uint32_t i = 0; i <= ABS_MAX; i++) {
+ if (!libevdev_has_event_code(dev, EV_ABS, i))
+ continue;
+
+ const struct input_absinfo *abs;
+
+ abs = libevdev_get_abs_info(dev, i);
+
+ s_abs_vals[i] = abs->value;
+ s_abs_map[i] = make_pair(abs->minimum, abs->maximum);
+ }
+}
+
+static void print_props(struct libevdev *dev)
+{
+ printf("Properties:\n");
+
+ for (uint32_t i = 0; i <= INPUT_PROP_MAX; i++) {
+ if (!libevdev_has_property(dev, i))
+ continue;
+
+ printf(" Property type %d (%s)\n", i, libevdev_property_get_name(i));
+ }
+}
+
+static void handle_event(struct input_event& ev, DumbFramebuffer* fb)
+{
+ static vector<pair<uint16_t, int32_t>> s_event_vec;
+
+ if (s_print_ev)
+ printf("%-6s %20s %6d\n",
+ libevdev_event_type_get_name(ev.type),
+ libevdev_event_code_get_name(ev.type, ev.code),
+ ev.value);
+
+ switch (ev.type) {
+ case EV_ABS:
+ s_event_vec.emplace_back(ev.code, ev.value);
+ break;
+
+ case EV_KEY:
+ s_event_vec.emplace_back(ev.code, ev.value);
+ break;
+
+ case EV_SYN:
+ switch (ev.code) {
+ case SYN_REPORT: {
+ int32_t min_x = s_abs_map[ABS_X].first;
+ int32_t max_x = s_abs_map[ABS_X].second;
+
+ int32_t min_y = s_abs_map[ABS_Y].first;
+ int32_t max_y = s_abs_map[ABS_Y].second;
+
+ for (const auto& p : s_event_vec) {
+ switch (p.first) {
+ case ABS_X:
+ case ABS_Y:
+ s_abs_vals[p.first] = p.second;
+ break;
+ default:
+ break;
+ }
+ }
+
+ int32_t abs_x = s_abs_vals[ABS_X];
+ int32_t abs_y = s_abs_vals[ABS_Y];
+
+ int32_t x = (abs_x - min_x) * (fb->width() - 1) / (max_x - min_x);
+ int32_t y = (abs_y - min_y) * (fb->height() - 1) / (max_y - min_y);
+
+ printf("%d, %d -> %d, %d\n", abs_x, abs_y, x, y);
+
+ draw_rgb_pixel(*fb, x, y, RGB(255, 255, 255));
+
+ s_event_vec.clear();
+
+ if (s_print_ev)
+ printf("----\n");
+ break;
+ }
+
+ default:
+ EXIT("Unhandled syn event code %u\n", ev.code);
+ break;
+ }
+
+ break;
+
+ default:
+ EXIT("Unhandled event type %u\n", ev.type);
+ break;
+ }
+}
+
+int main(int argc, char **argv)
+{
+ string drm_dev_path = "/dev/dri/card0";
+ string input_dev_path = "/dev/input/event0";
+ string conn_name;
+
+ OptionSet optionset = {
+ Option("i|input=", [&input_dev_path](string s)
+ {
+ input_dev_path = s;
+ }),
+ Option("|device=", [&drm_dev_path](string s)
+ {
+ drm_dev_path = s;
+ }),
+ Option("c|connector=", [&conn_name](string s)
+ {
+ conn_name = s;
+ }),
+ Option("h|help", []()
+ {
+ usage();
+ exit(-1);
+ }),
+ };
+
+ optionset.parse(argc, argv);
+
+ if (optionset.params().size() > 0) {
+ usage();
+ exit(-1);
+ }
+
+
+ struct libevdev *dev = nullptr;
+
+ int fd = open(input_dev_path.c_str(), O_RDONLY | O_NONBLOCK);
+ FAIL_IF(fd < 0, "Failed to open input device %s: %s\n", input_dev_path.c_str(), strerror(errno));
+ int rc = libevdev_new_from_fd(fd, &dev);
+ FAIL_IF(rc < 0, "Failed to init libevdev (%s)\n", strerror(-rc));
+
+ printf("Input device name: \"%s\"\n", libevdev_get_name(dev));
+ printf("Input device ID: bus %#x vendor %#x product %#x\n",
+ libevdev_get_id_bustype(dev),
+ libevdev_get_id_vendor(dev),
+ libevdev_get_id_product(dev));
+
+ if (!libevdev_has_event_type(dev, EV_ABS) ||
+ !libevdev_has_event_code(dev, EV_KEY, BTN_TOUCH)) {
+ printf("This device does not look like a mouse\n");
+ exit(1);
+ }
+
+ print_bits(dev);
+ print_props(dev);
+
+ collect_current(dev);
+
+
+ Card card(drm_dev_path);
+ ResourceManager resman(card);
+
+ auto pixfmt = PixelFormat::XRGB8888;
+
+ Connector* conn = resman.reserve_connector(conn_name);
+ Crtc* crtc = resman.reserve_crtc(conn);
+ Plane* plane = resman.reserve_overlay_plane(crtc, pixfmt);
+
+ Videomode mode = conn->get_default_mode();
+
+ uint32_t w = mode.hdisplay;
+ uint32_t h = mode.vdisplay;
+
+ auto fb = new DumbFramebuffer(card, w, h, pixfmt);
+
+ AtomicReq req(card);
+
+ req.add(plane, "CRTC_ID", crtc->id());
+ req.add(plane, "FB_ID", fb->id());
+
+ req.add(plane, "CRTC_X", 0);
+ req.add(plane, "CRTC_Y", 0);
+ req.add(plane, "CRTC_W", w);
+ req.add(plane, "CRTC_H", h);
+
+ req.add(plane, "SRC_X", 0);
+ req.add(plane, "SRC_Y", 0);
+ req.add(plane, "SRC_W", w << 16);
+ req.add(plane, "SRC_H", h << 16);
+
+ int r = req.commit_sync();
+ FAIL_IF(r, "initial plane setup failed");
+
+ do {
+ struct input_event ev {};
+ rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
+ if (rc == 0)
+ handle_event(ev, fb);
+
+ } while (rc == 1 || rc == 0 || rc == -EAGAIN);
+}