summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile2
-rw-r--r--events.c183
-rw-r--r--events.h48
-rw-r--r--list.h95
-rw-r--r--tools.h65
5 files changed, 392 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 4837ec9..490e268 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/list.h b/list.h
new file mode 100644
index 0000000..8854c6e
--- /dev/null
+++ b/list.h
@@ -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 */
diff --git a/tools.h b/tools.h
new file mode 100644
index 0000000..ff2f908
--- /dev/null
+++ b/tools.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__ */