diff options
-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__ */ |