// SPDX-License-Identifier: GPL-2.0
/* Copyright (c) 2022 Red Hat */
#include "hid.skel.h"
#include "../kselftest_harness.h"
#include <bpf/bpf.h>
#include <fcntl.h>
#include <fnmatch.h>
#include <dirent.h>
#include <poll.h>
#include <pthread.h>
#include <stdbool.h>
#include <linux/hidraw.h>
#include <linux/uhid.h>
#define SHOW_UHID_DEBUG 0
#define min(a, b) \
({ __typeof__(a) _a = (a); \
__typeof__(b) _b = (b); \
_a < _b ? _a : _b; })
static unsigned char rdesc[] = {
0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */
0x09, 0x21, /* Usage (Vendor Usage 0x21) */
0xa1, 0x01, /* COLLECTION (Application) */
0x09, 0x01, /* Usage (Vendor Usage 0x01) */
0xa1, 0x00, /* COLLECTION (Physical) */
0x85, 0x02, /* REPORT_ID (2) */
0x19, 0x01, /* USAGE_MINIMUM (1) */
0x29, 0x08, /* USAGE_MAXIMUM (3) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0xff, /* LOGICAL_MAXIMUM (255) */
0x95, 0x08, /* REPORT_COUNT (8) */
0x75, 0x08, /* REPORT_SIZE (8) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */
0xc0, /* END_COLLECTION */
0x09, 0x01, /* Usage (Vendor Usage 0x01) */
0xa1, 0x00, /* COLLECTION (Physical) */
0x85, 0x01, /* REPORT_ID (1) */
0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */
0x19, 0x01, /* USAGE_MINIMUM (1) */
0x29, 0x03, /* USAGE_MAXIMUM (3) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
0x95, 0x03, /* REPORT_COUNT (3) */
0x75, 0x01, /* REPORT_SIZE (1) */
0x81, 0x02, /* INPUT (Data,Var,Abs) */
0x95, 0x01, /* REPORT_COUNT (1) */
0x75, 0x05, /* REPORT_SIZE (5) */
0x81, 0x01, /* INPUT (Cnst,Var,Abs) */
0x05, 0x01, /* USAGE_PAGE (Generic Desktop) */
0x09, 0x30, /* USAGE (X) */
0x09, 0x31, /* USAGE (Y) */
0x15, 0x81, /* LOGICAL_MINIMUM (-127) */
0x25, 0x7f, /* LOGICAL_MAXIMUM (127) */
0x75, 0x10, /* REPORT_SIZE (16) */
0x95, 0x02, /* REPORT_COUNT (2) */
0x81, 0x06, /* INPUT (Data,Var,Rel) */
0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */
0x19, 0x01, /* USAGE_MINIMUM (1) */
0x29, 0x03, /* USAGE_MAXIMUM (3) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
0x95, 0x03, /* REPORT_COUNT (3) */
0x75, 0x01, /* REPORT_SIZE (1) */
0x91, 0x02, /* Output (Data,Var,Abs) */
0x95, 0x01, /* REPORT_COUNT (1) */
0x75, 0x05, /* REPORT_SIZE (5) */
0x91, 0x01, /* Output (Cnst,Var,Abs) */
0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) */
0x19, 0x06, /* USAGE_MINIMUM (6) */
0x29, 0x08, /* USAGE_MAXIMUM (8) */
0x15, 0x00, /* LOGICAL_MINIMUM (0) */
0x25, 0x01, /* LOGICAL_MAXIMUM (1) */
0x95, 0x03, /* REPORT_COUNT (3) */
0x75, 0x01, /* REPORT_SIZE (1) */
0xb1, 0x02, /* Feature (Data,Var,Abs) */
0x95, 0x01, /* REPORT_COUNT (1) */
0x75, 0x05, /* REPORT_SIZE (5) */
0x91, 0x01, /* Output (Cnst,Var,Abs) */
0xc0, /* END_COLLECTION */
0xc0, /* END_COLLECTION */
};
static __u8 feature_data[] = { 1, 2 };
struct attach_prog_args {
int prog_fd;
unsigned int hid;
int retval;
int insert_head;
};
struct hid_hw_request_syscall_args {
__u8 data[10];
unsigned int hid;
int retval;
size_t size;
enum hid_report_type type;
__u8 request_type;
};
#define ASSERT_OK(data) ASSERT_FALSE(data)
#define ASSERT_OK_PTR(ptr) ASSERT_NE(NULL, ptr)
#define UHID_LOG(fmt, ...) do { \
if (SHOW_UHID_DEBUG) \
TH_LOG(fmt, ##__VA_ARGS__); \
} while (0)
static pthread_mutex_t uhid_started_mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t uhid_started = PTHREAD_COND_INITIALIZER;
static pthread_mutex_t uhid_output_mtx = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t uhid_output_cond = PTHREAD_COND_INITIALIZER;
static unsigned char output_report[10];
/* no need to protect uhid_stopped, only one thread accesses it */
static bool uhid_stopped;
static int uhid_write(struct __test_metadata *_metadata, int fd, const struct uhid_event *ev)
{
ssize_t ret;
ret = write(fd, ev, sizeof(*ev));
if (ret < 0) {
TH_LOG("Cannot write to uhid: %m");
return -errno;
} else if (ret != sizeof(*ev)) {
TH_LOG("Wrong size written to uhid: %zd != %zu",
ret, sizeof