xref: /aosp_15_r20/external/libkmsxx/utils/kmstouch.cpp (revision f0687c8a10b3e371dbe09214db6664e37c283cca)
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