The bbcr broke off my compilation help plz
This commit is contained in:
parent
91a639852f
commit
37c23e1b62
28 changed files with 1042 additions and 1256 deletions
327
dev_in.c
Normal file
327
dev_in.c
Normal file
|
|
@ -0,0 +1,327 @@
|
|||
#include "dev_in.h"
|
||||
#include "message.h"
|
||||
#include "dev_evdev.h"
|
||||
#include <libevdev-1.0/libevdev/libevdev.h>
|
||||
|
||||
typedef enum dev_in_type {
|
||||
DEV_IN_TYPE_NONE,
|
||||
DEV_IN_TYPE_HIDRAW,
|
||||
DEV_IN_TYPE_IIO,
|
||||
DEV_IN_TYPE_EV,
|
||||
} dev_in_type_t;
|
||||
|
||||
typedef struct dev_in_iio {
|
||||
|
||||
int fd;
|
||||
|
||||
} dev_in_iio_t;
|
||||
|
||||
typedef struct dev_in_ev {
|
||||
bool ignore_msc_scan;
|
||||
|
||||
bool ignore_timestamp;
|
||||
|
||||
struct libevdev* evdev;
|
||||
|
||||
bool grabbed;
|
||||
|
||||
bool has_syn_report;
|
||||
|
||||
bool has_rumble_support;
|
||||
|
||||
struct ff_effect ff_effect;
|
||||
|
||||
} dev_in_ev_t;
|
||||
|
||||
typedef union dev_in_aggr {
|
||||
dev_in_ev_t evdev;
|
||||
dev_in_iio_t iio;
|
||||
} dev_in_aggr_t;
|
||||
|
||||
typedef struct dev_in {
|
||||
|
||||
dev_in_type_t type;
|
||||
|
||||
dev_in_aggr_t dev;
|
||||
|
||||
} dev_in_t;
|
||||
|
||||
static int fill_message_from_iio(dev_in_iio_t *const in_evdev, in_message_t *const out_msg) {
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
static int fill_message_from_evdev(dev_in_ev_t *const in_evdev, in_message_t *const out_msg) {
|
||||
int res = 0;
|
||||
|
||||
struct input_event read_ev;
|
||||
|
||||
// reset the events count
|
||||
out_msg->data.event.ev_count = 0;
|
||||
|
||||
// if the device does not support syn reports read just one event and return
|
||||
if (!in_evdev->has_syn_report) {
|
||||
res = libevdev_next_event(in_evdev->evdev, LIBEVDEV_READ_FLAG_NORMAL, &read_ev);
|
||||
if (res < 0) {
|
||||
goto fill_message_from_evdev_err;
|
||||
}
|
||||
|
||||
// just copy the input event
|
||||
out_msg->data.event.ev[out_msg->data.event.ev_count++] = read_ev;
|
||||
|
||||
goto fill_message_from_evdev_err_completed;
|
||||
}
|
||||
|
||||
// the device does support syn reports so read every event until one is found
|
||||
while (out_msg->data.event.ev_count < MAX_EVDEV_EVENTS_IN_MESSAGE) {
|
||||
res = libevdev_next_event(in_evdev->evdev, LIBEVDEV_READ_FLAG_BLOCKING, &read_ev);
|
||||
if (res < 0) {
|
||||
goto fill_message_from_evdev_err;
|
||||
}
|
||||
|
||||
// if the message is a syn_report exit the while as there are no more events
|
||||
if ((read_ev.type == EV_SYN) && (read_ev.code == SYN_REPORT)) {
|
||||
break;
|
||||
} else if ((in_evdev->ignore_msc_scan) && (read_ev.type == EV_MSC) && (read_ev.code == MSC_SCAN)) {
|
||||
continue;
|
||||
} else if ((in_evdev->ignore_timestamp) && (read_ev.type == EV_MSC) && (read_ev.code == MSC_TIMESTAMP)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// just copy the input event
|
||||
out_msg->data.event.ev[out_msg->data.event.ev_count++] = read_ev;
|
||||
}
|
||||
|
||||
fill_message_from_evdev_err:
|
||||
fill_message_from_evdev_err_completed:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int fill_message_from_device(dev_in_t *const in_dev, in_message_t *const out_msg) {
|
||||
if (in_dev->type == DEV_IN_TYPE_EV) {
|
||||
return fill_message_from_evdev(&in_dev->dev.evdev, out_msg);
|
||||
} else if (in_dev->type == DEV_IN_TYPE_EV) {
|
||||
return fill_message_from_iio(&in_dev->dev.iio, out_msg);
|
||||
}
|
||||
|
||||
fprintf(stderr, "Unable to recognise device type\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
int open_device(
|
||||
const uinput_filters_t *const in_filters,
|
||||
dev_in_ev_t *const out_dev
|
||||
) {
|
||||
int res = dev_evdev_open(in_filters, out_dev->evdev);
|
||||
if (res != 0) {
|
||||
fprintf(stderr, "Unable to open the specified device: %d\n", res);
|
||||
goto open_device_err;
|
||||
}
|
||||
|
||||
out_dev->has_rumble_support = libevdev_has_event_type(out_dev->evdev, EV_FF) && libevdev_has_event_code(out_dev->evdev, EV_FF, FF_RUMBLE);
|
||||
|
||||
const int grab_res = libevdev_grab(out_dev->evdev, LIBEVDEV_GRAB);
|
||||
out_dev->grabbed = grab_res == 0;
|
||||
if (!out_dev->grabbed) {
|
||||
fprintf(stderr, "Unable to grab the device (%s): %d.\n", libevdev_get_name(out_dev->evdev), grab_res);
|
||||
}
|
||||
|
||||
if (out_dev->has_rumble_support) {
|
||||
printf("Opened device\n name: %s\n rumble: %s\n",
|
||||
libevdev_get_name(out_dev->evdev),
|
||||
libevdev_has_event_code(out_dev->evdev, EV_FF, FF_RUMBLE) ? "true" : "false"
|
||||
);
|
||||
|
||||
// prepare the rumble effect
|
||||
out_dev->ff_effect.type = FF_RUMBLE;
|
||||
out_dev->ff_effect.id = -1;
|
||||
out_dev->ff_effect.replay.delay = 0;
|
||||
out_dev->ff_effect.replay.length = 5000;
|
||||
out_dev->ff_effect.u.rumble.strong_magnitude = 0x0000;
|
||||
out_dev->ff_effect.u.rumble.weak_magnitude = 0x0000;
|
||||
|
||||
const struct input_event gain = {
|
||||
.type = EV_FF,
|
||||
.code = FF_GAIN,
|
||||
.value = 0xFFFF, // TODO: give the user the ability to change this
|
||||
};
|
||||
|
||||
const int gain_set_res = write(libevdev_get_fd(out_dev->evdev), (const void*)&gain, sizeof(gain));
|
||||
if (gain_set_res != sizeof(gain)) {
|
||||
fprintf(stderr, "Unable to adjust gain for force-feedback: %d\n", gain_set_res);
|
||||
} else {
|
||||
printf("Gain for force-feedback set to %u for device %s\n", gain.value, libevdev_get_name(out_dev->evdev));
|
||||
}
|
||||
|
||||
} else {
|
||||
printf("Opened device\n name: %s\n rumble: no force-feedback\n",
|
||||
libevdev_get_name(out_dev->evdev)
|
||||
);
|
||||
}
|
||||
|
||||
open_device_err:
|
||||
return res;
|
||||
}
|
||||
|
||||
static void handle_rumble_device(dev_in_ev_t *const in_dev, const out_message_rumble_t *const in_rumble_msg) {
|
||||
if (!in_dev->has_rumble_support) {
|
||||
return;
|
||||
}
|
||||
|
||||
int fd = libevdev_get_fd(in_dev->evdev);
|
||||
|
||||
// here stop the previous rumble
|
||||
if (in_dev->ff_effect.id != -1) {
|
||||
struct input_event rumble_stop = {
|
||||
.type = EV_FF,
|
||||
.code = in_dev->ff_effect.id,
|
||||
.value = 0,
|
||||
};
|
||||
|
||||
const int rumble_stop_res = write(fd, (const void*) &rumble_stop, sizeof(rumble_stop));
|
||||
if (rumble_stop_res != sizeof(rumble_stop)) {
|
||||
fprintf(stderr, "Unable to stop the previous rumble: %d\n", rumble_stop_res);
|
||||
}
|
||||
}
|
||||
|
||||
// load the new effect data
|
||||
in_dev->ff_effect.u.rumble.strong_magnitude = in_rumble_msg->strong_magnitude;
|
||||
in_dev->ff_effect.u.rumble.weak_magnitude = in_rumble_msg->weak_magnitude;
|
||||
|
||||
// upload the new effect to the device
|
||||
const int effect_upload_res = ioctl(fd, EVIOCSFF, &in_dev->ff_effect);
|
||||
if (effect_upload_res == 0) {
|
||||
const struct input_event rumble_play = {
|
||||
.type = EV_FF,
|
||||
.code = in_dev->ff_effect.id,
|
||||
.value = 1,
|
||||
};
|
||||
|
||||
const int effect_start_res = write(fd, (const void*)&rumble_play, sizeof(rumble_play));
|
||||
if (effect_start_res == sizeof(rumble_play)) {
|
||||
#if defined(INCLUDE_INPUT_DEBUG)
|
||||
printf("Rumble effect play requested to driver\n");
|
||||
#endif
|
||||
} else {
|
||||
fprintf(stderr, "Unable to write input event starting the rumble: %d\n", effect_start_res);
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Unable to update force-feedback effect: %d\n", effect_upload_res);
|
||||
|
||||
in_dev->ff_effect.id = -1;
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_rumble(dev_in_t *const in_devs, size_t in_devs_count, const out_message_rumble_t *const in_rumble_msg) {
|
||||
for (size_t i = 0; i < in_devs_count; ++i) {
|
||||
if (in_devs[i].type == DEV_IN_TYPE_EV) {
|
||||
handle_rumble_device(&in_devs[i].dev.evdev, in_rumble_msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void* dev_in_thread_func(void *ptr) {
|
||||
dev_in_data_t *const devs = (dev_in_data_t*)ptr;
|
||||
|
||||
struct timeval timeout = {
|
||||
.tv_sec = (__time_t)devs->timeout_ms / (__time_t)1000,
|
||||
.tv_usec = ((__suseconds_t)devs->timeout_ms % (__suseconds_t)1000) * (__suseconds_t)1000000,
|
||||
};
|
||||
|
||||
fd_set read_fds;
|
||||
|
||||
dev_in_t* const devices = malloc(sizeof(dev_in_t) * devs->input_dev_cnt);
|
||||
if (devices == NULL) {
|
||||
fprintf(stderr, "Unable to allocate memory to hold devices -- aborting input thread\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// flag every device as disconnected
|
||||
for (size_t i = 0; i < devs->input_dev_cnt; ++i) {
|
||||
devices[i].type = DEV_IN_TYPE_NONE;
|
||||
}
|
||||
|
||||
in_message_t current_message;
|
||||
|
||||
for (;;) {
|
||||
FD_ZERO(&read_fds);
|
||||
FD_SET(devs->in_message_pipe_fd, &read_fds);
|
||||
for (size_t i = 0; i < devs->input_dev_cnt; ++i) {
|
||||
int fd = -1;
|
||||
if (devices[i].type == DEV_IN_TYPE_EV) {
|
||||
fd = libevdev_get_fd(devices[i].dev.evdev.evdev);
|
||||
} else if (devices[i].type == DEV_IN_TYPE_IIO) {
|
||||
|
||||
} else if (devices[i].type == DEV_IN_TYPE_NONE) {
|
||||
fprintf(stderr, "Device %zu not found -- Attempt reconnection", i);
|
||||
|
||||
if (devs->input_dev_decl[i].dev_type == input_dev_type_uinput) {
|
||||
const int open_res = open_device(&devs->input_dev_decl[i].filters.ev, &devices[i].dev.evdev);
|
||||
if (open_res == 0) {
|
||||
devices[i].type = DEV_IN_TYPE_EV;
|
||||
fd = libevdev_get_fd(devices[i].dev.evdev.evdev);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
FD_SET(fd, &read_fds);
|
||||
}
|
||||
|
||||
int ready_fds = select(FD_SETSIZE, &read_fds, NULL, NULL, &timeout);
|
||||
|
||||
if (ready_fds == -1) {
|
||||
const int err = errno;
|
||||
fprintf(stderr, "Error reading devices: %d\n", err);
|
||||
continue;
|
||||
} else if (ready_fds == 0) {
|
||||
// Timeout... simply retry
|
||||
continue;
|
||||
}
|
||||
|
||||
// check for messages incoming like set leds or activate rumble
|
||||
if (FD_ISSET(devs->out_message_pipe_fd, &read_fds)) {
|
||||
out_message_t out_msg;
|
||||
const ssize_t out_message_pipe_read_res = read(devs->out_message_pipe_fd, (void*)&out_msg, sizeof(out_message_t));
|
||||
if (out_message_pipe_read_res == sizeof(out_message_t)) {
|
||||
if (out_msg.type == OUT_MSG_TYPE_RUMBLE) {
|
||||
handle_rumble(devices, devs->input_dev_cnt, &out_msg.data.rumble);
|
||||
} else if (out_msg.type == OUT_MSG_TYPE_LEDS) {
|
||||
// TODO: handle LEDs
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Unable to read message: %zd\n", out_message_pipe_read_res);
|
||||
}
|
||||
}
|
||||
|
||||
// the following is only executed when there is actual data in at least one of the fd
|
||||
for (size_t i = 0; i < devs->input_dev_cnt; ++i) {
|
||||
int fd = -1;
|
||||
if (devices[i].type == DEV_IN_TYPE_EV) {
|
||||
fd = libevdev_get_fd(devices[i].dev.evdev.evdev);
|
||||
} else if (devices[i].type == DEV_IN_TYPE_IIO) {
|
||||
|
||||
}
|
||||
|
||||
if (!FD_ISSET(fd, &read_fds)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int fill_msg_res = fill_message_from_device(&devices[i], ¤t_message);
|
||||
if (!fill_msg_res) {
|
||||
fprintf(stderr, "Error reading from selected input device (%zu): %d\n", i, fill_msg_res);
|
||||
continue;
|
||||
}
|
||||
|
||||
const ssize_t in_message_pipe_write_res = write(devs->in_message_pipe_fd, (void*)¤t_message, sizeof(in_message_t));
|
||||
if (in_message_pipe_write_res != sizeof(in_message_t)) {
|
||||
fprintf(stderr, "Unable to write data to the in_message pipe: %zu\n", in_message_pipe_write_res);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: free every fd
|
||||
free(devices);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue