aboutsummaryrefslogtreecommitdiffhomepage
path: root/evdev.c
diff options
context:
space:
mode:
authorcbdev <cb@cbcdn.com>2018-03-02 03:20:11 +0100
committercbdev <cb@cbcdn.com>2018-03-02 03:20:11 +0100
commit2dfc564edc0c89c4a8de7e384806aae5d593426d (patch)
treeb1636ec14d3f35ed88b3f079e0c3d168f77b17b9 /evdev.c
parentbe5df1c4e639ca6a7cd70a3122039a1de4588e28 (diff)
downloadmidimonster-2dfc564edc0c89c4a8de7e384806aae5d593426d.tar.gz
midimonster-2dfc564edc0c89c4a8de7e384806aae5d593426d.tar.bz2
midimonster-2dfc564edc0c89c4a8de7e384806aae5d593426d.zip
Move backend implementations to subdirectory
Diffstat (limited to 'evdev.c')
-rw-r--r--evdev.c401
1 files changed, 0 insertions, 401 deletions
diff --git a/evdev.c b/evdev.c
deleted file mode 100644
index ac63850..0000000
--- a/evdev.c
+++ /dev/null
@@ -1,401 +0,0 @@
-#include <fcntl.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <libevdev/libevdev.h>
-#ifndef EVDEV_NO_UINPUT
-#include <libevdev/libevdev-uinput.h>
-#endif
-
-#include "midimonster.h"
-#include "evdev.h"
-
-#define BACKEND_NAME "evdev"
-
-typedef union {
- struct {
- uint32_t pad;
- uint16_t type;
- uint16_t code;
- } fields;
- uint64_t label;
-} evdev_channel_ident;
-
-int init(){
- backend evdev = {
- .name = BACKEND_NAME,
- .conf = evdev_configure,
- .create = evdev_instance,
- .conf_instance = evdev_configure_instance,
- .channel = evdev_channel,
- .handle = evdev_set,
- .process = evdev_handle,
- .start = evdev_start,
- .shutdown = evdev_shutdown
- };
-
- if(mm_backend_register(evdev)){
- fprintf(stderr, "Failed to register evdev backend\n");
- return 1;
- }
-
- return 0;
-}
-
-static int evdev_configure(char* option, char* value) {
- fprintf(stderr, "The evdev backend does not take any global configuration\n");
- return 1;
-}
-
-static instance* evdev_instance(){
- instance* inst = mm_instance();
- if(!inst){
- return NULL;
- }
-
- evdev_instance_data* data = calloc(1, sizeof(evdev_instance_data));
- if(!data){
- fprintf(stderr, "Failed to allocate memory\n");
- return NULL;
- }
-
- data->input_fd = -1;
-#ifndef EVDEV_NO_UINPUT
- data->output_proto = libevdev_new();
- if(!data->output_proto){
- fprintf(stderr, "Failed to initialize libevdev output prototype device\n");
- free(data);
- return NULL;
- }
-#endif
-
- inst->impl = data;
- return inst;
-}
-
-static int evdev_configure_instance(instance* inst, char* option, char* value) {
- evdev_instance_data* data = (evdev_instance_data*) inst->impl;
-#ifndef EVDEV_NO_UINPUT
- char* next_token = NULL;
- struct input_absinfo abs_info = {
- 0
- };
-#endif
-
- if(!strcmp(option, "input")){
- if(data->input_fd >= 0){
- fprintf(stderr, "Instance %s already was assigned an input device\n", inst->name);
- return 1;
- }
-
- data->input_fd = open(value, O_RDONLY | O_NONBLOCK);
- if(data->input_fd < 0){
- fprintf(stderr, "Failed to open evdev input device node %s: %s\n", value, strerror(errno));
- return 1;
- }
-
- if(libevdev_new_from_fd(data->input_fd, &data->input_ev)){
- fprintf(stderr, "Failed to initialize libevdev for %s\n", value);
- close(data->input_fd);
- data->input_fd = -1;
- return 1;
- }
-
- if(data->exclusive && libevdev_grab(data->input_ev, LIBEVDEV_GRAB)){
- fprintf(stderr, "Failed to obtain exclusive device access on %s\n", value);
- }
- }
- else if(!strcmp(option, "exclusive")){
- if(data->input_fd >= 0 && libevdev_grab(data->input_ev, LIBEVDEV_GRAB)){
- fprintf(stderr, "Failed to obtain exclusive device access on %s\n", inst->name);
- }
- data->exclusive = 1;
- }
-#ifndef EVDEV_NO_UINPUT
- else if(!strcmp(option, "name")){
- data->output_enabled = 1;
- libevdev_set_name(data->output_proto, value);
- }
- else if(!strcmp(option, "id")){
- next_token = value;
- libevdev_set_id_vendor(data->output_proto, strtol(next_token, &next_token, 0));
- libevdev_set_id_product(data->output_proto, strtol(next_token, &next_token, 0));
- libevdev_set_id_version(data->output_proto, strtol(next_token, &next_token, 0));
- }
- else if(!strncmp(option, "axis.", 5)){
- //value minimum maximum fuzz flat resolution
- next_token = value;
- abs_info.value = strtol(next_token, &next_token, 0);
- abs_info.minimum = strtol(next_token, &next_token, 0);
- abs_info.maximum = strtol(next_token, &next_token, 0);
- abs_info.fuzz = strtol(next_token, &next_token, 0);
- abs_info.flat = strtol(next_token, &next_token, 0);
- abs_info.resolution = strtol(next_token, &next_token, 0);
- if(libevdev_enable_event_code(data->output_proto, EV_ABS, libevdev_event_code_from_name(EV_ABS, option + 5), &abs_info)){
- fprintf(stderr, "Failed to enable absolute axis %s for output\n", option + 5);
- return 1;
- }
- }
-#endif
- else{
- fprintf(stderr, "Unknown configuration parameter %s for evdev backend\n", option);
- return 1;
- }
- return 0;
-}
-
-static channel* evdev_channel(instance* inst, char* spec){
-#ifndef EVDEV_NO_UINPUT
- evdev_instance_data* data = (evdev_instance_data*) inst->impl;
-#endif
- char* separator = strchr(spec, '.');
- evdev_channel_ident ident = {
- .label = 0
- };
-
- if(!separator){
- fprintf(stderr, "Invalid evdev channel specification %s\n", spec);
- return NULL;
- }
-
- *(separator++) = 0;
-
- if(libevdev_event_type_from_name(spec) < 0){
- fprintf(stderr, "Invalid evdev type specification: %s", spec);
- return NULL;
- }
- ident.fields.type = libevdev_event_type_from_name(spec);
-
- if(libevdev_event_code_from_name(ident.fields.type, separator) >= 0){
- ident.fields.code = libevdev_event_code_from_name(ident.fields.type, separator);
- }
- else{
- fprintf(stderr, "evdev Code name not recognized, using as number: %s\n", separator);
- ident.fields.code = strtoul(separator, NULL, 10);
- }
-
-#ifndef EVDEV_NO_UINPUT
- if(data->output_enabled){
- if(!libevdev_has_event_code(data->output_proto, ident.fields.type, ident.fields.code)){
- //enable the event on the device
- //the previous check is necessary to not fail while enabling axes, which require additional information
- if(libevdev_enable_event_code(data->output_proto, ident.fields.type, ident.fields.code, NULL)){
- fprintf(stderr, "Failed to enable output event %s.%s%s\n",
- libevdev_event_type_get_name(ident.fields.type),
- libevdev_event_code_get_name(ident.fields.type, ident.fields.code),
- (ident.fields.type == EV_ABS) ? ": To output absolute axes, specify their details in the configuration":"");
- return NULL;
- }
- }
- }
-#endif
-
- return mm_channel(inst, ident.label, 1);
-}
-
-static int evdev_push_event(instance* inst, evdev_instance_data* data, struct input_event event){
- uint64_t range = 0;
- channel_value val;
- evdev_channel_ident ident = {
- .fields.type = event.type,
- .fields.code = event.code
- };
- channel* chan = mm_channel(inst, ident.label, 0);
-
- if(chan){
- val.raw.u64 = event.value;
- switch(event.type){
- case EV_REL:
- val.normalised = 0.5 + ((event.value < 0) ? 0.5 : -0.5);
- break;
- case EV_ABS:
- range = libevdev_get_abs_maximum(data->input_ev, event.code) - libevdev_get_abs_minimum(data->input_ev, event.code);
- val.normalised = (event.value - libevdev_get_abs_minimum(data->input_ev, event.code)) / (double) range;
- break;
- case EV_KEY:
- case EV_SW:
- default:
- val.normalised = 1.0 * event.value;
- break;
- }
-
- if(mm_channel_event(chan, val)){
- fprintf(stderr, "Failed to push evdev channel event to core\n");
- return 1;
- }
- }
-
- return 0;
-}
-
-static int evdev_handle(size_t num, managed_fd* fds){
- instance* inst = NULL;
- evdev_instance_data* data = NULL;
- size_t fd;
- unsigned int read_flags = LIBEVDEV_READ_FLAG_NORMAL;
- int read_status;
- struct input_event ev;
-
- if(!num){
- return 0;
- }
-
- for(fd = 0; fd < num; fd++){
- inst = (instance*) fds[fd].impl;
- if(!inst){
- fprintf(stderr, "evdev backend signaled for unknown fd\n");
- continue;
- }
-
- data = (evdev_instance_data*) inst->impl;
-
- for(read_status = libevdev_next_event(data->input_ev, read_flags, &ev); read_status >= 0; read_status = libevdev_next_event(data->input_ev, read_flags, &ev)){
- read_flags = LIBEVDEV_READ_FLAG_NORMAL;
- if(read_status == LIBEVDEV_READ_STATUS_SYNC){
- read_flags = LIBEVDEV_READ_FLAG_SYNC;
- }
-
- //handle event
- if(evdev_push_event(inst, data, ev)){
- return 1;
- }
- }
- }
-
- return 0;
-}
-
-static int evdev_start(){
- size_t n, u, fds = 0;
- instance** inst = NULL;
- evdev_instance_data* data = NULL;
-
- if(mm_backend_instances(BACKEND_NAME, &n, &inst)){
- fprintf(stderr, "Failed to fetch instance list\n");
- return 1;
- }
-
- if(!n){
- free(inst);
- return 0;
- }
-
- for(u = 0; u < n; u++){
- data = (evdev_instance_data*) inst[u]->impl;
-
-#ifndef EVDEV_NO_UINPUT
- if(data->output_enabled){
- if(libevdev_uinput_create_from_device(data->output_proto, LIBEVDEV_UINPUT_OPEN_MANAGED, &data->output_ev)){
- fprintf(stderr, "Failed to create evdev output device: %s\n", strerror(errno));
- return 1;
- }
- fprintf(stderr, "Created device node %s for instance %s\n", libevdev_uinput_get_devnode(data->output_ev), inst[u]->name);
- }
-#endif
-
- inst[u]->ident = data->input_fd;
- if(data->input_fd >= 0){
- if(mm_manage_fd(data->input_fd, BACKEND_NAME, 1, inst[u])){
- fprintf(stderr, "Failed to register event input descriptor for instance %s\n", inst[u]->name);
- free(inst);
- return 1;
- }
- fds++;
- }
-
- }
-
- fprintf(stderr, "evdev backend registered %zu descriptors to core\n", fds);
- free(inst);
- return 0;
-}
-
-static int evdev_set(instance* inst, size_t num, channel** c, channel_value* v) {
-#ifndef EVDEV_NO_UINPUT
- size_t evt = 0;
- evdev_instance_data* data = (evdev_instance_data*) inst->impl;
- evdev_channel_ident ident = {
- .label = 0
- };
- int32_t value = 0;
- uint64_t range = 0;
-
- if(!num){
- return 0;
- }
-
- if(!data->output_enabled){
- fprintf(stderr, "Instance %s not enabled for output\n", inst->name);
- return 0;
- }
-
- for(evt = 0; evt < num; evt++){
- ident.label = c[evt]->ident;
-
- switch(ident.fields.type){
- case EV_REL:
- value = (v[evt].normalised < 0.5) ? -1 : ((v[evt].normalised > 0.5) ? 1 : 0);
- break;
- case EV_ABS:
- range = libevdev_get_abs_maximum(data->output_proto, ident.fields.code) - libevdev_get_abs_minimum(data->output_proto, ident.fields.code);
- value = (range * v[evt].normalised) + libevdev_get_abs_minimum(data->output_proto, ident.fields.code);
- break;
- case EV_KEY:
- case EV_SW:
- default:
- value = (v[evt].normalised > 0.9) ? 1 : 0;
- break;
- }
-
- if(libevdev_uinput_write_event(data->output_ev, ident.fields.type, ident.fields.code, value)){
- fprintf(stderr, "Failed to output event on instance %s\n", inst->name);
- return 1;
- }
- }
-
- //send syn event to publish all events
- if(libevdev_uinput_write_event(data->output_ev, EV_SYN, SYN_REPORT, 0)){
- fprintf(stderr, "Failed to output sync event on instance %s\n", inst->name);
- return 1;
- }
-
- return 0;
-#else
- fprintf(stderr, "The evdev backend does not support output on this platform\n");
- return 1;
-#endif
-}
-
-static int evdev_shutdown(){
- evdev_instance_data* data = NULL;
- instance** instances = NULL;
- size_t n, u;
-
- if(mm_backend_instances(BACKEND_NAME, &n, &instances)){
- fprintf(stderr, "Failed to fetch instance list\n");
- return 1;
- }
-
- for(u = 0; u < n; u++){
- data = (evdev_instance_data*) instances[u]->impl;
-
- if(data->input_fd >= 0){
- libevdev_free(data->input_ev);
- close(data->input_fd);
- }
-
-#ifndef EVDEV_NO_UINPUT
- if(data->output_enabled){
- libevdev_uinput_destroy(data->output_ev);
- }
-
- libevdev_free(data->output_proto);
-#endif
- free(data);
- }
-
- free(instances);
- return 0;
-}