blob: 16e6891535c30d59ba7ca9bd8da910b745e10d52 [file]
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* Copyright (c) 2015 Cedric Hnyda <chnyda@suse.com>
* Copyright (c) 2019 Cyril Hrubis <chrubis@suse.cz>
*/
#include <linux/input.h>
#include <linux/uinput.h>
#include <stdio.h>
#include <string.h>
#define TST_NO_DEFAULT_MAIN
#include "tst_test.h"
#include "tst_uinput.h"
#include "tst_safe_stdio.h"
#define VIRTUAL_DEVICE "virtual-device-ltp"
static const char *uinput_paths[] = {
"/dev/input/uinput",
"/dev/uinput",
};
int open_uinput(void)
{
unsigned int i;
int fd;
for (i = 0; i < ARRAY_SIZE(uinput_paths); i++) {
fd = open(uinput_paths[i], O_WRONLY | O_NONBLOCK);
if (fd > 0) {
tst_res(TINFO, "Found uinput dev at %s", uinput_paths[i]);
return fd;
}
if (fd < 0 && errno != ENOENT) {
tst_brk(TBROK | TERRNO, "open(%s)", uinput_paths[i]);
}
}
return -1;
}
#define SYSFS_PREFIX "Sysfs="
#define HANDLERS_PREFIX "Handlers="
static char *parse_field(char *line, char field)
{
char *value;
switch (field) {
case 'H':
value = strstr(line, HANDLERS_PREFIX) + sizeof(HANDLERS_PREFIX) - 1;
break;
case 'S':
value = strstr(line, SYSFS_PREFIX) + sizeof(SYSFS_PREFIX) - 1;
break;
default:
return NULL;
}
value[strlen(value) - 1] = 0;
return strdup(value);
}
char *get_input_field_value(char field)
{
FILE *file;
char line[1024];
int flag = 0;
file = fopen("/proc/bus/input/devices", "r");
if (!file)
return NULL;
while (fgets(line, sizeof(line), file)) {
if (strstr(line, "N: Name=\""VIRTUAL_DEVICE"\""))
flag = 1;
if (flag) {
if (line[0] == field)
return parse_field(line, field);
if (line[0] == '\n')
flag = 0;
}
}
fclose(file);
return NULL;
}
static int check_device(void)
{
FILE *file;
char line[256];
file = fopen("/proc/bus/input/devices", "r");
if (!file)
return 0;
while (fgets(line, sizeof(line), file)) {
if (strstr(line, "Name=\""VIRTUAL_DEVICE"\""))
return 1;
}
fclose(file);
return 0;
}
void setup_mouse_events(int fd)
{
SAFE_IOCTL(fd, UI_SET_EVBIT, EV_KEY);
SAFE_IOCTL(fd, UI_SET_KEYBIT, BTN_LEFT);
SAFE_IOCTL(fd, UI_SET_EVBIT, EV_REL);
SAFE_IOCTL(fd, UI_SET_RELBIT, REL_X);
SAFE_IOCTL(fd, UI_SET_RELBIT, REL_Y);
}
void destroy_input_device(int fd)
{
SAFE_IOCTL(fd, UI_DEV_DESTROY, NULL);
SAFE_CLOSE(fd);
}
static void check_ui_get_sysname_ioctl(int fd)
{
char sys_name[256];
char dev_name[256];
char *path;
SAFE_IOCTL(fd, UI_GET_SYSNAME(sizeof(sys_name)), sys_name, NULL);
SAFE_ASPRINTF(&path, "/sys/devices/virtual/input/%s/name", sys_name);
if (FILE_SCANF(path, "%s", dev_name)) {
free(path);
tst_brk(TBROK|TERRNO, "Failed to read '%s'", path);
return;
}
if (strcmp(VIRTUAL_DEVICE, dev_name)) {
free(path);
tst_brk(TBROK, "ioctl UI_GET_SYSNAME returned wrong name");
}
free(path);
}
void create_input_device(int fd)
{
int nb;
struct uinput_user_dev uidev = {
.name = VIRTUAL_DEVICE,
.id = {
.bustype = BUS_USB,
.vendor = 0x1,
.product = 0x1,
.version = 1,
}
};
SAFE_WRITE(SAFE_WRITE_ALL, fd, &uidev, sizeof(uidev));
SAFE_IOCTL(fd, UI_DEV_CREATE, NULL);
for (nb = 100; nb > 0; nb--) {
if (check_device()) {
check_ui_get_sysname_ioctl(fd);
return;
}
usleep(10000);
}
destroy_input_device(fd);
tst_brk(TBROK, "Failed to create device");
}