1*f0687c8aSRaman Tenneti #include <cstdio>
2*f0687c8aSRaman Tenneti #include <unistd.h>
3*f0687c8aSRaman Tenneti #include <algorithm>
4*f0687c8aSRaman Tenneti #include <sys/types.h>
5*f0687c8aSRaman Tenneti #include <sys/stat.h>
6*f0687c8aSRaman Tenneti #include <fcntl.h>
7*f0687c8aSRaman Tenneti #include <cstring>
8*f0687c8aSRaman Tenneti
9*f0687c8aSRaman Tenneti #include <libevdev/libevdev.h>
10*f0687c8aSRaman Tenneti #include <libevdev/libevdev-uinput.h>
11*f0687c8aSRaman Tenneti
12*f0687c8aSRaman Tenneti #include <kms++/kms++.h>
13*f0687c8aSRaman Tenneti #include <kms++util/kms++util.h>
14*f0687c8aSRaman Tenneti
15*f0687c8aSRaman Tenneti using namespace std;
16*f0687c8aSRaman Tenneti using namespace kms;
17*f0687c8aSRaman Tenneti
18*f0687c8aSRaman Tenneti static const char* usage_str =
19*f0687c8aSRaman Tenneti "Usage: kmstouch [OPTION]...\n\n"
20*f0687c8aSRaman Tenneti "Simple touchscreen tester\n\n"
21*f0687c8aSRaman Tenneti "Options:\n"
22*f0687c8aSRaman Tenneti " --input=DEVICE DEVICE is the path to input device to open\n"
23*f0687c8aSRaman Tenneti " --device=DEVICE DEVICE is the path to DRM card to open\n"
24*f0687c8aSRaman Tenneti " -c, --connector=CONN CONN is <connector>\n"
25*f0687c8aSRaman Tenneti "\n";
26*f0687c8aSRaman Tenneti
usage()27*f0687c8aSRaman Tenneti static void usage()
28*f0687c8aSRaman Tenneti {
29*f0687c8aSRaman Tenneti puts(usage_str);
30*f0687c8aSRaman Tenneti }
31*f0687c8aSRaman Tenneti
32*f0687c8aSRaman Tenneti static bool s_print_ev = false;
33*f0687c8aSRaman Tenneti
34*f0687c8aSRaman Tenneti static vector<pair<int32_t, int32_t>> s_coords;
35*f0687c8aSRaman Tenneti
36*f0687c8aSRaman Tenneti // axis -> min,max
37*f0687c8aSRaman Tenneti static map<int, pair<int32_t, int32_t>> s_abs_map;
38*f0687c8aSRaman Tenneti // axis -> value
39*f0687c8aSRaman Tenneti static map<int, int32_t> s_abs_vals;
40*f0687c8aSRaman Tenneti
print_abs_bits(struct libevdev * dev,int axis)41*f0687c8aSRaman Tenneti static void print_abs_bits(struct libevdev* dev, int axis)
42*f0687c8aSRaman Tenneti {
43*f0687c8aSRaman Tenneti const struct input_absinfo* abs;
44*f0687c8aSRaman Tenneti
45*f0687c8aSRaman Tenneti if (!libevdev_has_event_code(dev, EV_ABS, axis))
46*f0687c8aSRaman Tenneti return;
47*f0687c8aSRaman Tenneti
48*f0687c8aSRaman Tenneti abs = libevdev_get_abs_info(dev, axis);
49*f0687c8aSRaman Tenneti
50*f0687c8aSRaman Tenneti printf(" Value %6d\n", abs->value);
51*f0687c8aSRaman Tenneti printf(" Min %6d\n", abs->minimum);
52*f0687c8aSRaman Tenneti printf(" Max %6d\n", abs->maximum);
53*f0687c8aSRaman Tenneti if (abs->fuzz)
54*f0687c8aSRaman Tenneti printf(" Fuzz %6d\n", abs->fuzz);
55*f0687c8aSRaman Tenneti if (abs->flat)
56*f0687c8aSRaman Tenneti printf(" Flat %6d\n", abs->flat);
57*f0687c8aSRaman Tenneti if (abs->resolution)
58*f0687c8aSRaman Tenneti printf(" Resolution %6d\n", abs->resolution);
59*f0687c8aSRaman Tenneti }
60*f0687c8aSRaman Tenneti
print_code_bits(struct libevdev * dev,unsigned int type,unsigned int max)61*f0687c8aSRaman Tenneti static void print_code_bits(struct libevdev* dev, unsigned int type, unsigned int max)
62*f0687c8aSRaman Tenneti {
63*f0687c8aSRaman Tenneti for (uint32_t i = 0; i <= max; i++) {
64*f0687c8aSRaman Tenneti if (!libevdev_has_event_code(dev, type, i))
65*f0687c8aSRaman Tenneti continue;
66*f0687c8aSRaman Tenneti
67*f0687c8aSRaman Tenneti printf(" Event code %i (%s)\n", i, libevdev_event_code_get_name(type, i));
68*f0687c8aSRaman Tenneti if (type == EV_ABS)
69*f0687c8aSRaman Tenneti print_abs_bits(dev, i);
70*f0687c8aSRaman Tenneti }
71*f0687c8aSRaman Tenneti }
72*f0687c8aSRaman Tenneti
print_bits(struct libevdev * dev)73*f0687c8aSRaman Tenneti static void print_bits(struct libevdev* dev)
74*f0687c8aSRaman Tenneti {
75*f0687c8aSRaman Tenneti printf("Supported events:\n");
76*f0687c8aSRaman Tenneti
77*f0687c8aSRaman Tenneti for (uint32_t i = 0; i <= EV_MAX; i++) {
78*f0687c8aSRaman Tenneti if (!libevdev_has_event_type(dev, i))
79*f0687c8aSRaman Tenneti continue;
80*f0687c8aSRaman Tenneti
81*f0687c8aSRaman Tenneti printf(" Event type %d (%s)\n", i, libevdev_event_type_get_name(i));
82*f0687c8aSRaman Tenneti
83*f0687c8aSRaman Tenneti switch (i) {
84*f0687c8aSRaman Tenneti case EV_KEY:
85*f0687c8aSRaman Tenneti print_code_bits(dev, EV_KEY, KEY_MAX);
86*f0687c8aSRaman Tenneti break;
87*f0687c8aSRaman Tenneti case EV_REL:
88*f0687c8aSRaman Tenneti print_code_bits(dev, EV_REL, REL_MAX);
89*f0687c8aSRaman Tenneti break;
90*f0687c8aSRaman Tenneti case EV_ABS:
91*f0687c8aSRaman Tenneti print_code_bits(dev, EV_ABS, ABS_MAX);
92*f0687c8aSRaman Tenneti break;
93*f0687c8aSRaman Tenneti case EV_LED:
94*f0687c8aSRaman Tenneti print_code_bits(dev, EV_LED, LED_MAX);
95*f0687c8aSRaman Tenneti break;
96*f0687c8aSRaman Tenneti }
97*f0687c8aSRaman Tenneti }
98*f0687c8aSRaman Tenneti }
99*f0687c8aSRaman Tenneti
collect_current(struct libevdev * dev)100*f0687c8aSRaman Tenneti static void collect_current(struct libevdev* dev)
101*f0687c8aSRaman Tenneti {
102*f0687c8aSRaman Tenneti for (uint32_t i = 0; i <= ABS_MAX; i++) {
103*f0687c8aSRaman Tenneti if (!libevdev_has_event_code(dev, EV_ABS, i))
104*f0687c8aSRaman Tenneti continue;
105*f0687c8aSRaman Tenneti
106*f0687c8aSRaman Tenneti const struct input_absinfo* abs;
107*f0687c8aSRaman Tenneti
108*f0687c8aSRaman Tenneti abs = libevdev_get_abs_info(dev, i);
109*f0687c8aSRaman Tenneti
110*f0687c8aSRaman Tenneti s_abs_vals[i] = abs->value;
111*f0687c8aSRaman Tenneti s_abs_map[i] = make_pair(abs->minimum, abs->maximum);
112*f0687c8aSRaman Tenneti }
113*f0687c8aSRaman Tenneti }
114*f0687c8aSRaman Tenneti
print_props(struct libevdev * dev)115*f0687c8aSRaman Tenneti static void print_props(struct libevdev* dev)
116*f0687c8aSRaman Tenneti {
117*f0687c8aSRaman Tenneti printf("Properties:\n");
118*f0687c8aSRaman Tenneti
119*f0687c8aSRaman Tenneti for (uint32_t i = 0; i <= INPUT_PROP_MAX; i++) {
120*f0687c8aSRaman Tenneti if (!libevdev_has_property(dev, i))
121*f0687c8aSRaman Tenneti continue;
122*f0687c8aSRaman Tenneti
123*f0687c8aSRaman Tenneti printf(" Property type %d (%s)\n", i, libevdev_property_get_name(i));
124*f0687c8aSRaman Tenneti }
125*f0687c8aSRaman Tenneti }
126*f0687c8aSRaman Tenneti
handle_event(struct input_event & ev,DumbFramebuffer * fb)127*f0687c8aSRaman Tenneti static void handle_event(struct input_event& ev, DumbFramebuffer* fb)
128*f0687c8aSRaman Tenneti {
129*f0687c8aSRaman Tenneti static vector<pair<uint16_t, int32_t>> s_event_vec;
130*f0687c8aSRaman Tenneti
131*f0687c8aSRaman Tenneti if (s_print_ev)
132*f0687c8aSRaman Tenneti printf("%-6s %20s %6d\n",
133*f0687c8aSRaman Tenneti libevdev_event_type_get_name(ev.type),
134*f0687c8aSRaman Tenneti libevdev_event_code_get_name(ev.type, ev.code),
135*f0687c8aSRaman Tenneti ev.value);
136*f0687c8aSRaman Tenneti
137*f0687c8aSRaman Tenneti switch (ev.type) {
138*f0687c8aSRaman Tenneti case EV_ABS:
139*f0687c8aSRaman Tenneti s_event_vec.emplace_back(ev.code, ev.value);
140*f0687c8aSRaman Tenneti break;
141*f0687c8aSRaman Tenneti
142*f0687c8aSRaman Tenneti case EV_KEY:
143*f0687c8aSRaman Tenneti s_event_vec.emplace_back(ev.code, ev.value);
144*f0687c8aSRaman Tenneti break;
145*f0687c8aSRaman Tenneti
146*f0687c8aSRaman Tenneti case EV_SYN:
147*f0687c8aSRaman Tenneti switch (ev.code) {
148*f0687c8aSRaman Tenneti case SYN_REPORT: {
149*f0687c8aSRaman Tenneti int32_t min_x = s_abs_map[ABS_X].first;
150*f0687c8aSRaman Tenneti int32_t max_x = s_abs_map[ABS_X].second;
151*f0687c8aSRaman Tenneti
152*f0687c8aSRaman Tenneti int32_t min_y = s_abs_map[ABS_Y].first;
153*f0687c8aSRaman Tenneti int32_t max_y = s_abs_map[ABS_Y].second;
154*f0687c8aSRaman Tenneti
155*f0687c8aSRaman Tenneti for (const auto& p : s_event_vec) {
156*f0687c8aSRaman Tenneti switch (p.first) {
157*f0687c8aSRaman Tenneti case ABS_X:
158*f0687c8aSRaman Tenneti case ABS_Y:
159*f0687c8aSRaman Tenneti s_abs_vals[p.first] = p.second;
160*f0687c8aSRaman Tenneti break;
161*f0687c8aSRaman Tenneti default:
162*f0687c8aSRaman Tenneti break;
163*f0687c8aSRaman Tenneti }
164*f0687c8aSRaman Tenneti }
165*f0687c8aSRaman Tenneti
166*f0687c8aSRaman Tenneti int32_t abs_x = s_abs_vals[ABS_X];
167*f0687c8aSRaman Tenneti int32_t abs_y = s_abs_vals[ABS_Y];
168*f0687c8aSRaman Tenneti
169*f0687c8aSRaman Tenneti int32_t x = (abs_x - min_x) * (fb->width() - 1) / (max_x - min_x);
170*f0687c8aSRaman Tenneti int32_t y = (abs_y - min_y) * (fb->height() - 1) / (max_y - min_y);
171*f0687c8aSRaman Tenneti
172*f0687c8aSRaman Tenneti printf("%d, %d -> %d, %d\n", abs_x, abs_y, x, y);
173*f0687c8aSRaman Tenneti
174*f0687c8aSRaman Tenneti draw_rgb_pixel(*fb, x, y, RGB(255, 255, 255));
175*f0687c8aSRaman Tenneti
176*f0687c8aSRaman Tenneti s_event_vec.clear();
177*f0687c8aSRaman Tenneti
178*f0687c8aSRaman Tenneti if (s_print_ev)
179*f0687c8aSRaman Tenneti printf("----\n");
180*f0687c8aSRaman Tenneti break;
181*f0687c8aSRaman Tenneti }
182*f0687c8aSRaman Tenneti
183*f0687c8aSRaman Tenneti default:
184*f0687c8aSRaman Tenneti EXIT("Unhandled syn event code %u\n", ev.code);
185*f0687c8aSRaman Tenneti break;
186*f0687c8aSRaman Tenneti }
187*f0687c8aSRaman Tenneti
188*f0687c8aSRaman Tenneti break;
189*f0687c8aSRaman Tenneti
190*f0687c8aSRaman Tenneti default:
191*f0687c8aSRaman Tenneti EXIT("Unhandled event type %u\n", ev.type);
192*f0687c8aSRaman Tenneti break;
193*f0687c8aSRaman Tenneti }
194*f0687c8aSRaman Tenneti }
195*f0687c8aSRaman Tenneti
main(int argc,char ** argv)196*f0687c8aSRaman Tenneti int main(int argc, char** argv)
197*f0687c8aSRaman Tenneti {
198*f0687c8aSRaman Tenneti string drm_dev_path = "/dev/dri/card0";
199*f0687c8aSRaman Tenneti string input_dev_path = "/dev/input/event0";
200*f0687c8aSRaman Tenneti string conn_name;
201*f0687c8aSRaman Tenneti
202*f0687c8aSRaman Tenneti OptionSet optionset = {
203*f0687c8aSRaman Tenneti Option("i|input=", [&input_dev_path](string s) {
204*f0687c8aSRaman Tenneti input_dev_path = s;
205*f0687c8aSRaman Tenneti }),
206*f0687c8aSRaman Tenneti Option("|device=", [&drm_dev_path](string s) {
207*f0687c8aSRaman Tenneti drm_dev_path = s;
208*f0687c8aSRaman Tenneti }),
209*f0687c8aSRaman Tenneti Option("c|connector=", [&conn_name](string s) {
210*f0687c8aSRaman Tenneti conn_name = s;
211*f0687c8aSRaman Tenneti }),
212*f0687c8aSRaman Tenneti Option("h|help", []() {
213*f0687c8aSRaman Tenneti usage();
214*f0687c8aSRaman Tenneti exit(-1);
215*f0687c8aSRaman Tenneti }),
216*f0687c8aSRaman Tenneti };
217*f0687c8aSRaman Tenneti
218*f0687c8aSRaman Tenneti optionset.parse(argc, argv);
219*f0687c8aSRaman Tenneti
220*f0687c8aSRaman Tenneti if (optionset.params().size() > 0) {
221*f0687c8aSRaman Tenneti usage();
222*f0687c8aSRaman Tenneti exit(-1);
223*f0687c8aSRaman Tenneti }
224*f0687c8aSRaman Tenneti
225*f0687c8aSRaman Tenneti struct libevdev* dev = nullptr;
226*f0687c8aSRaman Tenneti
227*f0687c8aSRaman Tenneti int fd = open(input_dev_path.c_str(), O_RDONLY | O_NONBLOCK);
228*f0687c8aSRaman Tenneti FAIL_IF(fd < 0, "Failed to open input device %s: %s\n", input_dev_path.c_str(), strerror(errno));
229*f0687c8aSRaman Tenneti int rc = libevdev_new_from_fd(fd, &dev);
230*f0687c8aSRaman Tenneti FAIL_IF(rc < 0, "Failed to init libevdev (%s)\n", strerror(-rc));
231*f0687c8aSRaman Tenneti
232*f0687c8aSRaman Tenneti printf("Input device name: \"%s\"\n", libevdev_get_name(dev));
233*f0687c8aSRaman Tenneti printf("Input device ID: bus %#x vendor %#x product %#x\n",
234*f0687c8aSRaman Tenneti libevdev_get_id_bustype(dev),
235*f0687c8aSRaman Tenneti libevdev_get_id_vendor(dev),
236*f0687c8aSRaman Tenneti libevdev_get_id_product(dev));
237*f0687c8aSRaman Tenneti
238*f0687c8aSRaman Tenneti if (!libevdev_has_event_type(dev, EV_ABS) ||
239*f0687c8aSRaman Tenneti !libevdev_has_event_code(dev, EV_KEY, BTN_TOUCH)) {
240*f0687c8aSRaman Tenneti printf("This device does not look like a mouse\n");
241*f0687c8aSRaman Tenneti exit(1);
242*f0687c8aSRaman Tenneti }
243*f0687c8aSRaman Tenneti
244*f0687c8aSRaman Tenneti print_bits(dev);
245*f0687c8aSRaman Tenneti print_props(dev);
246*f0687c8aSRaman Tenneti
247*f0687c8aSRaman Tenneti collect_current(dev);
248*f0687c8aSRaman Tenneti
249*f0687c8aSRaman Tenneti Card card(drm_dev_path);
250*f0687c8aSRaman Tenneti ResourceManager resman(card);
251*f0687c8aSRaman Tenneti
252*f0687c8aSRaman Tenneti auto pixfmt = PixelFormat::XRGB8888;
253*f0687c8aSRaman Tenneti
254*f0687c8aSRaman Tenneti Connector* conn = resman.reserve_connector(conn_name);
255*f0687c8aSRaman Tenneti Crtc* crtc = resman.reserve_crtc(conn);
256*f0687c8aSRaman Tenneti Plane* plane = resman.reserve_overlay_plane(crtc, pixfmt);
257*f0687c8aSRaman Tenneti
258*f0687c8aSRaman Tenneti Videomode mode = conn->get_default_mode();
259*f0687c8aSRaman Tenneti
260*f0687c8aSRaman Tenneti uint32_t w = mode.hdisplay;
261*f0687c8aSRaman Tenneti uint32_t h = mode.vdisplay;
262*f0687c8aSRaman Tenneti
263*f0687c8aSRaman Tenneti auto fb = new DumbFramebuffer(card, w, h, pixfmt);
264*f0687c8aSRaman Tenneti
265*f0687c8aSRaman Tenneti AtomicReq req(card);
266*f0687c8aSRaman Tenneti
267*f0687c8aSRaman Tenneti req.add(plane, "CRTC_ID", crtc->id());
268*f0687c8aSRaman Tenneti req.add(plane, "FB_ID", fb->id());
269*f0687c8aSRaman Tenneti
270*f0687c8aSRaman Tenneti req.add(plane, "CRTC_X", 0);
271*f0687c8aSRaman Tenneti req.add(plane, "CRTC_Y", 0);
272*f0687c8aSRaman Tenneti req.add(plane, "CRTC_W", w);
273*f0687c8aSRaman Tenneti req.add(plane, "CRTC_H", h);
274*f0687c8aSRaman Tenneti
275*f0687c8aSRaman Tenneti req.add(plane, "SRC_X", 0);
276*f0687c8aSRaman Tenneti req.add(plane, "SRC_Y", 0);
277*f0687c8aSRaman Tenneti req.add(plane, "SRC_W", w << 16);
278*f0687c8aSRaman Tenneti req.add(plane, "SRC_H", h << 16);
279*f0687c8aSRaman Tenneti
280*f0687c8aSRaman Tenneti int r = req.commit_sync();
281*f0687c8aSRaman Tenneti FAIL_IF(r, "initial plane setup failed");
282*f0687c8aSRaman Tenneti
283*f0687c8aSRaman Tenneti do {
284*f0687c8aSRaman Tenneti struct input_event ev {
285*f0687c8aSRaman Tenneti };
286*f0687c8aSRaman Tenneti rc = libevdev_next_event(dev, LIBEVDEV_READ_FLAG_NORMAL, &ev);
287*f0687c8aSRaman Tenneti if (rc == 0)
288*f0687c8aSRaman Tenneti handle_event(ev, fb);
289*f0687c8aSRaman Tenneti
290*f0687c8aSRaman Tenneti } while (rc == 1 || rc == 0 || rc == -EAGAIN);
291*f0687c8aSRaman Tenneti
292*f0687c8aSRaman Tenneti delete fb;
293*f0687c8aSRaman Tenneti }
294