diff options
| -rw-r--r-- | evdev.c | 496 | ||||
| -rw-r--r-- | evdev.h | 19 | ||||
| -rw-r--r-- | makefile | 2 | ||||
| -rw-r--r-- | monster.cfg | 24 | 
4 files changed, 190 insertions, 351 deletions
| @@ -1,17 +1,25 @@ -#include <linux/input.h>  #include <fcntl.h>  #include <stdio.h>  #include <errno.h>  #include <string.h>  #include <unistd.h> -#include <linux/uinput.h>  #include <sys/ioctl.h> +#include <libevdev/libevdev.h> +#include <libevdev/libevdev-uinput.h>  #include "midimonster.h"  #include "evdev.h"  #define BACKEND_NAME "evdev" -#define UINPUT_PATH "/dev/uinput" + +typedef union { +	struct { +		uint32_t pad; +		uint16_t type; +		uint16_t code; +	} fields; +	uint64_t label; +} evdev_channel_ident;  int init(){  	backend evdev = { @@ -35,383 +43,232 @@ int init(){  }  static int evdev_configure(char* option, char* value) { -	//intentionally ignored -	return 0; -} - -static int evdev_configure_instance(instance* inst, char* option, char* value) { -	evdev_instance_data* data = (evdev_instance_data*) inst->impl; - -	if (!strcmp(option, "device")) { -		if (data->device_path) { -			free(data->device_path); -		} -		data->device_path = strdup(value); - -		if (!data->device_path) { -			fprintf(stderr, "Failed to allocate memory for device path: %s\n", strerror(errno)); -			return 1; -		} -	} else if (!strcmp(option, "exclusive")) { -		data->exclusive = strtoul(value, NULL, 10); -	} else if (!strcmp(option, "name")) { -		if (data->name) { -			free(data->name); -		} - -		data->name = strdup(value); - -		if (!data->name) { -			fprintf(stderr, "Failed to allocate memory for name: %s\n", strerror(errno)); -			return 1; -		} -	} else { -		fprintf(stderr, "Unkown configuration parameter %s for evdev backend\n", option); -		return 1; -	} -	return 0; +	fprintf(stderr, "The evdev backend does not take any global configuration\n"); +	return 1;  } -static channel* evdev_channel(instance* inst, char* spec) { -	evdev_instance_data* data = (evdev_instance_data*) inst->impl; -	char* next = spec; -	// type -	unsigned long type = strtoul(spec, &next, 10); - -	if (spec == next) { -		fprintf(stderr, "Cannot parse type\n"); -		return NULL; -	} - -	if (type >= EV_MAX) { -		fprintf(stderr, "Type is out of range\n"); +static instance* evdev_instance(){ +	instance* inst = mm_instance(); +	if(!inst){  		return NULL;  	} -	if (next[0] != '.') { -		fprintf(stderr, "Cannot parse code. Unknown character %c\n", next[0]); +	evdev_instance_data* data = calloc(1, sizeof(evdev_instance_data)); +	if(!data){ +		fprintf(stderr, "Failed to allocate memory\n");  		return NULL;  	} -	spec = next + 1; - -	unsigned long code = strtoul(spec, &next, 10); +	data->input_fd = -1; +	data->output_fd = -1; -	if (spec == next) { -		fprintf(stderr, "Cannot parse code\n"); -		return NULL; -	} +	inst->impl = data; +	return inst; +} -	if (type == EV_SYN && code >= SYN_MAX) { -		fprintf(stderr, "Code is out of range. Limit for SYN is %d\n", SYN_MAX); -	} else if (type == EV_KEY && code >= KEY_MAX) { -		fprintf(stderr, "Code is out of range. Limit for KEY is %d\n", KEY_MAX); -		return NULL; -	} else if (type == EV_REL && code >= REL_MAX) { -		fprintf(stderr, "Code is out of range. Limit for REL is %d\n", REL_MAX); -		return NULL; -	} else if (type == EV_ABS && code >= ABS_MAX) { -		fprintf(stderr, "Code is out of range. Limit for ABS is %d\n", ABS_MAX); -		return NULL; -	} else if (type == EV_SW && code >= SW_MAX) { -		fprintf(stderr, "Code is out of range. Limit for SW is %d\n", SW_MAX); -		return NULL; -	} else if (type == EV_MSC && code >= MSC_MAX) { -		fprintf(stderr, "Code is out of range. Limit for MSC is %d\n", MSC_MAX); -		return NULL; -	} else if (type == EV_LED && code >= LED_MAX) { -		fprintf(stderr, "Code is out of range. Limit for LED is %d\n", LED_MAX); -		return NULL; -	} else if (type == EV_REP && code >= REP_MAX) { -		fprintf(stderr, "Code is out of range. Limit for REP is %d\n", REP_MAX); -		return NULL; -	} else if (type == EV_SND && code >= SND_MAX) { -		fprintf(stderr, "Code is out of range. Limit for SND is %d\n", SND_MAX); -	} +static int evdev_configure_instance(instance* inst, char* option, char* value) { +	evdev_instance_data* data = (evdev_instance_data*) inst->impl; -	uint64_t u; -	if (next[0] == '.') { -		spec = next + 1; -		long value = strtol(spec, &next, 10); -		if (spec == next) { -			fprintf(stderr, "Cannot parse value\n"); -			return NULL; -		} -		if (type == EV_KEY && (value != 0 && value != 1)) { -			fprintf(stderr, "Value of KEY %ld is out of range. Only values 0 and 1 are supported for KEY.\n", value); -			return NULL; -		} -		// find event with value -		for (u = 0; u < data->size_events; u++) { -			if (data->events[u].type == type -					&& data->events[u].code == code -					&& data->events[u].value == value) { -				break; -			} -		} -	} else if (next[0] != '\0') { -		fprintf(stderr, "Unkown characters: %s\n", next); -		return NULL; -	} else { -		// find event -		for (u = 0; u < data->size_events; u++) { -			if (data->events[u].type == type -					&& data->events[u].code == code) { -				break; -			} +	if(!strcmp(option, "input")){ +		if(data->input_fd >= 0){ +			fprintf(stderr, "Instance %s already was assigned an input device\n", inst->name); +			return 1;  		} -	} - -	// check if no event was found -	if (u == data->size_events) { -		fprintf(stderr, "Alloc dev %ld: %ld, %ld\n", u, type, code); -		data->events = realloc(data->events, (u + 1) * sizeof(struct input_event)); -		if (!data->events) { -			fprintf(stderr, "Failed to allocate memory\n"); -			return NULL; +		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;  		} -		data->events[u].type = (uint16_t) type; -		data->events[u].code = (uint16_t) code; -		data->size_events++; -	} -	return mm_channel(inst, u, 1); -} - -static instance* evdev_instance() { -	instance* inst = mm_instance(); -	if (!inst) { -		return NULL; -	} - -	inst->impl = calloc(1, sizeof(evdev_instance_data)); -	if (!inst->impl) { -		fprintf(stderr, "Failed to allocate memory for instance\n"); -		return NULL; -	} -	return inst; -} +		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; +		} -static channel_value evdev_normalize(evdev_instance_data* data, uint64_t ident, struct input_event* event) { -	channel_value value = {}; - -	switch (event->type) { -		case EV_KEY: -			value.normalised = event->value > 0; -			break; -		case EV_REL: -			if (event->value > 0) { -				value.normalised = 1.0; -			} else { -				value.normalised = 0.0; -			} -			break; +		if(data->exclusive && libevdev_grab(data->input_ev, LIBEVDEV_GRAB)){ +			fprintf(stderr, "Failed to obtain exclusive device access on %s\n", value); +		}  	} - -	return value; -} - -static uint32_t evdev_convert_normalised(struct input_event event, channel_value* value) { -	switch (event.type) { -		case EV_KEY: -			return value->normalised < 0.5; -		case EV_REL: -			return (value->normalised < 0.5) - 1; -		default: -			return value->normalised < 0.5; +	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;  	} -} - - -static int evdev_handle(size_t num, managed_fd* fds) { -	struct input_event event; -	ssize_t bytes = 0; -	uint64_t ident; - -	evdev_instance_data* data; - -	channel* channel; -	for (int i = 0; i < num; i++) { -		bytes = read(fds[i].fd, &event, sizeof(struct input_event)); - -		if (bytes < sizeof(struct input_event)) { -			fprintf(stderr, "Failed to read an complete event\n"); +	else if (!strcmp(option, "name")){ +		if(data->output_name){ +			fprintf(stderr, "Instance %s evdev device name already assigned\n", inst->name);  			return 1;  		} -		data = (evdev_instance_data*) fds[0].impl; -		for (ident = 0; ident < data->size_events; ident++) { -			if (data->events[ident].type == event.type -					&& data->events[ident].code == event.code) { -				break; -			} -		} -		fprintf(stderr, "Found event: %d, %d, %d (%ld/%ld)\n", event.type, event.code, event.value, ident, data->size_events); -		if (ident >= data->size_events) { -			fprintf(stderr, "Event not registered.\n"); -			continue; -		} -		channel = mm_channel(mm_instance_find(BACKEND_NAME, data->ident), ident, 0); - -		if (channel) { -			fprintf(stderr, "Channel found\n"); -			if (mm_channel_event(channel, evdev_normalize(data, ident, &event))) { -				return 1; -			} +		data->output_name = strdup(value); +		if (!data->output_name) { +			fprintf(stderr, "Failed to allocate memory\n"); +			return 1;  		}  	} - +	else{ +		fprintf(stderr, "Unknown configuration parameter %s for evdev backend\n", option); +		return 1; +	}  	return 0;  } -static int evdev_open_input_device(evdev_instance_data* data) { -	if (!data->device_path) { -		return 0; +static channel* evdev_channel(instance* inst, char* spec) { +	char* separator = strchr(spec, '.'); +	evdev_instance_data* data = (evdev_instance_data*) inst->impl; +	evdev_channel_ident ident = { +		.label = 0 +	}; + +	if(!separator){ +		fprintf(stderr, "Invalid evdev channel specification %s\n", spec); +		return NULL;  	} -	data->fd_in = open(data->device_path, O_RDONLY | O_NONBLOCK); +	*(separator++) = 0; -	if (data->fd_in < 0) { -		fprintf(stderr, "Failed to open device %s: %s\n", data->device_path, strerror(errno)); -		return 1; -	} -	int grab = data->exclusive; -	if (ioctl(data->fd_in, EVIOCGRAB, &grab) > 0) { -		fprintf(stderr, "Cannot set exclusive lock on device %s\n", data->device_path); -		close(data->fd_in); -		data->fd_in = -1; -		return 1; +	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 (!mm_manage_fd(data->fd_in, BACKEND_NAME, 1, data)) { -		return 1; +	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);  	} -	return 0; +	//TODO If allowing output, push to enable list +	return mm_channel(inst, ident.label, 1);  } -static int enable_device_keys(evdev_instance_data* data, int uinput_fd, struct uinput_user_dev* dev) { -	unsigned int u; -	int ret; -	int action; -	uint8_t first_bits[EV_CNT]; -	memset(first_bits, 0, EV_CNT * sizeof(uint8_t)); -	for (u = 0; u < data->size_events; u++) { -		if (data->events[u].type < EV_MAX && !first_bits[data->events[u].type]) { -			ret = ioctl(uinput_fd, UI_SET_EVBIT, data->events[u].type); - -			if (ret < 0) { -				fprintf(stderr, "Cannot enable type: %d\n", data->events[u].type); -				return 1; -			} -		} -		switch (data->events[u].type) { -			case EV_KEY: -				action = UI_SET_KEYBIT; -				break; -			case EV_ABS: -				action = UI_SET_ABSBIT; -				break; +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: -				action = UI_SET_RELBIT; +				val.normalised = 0.5 + ((event.value < 0) ? 0.5 : -0.5);  				break; -			case EV_MSC: -				action = UI_SET_MSCBIT; +			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: -				fprintf(stderr, "Event code not supported: %d\n", data->events[u].type); -				return 1; +				val.normalised = 1.0 * event.value; +				break;  		} -		ret = ioctl(uinput_fd,  action, data->events[u].code); -		if (ret < 0) { -			fprintf(stderr, "Cannot enable code: %d\n", data->events[u].code); +		if(mm_channel_event(chan, val)){ +			fprintf(stderr, "Failed to push evdev channel event to core\n");  			return 1;  		}  	} +  	return 0;  } -static int uinput_create_output_device(evdev_instance_data* data) { - -	int uinput_fd = open(UINPUT_PATH, O_WRONLY | O_NONBLOCK); +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 (uinput_fd < 0) { -		fprintf(stderr, "Cannot open uinput device: %s\n", strerror(errno)); -		return 1; +	if(!num){ +		return 0;  	} -	struct uinput_user_dev dev = {}; -	memset(&dev, 0, sizeof(dev)); -	strncpy(dev.name, data->name, UINPUT_MAX_NAME_SIZE - 1); -	dev.id.bustype = 0; -	dev.id.vendor = 0; -	dev.id.product = 0; -	dev.id.version = 0; - -	if (enable_device_keys(data, uinput_fd, &dev)) { -		close(uinput_fd); -		return 1; -	} -	// write config to uinput -	int ret = write(uinput_fd, &dev, sizeof(dev)); +	for(fd = 0; fd < num; fd++){ +		inst = (instance*) fds[fd].impl; +		if(!inst){ +			fprintf(stderr, "evdev backend signaled for unknown fd\n"); +			continue; +		} -	if (ret < 0) { -		fprintf(stderr, "Cannot write to uinput device: %s\n", strerror(errno)); -		close(uinput_fd); -		return 1; -	} +		data = (evdev_instance_data*) inst->impl; -	ret = ioctl(uinput_fd, UI_DEV_CREATE); +		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; +			} -	if (ret < 0) { -		fprintf(stderr, "Cannot create device: %s\n", strerror(errno)); -		close(uinput_fd); -		return 1; +			//handle event +			if(evdev_push_event(inst, data, ev)){ +				return 1; +			} +		}  	} -	data->fd_out = uinput_fd; -  	return 0;  }  static int evdev_start() { -	size_t n; +	size_t n, u, fds = 0;  	instance** inst = NULL; -	evdev_instance_data* data; -	if (mm_backend_instances(BACKEND_NAME, &n, &inst)) { +	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) { +	if(!n){  		free(inst);  		return 0;  	} -	for (unsigned p = 0; p < n; p++) { -		data = (evdev_instance_data*) inst[p]->impl; +	for(u = 0; u < n; u++){ +		data = (evdev_instance_data*) inst[u]->impl; -		if (data->name) { -			uinput_create_output_device(data); +		if(data->output_name) { +			//TODO +			//if(evdev_create_output(data)){ +			//	return 1; +			//}  		} -		if (data->device_path) { -			evdev_open_input_device(data); +		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++;  		} -		data->ident = p; -		inst[p]->ident = data->ident; +  	} +	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) { -	size_t u; +	if(!num){ +		return 0; +	} +/*	size_t u;  	evdev_instance_data* data; -	uint64_t ident;  	int ret;  	struct input_event event = {}; @@ -438,47 +295,38 @@ static int evdev_set(instance* inst, size_t num, channel** c, channel_value* v)  		}  	} +	return 0;*/ +	fprintf(stderr, "Awaiting rework, %zu channels signaled\n", num);  	return 0;  }  static int evdev_shutdown() {  	evdev_instance_data* data = NULL;  	instance** instances = NULL; -	size_t n = 0; +	size_t n, u; -	if (mm_backend_instances(BACKEND_NAME, &n, &instances)) { +	if(mm_backend_instances(BACKEND_NAME, &n, &instances)){  		fprintf(stderr, "Failed to fetch instance list\n");  		return 1;  	} -	if (!n) { -		free(instances); -		return 0; -	} +	for(u = 0; u < n; u++){ +		data = (evdev_instance_data*) instances[u]->impl; -	for (unsigned p = 0; p < n; p++) { -		data = (evdev_instance_data*) instances[p]->impl; -		if (data->fd_in < 0) { -			close(data->fd_in); -			data->fd_in = -1; +		if(data->input_fd >= 0){ +			libevdev_free(data->input_ev); +			close(data->input_fd);  		} -		if (data->fd_out < 0) { -			int ret = ioctl(data->fd_out, UI_DEV_DESTROY); - -			if (ret < 0) { -				fprintf(stderr, "Could not destroy device: %s\n", strerror(errno)); -				return 1; -			} -			close(data->fd_out); -			data->fd_out = -1; +		if(data->output_fd >= 0){ +			libevdev_uinput_destroy(data->output_ev); +			close(data->output_fd);  		} -		free(data->events); -		free(data->name); -		free(data->device_path); -		free(data); +		free(data->output_name); +		free(data->enabled_events);  	} +  	free(instances);  	return 0;  } @@ -13,14 +13,15 @@ static int evdev_handle(size_t num, managed_fd* fds);  static int evdev_start();  static int evdev_shutdown(); -/* uinput_instance */ -typedef struct { -	int ident; -	char* device_path; -	char* name; -	int fd_in; -	int fd_out; +typedef struct /*_evdev_instance_model*/ { +	int input_fd; +	struct libevdev* input_ev;  	int exclusive; -	size_t size_events; -	struct input_event* events; + +	int output_fd; +	char* output_name; +	struct libevdev_uinput* output_ev; + +	size_t nenabled_events; +	struct input_event* enabled_events;  } evdev_instance_data; @@ -11,6 +11,8 @@ CFLAGS ?= -g -Wall  midimonster: LDLIBS = -ldl  midimonster: CFLAGS += -rdynamic -DPLUGINS=$(PLUGINDIR)  midi.so: LDLIBS = -lasound +evdev.so: CFLAGS += $(shell pkg-config --cflags libevdev) +evdev.so: LDLIBS = $(shell pkg-config --libs libevdev)  %.so :: %.c %.h diff --git a/monster.cfg b/monster.cfg index 558478e..ba0e94a 100644 --- a/monster.cfg +++ b/monster.cfg @@ -1,25 +1,13 @@  [backend midi]  name = MIDIMonster -[backend artnet] -bind = * -net = 0 +[evdev test] +input = /dev/input/event14 -[artnet net1] -iface = 0 -uni = 0 -dest = 255.255.255.255 +[midi foo] -[osc osc1] -bind = * 8000 -dest = learn@8001 -/1/fader1 = f 0.0 1.0 -/1/fader2 = f 0.0 1.0 -/1/fader3 = f 0.0 1.0 -/1/fader4 = f 0.0 1.0 -/1/xy = ff 0.0 1.0 0.0 1.0  [map] -osc1./1/xy:0 <> net1.1+2 -osc1./1/xy:1 <> net1.3+4 -osc1./1/fader1 <> net1.20+21 +test.EV_ABS.ABS_X > foo.cc0.81 +test.EV_ABS.ABS_GAS > foo.cc0.82 +test.EV_KEY.BTN_SOUTH > foo.cc0.83 | 
