1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (c) 2015 Cedric Hnyda <chnyda@suse.com>
4 * Copyright (c) 2019 Cyril Hrubis <chrubis@suse.cz>
5 */
6
7#include <linux/input.h>
8#include <linux/uinput.h>
9#include <stdio.h>
10#include <string.h>
11
12#define TST_NO_DEFAULT_MAIN
13#include "tst_test.h"
14
15#include "tst_uinput.h"
16
17#define VIRTUAL_DEVICE "virtual-device-ltp"
18
19static const char *uinput_paths[] = {
20	"/dev/input/uinput",
21	"/dev/uinput",
22};
23
24int open_uinput(void)
25{
26	unsigned int i;
27	int fd;
28
29	for (i = 0; i < ARRAY_SIZE(uinput_paths); i++) {
30		fd = open(uinput_paths[i], O_WRONLY | O_NONBLOCK);
31
32		if (fd > 0) {
33			tst_res(TINFO, "Found uinput dev at %s", uinput_paths[i]);
34			return fd;
35		}
36
37		if (fd < 0 && errno != ENOENT) {
38			tst_brk(TBROK | TERRNO, "open(%s)", uinput_paths[i]);
39		}
40	}
41
42	return -1;
43}
44
45
46#define SYSFS_PREFIX "Sysfs="
47#define HANDLERS_PREFIX "Handlers="
48
49static char *parse_field(char *line, char field)
50{
51	char *value;
52
53	switch (field) {
54	case 'H':
55		value = strstr(line, HANDLERS_PREFIX) + sizeof(HANDLERS_PREFIX) - 1;
56		break;
57	case 'S':
58		value = strstr(line, SYSFS_PREFIX) + sizeof(SYSFS_PREFIX) - 1;
59		break;
60	default:
61		return NULL;
62	}
63
64	value[strlen(value) - 1] = 0;
65
66	return strdup(value);
67}
68
69char *get_input_field_value(char field)
70{
71	FILE *file;
72	char line[1024];
73	int flag = 0;
74
75	file = fopen("/proc/bus/input/devices", "r");
76	if (!file)
77		return NULL;
78
79	while (fgets(line, sizeof(line), file)) {
80		if (strstr(line, "N: Name=\""VIRTUAL_DEVICE"\""))
81			flag = 1;
82
83		if (flag) {
84			if (line[0] == field)
85				return parse_field(line, field);
86
87			if (line[0] == '\n')
88				flag = 0;
89		}
90	}
91
92	fclose(file);
93	return NULL;
94}
95
96static int check_device(void)
97{
98	FILE *file;
99	char line[256];
100
101	file = fopen("/proc/bus/input/devices", "r");
102	if (!file)
103		return 0;
104
105	while (fgets(line, sizeof(line), file)) {
106		if (strstr(line, "Name=\""VIRTUAL_DEVICE"\""))
107			return 1;
108	}
109
110	fclose(file);
111
112	return 0;
113}
114
115void setup_mouse_events(int fd)
116{
117	SAFE_IOCTL(fd, UI_SET_EVBIT, EV_KEY);
118	SAFE_IOCTL(fd, UI_SET_KEYBIT, BTN_LEFT);
119	SAFE_IOCTL(fd, UI_SET_EVBIT, EV_REL);
120	SAFE_IOCTL(fd, UI_SET_RELBIT, REL_X);
121	SAFE_IOCTL(fd, UI_SET_RELBIT, REL_Y);
122}
123
124void destroy_input_device(int fd)
125{
126	SAFE_IOCTL(fd, UI_DEV_DESTROY, NULL);
127	SAFE_CLOSE(fd);
128}
129
130void create_input_device(int fd)
131{
132	int nb;
133	struct uinput_user_dev uidev = {
134		.name = VIRTUAL_DEVICE,
135		.id = {
136			.bustype = BUS_USB,
137			.vendor = 0x1,
138			.product = 0x1,
139			.version = 1,
140		}
141	};
142
143	SAFE_WRITE(SAFE_WRITE_ALL, fd, &uidev, sizeof(uidev));
144	SAFE_IOCTL(fd, UI_DEV_CREATE, NULL);
145
146	for (nb = 100; nb > 0; nb--) {
147		if (check_device())
148			return;
149		usleep(10000);
150	}
151
152	destroy_input_device(fd);
153	tst_brk(TBROK, "Failed to create device");
154}
155