diff options
| author | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2018-05-21 14:39:40 +0300 | 
|---|---|---|
| committer | Laurent Pinchart <laurent.pinchart@ideasonboard.com> | 2018-05-21 16:33:34 +0300 | 
| commit | 72ec206080350e75a87780895f246f5c4f52e790 (patch) | |
| tree | 76a4813d2adf5b054d6a322142bd6ac9542bd44d | |
| parent | 12c8541a416a73e989f536f2358c369301524825 (diff) | |
events: Import event handling library from omap3-isp-live
The omap3-isp-live project [1] includes a generic event handling library
that implements a select-based loop. Instead of reinventing the wheel,
import the library and use it.
The original license hasn't been modified, and includes both GPL-2.0+
and LGPL-2.1+ code. The sole copyright owner is Laurent Pinchart.
[1] git://git.ideasonboard.org/omap3-isp-live.git
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
| -rw-r--r-- | Makefile | 2 | ||||
| -rw-r--r-- | events.c | 183 | ||||
| -rw-r--r-- | events.h | 48 | ||||
| -rw-r--r-- | list.h | 95 | ||||
| -rw-r--r-- | tools.h | 65 | 
5 files changed, 392 insertions, 1 deletions
| @@ -9,7 +9,7 @@ LDFLAGS		:= -g  all: uvc-gadget -uvc-gadget: uvc-gadget.o +uvc-gadget: events.o uvc-gadget.o  	$(CC) $(LDFLAGS) -o $@ $^  clean: diff --git a/events.c b/events.c new file mode 100644 index 0000000..6fcca7d --- /dev/null +++ b/events.c @@ -0,0 +1,183 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Generic Event Handling + * + * Copyright (C) 2018 Laurent Pinchart + * + * This file comes from the omap3-isp-live project + * (git://git.ideasonboard.org/omap3-isp-live.git) + * + * Copyright (C) 2010-2011 Ideas on board SPRL + * + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + */ + +#define _BSD_SOURCE +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <sys/select.h> + +#include "events.h" +#include "list.h" +#include "tools.h" + +#define SELECT_TIMEOUT		2000		/* in milliseconds */ + +struct event_fd { +	struct list_entry list; + +	int fd; +	enum event_type type; +	void (*callback)(void *priv); +	void *priv; +}; + +void events_watch_fd(struct events *events, int fd, enum event_type type, +		     void(*callback)(void *), void *priv) +{ +	struct event_fd *event; + +	event = malloc(sizeof *event); +	if (event == NULL) +		return; + +	event->fd = fd; +	event->type = type; +	event->callback = callback; +	event->priv = priv; + +	switch (event->type) { +	case EVENT_READ: +		FD_SET(fd, &events->rfds); +		break; +	case EVENT_WRITE: +		FD_SET(fd, &events->wfds); +		break; +	case EVENT_EXCEPTION: +		FD_SET(fd, &events->efds); +		break; +	} + +	events->maxfd = max(events->maxfd, fd); + +	list_append(&event->list, &events->events); +} + +void events_unwatch_fd(struct events *events, int fd) +{ +	struct event_fd *event = NULL; +	struct event_fd *entry; +	int maxfd = 0; + +	list_for_each_entry(entry, &events->events, list) { +		if (entry->fd == fd) +			event = entry; +		else +			maxfd = max(maxfd, entry->fd); +	} + +	if (event == NULL) +		return; + +	switch (event->type) { +	case EVENT_READ: +		FD_CLR(fd, &events->rfds); +		break; +	case EVENT_WRITE: +		FD_CLR(fd, &events->wfds); +		break; +	case EVENT_EXCEPTION: +		FD_CLR(fd, &events->efds); +		break; +	} + +	events->maxfd = maxfd; + +	list_remove(&event->list); +	free(event); +} + +static void events_dispatch(struct events *events, const fd_set *rfds, +			    const fd_set *wfds, const fd_set *efds) +{ +	struct event_fd *event; +	struct event_fd *next; + +	list_for_each_entry_safe(event, next, &events->events, list) { +		if (event->type == EVENT_READ && +		    FD_ISSET(event->fd, rfds)) +			event->callback(event->priv); +		else if (event->type == EVENT_WRITE && +			 FD_ISSET(event->fd, wfds)) +			event->callback(event->priv); +		else if (event->type == EVENT_EXCEPTION && +			 FD_ISSET(event->fd, efds)) +			event->callback(event->priv); + +		/* If the callback stopped events processing, we're done. */ +		if (events->done) +			break; +	} +} + +bool events_loop(struct events *events) +{ +	events->done = false; + +	while (!events->done) { +		struct timeval timeout; +		fd_set rfds; +		fd_set wfds; +		fd_set efds; +		int ret; + +		timeout.tv_sec = SELECT_TIMEOUT / 1000; +		timeout.tv_usec = (SELECT_TIMEOUT % 1000) * 1000; +		rfds = events->rfds; +		wfds = events->wfds; +		efds = events->efds; + +		ret = select(events->maxfd + 1, &rfds, &wfds, &efds, &timeout); +		if (ret < 0) { +			/* EINTR means that a signal has been received, continue +			 * to the next iteration in that case. +			 */ +			if (errno == EINTR) +				continue; + +			printf("error: select failed with %d\n", errno); +			break; +		} +		if (ret == 0) { +			/* select() should never time out as the ISP is supposed +			 * to capture images continuously. A timeout is thus +			 * considered as a fatal error. +			 */ +			printf("error: select timeout\n"); +			break; +		} + +		events_dispatch(events, &rfds, &wfds, &efds); +	} + +	return !events->done; +} + +void events_stop(struct events *events) +{ +	events->done = true; +} + +void events_init(struct events *events) +{ +	memset(events, 0, sizeof *events); + +	FD_ZERO(&events->rfds); +	FD_ZERO(&events->wfds); +	FD_ZERO(&events->efds); +	events->maxfd = 0; +	list_init(&events->events); +} diff --git a/events.h b/events.h new file mode 100644 index 0000000..b80cd75 --- /dev/null +++ b/events.h @@ -0,0 +1,48 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Generic Event Handling + * + * Copyright (C) 2018 Laurent Pinchart + * + * This file comes from the omap3-isp-live project + * (git://git.ideasonboard.org/omap3-isp-live.git) + * + * Copyright (C) 2010-2011 Ideas on board SPRL + * + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + */ + +#ifndef __EVENTS_H__ +#define __EVENTS_H__ + +#include <stdbool.h> +#include <sys/select.h> + +#include "list.h" + +struct events { +	struct list_entry events; +	bool done; + +	int maxfd; +	fd_set rfds; +	fd_set wfds; +	fd_set efds; +}; + +enum event_type { +	EVENT_READ = 1, +	EVENT_WRITE = 2, +	EVENT_EXCEPTION = 4, +}; + +void events_watch_fd(struct events *events, int fd, enum event_type type, +		     void(*callback)(void *), void *priv); +void events_unwatch_fd(struct events *events, int fd); + +bool events_loop(struct events *events); +void events_stop(struct events *events); + +void events_init(struct events *events); + +#endif @@ -0,0 +1,95 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Double Linked Lists + * + * Copyright (C) 2018 Laurent Pinchart + * + * This file comes from the omap3-isp-live project + * (git://git.ideasonboard.org/omap3-isp-live.git) + * + * Copyright (C) 2010-2011 Ideas on board SPRL + * + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + */ + +#ifndef __LIST_H +#define __LIST_H + +#include <stddef.h> + +struct list_entry { +	struct list_entry *prev; +	struct list_entry *next; +}; + +static inline void list_init(struct list_entry *list) +{ +	list->next = list; +	list->prev = list; +} + +static inline int list_empty(struct list_entry *list) +{ +	return list->next == list; +} + +static inline void list_append(struct list_entry *entry, struct list_entry *list) +{ +	entry->next = list; +	entry->prev = list->prev; +	list->prev->next = entry; +	list->prev = entry; +} + +static inline void list_prepend(struct list_entry *entry, struct list_entry *list) +{ +	entry->next = list->next; +	entry->prev = list; +	list->next->prev = entry; +	list->next = entry; +} + +static inline void list_insert_after(struct list_entry *entry, struct list_entry *after) +{ +	list_prepend(entry, after); +} + +static inline void list_insert_before(struct list_entry *entry, struct list_entry *before) +{ +	list_append(entry, before); +} + +static inline void list_remove(struct list_entry *entry) +{ +	entry->prev->next = entry->next; +	entry->next->prev = entry->prev; +} + +#define list_entry(entry, type, member) \ +	(type *)((char *)(entry) - offsetof(type, member)) + +#define list_first_entry(list, type, member) \ +	list_entry((list)->next, type, member) + +#define list_last_entry(list, type, member) \ +	list_entry((list)->prev, type, member) + +#define list_for_each(entry, list) \ +	for (entry = (list)->next; entry != (list); entry = entry->next) + +#define list_for_each_entry(entry, list, member) \ +	for (entry = list_entry((list)->next, typeof(*entry), member); \ +	     &entry->member != (list); \ +	     entry = list_entry(entry->member.next, typeof(*entry), member)) + +#define list_for_each_safe(entry, __next, list) \ +	for (entry = (list)->next, __next = entry->next; entry != (list); \ +	     entry = __next, __next = entry->next) + +#define list_for_each_entry_safe(entry, __next, list, member) \ +	for (entry = list_entry((list)->next, typeof(*entry), member), \ +	     __next = list_entry(entry->member.next, typeof(*entry), member); \ +	     &entry->member != (list); \ +	     entry = __next, __next = list_entry(entry->member.next, typeof(*entry), member)) + +#endif /* __LIST_H */ @@ -0,0 +1,65 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Miscellaneous Tools + * + * Copyright (C) 2018 Laurent Pinchart + * + * This file comes from the omap3-isp-live project + * (git://git.ideasonboard.org/omap3-isp-live.git) + * + * Copyright (C) 2010-2011 Ideas on board SPRL + * + * Contact: Laurent Pinchart <laurent.pinchart@ideasonboard.com> + */ + +#ifndef __TOOLS_H__ +#define __TOOLS_H__ + +#define ARRAY_SIZE(array)	(sizeof(array) / sizeof((array)[0])) + +#define min(a, b) ({				\ +	typeof(a) __a = (a);			\ +	typeof(b) __b = (b);			\ +	__a < __b ? __a : __b;			\ +}) + +#define min_t(type, a, b) ({			\ +	type __a = (a);				\ +	type __b = (b);				\ +	__a < __b ? __a : __b;			\ +}) + +#define max(a, b) ({				\ +	typeof(a) __a = (a);			\ +	typeof(b) __b = (b);			\ +	__a > __b ? __a : __b;			\ +}) + +#define max_t(type, a, b) ({			\ +	type __a = (a);				\ +	type __b = (b);				\ +	__a > __b ? __a : __b;			\ +}) + +#define clamp(val, min, max) ({			\ +	typeof(val) __val = (val);		\ +	typeof(min) __min = (min);		\ +	typeof(max) __max = (max);		\ +	__val = __val < __min ? __min : __val;	\ +	__val > __max ? __max : __val;		\ +}) + +#define clamp_t(type, val, min, max) ({		\ +	type __val = (val);			\ +	type __min = (min);			\ +	type __max = (max);			\ +	__val = __val < __min ? __min : __val;	\ +	__val > __max ? __max : __val;		\ +}) + +#define div_round_up(num, denom)	(((num) + (denom) - 1) / (denom)) + +#define container_of(ptr, type, member) \ +	(type *)((char *)(ptr) - offsetof(type, member)) + +#endif /* __TOOLS_H__ */ | 
