You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
294 lines
6.5 KiB
294 lines
6.5 KiB
#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);
|
|
|
|
delete fb;
|
|
}
|